cxgbtool.c revision 216285
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 216285 2010-12-08 01:35:19Z kevlo $"); 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 1018 close(fd); 1019 return 0; 1020} 1021 1022/* Max BOOT size is 255*512 bytes including the BIOS boot ROM basic header */ 1023#define MAX_BOOT_IMAGE_SIZE (0xff * 512) 1024 1025static int 1026load_boot(int argc, char *argv[], int start_arg, const char *iff_name) 1027{ 1028 int fd, len; 1029 struct ch_mem_range op; 1030 const char *fname = argv[start_arg]; 1031 1032 if (argc != start_arg + 1) return -1; 1033 1034 fd = open(fname, O_RDONLY); 1035 if (fd < 0) 1036 err(1, "load boot image"); 1037 1038 op.buf = malloc(MAX_BOOT_IMAGE_SIZE + 1); 1039 if (!op.buf) 1040 err(1, "load boot image"); 1041 1042 len = read(fd, op.buf, MAX_BOOT_IMAGE_SIZE + 1); 1043 if (len < 0) 1044 err(1, "load boot image"); 1045 if (len > MAX_BOOT_IMAGE_SIZE) 1046 errx(1, "boot image too large"); 1047 1048 op.len = len; 1049 1050 if (doit(iff_name, CHELSIO_LOAD_BOOT, &op) < 0) 1051 err(1, "load boot image"); 1052 1053 close(fd); 1054 return 0; 1055} 1056 1057static int 1058dump_proto_sram(const char *iff_name) 1059{ 1060 int i, j; 1061 uint8_t buf[PROTO_SRAM_SIZE]; 1062 struct ch_eeprom ee; 1063 uint8_t *p = buf; 1064 1065 bzero(buf, sizeof(buf)); 1066 ee.offset = PROTO_SRAM_EEPROM_ADDR; 1067 ee.data = p; 1068 ee.len = sizeof(buf); 1069 if (doit(iff_name, CHELSIO_GET_EEPROM, &ee)) 1070 err(1, "show protocol sram"); 1071 1072 for (i = 0; i < PROTO_SRAM_LINES; i++) { 1073 for (j = PROTO_SRAM_LINE_NIBBLES - 1; j >= 0; j--) { 1074 int nibble_idx = i * PROTO_SRAM_LINE_NIBBLES + j; 1075 uint8_t nibble = p[nibble_idx / 2]; 1076 1077 if (nibble_idx & 1) 1078 nibble >>= 4; 1079 else 1080 nibble &= 0xf; 1081 printf("%x", nibble); 1082 } 1083 putchar('\n'); 1084 } 1085 return 0; 1086} 1087 1088static int 1089proto_sram_op(int argc, char *argv[], int start_arg, 1090 const char *iff_name) 1091{ 1092 (void) argv; 1093 (void) start_arg; 1094 1095 if (argc == start_arg) 1096 return dump_proto_sram(iff_name); 1097 return -1; 1098} 1099 1100static int 1101dump_qset_params(const char *iff_name) 1102{ 1103 struct ch_qset_params qp; 1104 1105 qp.qset_idx = 0; 1106 1107 while (doit(iff_name, CHELSIO_GET_QSET_PARAMS, &qp) == 0) { 1108 if (!qp.qset_idx) 1109 printf("Qset TxQ0 TxQ1 TxQ2 RspQ RxQ0 RxQ1" 1110 " Cong Lat IRQ\n"); 1111 printf("%4u %6u %6u %6u %6u %6u %6u %5u %4u %5d\n", 1112 qp.qnum, 1113 qp.txq_size[0], qp.txq_size[1], qp.txq_size[2], 1114 qp.rspq_size, qp.fl_size[0], qp.fl_size[1], 1115 qp.cong_thres, qp.intr_lat, qp.vector); 1116 qp.qset_idx++; 1117 } 1118 if (!qp.qset_idx || (errno && errno != EINVAL)) 1119 err(1, "get qset parameters"); 1120 return 0; 1121} 1122 1123static int 1124qset_config(int argc, char *argv[], int start_arg, const char *iff_name) 1125{ 1126 (void) argv; 1127 1128 if (argc == start_arg) 1129 return dump_qset_params(iff_name); 1130 1131 return -1; 1132} 1133 1134static int 1135qset_num_config(int argc, char *argv[], int start_arg, const char *iff_name) 1136{ 1137 struct ch_reg reg; 1138 1139 (void) argv; 1140 1141 if (argc == start_arg) { 1142 if (doit(iff_name, CHELSIO_GET_QSET_NUM, ®) < 0) 1143 err(1, "get qsets"); 1144 printf("%u\n", reg.val); 1145 return 0; 1146 } 1147 1148 return -1; 1149} 1150 1151/* 1152 * Parse a string containing an IP address with an optional network prefix. 1153 */ 1154static int 1155parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask) 1156{ 1157 char *p, *slash; 1158 struct in_addr ia; 1159 1160 *mask = 0xffffffffU; 1161 slash = strchr(s, '/'); 1162 if (slash) 1163 *slash = 0; 1164 if (!inet_aton(s, &ia)) { 1165 if (slash) 1166 *slash = '/'; 1167 *addr = 0; 1168 return -1; 1169 } 1170 *addr = ntohl(ia.s_addr); 1171 if (slash) { 1172 unsigned int prefix = strtoul(slash + 1, &p, 10); 1173 1174 *slash = '/'; 1175 if (p == slash + 1 || *p || prefix > 32) 1176 return -1; 1177 *mask <<= (32 - prefix); 1178 } 1179 return 0; 1180} 1181 1182/* 1183 * Parse a string containing a value and an optional colon separated mask. 1184 */ 1185static int 1186parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask, 1187 uint32_t default_mask) 1188{ 1189 char *p; 1190 1191 *mask = default_mask; 1192 *val = strtoul(s, &p, 0); 1193 if (p == s || *val > default_mask) 1194 return -1; 1195 if (*p == ':' && p[1]) 1196 *mask = strtoul(p + 1, &p, 0); 1197 return *p || *mask > default_mask ? -1 : 0; 1198} 1199 1200static int 1201parse_trace_param(const char *s, uint32_t *val, uint32_t *mask) 1202{ 1203 return strchr(s, '.') ? parse_ipaddr(s, val, mask) : 1204 parse_val_mask_param(s, val, mask, 0xffffffffU); 1205} 1206 1207static int 1208trace_config(int argc, char *argv[], int start_arg, const char *iff_name) 1209{ 1210 uint32_t val, mask; 1211 struct ch_trace trace; 1212 1213 if (argc == start_arg) 1214 return -1; 1215 1216 memset(&trace, 0, sizeof(trace)); 1217 if (!strcmp(argv[start_arg], "tx")) 1218 trace.config_tx = 1; 1219 else if (!strcmp(argv[start_arg], "rx")) 1220 trace.config_rx = 1; 1221 else if (!strcmp(argv[start_arg], "all")) 1222 trace.config_tx = trace.config_rx = 1; 1223 else 1224 errx(1, "bad trace filter \"%s\"; must be one of \"rx\", " 1225 "\"tx\" or \"all\"", argv[start_arg]); 1226 1227 if (argc == ++start_arg) 1228 return -1; 1229 if (!strcmp(argv[start_arg], "on")) { 1230 trace.trace_tx = trace.config_tx; 1231 trace.trace_rx = trace.config_rx; 1232 } else if (strcmp(argv[start_arg], "off")) 1233 errx(1, "bad argument \"%s\"; must be \"on\" or \"off\"", 1234 argv[start_arg]); 1235 1236 start_arg++; 1237 if (start_arg < argc && !strcmp(argv[start_arg], "not")) { 1238 trace.invert_match = 1; 1239 start_arg++; 1240 } 1241 1242 while (start_arg + 2 <= argc) { 1243 int ret = parse_trace_param(argv[start_arg + 1], &val, &mask); 1244 1245 if (!strcmp(argv[start_arg], "interface")) { 1246 trace.intf = val; 1247 trace.intf_mask = mask; 1248 } else if (!strcmp(argv[start_arg], "sip")) { 1249 trace.sip = val; 1250 trace.sip_mask = mask; 1251 } else if (!strcmp(argv[start_arg], "dip")) { 1252 trace.dip = val; 1253 trace.dip_mask = mask; 1254 } else if (!strcmp(argv[start_arg], "sport")) { 1255 trace.sport = val; 1256 trace.sport_mask = mask; 1257 } else if (!strcmp(argv[start_arg], "dport")) { 1258 trace.dport = val; 1259 trace.dport_mask = mask; 1260 } else if (!strcmp(argv[start_arg], "vlan")) { 1261 trace.vlan = val; 1262 trace.vlan_mask = mask; 1263 } else if (!strcmp(argv[start_arg], "proto")) { 1264 trace.proto = val; 1265 trace.proto_mask = mask; 1266 } else 1267 errx(1, "unknown trace parameter \"%s\"\n" 1268 "known parameters are \"interface\", \"sip\", " 1269 "\"dip\", \"sport\", \"dport\", \"vlan\", " 1270 "\"proto\"", argv[start_arg]); 1271 if (ret < 0) 1272 errx(1, "bad parameter \"%s\"", argv[start_arg + 1]); 1273 start_arg += 2; 1274 } 1275 if (start_arg != argc) 1276 errx(1, "unknown parameter \"%s\"", argv[start_arg]); 1277 1278 if (doit(iff_name, CHELSIO_SET_TRACE_FILTER, &trace) < 0) 1279 err(1, "trace"); 1280 return 0; 1281} 1282 1283static void 1284show_filters(const char *iff_name) 1285{ 1286 static const char *pkt_type[] = { "*", "tcp", "udp", "frag" }; 1287 struct ch_filter op; 1288 union { 1289 uint32_t nip; 1290 uint8_t octet[4]; 1291 } nsip, ndip; 1292 char sip[20], dip[20]; 1293 int header = 0; 1294 1295 bzero(&op, sizeof(op)); 1296 op.filter_id = 0xffffffff; 1297 1298 do { 1299 if (doit(iff_name, CHELSIO_GET_FILTER, &op) < 0) 1300 err(1, "list filters"); 1301 1302 if (op.filter_id == 0xffffffff) 1303 break; 1304 1305 if (!header) { 1306 printf("index SIP DIP sport " 1307 "dport VLAN PRI P/MAC type Q\n"); 1308 header = 1; 1309 } 1310 1311 nsip.nip = htonl(op.val.sip); 1312 ndip.nip = htonl(op.val.dip); 1313 1314 sprintf(sip, "%u.%u.%u.%u/%-2u", nsip.octet[0], nsip.octet[1], 1315 nsip.octet[2], nsip.octet[3], 1316 op.mask.sip ? 33 - ffs(op.mask.sip) : 0); 1317 sprintf(dip, "%u.%u.%u.%u", ndip.octet[0], ndip.octet[1], 1318 ndip.octet[2], ndip.octet[3]); 1319 printf("%5zu %18s %15s ", (size_t)op.filter_id, sip, dip); 1320 printf(op.val.sport ? "%5u " : " * ", op.val.sport); 1321 printf(op.val.dport ? "%5u " : " * ", op.val.dport); 1322 printf(op.val.vlan != 0xfff ? "%4u " : " * ", op.val.vlan); 1323 printf(op.val.vlan_prio == 7 ? " * " : 1324 "%1u/%1u ", op.val.vlan_prio, op.val.vlan_prio | 1); 1325 if (op.mac_addr_idx == 0xffff) 1326 printf("*/* "); 1327 else if (op.mac_hit) 1328 printf("%1u/%3u ", (op.mac_addr_idx >> 3) & 0x1, 1329 (op.mac_addr_idx) & 0x7); 1330 else 1331 printf("%1u/ * ", (op.mac_addr_idx >> 3) & 0x1); 1332 printf("%4s ", pkt_type[op.proto]); 1333 if (!op.pass) 1334 printf("-\n"); 1335 else if (op.rss) 1336 printf("*\n"); 1337 else 1338 printf("%1u\n", op.qset); 1339 } while (1); 1340} 1341 1342static int 1343filter_config(int argc, char *argv[], int start_arg, const char *iff_name) 1344{ 1345 int ret = 0; 1346 uint32_t val, mask; 1347 struct ch_filter op; 1348 1349 if (argc < start_arg + 1) 1350 return -1; 1351 1352 memset(&op, 0, sizeof(op)); 1353 op.mac_addr_idx = 0xffff; 1354 op.rss = 1; 1355 1356 if (argc == start_arg + 1 && !strcmp(argv[start_arg], "list")) { 1357 show_filters(iff_name); 1358 return 0; 1359 } 1360 1361 if (get_int_arg(argv[start_arg++], &op.filter_id)) 1362 return -1; 1363 if (argc == start_arg + 1 && (!strcmp(argv[start_arg], "delete") || 1364 !strcmp(argv[start_arg], "clear"))) { 1365 if (doit(iff_name, CHELSIO_DEL_FILTER, &op) < 0) { 1366 if (errno == EBUSY) 1367 err(1, "no filter support when offload in use"); 1368 err(1, "delete filter"); 1369 } 1370 return 0; 1371 } 1372 1373 while (start_arg + 2 <= argc) { 1374 if (!strcmp(argv[start_arg], "sip")) { 1375 ret = parse_ipaddr(argv[start_arg + 1], &op.val.sip, 1376 &op.mask.sip); 1377 } else if (!strcmp(argv[start_arg], "dip")) { 1378 ret = parse_ipaddr(argv[start_arg + 1], &op.val.dip, 1379 &op.mask.dip); 1380 } else if (!strcmp(argv[start_arg], "sport")) { 1381 ret = parse_val_mask_param(argv[start_arg + 1], 1382 &val, &mask, 0xffff); 1383 op.val.sport = val; 1384 op.mask.sport = mask; 1385 } else if (!strcmp(argv[start_arg], "dport")) { 1386 ret = parse_val_mask_param(argv[start_arg + 1], 1387 &val, &mask, 0xffff); 1388 op.val.dport = val; 1389 op.mask.dport = mask; 1390 } else if (!strcmp(argv[start_arg], "vlan")) { 1391 ret = parse_val_mask_param(argv[start_arg + 1], 1392 &val, &mask, 0xfff); 1393 op.val.vlan = val; 1394 op.mask.vlan = mask; 1395 } else if (!strcmp(argv[start_arg], "prio")) { 1396 ret = parse_val_mask_param(argv[start_arg + 1], 1397 &val, &mask, 7); 1398 op.val.vlan_prio = val; 1399 op.mask.vlan_prio = mask; 1400 } else if (!strcmp(argv[start_arg], "mac")) { 1401 if (!strcmp(argv[start_arg + 1], "none")) 1402 val = -1; 1403 else 1404 ret = get_int_arg(argv[start_arg + 1], &val); 1405 op.mac_hit = val != (uint32_t)-1; 1406 op.mac_addr_idx = op.mac_hit ? val : 0; 1407 } else if (!strcmp(argv[start_arg], "type")) { 1408 if (!strcmp(argv[start_arg + 1], "tcp")) 1409 op.proto = 1; 1410 else if (!strcmp(argv[start_arg + 1], "udp")) 1411 op.proto = 2; 1412 else if (!strcmp(argv[start_arg + 1], "frag")) 1413 op.proto = 3; 1414 else 1415 errx(1, "unknown type \"%s\"; must be one of " 1416 "\"tcp\", \"udp\", or \"frag\"", 1417 argv[start_arg + 1]); 1418 } else if (!strcmp(argv[start_arg], "queue")) { 1419 ret = get_int_arg(argv[start_arg + 1], &val); 1420 op.qset = val; 1421 op.rss = 0; 1422 } else if (!strcmp(argv[start_arg], "action")) { 1423 if (!strcmp(argv[start_arg + 1], "pass")) 1424 op.pass = 1; 1425 else if (strcmp(argv[start_arg + 1], "drop")) 1426 errx(1, "unknown action \"%s\"; must be one of " 1427 "\"pass\" or \"drop\"", 1428 argv[start_arg + 1]); 1429 } else 1430 errx(1, "unknown filter parameter \"%s\"\n" 1431 "known parameters are \"mac\", \"sip\", " 1432 "\"dip\", \"sport\", \"dport\", \"vlan\", " 1433 "\"prio\", \"type\", \"queue\", and \"action\"", 1434 argv[start_arg]); 1435 if (ret < 0) 1436 errx(1, "bad value \"%s\" for parameter \"%s\"", 1437 argv[start_arg + 1], argv[start_arg]); 1438 start_arg += 2; 1439 } 1440 if (start_arg != argc) 1441 errx(1, "no value for \"%s\"", argv[start_arg]); 1442 1443 if (doit(iff_name, CHELSIO_SET_FILTER, &op) < 0) { 1444 if (errno == EBUSY) 1445 err(1, "no filter support when offload in use"); 1446 err(1, "set filter"); 1447 } 1448 1449 return 0; 1450} 1451static int 1452get_sched_param(int argc, char *argv[], int pos, unsigned int *valp) 1453{ 1454 if (pos + 1 >= argc) 1455 errx(1, "missing value for %s", argv[pos]); 1456 if (get_int_arg(argv[pos + 1], valp)) 1457 exit(1); 1458 return 0; 1459} 1460 1461static int 1462tx_sched(int argc, char *argv[], int start_arg, const char *iff_name) 1463{ 1464 struct ch_hw_sched op; 1465 unsigned int idx, val; 1466 1467 if (argc < 5 || get_int_arg(argv[start_arg++], &idx)) 1468 return -1; 1469 1470 op.sched = idx; 1471 op.mode = op.channel = -1; 1472 op.kbps = op.class_ipg = op.flow_ipg = -1; 1473 1474 while (argc > start_arg) { 1475 if (!strcmp(argv[start_arg], "mode")) { 1476 if (start_arg + 1 >= argc) 1477 errx(1, "missing value for mode"); 1478 if (!strcmp(argv[start_arg + 1], "class")) 1479 op.mode = 0; 1480 else if (!strcmp(argv[start_arg + 1], "flow")) 1481 op.mode = 1; 1482 else 1483 errx(1, "bad mode \"%s\"", argv[start_arg + 1]); 1484 } else if (!strcmp(argv[start_arg], "channel") && 1485 !get_sched_param(argc, argv, start_arg, &val)) 1486 op.channel = val; 1487 else if (!strcmp(argv[start_arg], "rate") && 1488 !get_sched_param(argc, argv, start_arg, &val)) 1489 op.kbps = val; 1490 else if (!strcmp(argv[start_arg], "ipg") && 1491 !get_sched_param(argc, argv, start_arg, &val)) 1492 op.class_ipg = val; 1493 else if (!strcmp(argv[start_arg], "flowipg") && 1494 !get_sched_param(argc, argv, start_arg, &val)) 1495 op.flow_ipg = val; 1496 else 1497 errx(1, "unknown scheduler parameter \"%s\"", 1498 argv[start_arg]); 1499 start_arg += 2; 1500 } 1501 1502 if (doit(iff_name, CHELSIO_SET_HW_SCHED, &op) < 0) 1503 err(1, "pktsched"); 1504 1505 return 0; 1506} 1507 1508static int 1509pktsched(int argc, char *argv[], int start_arg, const char *iff_name) 1510{ 1511 struct ch_pktsched_params op; 1512 unsigned int idx, min = -1, max, binding = -1; 1513 1514 if (argc < 4) 1515 errx(1, "no scheduler specified"); 1516 1517 if (!strcmp(argv[start_arg], "port")) { 1518 if (argc != start_arg + 4) 1519 return -1; 1520 if (get_int_arg(argv[start_arg + 1], &idx) || 1521 get_int_arg(argv[start_arg + 2], &min) || 1522 get_int_arg(argv[start_arg + 3], &max)) 1523 return -1; 1524 op.sched = 0; 1525 } else if (!strcmp(argv[start_arg], "tunnelq")) { 1526 if (argc != start_arg + 4) 1527 return -1; 1528 if (get_int_arg(argv[start_arg + 1], &idx) || 1529 get_int_arg(argv[start_arg + 2], &max) || 1530 get_int_arg(argv[start_arg + 3], &binding)) 1531 return -1; 1532 op.sched = 1; 1533 } else if (!strcmp(argv[start_arg], "tx")) 1534 return tx_sched(argc, argv, start_arg + 1, iff_name); 1535 else 1536 errx(1, "unknown scheduler \"%s\"; must be one of \"port\", " 1537 "\"tunnelq\" or \"tx\"", argv[start_arg]); 1538 1539 op.idx = idx; 1540 op.min = min; 1541 op.max = max; 1542 op.binding = binding; 1543 if (doit(iff_name, CHELSIO_SET_PKTSCHED, &op) < 0) 1544 err(1, "pktsched"); 1545 1546 return 0; 1547} 1548 1549static int 1550clear_stats(int argc, char *argv[], int start_arg, const char *iff_name) 1551{ 1552 (void) argc; 1553 (void) argv; 1554 (void) start_arg; 1555 1556 if (doit(iff_name, CHELSIO_CLEAR_STATS, NULL) < 0) 1557 err(1, "clearstats"); 1558 1559 return 0; 1560} 1561 1562static int 1563get_up_la(int argc, char *argv[], int start_arg, const char *iff_name) 1564{ 1565 struct ch_up_la la; 1566 int i, idx, max_idx, entries; 1567 1568 (void) argc; 1569 (void) argv; 1570 (void) start_arg; 1571 1572 la.stopped = 0; 1573 la.idx = -1; 1574 la.bufsize = LA_BUFSIZE; 1575 la.data = malloc(la.bufsize); 1576 if (!la.data) 1577 err(1, "uP_LA malloc"); 1578 1579 if (doit(iff_name, CHELSIO_GET_UP_LA, &la) < 0) 1580 err(1, "uP_LA"); 1581 1582 if (la.stopped) 1583 printf("LA is not running\n"); 1584 1585 entries = la.bufsize / 4; 1586 idx = (int)la.idx; 1587 max_idx = (entries / 4) - 1; 1588 for (i = 0; i < max_idx; i++) { 1589 printf("%04x %08x %08x\n", 1590 la.data[idx], la.data[idx+2], la.data[idx+1]); 1591 idx = (idx + 4) & (entries - 1); 1592 } 1593 1594 return 0; 1595} 1596 1597static int 1598get_up_ioqs(int argc, char *argv[], int start_arg, const char *iff_name) 1599{ 1600 struct ch_up_ioqs ioqs; 1601 int i, entries; 1602 1603 (void) argc; 1604 (void) argv; 1605 (void) start_arg; 1606 1607 bzero(&ioqs, sizeof(ioqs)); 1608 ioqs.bufsize = IOQS_BUFSIZE; 1609 ioqs.data = malloc(IOQS_BUFSIZE); 1610 if (!ioqs.data) 1611 err(1, "uP_IOQs malloc"); 1612 1613 if (doit(iff_name, CHELSIO_GET_UP_IOQS, &ioqs) < 0) 1614 err(1, "uP_IOQs"); 1615 1616 printf("ioq_rx_enable : 0x%08x\n", ioqs.ioq_rx_enable); 1617 printf("ioq_tx_enable : 0x%08x\n", ioqs.ioq_tx_enable); 1618 printf("ioq_rx_status : 0x%08x\n", ioqs.ioq_rx_status); 1619 printf("ioq_tx_status : 0x%08x\n", ioqs.ioq_tx_status); 1620 1621 entries = ioqs.bufsize / sizeof(struct t3_ioq_entry); 1622 for (i = 0; i < entries; i++) { 1623 printf("\nioq[%d].cp : 0x%08x\n", i, 1624 ioqs.data[i].ioq_cp); 1625 printf("ioq[%d].pp : 0x%08x\n", i, 1626 ioqs.data[i].ioq_pp); 1627 printf("ioq[%d].alen : 0x%08x\n", i, 1628 ioqs.data[i].ioq_alen); 1629 printf("ioq[%d].stats : 0x%08x\n", i, 1630 ioqs.data[i].ioq_stats); 1631 printf(" sop %u\n", ioqs.data[i].ioq_stats >> 16); 1632 printf(" eop %u\n", ioqs.data[i].ioq_stats & 0xFFFF); 1633 } 1634 1635 return 0; 1636} 1637 1638static int 1639run_cmd(int argc, char *argv[], const char *iff_name) 1640{ 1641 int r = -1; 1642 1643 if (!strcmp(argv[2], "reg")) 1644 r = register_io(argc, argv, 3, iff_name); 1645 else if (!strcmp(argv[2], "mdio")) 1646 r = mdio_io(argc, argv, 3, iff_name); 1647 else if (!strcmp(argv[2], "mtus")) 1648 r = mtu_tab_op(argc, argv, 3, iff_name); 1649 else if (!strcmp(argv[2], "pm")) 1650 r = conf_pm(argc, argv, 3, iff_name); 1651 else if (!strcmp(argv[2], "regdump")) 1652 r = dump_regs(argc, argv, 3, iff_name); 1653 else if (!strcmp(argv[2], "tcamdump")) 1654 r = dump_tcam(argc, argv, 3, iff_name); 1655 else if (!strcmp(argv[2], "memdump")) 1656 r = dump_mc7(argc, argv, 3, iff_name); 1657 else if (!strcmp(argv[2], "meminfo")) 1658 r = meminfo(argc, argv, 3, iff_name); 1659 else if (!strcmp(argv[2], "context")) 1660 r = get_sge_context(argc, argv, 3, iff_name); 1661 else if (!strcmp(argv[2], "desc")) 1662 r = get_sge_desc(argc, argv, 3, iff_name); 1663 else if (!strcmp(argv[2], "loadfw")) 1664 r = load_fw(argc, argv, 3, iff_name); 1665 else if (!strcmp(argv[2], "loadboot")) 1666 r = load_boot(argc, argv, 3, iff_name); 1667 else if (!strcmp(argv[2], "proto")) 1668 r = proto_sram_op(argc, argv, 3, iff_name); 1669 else if (!strcmp(argv[2], "qset")) 1670 r = qset_config(argc, argv, 3, iff_name); 1671 else if (!strcmp(argv[2], "qsets")) 1672 r = qset_num_config(argc, argv, 3, iff_name); 1673 else if (!strcmp(argv[2], "trace")) 1674 r = trace_config(argc, argv, 3, iff_name); 1675 else if (!strcmp(argv[2], "pktsched")) 1676 r = pktsched(argc, argv, 3, iff_name); 1677 else if (!strcmp(argv[2], "tcb")) 1678 r = get_tcb2(argc, argv, 3, iff_name); 1679 else if (!strcmp(argv[2], "filter")) 1680 r = filter_config(argc, argv, 3, iff_name); 1681 else if (!strcmp(argv[2], "clearstats")) 1682 r = clear_stats(argc, argv, 3, iff_name); 1683 else if (!strcmp(argv[2], "la")) 1684 r = get_up_la(argc, argv, 3, iff_name); 1685 else if (!strcmp(argv[2], "ioqs")) 1686 r = get_up_ioqs(argc, argv, 3, iff_name); 1687 1688 if (r == -1) 1689 usage(stderr); 1690 1691 return (0); 1692} 1693 1694static int 1695run_cmd_loop(int argc, char *argv[], const char *iff_name) 1696{ 1697 int n; 1698 unsigned int i; 1699 char buf[64]; 1700 char *args[8], *s; 1701 1702 (void) argc; 1703 args[0] = argv[0]; 1704 args[1] = argv[1]; 1705 1706 /* 1707 * Fairly simplistic loop. Displays a "> " prompt and processes any 1708 * input as a cxgbtool command. You're supposed to enter only the part 1709 * after "cxgbtool cxgbX". Use "quit" or "exit" to exit. Any error in 1710 * the command will also terminate cxgbtool. 1711 */ 1712 for (;;) { 1713 fprintf(stdout, "> "); 1714 fflush(stdout); 1715 n = read(STDIN_FILENO, buf, sizeof(buf) - 1); 1716 if (n <= 0) 1717 return (0); 1718 1719 if (buf[--n] != '\n') 1720 continue; 1721 else 1722 buf[n] = 0; 1723 1724 s = &buf[0]; 1725 for (i = 2; i < sizeof(args)/sizeof(args[0]) - 1; i++) { 1726 while (s && (*s == ' ' || *s == '\t')) 1727 s++; 1728 if ((args[i] = strsep(&s, " \t")) == NULL) 1729 break; 1730 } 1731 args[sizeof(args)/sizeof(args[0]) - 1] = 0; 1732 1733 if (!strcmp(args[2], "quit") || !strcmp(args[2], "exit")) 1734 return (0); 1735 1736 (void) run_cmd(i, args, iff_name); 1737 } 1738 1739 /* Can't really get here */ 1740 return (0); 1741} 1742 1743int 1744main(int argc, char *argv[]) 1745{ 1746 int r = -1; 1747 const char *iff_name; 1748 1749 progname = argv[0]; 1750 1751 if (argc == 2) { 1752 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) 1753 usage(stdout); 1754 if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) { 1755 printf("%s version %s\n", PROGNAME, VERSION); 1756 printf("%s\n", COPYRIGHT); 1757 exit(0); 1758 } 1759 } 1760 1761 if (argc < 3) usage(stderr); 1762 1763 iff_name = argv[1]; 1764 1765 if (argc == 3 && !strcmp(argv[2], "stdio")) 1766 r = run_cmd_loop(argc, argv, iff_name); 1767 else 1768 r = run_cmd(argc, argv, iff_name); 1769 1770 return (r); 1771} 1772