1 /************************************************************************** 2 SPDX-License-Identifier: BSD-3-Clause 3 4 Copyright (c) 2007-2010, Chelsio Inc. 5 All rights reserved. 6 7 Redistribution and use in source and binary forms, with or without 8 modification, are permitted provided that the following conditions are met: 9 10 1. Redistributions of source code must retain the above copyright notice, 11 this list of conditions and the following disclaimer. 12 13 2. Redistributions in binary form must reproduce the above copyright 14 notice, this list of conditions and the following disclaimer in the 15 documentation and/or other materials provided with the distribution. 16 17 3. Neither the name of the Chelsio Corporation nor the names of its 18 contributors may be used to endorse or promote products derived from 19 this software without specific prior written permission. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 POSSIBILITY OF SUCH DAMAGE. 32 33 34 ***************************************************************************/ 35 #include <sys/cdefs.h> 36 #include <stdlib.h> 37 #include <stdio.h> 38 #include <stdint.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <fcntl.h> 42 #include <err.h> 43 #include <errno.h> 44 #include <inttypes.h> 45 #include <sys/param.h> 46 #include <sys/time.h> 47 #include <sys/ioctl.h> 48 #include <sys/socket.h> 49 50 #include <netinet/in.h> 51 #include <arpa/inet.h> 52 53 #include <net/if.h> 54 #include <net/if_types.h> 55 #include <sys/endian.h> 56 57 #define NMTUS 16 58 #define TCB_SIZE 128 59 #define TCB_WORDS (TCB_SIZE / 4) 60 #define PROTO_SRAM_LINES 128 61 #define PROTO_SRAM_LINE_BITS 132 62 #define PROTO_SRAM_LINE_NIBBLES (132 / 4) 63 #define PROTO_SRAM_SIZE (PROTO_SRAM_LINE_NIBBLES * PROTO_SRAM_LINES / 2) 64 #define PROTO_SRAM_EEPROM_ADDR 4096 65 66 #include <cxgb_ioctl.h> 67 #include <common/cxgb_regs.h> 68 #include "version.h" 69 70 struct reg_info { 71 const char *name; 72 uint16_t addr; 73 uint16_t len; 74 }; 75 76 77 #include "reg_defs.c" 78 #if defined(CONFIG_T3_REGS) 79 # include "reg_defs_t3.c" 80 # include "reg_defs_t3b.c" 81 # include "reg_defs_t3c.c" 82 #endif 83 84 static const char *progname; 85 86 static void 87 usage(FILE *fp) 88 { 89 fprintf(fp, "Usage: %s <interface> [operation]\n", progname); 90 fprintf(fp, 91 "\tclearstats clear MAC statistics\n" 92 "\tcontext <type> <id> show an SGE context\n" 93 "\tdesc <qset> <queue> <idx> [<cnt>] dump SGE descriptors\n" 94 "\tfilter <idx> [<param> <val>] ... set a filter\n" 95 "\tfilter <idx> delete|clear delete a filter\n" 96 "\tfilter list list all filters\n" 97 "\tioqs dump uP IOQs\n" 98 "\tla dump uP logic analyzer info\n" 99 "\tloadboot <boot image> download boot image\n" 100 "\tloadfw <FW image> download firmware\n" 101 "\tmdio <phy_addr> <mmd_addr>\n" 102 "\t <reg_addr> [<val>] read/write MDIO register\n" 103 "\tmemdump cm|tx|rx <addr> <len> dump a mem range\n" 104 "\tmeminfo show memory info\n" 105 "\tmtus [<mtu0>...<mtuN>] read/write MTU table\n" 106 "\tpktsched port <idx> <min> <max> set TX port scheduler params\n" 107 "\tpktsched tunnelq <idx> <max>\n" 108 "\t <binding> set TX tunnelq scheduler params\n" 109 "\tpktsched tx <idx>\n" 110 "\t [<param> <val>] ... set Tx HW scheduler\n" 111 "\tpm [<TX page spec> <RX page spec>] read/write PM config\n" 112 "\tproto read proto SRAM\n" 113 "\tqset read qset parameters\n" 114 "\tqsets read # of qsets\n" 115 "\treg <address>[=<val>] read/write register\n" 116 "\tregdump [<module>] dump registers\n" 117 "\ttcamdump <address> <count> show TCAM contents\n" 118 "\ttcb <index> read TCB\n" 119 "\ttrace tx|rx|all on|off [not]\n" 120 "\t [<param> <val>[:<mask>]] ... write trace parameters\n" 121 ); 122 exit(fp == stderr ? 1 : 0); 123 } 124 125 static int 126 doit(const char *iff_name, unsigned long cmd, void *data) 127 { 128 static int fd = 0; 129 130 if (fd == 0) { 131 char buf[64]; 132 snprintf(buf, 64, "/dev/%s", iff_name); 133 134 if ((fd = open(buf, O_RDWR)) < 0) 135 return -1; 136 } 137 138 return ioctl(fd, cmd, data) < 0 ? -1 : 0; 139 } 140 141 static int 142 get_int_arg(const char *s, uint32_t *valp) 143 { 144 char *p; 145 146 *valp = strtoul(s, &p, 0); 147 if (*p) { 148 warnx("bad parameter \"%s\"", s); 149 return -1; 150 } 151 return 0; 152 } 153 154 static uint32_t 155 read_reg(const char *iff_name, uint32_t addr) 156 { 157 struct ch_reg reg; 158 159 reg.addr = addr; 160 161 if (doit(iff_name, CHELSIO_GETREG, ®) < 0) 162 err(1, "register read"); 163 return reg.val; 164 } 165 166 static void 167 write_reg(const char *iff_name, uint32_t addr, uint32_t val) 168 { 169 struct ch_reg ch_reg; 170 171 ch_reg.addr = addr; 172 ch_reg.val = val; 173 174 if (doit(iff_name, CHELSIO_SETREG, &ch_reg) < 0) 175 err(1, "register write"); 176 } 177 178 static int 179 register_io(int argc, char *argv[], int start_arg, 180 const char *iff_name) 181 { 182 char *p; 183 uint32_t addr, val = 0, w = 0; 184 185 if (argc != start_arg + 1) return -1; 186 187 addr = strtoul(argv[start_arg], &p, 0); 188 if (p == argv[start_arg]) return -1; 189 if (*p == '=' && p[1]) { 190 val = strtoul(p + 1, &p, 0); 191 w = 1; 192 } 193 if (*p) { 194 warnx("bad parameter \"%s\"", argv[start_arg]); 195 return -1; 196 } 197 198 if (w) 199 write_reg(iff_name, addr, val); 200 else { 201 val = read_reg(iff_name, addr); 202 printf("%#x [%u]\n", val, val); 203 } 204 return 0; 205 } 206 207 static int 208 mdio_io(int argc, char *argv[], int start_arg, const char *iff_name) 209 { 210 struct ch_mii_data p; 211 unsigned int cmd, phy_addr, reg, mmd, val; 212 213 if (argc == start_arg + 3) 214 cmd = CHELSIO_GET_MIIREG; 215 else if (argc == start_arg + 4) 216 cmd = CHELSIO_SET_MIIREG; 217 else 218 return -1; 219 220 if (get_int_arg(argv[start_arg], &phy_addr) || 221 get_int_arg(argv[start_arg + 1], &mmd) || 222 get_int_arg(argv[start_arg + 2], ®) || 223 (cmd == CHELSIO_SET_MIIREG && get_int_arg(argv[start_arg + 3], &val))) 224 return -1; 225 226 p.phy_id = phy_addr | (mmd << 8); 227 p.reg_num = reg; 228 p.val_in = val; 229 230 if (doit(iff_name, cmd, &p) < 0) 231 err(1, "MDIO %s", cmd == CHELSIO_GET_MIIREG ? "read" : "write"); 232 if (cmd == CHELSIO_GET_MIIREG) 233 printf("%#x [%u]\n", p.val_out, p.val_out); 234 return 0; 235 } 236 237 static inline 238 uint32_t xtract(uint32_t val, int shift, int len) 239 { 240 return (val >> shift) & ((1 << len) - 1); 241 } 242 243 static int 244 dump_block_regs(const struct reg_info *reg_array, uint32_t *regs) 245 { 246 uint32_t reg_val = 0; // silence compiler warning 247 248 for ( ; reg_array->name; ++reg_array) 249 if (!reg_array->len) { 250 reg_val = regs[reg_array->addr / 4]; 251 printf("[%#5x] %-40s %#-10x [%u]\n", reg_array->addr, 252 reg_array->name, reg_val, reg_val); 253 } else { 254 uint32_t v = xtract(reg_val, reg_array->addr, 255 reg_array->len); 256 257 printf(" %-40s %#-10x [%u]\n", reg_array->name, 258 v, v); 259 } 260 return 1; 261 } 262 263 static int 264 dump_regs_t2(int argc, char *argv[], int start_arg, uint32_t *regs) 265 { 266 int match = 0; 267 char *block_name = NULL; 268 269 if (argc == start_arg + 1) 270 block_name = argv[start_arg]; 271 else if (argc != start_arg) 272 return -1; 273 274 if (!block_name || !strcmp(block_name, "sge")) 275 match += dump_block_regs(sge_regs, regs); 276 if (!block_name || !strcmp(block_name, "mc3")) 277 match += dump_block_regs(mc3_regs, regs); 278 if (!block_name || !strcmp(block_name, "mc4")) 279 match += dump_block_regs(mc4_regs, regs); 280 if (!block_name || !strcmp(block_name, "tpi")) 281 match += dump_block_regs(tpi_regs, regs); 282 if (!block_name || !strcmp(block_name, "tp")) 283 match += dump_block_regs(tp_regs, regs); 284 if (!block_name || !strcmp(block_name, "rat")) 285 match += dump_block_regs(rat_regs, regs); 286 if (!block_name || !strcmp(block_name, "cspi")) 287 match += dump_block_regs(cspi_regs, regs); 288 if (!block_name || !strcmp(block_name, "espi")) 289 match += dump_block_regs(espi_regs, regs); 290 if (!block_name || !strcmp(block_name, "ulp")) 291 match += dump_block_regs(ulp_regs, regs); 292 if (!block_name || !strcmp(block_name, "pl")) 293 match += dump_block_regs(pl_regs, regs); 294 if (!block_name || !strcmp(block_name, "mc5")) 295 match += dump_block_regs(mc5_regs, regs); 296 if (!match) 297 errx(1, "unknown block \"%s\"", block_name); 298 return 0; 299 } 300 301 #if defined(CONFIG_T3_REGS) 302 static int 303 dump_regs_t3(int argc, char *argv[], int start_arg, uint32_t *regs, int is_pcie) 304 { 305 int match = 0; 306 char *block_name = NULL; 307 308 if (argc == start_arg + 1) 309 block_name = argv[start_arg]; 310 else if (argc != start_arg) 311 return -1; 312 313 if (!block_name || !strcmp(block_name, "sge")) 314 match += dump_block_regs(sge3_regs, regs); 315 if (!block_name || !strcmp(block_name, "pci")) 316 match += dump_block_regs(is_pcie ? pcie0_regs : pcix1_regs, 317 regs); 318 if (!block_name || !strcmp(block_name, "t3dbg")) 319 match += dump_block_regs(t3dbg_regs, regs); 320 if (!block_name || !strcmp(block_name, "pmrx")) 321 match += dump_block_regs(mc7_pmrx_regs, regs); 322 if (!block_name || !strcmp(block_name, "pmtx")) 323 match += dump_block_regs(mc7_pmtx_regs, regs); 324 if (!block_name || !strcmp(block_name, "cm")) 325 match += dump_block_regs(mc7_cm_regs, regs); 326 if (!block_name || !strcmp(block_name, "cim")) 327 match += dump_block_regs(cim_regs, regs); 328 if (!block_name || !strcmp(block_name, "tp")) 329 match += dump_block_regs(tp1_regs, regs); 330 if (!block_name || !strcmp(block_name, "ulp_rx")) 331 match += dump_block_regs(ulp2_rx_regs, regs); 332 if (!block_name || !strcmp(block_name, "ulp_tx")) 333 match += dump_block_regs(ulp2_tx_regs, regs); 334 if (!block_name || !strcmp(block_name, "pmrx")) 335 match += dump_block_regs(pm1_rx_regs, regs); 336 if (!block_name || !strcmp(block_name, "pmtx")) 337 match += dump_block_regs(pm1_tx_regs, regs); 338 if (!block_name || !strcmp(block_name, "mps")) 339 match += dump_block_regs(mps0_regs, regs); 340 if (!block_name || !strcmp(block_name, "cplsw")) 341 match += dump_block_regs(cpl_switch_regs, regs); 342 if (!block_name || !strcmp(block_name, "smb")) 343 match += dump_block_regs(smb0_regs, regs); 344 if (!block_name || !strcmp(block_name, "i2c")) 345 match += dump_block_regs(i2cm0_regs, regs); 346 if (!block_name || !strcmp(block_name, "mi1")) 347 match += dump_block_regs(mi1_regs, regs); 348 if (!block_name || !strcmp(block_name, "sf")) 349 match += dump_block_regs(sf1_regs, regs); 350 if (!block_name || !strcmp(block_name, "pl")) 351 match += dump_block_regs(pl3_regs, regs); 352 if (!block_name || !strcmp(block_name, "mc5")) 353 match += dump_block_regs(mc5a_regs, regs); 354 if (!block_name || !strcmp(block_name, "xgmac0")) 355 match += dump_block_regs(xgmac0_0_regs, regs); 356 if (!block_name || !strcmp(block_name, "xgmac1")) 357 match += dump_block_regs(xgmac0_1_regs, regs); 358 if (!match) 359 errx(1, "unknown block \"%s\"", block_name); 360 return 0; 361 } 362 363 static int 364 dump_regs_t3b(int argc, char *argv[], int start_arg, uint32_t *regs, 365 int is_pcie) 366 { 367 int match = 0; 368 char *block_name = NULL; 369 370 if (argc == start_arg + 1) 371 block_name = argv[start_arg]; 372 else if (argc != start_arg) 373 return -1; 374 375 if (!block_name || !strcmp(block_name, "sge")) 376 match += dump_block_regs(t3b_sge3_regs, regs); 377 if (!block_name || !strcmp(block_name, "pci")) 378 match += dump_block_regs(is_pcie ? t3b_pcie0_regs : 379 t3b_pcix1_regs, regs); 380 if (!block_name || !strcmp(block_name, "t3dbg")) 381 match += dump_block_regs(t3b_t3dbg_regs, regs); 382 if (!block_name || !strcmp(block_name, "pmrx")) 383 match += dump_block_regs(t3b_mc7_pmrx_regs, regs); 384 if (!block_name || !strcmp(block_name, "pmtx")) 385 match += dump_block_regs(t3b_mc7_pmtx_regs, regs); 386 if (!block_name || !strcmp(block_name, "cm")) 387 match += dump_block_regs(t3b_mc7_cm_regs, regs); 388 if (!block_name || !strcmp(block_name, "cim")) 389 match += dump_block_regs(t3b_cim_regs, regs); 390 if (!block_name || !strcmp(block_name, "tp")) 391 match += dump_block_regs(t3b_tp1_regs, regs); 392 if (!block_name || !strcmp(block_name, "ulp_rx")) 393 match += dump_block_regs(t3b_ulp2_rx_regs, regs); 394 if (!block_name || !strcmp(block_name, "ulp_tx")) 395 match += dump_block_regs(t3b_ulp2_tx_regs, regs); 396 if (!block_name || !strcmp(block_name, "pmrx")) 397 match += dump_block_regs(t3b_pm1_rx_regs, regs); 398 if (!block_name || !strcmp(block_name, "pmtx")) 399 match += dump_block_regs(t3b_pm1_tx_regs, regs); 400 if (!block_name || !strcmp(block_name, "mps")) 401 match += dump_block_regs(t3b_mps0_regs, regs); 402 if (!block_name || !strcmp(block_name, "cplsw")) 403 match += dump_block_regs(t3b_cpl_switch_regs, regs); 404 if (!block_name || !strcmp(block_name, "smb")) 405 match += dump_block_regs(t3b_smb0_regs, regs); 406 if (!block_name || !strcmp(block_name, "i2c")) 407 match += dump_block_regs(t3b_i2cm0_regs, regs); 408 if (!block_name || !strcmp(block_name, "mi1")) 409 match += dump_block_regs(t3b_mi1_regs, regs); 410 if (!block_name || !strcmp(block_name, "sf")) 411 match += dump_block_regs(t3b_sf1_regs, regs); 412 if (!block_name || !strcmp(block_name, "pl")) 413 match += dump_block_regs(t3b_pl3_regs, regs); 414 if (!block_name || !strcmp(block_name, "mc5")) 415 match += dump_block_regs(t3b_mc5a_regs, regs); 416 if (!block_name || !strcmp(block_name, "xgmac0")) 417 match += dump_block_regs(t3b_xgmac0_0_regs, regs); 418 if (!block_name || !strcmp(block_name, "xgmac1")) 419 match += dump_block_regs(t3b_xgmac0_1_regs, regs); 420 if (!match) 421 errx(1, "unknown block \"%s\"", block_name); 422 return 0; 423 } 424 425 static int 426 dump_regs_t3c(int argc, char *argv[], int start_arg, uint32_t *regs, 427 int is_pcie) 428 { 429 int match = 0; 430 char *block_name = NULL; 431 432 if (argc == start_arg + 1) 433 block_name = argv[start_arg]; 434 else if (argc != start_arg) 435 return -1; 436 437 if (!block_name || !strcmp(block_name, "sge")) 438 match += dump_block_regs(t3c_sge3_regs, regs); 439 if (!block_name || !strcmp(block_name, "pci")) 440 match += dump_block_regs(is_pcie ? t3c_pcie0_regs : 441 t3c_pcix1_regs, regs); 442 if (!block_name || !strcmp(block_name, "t3dbg")) 443 match += dump_block_regs(t3c_t3dbg_regs, regs); 444 if (!block_name || !strcmp(block_name, "pmrx")) 445 match += dump_block_regs(t3c_mc7_pmrx_regs, regs); 446 if (!block_name || !strcmp(block_name, "pmtx")) 447 match += dump_block_regs(t3c_mc7_pmtx_regs, regs); 448 if (!block_name || !strcmp(block_name, "cm")) 449 match += dump_block_regs(t3c_mc7_cm_regs, regs); 450 if (!block_name || !strcmp(block_name, "cim")) 451 match += dump_block_regs(t3c_cim_regs, regs); 452 if (!block_name || !strcmp(block_name, "tp")) 453 match += dump_block_regs(t3c_tp1_regs, regs); 454 if (!block_name || !strcmp(block_name, "ulp_rx")) 455 match += dump_block_regs(t3c_ulp2_rx_regs, regs); 456 if (!block_name || !strcmp(block_name, "ulp_tx")) 457 match += dump_block_regs(t3c_ulp2_tx_regs, regs); 458 if (!block_name || !strcmp(block_name, "pmrx")) 459 match += dump_block_regs(t3c_pm1_rx_regs, regs); 460 if (!block_name || !strcmp(block_name, "pmtx")) 461 match += dump_block_regs(t3c_pm1_tx_regs, regs); 462 if (!block_name || !strcmp(block_name, "mps")) 463 match += dump_block_regs(t3c_mps0_regs, regs); 464 if (!block_name || !strcmp(block_name, "cplsw")) 465 match += dump_block_regs(t3c_cpl_switch_regs, regs); 466 if (!block_name || !strcmp(block_name, "smb")) 467 match += dump_block_regs(t3c_smb0_regs, regs); 468 if (!block_name || !strcmp(block_name, "i2c")) 469 match += dump_block_regs(t3c_i2cm0_regs, regs); 470 if (!block_name || !strcmp(block_name, "mi1")) 471 match += dump_block_regs(t3c_mi1_regs, regs); 472 if (!block_name || !strcmp(block_name, "sf")) 473 match += dump_block_regs(t3c_sf1_regs, regs); 474 if (!block_name || !strcmp(block_name, "pl")) 475 match += dump_block_regs(t3c_pl3_regs, regs); 476 if (!block_name || !strcmp(block_name, "mc5")) 477 match += dump_block_regs(t3c_mc5a_regs, regs); 478 if (!block_name || !strcmp(block_name, "xgmac0")) 479 match += dump_block_regs(t3c_xgmac0_0_regs, regs); 480 if (!block_name || !strcmp(block_name, "xgmac1")) 481 match += dump_block_regs(t3c_xgmac0_1_regs, regs); 482 if (!match) 483 errx(1, "unknown block \"%s\"", block_name); 484 return 0; 485 } 486 #endif 487 488 static int 489 dump_regs(int argc, char *argv[], int start_arg, const char *iff_name) 490 { 491 int vers, revision, is_pcie; 492 struct ch_ifconf_regs regs; 493 494 regs.len = REGDUMP_SIZE; 495 496 /* XXX: This is never freed. Looks like we don't care. */ 497 if ((regs.data = malloc(regs.len)) == NULL) 498 err(1, "can't malloc"); 499 500 if (doit(iff_name, CHELSIO_IFCONF_GETREGS, ®s)) 501 err(1, "can't read registers"); 502 503 vers = regs.version & 0x3ff; 504 revision = (regs.version >> 10) & 0x3f; 505 is_pcie = (regs.version & 0x80000000) != 0; 506 507 if (vers <= 2) 508 return dump_regs_t2(argc, argv, start_arg, (uint32_t *)regs.data); 509 #if defined(CONFIG_T3_REGS) 510 if (vers == 3) { 511 if (revision == 0) 512 return dump_regs_t3(argc, argv, start_arg, 513 (uint32_t *)regs.data, is_pcie); 514 if (revision == 2 || revision == 3) 515 return dump_regs_t3b(argc, argv, start_arg, 516 (uint32_t *)regs.data, is_pcie); 517 if (revision == 4) 518 return dump_regs_t3c(argc, argv, start_arg, 519 (uint32_t *)regs.data, is_pcie); 520 } 521 #endif 522 errx(1, "unknown card type %d.%d", vers, revision); 523 return 0; 524 } 525 526 static int 527 t3_meminfo(const uint32_t *regs) 528 { 529 enum { 530 SG_EGR_CNTX_BADDR = 0x58, 531 SG_CQ_CONTEXT_BADDR = 0x6c, 532 CIM_SDRAM_BASE_ADDR = 0x28c, 533 CIM_SDRAM_ADDR_SIZE = 0x290, 534 TP_CMM_MM_BASE = 0x314, 535 TP_CMM_TIMER_BASE = 0x318, 536 TP_CMM_MM_RX_FLST_BASE = 0x460, 537 TP_CMM_MM_TX_FLST_BASE = 0x464, 538 TP_CMM_MM_PS_FLST_BASE = 0x468, 539 ULPRX_ISCSI_LLIMIT = 0x50c, 540 ULPRX_ISCSI_ULIMIT = 0x510, 541 ULPRX_TDDP_LLIMIT = 0x51c, 542 ULPRX_TDDP_ULIMIT = 0x520, 543 ULPRX_STAG_LLIMIT = 0x52c, 544 ULPRX_STAG_ULIMIT = 0x530, 545 ULPRX_RQ_LLIMIT = 0x534, 546 ULPRX_RQ_ULIMIT = 0x538, 547 ULPRX_PBL_LLIMIT = 0x53c, 548 ULPRX_PBL_ULIMIT = 0x540, 549 }; 550 551 unsigned int egr_cntxt = regs[SG_EGR_CNTX_BADDR / 4], 552 cq_cntxt = regs[SG_CQ_CONTEXT_BADDR / 4], 553 timers = regs[TP_CMM_TIMER_BASE / 4] & 0xfffffff, 554 pstructs = regs[TP_CMM_MM_BASE / 4], 555 pstruct_fl = regs[TP_CMM_MM_PS_FLST_BASE / 4], 556 rx_fl = regs[TP_CMM_MM_RX_FLST_BASE / 4], 557 tx_fl = regs[TP_CMM_MM_TX_FLST_BASE / 4], 558 cim_base = regs[CIM_SDRAM_BASE_ADDR / 4], 559 cim_size = regs[CIM_SDRAM_ADDR_SIZE / 4]; 560 unsigned int iscsi_ll = regs[ULPRX_ISCSI_LLIMIT / 4], 561 iscsi_ul = regs[ULPRX_ISCSI_ULIMIT / 4], 562 tddp_ll = regs[ULPRX_TDDP_LLIMIT / 4], 563 tddp_ul = regs[ULPRX_TDDP_ULIMIT / 4], 564 stag_ll = regs[ULPRX_STAG_LLIMIT / 4], 565 stag_ul = regs[ULPRX_STAG_ULIMIT / 4], 566 rq_ll = regs[ULPRX_RQ_LLIMIT / 4], 567 rq_ul = regs[ULPRX_RQ_ULIMIT / 4], 568 pbl_ll = regs[ULPRX_PBL_LLIMIT / 4], 569 pbl_ul = regs[ULPRX_PBL_ULIMIT / 4]; 570 571 printf("CM memory map:\n"); 572 printf(" TCB region: 0x%08x - 0x%08x [%u]\n", 0, egr_cntxt - 1, 573 egr_cntxt); 574 printf(" Egress contexts: 0x%08x - 0x%08x [%u]\n", egr_cntxt, 575 cq_cntxt - 1, cq_cntxt - egr_cntxt); 576 printf(" CQ contexts: 0x%08x - 0x%08x [%u]\n", cq_cntxt, 577 timers - 1, timers - cq_cntxt); 578 printf(" Timers: 0x%08x - 0x%08x [%u]\n", timers, 579 pstructs - 1, pstructs - timers); 580 printf(" Pstructs: 0x%08x - 0x%08x [%u]\n", pstructs, 581 pstruct_fl - 1, pstruct_fl - pstructs); 582 printf(" Pstruct FL: 0x%08x - 0x%08x [%u]\n", pstruct_fl, 583 rx_fl - 1, rx_fl - pstruct_fl); 584 printf(" Rx FL: 0x%08x - 0x%08x [%u]\n", rx_fl, tx_fl - 1, 585 tx_fl - rx_fl); 586 printf(" Tx FL: 0x%08x - 0x%08x [%u]\n", tx_fl, cim_base - 1, 587 cim_base - tx_fl); 588 printf(" uP RAM: 0x%08x - 0x%08x [%u]\n", cim_base, 589 cim_base + cim_size - 1, cim_size); 590 591 printf("\nPMRX memory map:\n"); 592 printf(" iSCSI region: 0x%08x - 0x%08x [%u]\n", iscsi_ll, iscsi_ul, 593 iscsi_ul - iscsi_ll + 1); 594 printf(" TCP DDP region: 0x%08x - 0x%08x [%u]\n", tddp_ll, tddp_ul, 595 tddp_ul - tddp_ll + 1); 596 printf(" TPT region: 0x%08x - 0x%08x [%u]\n", stag_ll, stag_ul, 597 stag_ul - stag_ll + 1); 598 printf(" RQ region: 0x%08x - 0x%08x [%u]\n", rq_ll, rq_ul, 599 rq_ul - rq_ll + 1); 600 printf(" PBL region: 0x%08x - 0x%08x [%u]\n", pbl_ll, pbl_ul, 601 pbl_ul - pbl_ll + 1); 602 return 0; 603 } 604 605 static int 606 meminfo(int argc, char *argv[], int start_arg, const char *iff_name) 607 { 608 int vers; 609 struct ch_ifconf_regs regs; 610 611 (void) argc; 612 (void) argv; 613 (void) start_arg; 614 615 regs.len = REGDUMP_SIZE; 616 if ((regs.data = malloc(regs.len)) == NULL) 617 err(1, "can't malloc"); 618 619 if (doit(iff_name, CHELSIO_IFCONF_GETREGS, ®s)) 620 err(1, "can't read registers"); 621 622 vers = regs.version & 0x3ff; 623 if (vers == 3) 624 return t3_meminfo((uint32_t *)regs.data); 625 626 errx(1, "unknown card type %d", vers); 627 return 0; 628 } 629 630 static int 631 mtu_tab_op(int argc, char *argv[], int start_arg, const char *iff_name) 632 { 633 struct ch_mtus m; 634 unsigned int i; 635 636 if (argc == start_arg) { 637 if (doit(iff_name, CHELSIO_GETMTUTAB, &m) < 0) 638 err(1, "get MTU table"); 639 for (i = 0; i < m.nmtus; ++i) 640 printf("%u ", m.mtus[i]); 641 printf("\n"); 642 } else if (argc <= start_arg + NMTUS) { 643 m.nmtus = argc - start_arg; 644 645 for (i = 0; i < m.nmtus; ++i) { 646 char *p; 647 unsigned long mt = strtoul(argv[start_arg + i], &p, 0); 648 649 if (*p || mt > 9600) { 650 warnx("bad parameter \"%s\"", 651 argv[start_arg + i]); 652 return -1; 653 } 654 if (i && mt < m.mtus[i - 1]) 655 errx(1, "MTUs must be in ascending order"); 656 m.mtus[i] = mt; 657 } 658 if (doit(iff_name, CHELSIO_SETMTUTAB, &m) < 0) 659 err(1, "set MTU table"); 660 } else 661 return -1; 662 663 return 0; 664 } 665 666 #ifdef CHELSIO_INTERNAL 667 static void 668 show_egress_cntxt(uint32_t data[]) 669 { 670 printf("credits: %u\n", data[0] & 0x7fff); 671 printf("GTS: %u\n", (data[0] >> 15) & 1); 672 printf("index: %u\n", data[0] >> 16); 673 printf("queue size: %u\n", data[1] & 0xffff); 674 printf("base address: 0x%" PRIx64 "\n", 675 ((data[1] >> 16) | ((uint64_t)data[2] << 16) | 676 (((uint64_t)data[3] & 0xf) << 48)) << 12); 677 printf("rsp queue #: %u\n", (data[3] >> 4) & 7); 678 printf("cmd queue #: %u\n", (data[3] >> 7) & 1); 679 printf("TUN: %u\n", (data[3] >> 8) & 1); 680 printf("TOE: %u\n", (data[3] >> 9) & 1); 681 printf("generation: %u\n", (data[3] >> 10) & 1); 682 printf("uP token: %u\n", (data[3] >> 11) & 0xfffff); 683 printf("valid: %u\n", (data[3] >> 31) & 1); 684 } 685 686 static void 687 show_fl_cntxt(uint32_t data[]) 688 { 689 printf("base address: 0x%" PRIx64 "\n", 690 ((uint64_t)data[0] | ((uint64_t)data[1] & 0xfffff) << 32) << 12); 691 printf("index: %u\n", (data[1] >> 20) | ((data[2] & 0xf) << 12)); 692 printf("queue size: %u\n", (data[2] >> 4) & 0xffff); 693 printf("generation: %u\n", (data[2] >> 20) & 1); 694 printf("entry size: %u\n", 695 (data[2] >> 21) | (data[3] & 0x1fffff) << 11); 696 printf("congest thr: %u\n", (data[3] >> 21) & 0x3ff); 697 printf("GTS: %u\n", (data[3] >> 31) & 1); 698 } 699 700 static void 701 show_response_cntxt(uint32_t data[]) 702 { 703 printf("index: %u\n", data[0] & 0xffff); 704 printf("size: %u\n", data[0] >> 16); 705 printf("base address: 0x%" PRIx64 "\n", 706 ((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12); 707 printf("MSI-X/RspQ: %u\n", (data[2] >> 20) & 0x3f); 708 printf("intr enable: %u\n", (data[2] >> 26) & 1); 709 printf("intr armed: %u\n", (data[2] >> 27) & 1); 710 printf("generation: %u\n", (data[2] >> 28) & 1); 711 printf("CQ mode: %u\n", (data[2] >> 31) & 1); 712 printf("FL threshold: %u\n", data[3]); 713 } 714 715 static void 716 show_cq_cntxt(uint32_t data[]) 717 { 718 printf("index: %u\n", data[0] & 0xffff); 719 printf("size: %u\n", data[0] >> 16); 720 printf("base address: 0x%" PRIx64 "\n", 721 ((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12); 722 printf("rsp queue #: %u\n", (data[2] >> 20) & 0x3f); 723 printf("AN: %u\n", (data[2] >> 26) & 1); 724 printf("armed: %u\n", (data[2] >> 27) & 1); 725 printf("ANS: %u\n", (data[2] >> 28) & 1); 726 printf("generation: %u\n", (data[2] >> 29) & 1); 727 printf("overflow mode: %u\n", (data[2] >> 31) & 1); 728 printf("credits: %u\n", data[3] & 0xffff); 729 printf("credit threshold: %u\n", data[3] >> 16); 730 } 731 732 static int 733 get_sge_context(int argc, char *argv[], int start_arg, const char *iff_name) 734 { 735 struct ch_cntxt ctx; 736 737 if (argc != start_arg + 2) return -1; 738 739 if (!strcmp(argv[start_arg], "egress")) 740 ctx.cntxt_type = CNTXT_TYPE_EGRESS; 741 else if (!strcmp(argv[start_arg], "fl")) 742 ctx.cntxt_type = CNTXT_TYPE_FL; 743 else if (!strcmp(argv[start_arg], "response")) 744 ctx.cntxt_type = CNTXT_TYPE_RSP; 745 else if (!strcmp(argv[start_arg], "cq")) 746 ctx.cntxt_type = CNTXT_TYPE_CQ; 747 else { 748 warnx("unknown context type \"%s\"; known types are egress, " 749 "fl, cq, and response", argv[start_arg]); 750 return -1; 751 } 752 753 if (get_int_arg(argv[start_arg + 1], &ctx.cntxt_id)) 754 return -1; 755 756 if (doit(iff_name, CHELSIO_GET_SGE_CONTEXT, &ctx) < 0) 757 err(1, "get SGE context"); 758 759 if (!strcmp(argv[start_arg], "egress")) 760 show_egress_cntxt(ctx.data); 761 else if (!strcmp(argv[start_arg], "fl")) 762 show_fl_cntxt(ctx.data); 763 else if (!strcmp(argv[start_arg], "response")) 764 show_response_cntxt(ctx.data); 765 else if (!strcmp(argv[start_arg], "cq")) 766 show_cq_cntxt(ctx.data); 767 return 0; 768 } 769 770 #define ntohll(x) be64toh((x)) 771 772 static int 773 get_sge_desc(int argc, char *argv[], int start_arg, const char *iff_name) 774 { 775 uint64_t *p, wr_hdr; 776 unsigned int n = 1, qset, qnum; 777 struct ch_desc desc; 778 779 if (argc != start_arg + 3 && argc != start_arg + 4) 780 return -1; 781 782 if (get_int_arg(argv[start_arg], &qset) || 783 get_int_arg(argv[start_arg + 1], &qnum) || 784 get_int_arg(argv[start_arg + 2], &desc.idx)) 785 return -1; 786 787 if (argc == start_arg + 4 && get_int_arg(argv[start_arg + 3], &n)) 788 return -1; 789 790 if (qnum > 5) 791 errx(1, "invalid queue number %d, range is 0..5", qnum); 792 793 desc.queue_num = qset * 6 + qnum; 794 795 for (; n--; desc.idx++) { 796 if (doit(iff_name, CHELSIO_GET_SGE_DESC, &desc) < 0) 797 err(1, "get SGE descriptor"); 798 799 p = (uint64_t *)desc.data; 800 wr_hdr = ntohll(*p); 801 printf("Descriptor %u: cmd %u, TID %u, %s%s%s%s%u flits\n", 802 desc.idx, (unsigned int)(wr_hdr >> 56), 803 ((unsigned int)wr_hdr >> 8) & 0xfffff, 804 ((wr_hdr >> 55) & 1) ? "SOP, " : "", 805 ((wr_hdr >> 54) & 1) ? "EOP, " : "", 806 ((wr_hdr >> 53) & 1) ? "COMPL, " : "", 807 ((wr_hdr >> 52) & 1) ? "SGL, " : "", 808 (unsigned int)wr_hdr & 0xff); 809 810 for (; desc.size; p++, desc.size -= sizeof(uint64_t)) 811 printf("%016" PRIx64 "%c", ntohll(*p), 812 desc.size % 32 == 8 ? '\n' : ' '); 813 } 814 return 0; 815 } 816 #endif 817 818 static int 819 get_tcb2(int argc, char *argv[], int start_arg, const char *iff_name) 820 { 821 uint64_t *d; 822 unsigned int i; 823 unsigned int tcb_idx; 824 struct ch_mem_range mr; 825 826 if (argc != start_arg + 1) 827 return -1; 828 829 if (get_int_arg(argv[start_arg], &tcb_idx)) 830 return -1; 831 832 mr.buf = calloc(1, TCB_SIZE); 833 if (!mr.buf) 834 err(1, "get TCB"); 835 836 mr.mem_id = MEM_CM; 837 mr.addr = tcb_idx * TCB_SIZE; 838 mr.len = TCB_SIZE; 839 840 if (doit(iff_name, CHELSIO_GET_MEM, &mr) < 0) 841 err(1, "get TCB"); 842 843 for (d = (uint64_t *)mr.buf, i = 0; i < TCB_SIZE / 32; i++) { 844 printf("%2u:", i); 845 printf(" %08x %08x %08x %08x", (uint32_t)d[1], 846 (uint32_t)(d[1] >> 32), (uint32_t)d[0], 847 (uint32_t)(d[0] >> 32)); 848 d += 2; 849 printf(" %08x %08x %08x %08x\n", (uint32_t)d[1], 850 (uint32_t)(d[1] >> 32), (uint32_t)d[0], 851 (uint32_t)(d[0] >> 32)); 852 d += 2; 853 } 854 free(mr.buf); 855 return 0; 856 } 857 858 static int 859 get_pm_page_spec(const char *s, unsigned int *page_size, 860 unsigned int *num_pages) 861 { 862 char *p; 863 unsigned long val; 864 865 val = strtoul(s, &p, 0); 866 if (p == s) return -1; 867 if (*p == 'x' && p[1]) { 868 *num_pages = val; 869 *page_size = strtoul(p + 1, &p, 0); 870 } else { 871 *num_pages = -1; 872 *page_size = val; 873 } 874 *page_size <<= 10; // KB -> bytes 875 return *p; 876 } 877 878 static int 879 conf_pm(int argc, char *argv[], int start_arg, const char *iff_name) 880 { 881 struct ch_pm pm; 882 883 if (argc == start_arg) { 884 if (doit(iff_name, CHELSIO_GET_PM, &pm) < 0) 885 err(1, "read pm config"); 886 printf("%ux%uKB TX pages, %ux%uKB RX pages, %uKB total memory\n", 887 pm.tx_num_pg, pm.tx_pg_sz >> 10, pm.rx_num_pg, 888 pm.rx_pg_sz >> 10, pm.pm_total >> 10); 889 return 0; 890 } 891 892 if (argc != start_arg + 2) return -1; 893 894 if (get_pm_page_spec(argv[start_arg], &pm.tx_pg_sz, &pm.tx_num_pg)) { 895 warnx("bad parameter \"%s\"", argv[start_arg]); 896 return -1; 897 } 898 if (get_pm_page_spec(argv[start_arg + 1], &pm.rx_pg_sz, 899 &pm.rx_num_pg)) { 900 warnx("bad parameter \"%s\"", argv[start_arg + 1]); 901 return -1; 902 } 903 if (doit(iff_name, CHELSIO_SET_PM, &pm) < 0) 904 err(1, "pm config"); 905 return 0; 906 } 907 908 #ifdef CHELSIO_INTERNAL 909 static int 910 dump_tcam(int argc, char *argv[], int start_arg, const char *iff_name) 911 { 912 unsigned int nwords; 913 struct ch_tcam_word op; 914 915 if (argc != start_arg + 2) return -1; 916 917 if (get_int_arg(argv[start_arg], &op.addr) || 918 get_int_arg(argv[start_arg + 1], &nwords)) 919 return -1; 920 921 while (nwords--) { 922 if (doit(iff_name, CHELSIO_READ_TCAM_WORD, &op) < 0) 923 err(1, "tcam dump"); 924 925 printf("0x%08x: 0x%02x 0x%08x 0x%08x\n", op.addr, 926 op.buf[0] & 0xff, op.buf[1], op.buf[2]); 927 op.addr++; 928 } 929 return 0; 930 } 931 932 static void 933 hexdump_8b(unsigned int start, uint64_t *data, unsigned int len) 934 { 935 int i; 936 937 while (len) { 938 printf("0x%08x:", start); 939 for (i = 0; i < 4 && len; ++i, --len) 940 printf(" %016llx", (unsigned long long)*data++); 941 printf("\n"); 942 start += 32; 943 } 944 } 945 946 static int 947 dump_mc7(int argc, char *argv[], int start_arg, const char *iff_name) 948 { 949 struct ch_mem_range mem; 950 unsigned int mem_id, addr, len; 951 952 if (argc != start_arg + 3) return -1; 953 954 if (!strcmp(argv[start_arg], "cm")) 955 mem_id = MEM_CM; 956 else if (!strcmp(argv[start_arg], "rx")) 957 mem_id = MEM_PMRX; 958 else if (!strcmp(argv[start_arg], "tx")) 959 mem_id = MEM_PMTX; 960 else 961 errx(1, "unknown memory \"%s\"; must be one of \"cm\", \"tx\"," 962 " or \"rx\"", argv[start_arg]); 963 964 if (get_int_arg(argv[start_arg + 1], &addr) || 965 get_int_arg(argv[start_arg + 2], &len)) 966 return -1; 967 968 mem.buf = malloc(len); 969 if (!mem.buf) 970 err(1, "memory dump"); 971 972 mem.mem_id = mem_id; 973 mem.addr = addr; 974 mem.len = len; 975 976 if (doit(iff_name, CHELSIO_GET_MEM, &mem) < 0) 977 err(1, "memory dump"); 978 979 hexdump_8b(mem.addr, (uint64_t *)mem.buf, mem.len >> 3); 980 free(mem.buf); 981 return 0; 982 } 983 #endif 984 985 /* Max FW size is 64K including version, +4 bytes for the checksum. */ 986 #define MAX_FW_IMAGE_SIZE (64 * 1024) 987 988 static int 989 load_fw(int argc, char *argv[], int start_arg, const char *iff_name) 990 { 991 int fd, len; 992 struct ch_mem_range op; 993 const char *fname = argv[start_arg]; 994 995 if (argc != start_arg + 1) return -1; 996 997 fd = open(fname, O_RDONLY); 998 if (fd < 0) 999 err(1, "load firmware"); 1000 1001 bzero(&op, sizeof(op)); 1002 op.buf = malloc(MAX_FW_IMAGE_SIZE + 1); 1003 if (!op.buf) 1004 err(1, "load firmware"); 1005 1006 len = read(fd, op.buf, MAX_FW_IMAGE_SIZE + 1); 1007 if (len < 0) 1008 err(1, "load firmware"); 1009 if (len > MAX_FW_IMAGE_SIZE) 1010 errx(1, "FW image too large"); 1011 1012 op.len = len; 1013 if (doit(iff_name, CHELSIO_LOAD_FW, &op) < 0) 1014 err(1, "load firmware"); 1015 1016 close(fd); 1017 return 0; 1018 } 1019 1020 /* Max BOOT size is 255*512 bytes including the BIOS boot ROM basic header */ 1021 #define MAX_BOOT_IMAGE_SIZE (0xff * 512) 1022 1023 static int 1024 load_boot(int argc, char *argv[], int start_arg, const char *iff_name) 1025 { 1026 int fd, len; 1027 struct ch_mem_range op; 1028 const char *fname = argv[start_arg]; 1029 1030 if (argc != start_arg + 1) return -1; 1031 1032 fd = open(fname, O_RDONLY); 1033 if (fd < 0) 1034 err(1, "load boot image"); 1035 1036 op.buf = malloc(MAX_BOOT_IMAGE_SIZE + 1); 1037 if (!op.buf) 1038 err(1, "load boot image"); 1039 1040 len = read(fd, op.buf, MAX_BOOT_IMAGE_SIZE + 1); 1041 if (len < 0) 1042 err(1, "load boot image"); 1043 if (len > MAX_BOOT_IMAGE_SIZE) 1044 errx(1, "boot image too large"); 1045 1046 op.len = len; 1047 1048 if (doit(iff_name, CHELSIO_LOAD_BOOT, &op) < 0) 1049 err(1, "load boot image"); 1050 1051 close(fd); 1052 return 0; 1053 } 1054 1055 static int 1056 dump_proto_sram(const char *iff_name) 1057 { 1058 int i, j; 1059 uint8_t buf[PROTO_SRAM_SIZE]; 1060 struct ch_eeprom ee; 1061 uint8_t *p = buf; 1062 1063 bzero(buf, sizeof(buf)); 1064 ee.offset = PROTO_SRAM_EEPROM_ADDR; 1065 ee.data = p; 1066 ee.len = sizeof(buf); 1067 if (doit(iff_name, CHELSIO_GET_EEPROM, &ee)) 1068 err(1, "show protocol sram"); 1069 1070 for (i = 0; i < PROTO_SRAM_LINES; i++) { 1071 for (j = PROTO_SRAM_LINE_NIBBLES - 1; j >= 0; j--) { 1072 int nibble_idx = i * PROTO_SRAM_LINE_NIBBLES + j; 1073 uint8_t nibble = p[nibble_idx / 2]; 1074 1075 if (nibble_idx & 1) 1076 nibble >>= 4; 1077 else 1078 nibble &= 0xf; 1079 printf("%x", nibble); 1080 } 1081 putchar('\n'); 1082 } 1083 return 0; 1084 } 1085 1086 static int 1087 proto_sram_op(int argc, char *argv[], int start_arg, 1088 const char *iff_name) 1089 { 1090 (void) argv; 1091 (void) start_arg; 1092 1093 if (argc == start_arg) 1094 return dump_proto_sram(iff_name); 1095 return -1; 1096 } 1097 1098 static int 1099 dump_qset_params(const char *iff_name) 1100 { 1101 struct ch_qset_params qp; 1102 1103 qp.qset_idx = 0; 1104 1105 while (doit(iff_name, CHELSIO_GET_QSET_PARAMS, &qp) == 0) { 1106 if (!qp.qset_idx) 1107 printf("Qset TxQ0 TxQ1 TxQ2 RspQ RxQ0 RxQ1" 1108 " Cong Lat IRQ\n"); 1109 printf("%4u %6u %6u %6u %6u %6u %6u %5u %4u %5d\n", 1110 qp.qnum, 1111 qp.txq_size[0], qp.txq_size[1], qp.txq_size[2], 1112 qp.rspq_size, qp.fl_size[0], qp.fl_size[1], 1113 qp.cong_thres, qp.intr_lat, qp.vector); 1114 qp.qset_idx++; 1115 } 1116 if (!qp.qset_idx || (errno && errno != EINVAL)) 1117 err(1, "get qset parameters"); 1118 return 0; 1119 } 1120 1121 static int 1122 qset_config(int argc, char *argv[], int start_arg, const char *iff_name) 1123 { 1124 (void) argv; 1125 1126 if (argc == start_arg) 1127 return dump_qset_params(iff_name); 1128 1129 return -1; 1130 } 1131 1132 static int 1133 qset_num_config(int argc, char *argv[], int start_arg, const char *iff_name) 1134 { 1135 struct ch_reg reg; 1136 1137 (void) argv; 1138 1139 if (argc == start_arg) { 1140 if (doit(iff_name, CHELSIO_GET_QSET_NUM, ®) < 0) 1141 err(1, "get qsets"); 1142 printf("%u\n", reg.val); 1143 return 0; 1144 } 1145 1146 return -1; 1147 } 1148 1149 /* 1150 * Parse a string containing an IP address with an optional network prefix. 1151 */ 1152 static int 1153 parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask) 1154 { 1155 char *p, *slash; 1156 struct in_addr ia; 1157 1158 *mask = 0xffffffffU; 1159 slash = strchr(s, '/'); 1160 if (slash) 1161 *slash = 0; 1162 if (!inet_aton(s, &ia)) { 1163 if (slash) 1164 *slash = '/'; 1165 *addr = 0; 1166 return -1; 1167 } 1168 *addr = ntohl(ia.s_addr); 1169 if (slash) { 1170 unsigned int prefix = strtoul(slash + 1, &p, 10); 1171 1172 *slash = '/'; 1173 if (p == slash + 1 || *p || prefix > 32) 1174 return -1; 1175 *mask <<= (32 - prefix); 1176 } 1177 return 0; 1178 } 1179 1180 /* 1181 * Parse a string containing a value and an optional colon separated mask. 1182 */ 1183 static int 1184 parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask, 1185 uint32_t default_mask) 1186 { 1187 char *p; 1188 1189 *mask = default_mask; 1190 *val = strtoul(s, &p, 0); 1191 if (p == s || *val > default_mask) 1192 return -1; 1193 if (*p == ':' && p[1]) 1194 *mask = strtoul(p + 1, &p, 0); 1195 return *p || *mask > default_mask ? -1 : 0; 1196 } 1197 1198 static int 1199 parse_trace_param(const char *s, uint32_t *val, uint32_t *mask) 1200 { 1201 return strchr(s, '.') ? parse_ipaddr(s, val, mask) : 1202 parse_val_mask_param(s, val, mask, 0xffffffffU); 1203 } 1204 1205 static int 1206 trace_config(int argc, char *argv[], int start_arg, const char *iff_name) 1207 { 1208 uint32_t val, mask; 1209 struct ch_trace trace; 1210 1211 if (argc == start_arg) 1212 return -1; 1213 1214 memset(&trace, 0, sizeof(trace)); 1215 if (!strcmp(argv[start_arg], "tx")) 1216 trace.config_tx = 1; 1217 else if (!strcmp(argv[start_arg], "rx")) 1218 trace.config_rx = 1; 1219 else if (!strcmp(argv[start_arg], "all")) 1220 trace.config_tx = trace.config_rx = 1; 1221 else 1222 errx(1, "bad trace filter \"%s\"; must be one of \"rx\", " 1223 "\"tx\" or \"all\"", argv[start_arg]); 1224 1225 if (argc == ++start_arg) 1226 return -1; 1227 if (!strcmp(argv[start_arg], "on")) { 1228 trace.trace_tx = trace.config_tx; 1229 trace.trace_rx = trace.config_rx; 1230 } else if (strcmp(argv[start_arg], "off")) 1231 errx(1, "bad argument \"%s\"; must be \"on\" or \"off\"", 1232 argv[start_arg]); 1233 1234 start_arg++; 1235 if (start_arg < argc && !strcmp(argv[start_arg], "not")) { 1236 trace.invert_match = 1; 1237 start_arg++; 1238 } 1239 1240 while (start_arg + 2 <= argc) { 1241 int ret = parse_trace_param(argv[start_arg + 1], &val, &mask); 1242 1243 if (!strcmp(argv[start_arg], "interface")) { 1244 trace.intf = val; 1245 trace.intf_mask = mask; 1246 } else if (!strcmp(argv[start_arg], "sip")) { 1247 trace.sip = val; 1248 trace.sip_mask = mask; 1249 } else if (!strcmp(argv[start_arg], "dip")) { 1250 trace.dip = val; 1251 trace.dip_mask = mask; 1252 } else if (!strcmp(argv[start_arg], "sport")) { 1253 trace.sport = val; 1254 trace.sport_mask = mask; 1255 } else if (!strcmp(argv[start_arg], "dport")) { 1256 trace.dport = val; 1257 trace.dport_mask = mask; 1258 } else if (!strcmp(argv[start_arg], "vlan")) { 1259 trace.vlan = val; 1260 trace.vlan_mask = mask; 1261 } else if (!strcmp(argv[start_arg], "proto")) { 1262 trace.proto = val; 1263 trace.proto_mask = mask; 1264 } else 1265 errx(1, "unknown trace parameter \"%s\"\n" 1266 "known parameters are \"interface\", \"sip\", " 1267 "\"dip\", \"sport\", \"dport\", \"vlan\", " 1268 "\"proto\"", argv[start_arg]); 1269 if (ret < 0) 1270 errx(1, "bad parameter \"%s\"", argv[start_arg + 1]); 1271 start_arg += 2; 1272 } 1273 if (start_arg != argc) 1274 errx(1, "unknown parameter \"%s\"", argv[start_arg]); 1275 1276 if (doit(iff_name, CHELSIO_SET_TRACE_FILTER, &trace) < 0) 1277 err(1, "trace"); 1278 return 0; 1279 } 1280 1281 static void 1282 show_filters(const char *iff_name) 1283 { 1284 static const char *pkt_type[] = { "*", "tcp", "udp", "frag" }; 1285 struct ch_filter op; 1286 union { 1287 uint32_t nip; 1288 uint8_t octet[4]; 1289 } nsip, ndip; 1290 char sip[20], dip[20]; 1291 int header = 0; 1292 1293 bzero(&op, sizeof(op)); 1294 op.filter_id = 0xffffffff; 1295 1296 do { 1297 if (doit(iff_name, CHELSIO_GET_FILTER, &op) < 0) 1298 err(1, "list filters"); 1299 1300 if (op.filter_id == 0xffffffff) 1301 break; 1302 1303 if (!header) { 1304 printf("index SIP DIP sport " 1305 "dport VLAN PRI P/MAC type Q\n"); 1306 header = 1; 1307 } 1308 1309 nsip.nip = htonl(op.val.sip); 1310 ndip.nip = htonl(op.val.dip); 1311 1312 sprintf(sip, "%u.%u.%u.%u/%-2u", nsip.octet[0], nsip.octet[1], 1313 nsip.octet[2], nsip.octet[3], 1314 op.mask.sip ? 33 - ffs(op.mask.sip) : 0); 1315 sprintf(dip, "%u.%u.%u.%u", ndip.octet[0], ndip.octet[1], 1316 ndip.octet[2], ndip.octet[3]); 1317 printf("%5zu %18s %15s ", (size_t)op.filter_id, sip, dip); 1318 printf(op.val.sport ? "%5u " : " * ", op.val.sport); 1319 printf(op.val.dport ? "%5u " : " * ", op.val.dport); 1320 printf(op.val.vlan != 0xfff ? "%4u " : " * ", op.val.vlan); 1321 printf(op.val.vlan_prio == 7 ? " * " : 1322 "%1u/%1u ", op.val.vlan_prio, op.val.vlan_prio | 1); 1323 if (op.mac_addr_idx == 0xffff) 1324 printf("*/* "); 1325 else if (op.mac_hit) 1326 printf("%1u/%3u ", (op.mac_addr_idx >> 3) & 0x1, 1327 (op.mac_addr_idx) & 0x7); 1328 else 1329 printf("%1u/ * ", (op.mac_addr_idx >> 3) & 0x1); 1330 printf("%4s ", pkt_type[op.proto]); 1331 if (!op.pass) 1332 printf("-\n"); 1333 else if (op.rss) 1334 printf("*\n"); 1335 else 1336 printf("%1u\n", op.qset); 1337 } while (1); 1338 } 1339 1340 static int 1341 filter_config(int argc, char *argv[], int start_arg, const char *iff_name) 1342 { 1343 int ret = 0; 1344 uint32_t val, mask; 1345 struct ch_filter op; 1346 1347 if (argc < start_arg + 1) 1348 return -1; 1349 1350 memset(&op, 0, sizeof(op)); 1351 op.mac_addr_idx = 0xffff; 1352 op.rss = 1; 1353 1354 if (argc == start_arg + 1 && !strcmp(argv[start_arg], "list")) { 1355 show_filters(iff_name); 1356 return 0; 1357 } 1358 1359 if (get_int_arg(argv[start_arg++], &op.filter_id)) 1360 return -1; 1361 if (argc == start_arg + 1 && (!strcmp(argv[start_arg], "delete") || 1362 !strcmp(argv[start_arg], "clear"))) { 1363 if (doit(iff_name, CHELSIO_DEL_FILTER, &op) < 0) { 1364 if (errno == EBUSY) 1365 err(1, "no filter support when offload in use"); 1366 err(1, "delete filter"); 1367 } 1368 return 0; 1369 } 1370 1371 while (start_arg + 2 <= argc) { 1372 if (!strcmp(argv[start_arg], "sip")) { 1373 ret = parse_ipaddr(argv[start_arg + 1], &op.val.sip, 1374 &op.mask.sip); 1375 } else if (!strcmp(argv[start_arg], "dip")) { 1376 ret = parse_ipaddr(argv[start_arg + 1], &op.val.dip, 1377 &op.mask.dip); 1378 } else if (!strcmp(argv[start_arg], "sport")) { 1379 ret = parse_val_mask_param(argv[start_arg + 1], 1380 &val, &mask, 0xffff); 1381 op.val.sport = val; 1382 op.mask.sport = mask; 1383 } else if (!strcmp(argv[start_arg], "dport")) { 1384 ret = parse_val_mask_param(argv[start_arg + 1], 1385 &val, &mask, 0xffff); 1386 op.val.dport = val; 1387 op.mask.dport = mask; 1388 } else if (!strcmp(argv[start_arg], "vlan")) { 1389 ret = parse_val_mask_param(argv[start_arg + 1], 1390 &val, &mask, 0xfff); 1391 op.val.vlan = val; 1392 op.mask.vlan = mask; 1393 } else if (!strcmp(argv[start_arg], "prio")) { 1394 ret = parse_val_mask_param(argv[start_arg + 1], 1395 &val, &mask, 7); 1396 op.val.vlan_prio = val; 1397 op.mask.vlan_prio = mask; 1398 } else if (!strcmp(argv[start_arg], "mac")) { 1399 if (!strcmp(argv[start_arg + 1], "none")) 1400 val = -1; 1401 else 1402 ret = get_int_arg(argv[start_arg + 1], &val); 1403 op.mac_hit = val != (uint32_t)-1; 1404 op.mac_addr_idx = op.mac_hit ? val : 0; 1405 } else if (!strcmp(argv[start_arg], "type")) { 1406 if (!strcmp(argv[start_arg + 1], "tcp")) 1407 op.proto = 1; 1408 else if (!strcmp(argv[start_arg + 1], "udp")) 1409 op.proto = 2; 1410 else if (!strcmp(argv[start_arg + 1], "frag")) 1411 op.proto = 3; 1412 else 1413 errx(1, "unknown type \"%s\"; must be one of " 1414 "\"tcp\", \"udp\", or \"frag\"", 1415 argv[start_arg + 1]); 1416 } else if (!strcmp(argv[start_arg], "queue")) { 1417 ret = get_int_arg(argv[start_arg + 1], &val); 1418 op.qset = val; 1419 op.rss = 0; 1420 } else if (!strcmp(argv[start_arg], "action")) { 1421 if (!strcmp(argv[start_arg + 1], "pass")) 1422 op.pass = 1; 1423 else if (strcmp(argv[start_arg + 1], "drop")) 1424 errx(1, "unknown action \"%s\"; must be one of " 1425 "\"pass\" or \"drop\"", 1426 argv[start_arg + 1]); 1427 } else 1428 errx(1, "unknown filter parameter \"%s\"\n" 1429 "known parameters are \"mac\", \"sip\", " 1430 "\"dip\", \"sport\", \"dport\", \"vlan\", " 1431 "\"prio\", \"type\", \"queue\", and \"action\"", 1432 argv[start_arg]); 1433 if (ret < 0) 1434 errx(1, "bad value \"%s\" for parameter \"%s\"", 1435 argv[start_arg + 1], argv[start_arg]); 1436 start_arg += 2; 1437 } 1438 if (start_arg != argc) 1439 errx(1, "no value for \"%s\"", argv[start_arg]); 1440 1441 if (doit(iff_name, CHELSIO_SET_FILTER, &op) < 0) { 1442 if (errno == EBUSY) 1443 err(1, "no filter support when offload in use"); 1444 err(1, "set filter"); 1445 } 1446 1447 return 0; 1448 } 1449 static int 1450 get_sched_param(int argc, char *argv[], int pos, unsigned int *valp) 1451 { 1452 if (pos + 1 >= argc) 1453 errx(1, "missing value for %s", argv[pos]); 1454 if (get_int_arg(argv[pos + 1], valp)) 1455 exit(1); 1456 return 0; 1457 } 1458 1459 static int 1460 tx_sched(int argc, char *argv[], int start_arg, const char *iff_name) 1461 { 1462 struct ch_hw_sched op; 1463 unsigned int idx, val; 1464 1465 if (argc < 5 || get_int_arg(argv[start_arg++], &idx)) 1466 return -1; 1467 1468 op.sched = idx; 1469 op.mode = op.channel = -1; 1470 op.kbps = op.class_ipg = op.flow_ipg = -1; 1471 1472 while (argc > start_arg) { 1473 if (!strcmp(argv[start_arg], "mode")) { 1474 if (start_arg + 1 >= argc) 1475 errx(1, "missing value for mode"); 1476 if (!strcmp(argv[start_arg + 1], "class")) 1477 op.mode = 0; 1478 else if (!strcmp(argv[start_arg + 1], "flow")) 1479 op.mode = 1; 1480 else 1481 errx(1, "bad mode \"%s\"", argv[start_arg + 1]); 1482 } else if (!strcmp(argv[start_arg], "channel") && 1483 !get_sched_param(argc, argv, start_arg, &val)) 1484 op.channel = val; 1485 else if (!strcmp(argv[start_arg], "rate") && 1486 !get_sched_param(argc, argv, start_arg, &val)) 1487 op.kbps = val; 1488 else if (!strcmp(argv[start_arg], "ipg") && 1489 !get_sched_param(argc, argv, start_arg, &val)) 1490 op.class_ipg = val; 1491 else if (!strcmp(argv[start_arg], "flowipg") && 1492 !get_sched_param(argc, argv, start_arg, &val)) 1493 op.flow_ipg = val; 1494 else 1495 errx(1, "unknown scheduler parameter \"%s\"", 1496 argv[start_arg]); 1497 start_arg += 2; 1498 } 1499 1500 if (doit(iff_name, CHELSIO_SET_HW_SCHED, &op) < 0) 1501 err(1, "pktsched"); 1502 1503 return 0; 1504 } 1505 1506 static int 1507 pktsched(int argc, char *argv[], int start_arg, const char *iff_name) 1508 { 1509 struct ch_pktsched_params op; 1510 unsigned int idx, min = -1, max, binding = -1; 1511 1512 if (argc < 4) 1513 errx(1, "no scheduler specified"); 1514 1515 if (!strcmp(argv[start_arg], "port")) { 1516 if (argc != start_arg + 4) 1517 return -1; 1518 if (get_int_arg(argv[start_arg + 1], &idx) || 1519 get_int_arg(argv[start_arg + 2], &min) || 1520 get_int_arg(argv[start_arg + 3], &max)) 1521 return -1; 1522 op.sched = 0; 1523 } else if (!strcmp(argv[start_arg], "tunnelq")) { 1524 if (argc != start_arg + 4) 1525 return -1; 1526 if (get_int_arg(argv[start_arg + 1], &idx) || 1527 get_int_arg(argv[start_arg + 2], &max) || 1528 get_int_arg(argv[start_arg + 3], &binding)) 1529 return -1; 1530 op.sched = 1; 1531 } else if (!strcmp(argv[start_arg], "tx")) 1532 return tx_sched(argc, argv, start_arg + 1, iff_name); 1533 else 1534 errx(1, "unknown scheduler \"%s\"; must be one of \"port\", " 1535 "\"tunnelq\" or \"tx\"", argv[start_arg]); 1536 1537 op.idx = idx; 1538 op.min = min; 1539 op.max = max; 1540 op.binding = binding; 1541 if (doit(iff_name, CHELSIO_SET_PKTSCHED, &op) < 0) 1542 err(1, "pktsched"); 1543 1544 return 0; 1545 } 1546 1547 static int 1548 clear_stats(int argc, char *argv[], int start_arg, const char *iff_name) 1549 { 1550 (void) argc; 1551 (void) argv; 1552 (void) start_arg; 1553 1554 if (doit(iff_name, CHELSIO_CLEAR_STATS, NULL) < 0) 1555 err(1, "clearstats"); 1556 1557 return 0; 1558 } 1559 1560 static int 1561 get_up_la(int argc, char *argv[], int start_arg, const char *iff_name) 1562 { 1563 struct ch_up_la la; 1564 int i, idx, max_idx, entries; 1565 1566 (void) argc; 1567 (void) argv; 1568 (void) start_arg; 1569 1570 la.stopped = 0; 1571 la.idx = -1; 1572 la.bufsize = LA_BUFSIZE; 1573 la.data = malloc(la.bufsize); 1574 if (!la.data) 1575 err(1, "uP_LA malloc"); 1576 1577 if (doit(iff_name, CHELSIO_GET_UP_LA, &la) < 0) 1578 err(1, "uP_LA"); 1579 1580 if (la.stopped) 1581 printf("LA is not running\n"); 1582 1583 entries = la.bufsize / 4; 1584 idx = (int)la.idx; 1585 max_idx = (entries / 4) - 1; 1586 for (i = 0; i < max_idx; i++) { 1587 printf("%04x %08x %08x\n", 1588 la.data[idx], la.data[idx+2], la.data[idx+1]); 1589 idx = (idx + 4) & (entries - 1); 1590 } 1591 1592 return 0; 1593 } 1594 1595 static int 1596 get_up_ioqs(int argc, char *argv[], int start_arg, const char *iff_name) 1597 { 1598 struct ch_up_ioqs ioqs; 1599 int i, entries; 1600 1601 (void) argc; 1602 (void) argv; 1603 (void) start_arg; 1604 1605 bzero(&ioqs, sizeof(ioqs)); 1606 ioqs.bufsize = IOQS_BUFSIZE; 1607 ioqs.data = malloc(IOQS_BUFSIZE); 1608 if (!ioqs.data) 1609 err(1, "uP_IOQs malloc"); 1610 1611 if (doit(iff_name, CHELSIO_GET_UP_IOQS, &ioqs) < 0) 1612 err(1, "uP_IOQs"); 1613 1614 printf("ioq_rx_enable : 0x%08x\n", ioqs.ioq_rx_enable); 1615 printf("ioq_tx_enable : 0x%08x\n", ioqs.ioq_tx_enable); 1616 printf("ioq_rx_status : 0x%08x\n", ioqs.ioq_rx_status); 1617 printf("ioq_tx_status : 0x%08x\n", ioqs.ioq_tx_status); 1618 1619 entries = ioqs.bufsize / sizeof(struct t3_ioq_entry); 1620 for (i = 0; i < entries; i++) { 1621 printf("\nioq[%d].cp : 0x%08x\n", i, 1622 ioqs.data[i].ioq_cp); 1623 printf("ioq[%d].pp : 0x%08x\n", i, 1624 ioqs.data[i].ioq_pp); 1625 printf("ioq[%d].alen : 0x%08x\n", i, 1626 ioqs.data[i].ioq_alen); 1627 printf("ioq[%d].stats : 0x%08x\n", i, 1628 ioqs.data[i].ioq_stats); 1629 printf(" sop %u\n", ioqs.data[i].ioq_stats >> 16); 1630 printf(" eop %u\n", ioqs.data[i].ioq_stats & 0xFFFF); 1631 } 1632 1633 return 0; 1634 } 1635 1636 static int 1637 run_cmd(int argc, char *argv[], const char *iff_name) 1638 { 1639 int r = -1; 1640 1641 if (!strcmp(argv[2], "reg")) 1642 r = register_io(argc, argv, 3, iff_name); 1643 else if (!strcmp(argv[2], "mdio")) 1644 r = mdio_io(argc, argv, 3, iff_name); 1645 else if (!strcmp(argv[2], "mtus")) 1646 r = mtu_tab_op(argc, argv, 3, iff_name); 1647 else if (!strcmp(argv[2], "pm")) 1648 r = conf_pm(argc, argv, 3, iff_name); 1649 else if (!strcmp(argv[2], "regdump")) 1650 r = dump_regs(argc, argv, 3, iff_name); 1651 else if (!strcmp(argv[2], "tcamdump")) 1652 r = dump_tcam(argc, argv, 3, iff_name); 1653 else if (!strcmp(argv[2], "memdump")) 1654 r = dump_mc7(argc, argv, 3, iff_name); 1655 else if (!strcmp(argv[2], "meminfo")) 1656 r = meminfo(argc, argv, 3, iff_name); 1657 else if (!strcmp(argv[2], "context")) 1658 r = get_sge_context(argc, argv, 3, iff_name); 1659 else if (!strcmp(argv[2], "desc")) 1660 r = get_sge_desc(argc, argv, 3, iff_name); 1661 else if (!strcmp(argv[2], "loadfw")) 1662 r = load_fw(argc, argv, 3, iff_name); 1663 else if (!strcmp(argv[2], "loadboot")) 1664 r = load_boot(argc, argv, 3, iff_name); 1665 else if (!strcmp(argv[2], "proto")) 1666 r = proto_sram_op(argc, argv, 3, iff_name); 1667 else if (!strcmp(argv[2], "qset")) 1668 r = qset_config(argc, argv, 3, iff_name); 1669 else if (!strcmp(argv[2], "qsets")) 1670 r = qset_num_config(argc, argv, 3, iff_name); 1671 else if (!strcmp(argv[2], "trace")) 1672 r = trace_config(argc, argv, 3, iff_name); 1673 else if (!strcmp(argv[2], "pktsched")) 1674 r = pktsched(argc, argv, 3, iff_name); 1675 else if (!strcmp(argv[2], "tcb")) 1676 r = get_tcb2(argc, argv, 3, iff_name); 1677 else if (!strcmp(argv[2], "filter")) 1678 r = filter_config(argc, argv, 3, iff_name); 1679 else if (!strcmp(argv[2], "clearstats")) 1680 r = clear_stats(argc, argv, 3, iff_name); 1681 else if (!strcmp(argv[2], "la")) 1682 r = get_up_la(argc, argv, 3, iff_name); 1683 else if (!strcmp(argv[2], "ioqs")) 1684 r = get_up_ioqs(argc, argv, 3, iff_name); 1685 1686 if (r == -1) 1687 usage(stderr); 1688 1689 return (0); 1690 } 1691 1692 static int 1693 run_cmd_loop(int argc, char *argv[], const char *iff_name) 1694 { 1695 int n; 1696 unsigned int i; 1697 char buf[64]; 1698 char *args[8], *s; 1699 1700 (void) argc; 1701 args[0] = argv[0]; 1702 args[1] = argv[1]; 1703 1704 /* 1705 * Fairly simplistic loop. Displays a "> " prompt and processes any 1706 * input as a cxgbtool command. You're supposed to enter only the part 1707 * after "cxgbtool cxgbX". Use "quit" or "exit" to exit. Any error in 1708 * the command will also terminate cxgbtool. 1709 */ 1710 for (;;) { 1711 fprintf(stdout, "> "); 1712 fflush(stdout); 1713 n = read(STDIN_FILENO, buf, sizeof(buf) - 1); 1714 if (n <= 0) 1715 return (0); 1716 1717 if (buf[--n] != '\n') 1718 continue; 1719 else 1720 buf[n] = 0; 1721 1722 s = &buf[0]; 1723 for (i = 2; i < sizeof(args)/sizeof(args[0]) - 1; i++) { 1724 while (s && (*s == ' ' || *s == '\t')) 1725 s++; 1726 if ((args[i] = strsep(&s, " \t")) == NULL) 1727 break; 1728 } 1729 args[sizeof(args)/sizeof(args[0]) - 1] = 0; 1730 1731 if (!strcmp(args[2], "quit") || !strcmp(args[2], "exit")) 1732 return (0); 1733 1734 (void) run_cmd(i, args, iff_name); 1735 } 1736 1737 /* Can't really get here */ 1738 return (0); 1739 } 1740 1741 int 1742 main(int argc, char *argv[]) 1743 { 1744 int r = -1; 1745 const char *iff_name; 1746 1747 progname = argv[0]; 1748 1749 if (argc == 2) { 1750 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) 1751 usage(stdout); 1752 if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) { 1753 printf("%s version %s\n", PROGNAME, VERSION); 1754 printf("%s\n", COPYRIGHT); 1755 exit(0); 1756 } 1757 } 1758 1759 if (argc < 3) usage(stderr); 1760 1761 iff_name = argv[1]; 1762 1763 if (argc == 3 && !strcmp(argv[2], "stdio")) 1764 r = run_cmd_loop(argc, argv, iff_name); 1765 else 1766 r = run_cmd(argc, argv, iff_name); 1767 1768 return (r); 1769 } 1770