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