1222900Snp/*- 2222900Snp * Copyright (c) 2011 Chelsio Communications, Inc. 3222900Snp * All rights reserved. 4222900Snp * Written by: Navdeep Parhar <np@FreeBSD.org> 5222900Snp * 6222900Snp * Redistribution and use in source and binary forms, with or without 7222900Snp * modification, are permitted provided that the following conditions 8222900Snp * are met: 9222900Snp * 1. Redistributions of source code must retain the above copyright 10222900Snp * notice, this list of conditions and the following disclaimer. 11222900Snp * 2. Redistributions in binary form must reproduce the above copyright 12222900Snp * notice, this list of conditions and the following disclaimer in the 13222900Snp * documentation and/or other materials provided with the distribution. 14222900Snp * 15222900Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16222900Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17222900Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18222900Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19222900Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20222900Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21222900Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22222900Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23222900Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24222900Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25222900Snp * SUCH DAMAGE. 26222900Snp */ 27222900Snp 28222900Snp#include <sys/cdefs.h> 29222900Snp__FBSDID("$FreeBSD: stable/10/usr.sbin/cxgbetool/cxgbetool.c 306823 2016-10-07 19:13:29Z np $"); 30222900Snp 31287297Srodrigc#include <sys/param.h> 32222900Snp#include <sys/ioctl.h> 33228594Snp#include <sys/mman.h> 34222900Snp#include <sys/socket.h> 35228594Snp#include <sys/stat.h> 36287297Srodrigc 37287297Srodrigc#include <arpa/inet.h> 38222900Snp#include <net/ethernet.h> 39287297Srodrigc#include <net/sff8472.h> 40222900Snp#include <netinet/in.h> 41222900Snp 42287297Srodrigc#include <ctype.h> 43287297Srodrigc#include <err.h> 44287297Srodrigc#include <errno.h> 45287297Srodrigc#include <fcntl.h> 46287297Srodrigc#include <limits.h> 47287297Srodrigc#include <stdint.h> 48287297Srodrigc#include <stdio.h> 49287297Srodrigc#include <stdlib.h> 50287297Srodrigc#include <string.h> 51287297Srodrigc#include <unistd.h> 52287297Srodrigc 53222900Snp#include "t4_ioctl.h" 54222900Snp 55259048Snp#define in_range(val, lo, hi) ( val < 0 || (val <= hi && val >= lo)) 56222974Snp#define max(x, y) ((x) > (y) ? (x) : (y)) 57222974Snp 58222900Snpstatic const char *progname, *nexus; 59253870Snpstatic int chip_id; /* 4 for T4, 5 for T5 */ 60222900Snp 61222900Snpstruct reg_info { 62222900Snp const char *name; 63222900Snp uint32_t addr; 64222900Snp uint32_t len; 65222900Snp}; 66222900Snp 67222900Snpstruct mod_regs { 68222900Snp const char *name; 69222900Snp const struct reg_info *ri; 70222900Snp}; 71222900Snp 72222974Snpstruct field_desc { 73222974Snp const char *name; /* Field name */ 74222974Snp unsigned short start; /* Start bit position */ 75222974Snp unsigned short end; /* End bit position */ 76222974Snp unsigned char shift; /* # of low order bits omitted and implicitly 0 */ 77222974Snp unsigned char hex; /* Print field in hex instead of decimal */ 78222974Snp unsigned char islog2; /* Field contains the base-2 log of the value */ 79222974Snp}; 80222974Snp 81222900Snp#include "reg_defs_t4.c" 82296471Snp#include "reg_defs_t5.c" 83296471Snp#include "reg_defs_t6.c" 84222900Snp#include "reg_defs_t4vf.c" 85222900Snp 86222900Snpstatic void 87222900Snpusage(FILE *fp) 88222900Snp{ 89222900Snp fprintf(fp, "Usage: %s <nexus> [operation]\n", progname); 90222900Snp fprintf(fp, 91241416Snp "\tclearstats <port> clear port statistics\n" 92222974Snp "\tcontext <type> <id> show an SGE context\n" 93222900Snp "\tfilter <idx> [<param> <val>] ... set a filter\n" 94222900Snp "\tfilter <idx> delete|clear delete a filter\n" 95222900Snp "\tfilter list list all filters\n" 96222900Snp "\tfilter mode [<match>] ... get/set global filter mode\n" 97241401Snp "\ti2c <port> <devaddr> <addr> [<len>] read from i2c device\n" 98306823Snp "\tloadcfg <fw-config.txt> install configuration file\n" 99306823Snp "\tloadcfg clear remove configuration file\n" 100228594Snp "\tloadfw <fw-image.bin> install firmware\n" 101228594Snp "\tmemdump <addr> <len> dump a memory range\n" 102269106Snp "\tmodinfo <port> [raw] optics/cable information\n" 103222900Snp "\treg <address>[=<val>] read/write register\n" 104222900Snp "\treg64 <address>[=<val>] read/write 64 bit register\n" 105222900Snp "\tregdump [<module>] ... dump registers\n" 106259048Snp "\tsched-class params <param> <val> .. configure TX scheduler class\n" 107259048Snp "\tsched-queue <port> <queue> <class> bind NIC queues to TX Scheduling class\n" 108222900Snp "\tstdio interactive mode\n" 109228594Snp "\ttcb <tid> read TCB\n" 110259048Snp "\ttracer <idx> tx<n>|rx<n> set and enable a tracer\n" 111253691Snp "\ttracer <idx> disable|enable disable or enable a tracer\n" 112253691Snp "\ttracer list list all tracers\n" 113222900Snp ); 114222900Snp} 115222900Snp 116222900Snpstatic inline unsigned int 117222900Snpget_card_vers(unsigned int version) 118222900Snp{ 119222900Snp return (version & 0x3ff); 120222900Snp} 121222900Snp 122222900Snpstatic int 123222900Snpreal_doit(unsigned long cmd, void *data, const char *cmdstr) 124222900Snp{ 125222900Snp static int fd = -1; 126222900Snp int rc = 0; 127222900Snp 128222900Snp if (fd == -1) { 129222900Snp char buf[64]; 130222900Snp 131222900Snp snprintf(buf, sizeof(buf), "/dev/%s", nexus); 132222900Snp if ((fd = open(buf, O_RDWR)) < 0) { 133222900Snp warn("open(%s)", nexus); 134222900Snp rc = errno; 135222900Snp return (rc); 136222900Snp } 137253870Snp chip_id = nexus[1] - '0'; 138222900Snp } 139222900Snp 140222900Snp rc = ioctl(fd, cmd, data); 141222900Snp if (rc < 0) { 142222900Snp warn("%s", cmdstr); 143222900Snp rc = errno; 144222900Snp } 145222900Snp 146222900Snp return (rc); 147222900Snp} 148222900Snp#define doit(x, y) real_doit(x, y, #x) 149222900Snp 150222900Snpstatic char * 151222900Snpstr_to_number(const char *s, long *val, long long *vall) 152222900Snp{ 153222900Snp char *p; 154222900Snp 155222900Snp if (vall) 156222900Snp *vall = strtoll(s, &p, 0); 157222900Snp else if (val) 158222900Snp *val = strtol(s, &p, 0); 159222900Snp else 160222900Snp p = NULL; 161222900Snp 162222900Snp return (p); 163222900Snp} 164222900Snp 165222900Snpstatic int 166222900Snpread_reg(long addr, int size, long long *val) 167222900Snp{ 168222900Snp struct t4_reg reg; 169222900Snp int rc; 170222900Snp 171222900Snp reg.addr = (uint32_t) addr; 172222900Snp reg.size = (uint32_t) size; 173222900Snp reg.val = 0; 174222900Snp 175222900Snp rc = doit(CHELSIO_T4_GETREG, ®); 176222900Snp 177222900Snp *val = reg.val; 178222900Snp 179222900Snp return (rc); 180222900Snp} 181222900Snp 182222900Snpstatic int 183222900Snpwrite_reg(long addr, int size, long long val) 184222900Snp{ 185222900Snp struct t4_reg reg; 186222900Snp 187222900Snp reg.addr = (uint32_t) addr; 188222900Snp reg.size = (uint32_t) size; 189222900Snp reg.val = (uint64_t) val; 190222900Snp 191222900Snp return doit(CHELSIO_T4_SETREG, ®); 192222900Snp} 193222900Snp 194222900Snpstatic int 195222900Snpregister_io(int argc, const char *argv[], int size) 196222900Snp{ 197222900Snp char *p, *v; 198222900Snp long addr; 199222900Snp long long val; 200222900Snp int w = 0, rc; 201222900Snp 202222900Snp if (argc == 1) { 203222900Snp /* <reg> OR <reg>=<value> */ 204222900Snp 205222900Snp p = str_to_number(argv[0], &addr, NULL); 206222900Snp if (*p) { 207222900Snp if (*p != '=') { 208222900Snp warnx("invalid register \"%s\"", argv[0]); 209222900Snp return (EINVAL); 210222900Snp } 211222900Snp 212222900Snp w = 1; 213222900Snp v = p + 1; 214222900Snp p = str_to_number(v, NULL, &val); 215222900Snp 216222900Snp if (*p) { 217222900Snp warnx("invalid value \"%s\"", v); 218222900Snp return (EINVAL); 219222900Snp } 220222900Snp } 221222900Snp 222222900Snp } else if (argc == 2) { 223222900Snp /* <reg> <value> */ 224222900Snp 225222900Snp w = 1; 226222900Snp 227222900Snp p = str_to_number(argv[0], &addr, NULL); 228222900Snp if (*p) { 229222900Snp warnx("invalid register \"%s\"", argv[0]); 230222900Snp return (EINVAL); 231222900Snp } 232222900Snp 233222900Snp p = str_to_number(argv[1], NULL, &val); 234222900Snp if (*p) { 235222900Snp warnx("invalid value \"%s\"", argv[1]); 236222900Snp return (EINVAL); 237222900Snp } 238222900Snp } else { 239222900Snp warnx("reg: invalid number of arguments (%d)", argc); 240222900Snp return (EINVAL); 241222900Snp } 242222900Snp 243222900Snp if (w) 244222900Snp rc = write_reg(addr, size, val); 245222900Snp else { 246222900Snp rc = read_reg(addr, size, &val); 247222900Snp if (rc == 0) 248222900Snp printf("0x%llx [%llu]\n", val, val); 249222900Snp } 250222900Snp 251222900Snp return (rc); 252222900Snp} 253222900Snp 254222900Snpstatic inline uint32_t 255222900Snpxtract(uint32_t val, int shift, int len) 256222900Snp{ 257222900Snp return (val >> shift) & ((1 << len) - 1); 258222900Snp} 259222900Snp 260222900Snpstatic int 261222900Snpdump_block_regs(const struct reg_info *reg_array, const uint32_t *regs) 262222900Snp{ 263222900Snp uint32_t reg_val = 0; 264222900Snp 265222900Snp for ( ; reg_array->name; ++reg_array) 266222900Snp if (!reg_array->len) { 267222900Snp reg_val = regs[reg_array->addr / 4]; 268222900Snp printf("[%#7x] %-47s %#-10x %u\n", reg_array->addr, 269222900Snp reg_array->name, reg_val, reg_val); 270222900Snp } else { 271222900Snp uint32_t v = xtract(reg_val, reg_array->addr, 272222900Snp reg_array->len); 273222900Snp 274222900Snp printf(" %*u:%u %-47s %#-10x %u\n", 275222900Snp reg_array->addr < 10 ? 3 : 2, 276222900Snp reg_array->addr + reg_array->len - 1, 277222900Snp reg_array->addr, reg_array->name, v, v); 278222900Snp } 279222900Snp 280222900Snp return (1); 281222900Snp} 282222900Snp 283222900Snpstatic int 284222900Snpdump_regs_table(int argc, const char *argv[], const uint32_t *regs, 285222900Snp const struct mod_regs *modtab, int nmodules) 286222900Snp{ 287222900Snp int i, j, match; 288222900Snp 289222900Snp for (i = 0; i < argc; i++) { 290222900Snp for (j = 0; j < nmodules; j++) { 291222900Snp if (!strcmp(argv[i], modtab[j].name)) 292222900Snp break; 293222900Snp } 294222900Snp 295222900Snp if (j == nmodules) { 296222900Snp warnx("invalid register block \"%s\"", argv[i]); 297222900Snp fprintf(stderr, "\nAvailable blocks:"); 298222900Snp for ( ; nmodules; nmodules--, modtab++) 299222900Snp fprintf(stderr, " %s", modtab->name); 300222900Snp fprintf(stderr, "\n"); 301222900Snp return (EINVAL); 302222900Snp } 303222900Snp } 304222900Snp 305222900Snp for ( ; nmodules; nmodules--, modtab++) { 306222900Snp 307222900Snp match = argc == 0 ? 1 : 0; 308222900Snp for (i = 0; !match && i < argc; i++) { 309222900Snp if (!strcmp(argv[i], modtab->name)) 310222900Snp match = 1; 311222900Snp } 312222900Snp 313222900Snp if (match) 314222900Snp dump_block_regs(modtab->ri, regs); 315222900Snp } 316222900Snp 317222900Snp return (0); 318222900Snp} 319222900Snp 320222900Snp#define T4_MODREGS(name) { #name, t4_##name##_regs } 321222900Snpstatic int 322222900Snpdump_regs_t4(int argc, const char *argv[], const uint32_t *regs) 323222900Snp{ 324222900Snp static struct mod_regs t4_mod[] = { 325222900Snp T4_MODREGS(sge), 326222900Snp { "pci", t4_pcie_regs }, 327222900Snp T4_MODREGS(dbg), 328222900Snp T4_MODREGS(mc), 329222900Snp T4_MODREGS(ma), 330222900Snp { "edc0", t4_edc_0_regs }, 331222900Snp { "edc1", t4_edc_1_regs }, 332259048Snp T4_MODREGS(cim), 333222900Snp T4_MODREGS(tp), 334222900Snp T4_MODREGS(ulp_rx), 335222900Snp T4_MODREGS(ulp_tx), 336222900Snp { "pmrx", t4_pm_rx_regs }, 337222900Snp { "pmtx", t4_pm_tx_regs }, 338222900Snp T4_MODREGS(mps), 339222900Snp { "cplsw", t4_cpl_switch_regs }, 340222900Snp T4_MODREGS(smb), 341222900Snp { "i2c", t4_i2cm_regs }, 342222900Snp T4_MODREGS(mi), 343222900Snp T4_MODREGS(uart), 344259048Snp T4_MODREGS(pmu), 345222900Snp T4_MODREGS(sf), 346222900Snp T4_MODREGS(pl), 347222900Snp T4_MODREGS(le), 348222900Snp T4_MODREGS(ncsi), 349222900Snp T4_MODREGS(xgmac) 350222900Snp }; 351222900Snp 352287297Srodrigc return dump_regs_table(argc, argv, regs, t4_mod, nitems(t4_mod)); 353222900Snp} 354222900Snp#undef T4_MODREGS 355222900Snp 356248925Snp#define T5_MODREGS(name) { #name, t5_##name##_regs } 357222900Snpstatic int 358248925Snpdump_regs_t5(int argc, const char *argv[], const uint32_t *regs) 359248925Snp{ 360248925Snp static struct mod_regs t5_mod[] = { 361248925Snp T5_MODREGS(sge), 362248925Snp { "pci", t5_pcie_regs }, 363248925Snp T5_MODREGS(dbg), 364248925Snp { "mc0", t5_mc_0_regs }, 365248925Snp { "mc1", t5_mc_1_regs }, 366248925Snp T5_MODREGS(ma), 367248925Snp { "edc0", t5_edc_t50_regs }, 368248925Snp { "edc1", t5_edc_t51_regs }, 369248925Snp T5_MODREGS(cim), 370248925Snp T5_MODREGS(tp), 371248925Snp { "ulprx", t5_ulp_rx_regs }, 372248925Snp { "ulptx", t5_ulp_tx_regs }, 373248925Snp { "pmrx", t5_pm_rx_regs }, 374248925Snp { "pmtx", t5_pm_tx_regs }, 375248925Snp T5_MODREGS(mps), 376248925Snp { "cplsw", t5_cpl_switch_regs }, 377248925Snp T5_MODREGS(smb), 378248925Snp { "i2c", t5_i2cm_regs }, 379248925Snp T5_MODREGS(mi), 380248925Snp T5_MODREGS(uart), 381248925Snp T5_MODREGS(pmu), 382248925Snp T5_MODREGS(sf), 383248925Snp T5_MODREGS(pl), 384248925Snp T5_MODREGS(le), 385248925Snp T5_MODREGS(ncsi), 386248925Snp T5_MODREGS(mac), 387248925Snp { "hma", t5_hma_t5_regs } 388248925Snp }; 389248925Snp 390287297Srodrigc return dump_regs_table(argc, argv, regs, t5_mod, nitems(t5_mod)); 391248925Snp} 392248925Snp#undef T5_MODREGS 393248925Snp 394296471Snp#define T6_MODREGS(name) { #name, t6_##name##_regs } 395248925Snpstatic int 396296471Snpdump_regs_t6(int argc, const char *argv[], const uint32_t *regs) 397296471Snp{ 398296471Snp static struct mod_regs t6_mod[] = { 399296471Snp T6_MODREGS(sge), 400296471Snp { "pci", t6_pcie_regs }, 401296471Snp T6_MODREGS(dbg), 402296471Snp { "mc0", t6_mc_0_regs }, 403296471Snp T6_MODREGS(ma), 404296471Snp { "edc0", t6_edc_t60_regs }, 405296471Snp { "edc1", t6_edc_t61_regs }, 406296471Snp T6_MODREGS(cim), 407296471Snp T6_MODREGS(tp), 408296471Snp { "ulprx", t6_ulp_rx_regs }, 409296471Snp { "ulptx", t6_ulp_tx_regs }, 410296471Snp { "pmrx", t6_pm_rx_regs }, 411296471Snp { "pmtx", t6_pm_tx_regs }, 412296471Snp T6_MODREGS(mps), 413296471Snp { "cplsw", t6_cpl_switch_regs }, 414296471Snp T6_MODREGS(smb), 415296471Snp { "i2c", t6_i2cm_regs }, 416296471Snp T6_MODREGS(mi), 417296471Snp T6_MODREGS(uart), 418296471Snp T6_MODREGS(pmu), 419296471Snp T6_MODREGS(sf), 420296471Snp T6_MODREGS(pl), 421296471Snp T6_MODREGS(le), 422296471Snp T6_MODREGS(ncsi), 423296471Snp T6_MODREGS(mac), 424296471Snp { "hma", t6_hma_t6_regs } 425296471Snp }; 426296471Snp 427296471Snp return dump_regs_table(argc, argv, regs, t6_mod, nitems(t6_mod)); 428296471Snp} 429296471Snp#undef T6_MODREGS 430296471Snp 431296471Snpstatic int 432296471Snpdump_regs_t4vf(int argc, const char *argv[], const uint32_t *regs) 433296471Snp{ 434296471Snp static struct mod_regs t4vf_mod[] = { 435296471Snp { "sge", t4vf_sge_regs }, 436296471Snp { "mps", t4vf_mps_regs }, 437296471Snp { "pl", t4vf_pl_regs }, 438296471Snp { "mbdata", t4vf_mbdata_regs }, 439296471Snp { "cim", t4vf_cim_regs }, 440296471Snp }; 441296471Snp 442296471Snp return dump_regs_table(argc, argv, regs, t4vf_mod, nitems(t4vf_mod)); 443296471Snp} 444296471Snp 445296471Snpstatic int 446296471Snpdump_regs_t5vf(int argc, const char *argv[], const uint32_t *regs) 447296471Snp{ 448296471Snp static struct mod_regs t5vf_mod[] = { 449296471Snp { "sge", t5vf_sge_regs }, 450296471Snp { "mps", t4vf_mps_regs }, 451296471Snp { "pl", t5vf_pl_regs }, 452296471Snp { "mbdata", t4vf_mbdata_regs }, 453296471Snp { "cim", t4vf_cim_regs }, 454296471Snp }; 455296471Snp 456296471Snp return dump_regs_table(argc, argv, regs, t5vf_mod, nitems(t5vf_mod)); 457296471Snp} 458296471Snp 459296471Snpstatic int 460296471Snpdump_regs_t6vf(int argc, const char *argv[], const uint32_t *regs) 461296471Snp{ 462296471Snp static struct mod_regs t6vf_mod[] = { 463296471Snp { "sge", t5vf_sge_regs }, 464296471Snp { "mps", t4vf_mps_regs }, 465296471Snp { "pl", t6vf_pl_regs }, 466296471Snp { "mbdata", t4vf_mbdata_regs }, 467296471Snp { "cim", t4vf_cim_regs }, 468296471Snp }; 469296471Snp 470296471Snp return dump_regs_table(argc, argv, regs, t6vf_mod, nitems(t6vf_mod)); 471296471Snp} 472296471Snp 473296471Snpstatic int 474222900Snpdump_regs(int argc, const char *argv[]) 475222900Snp{ 476248925Snp int vers, revision, rc; 477222900Snp struct t4_regdump regs; 478248925Snp uint32_t len; 479222900Snp 480248925Snp len = max(T4_REGDUMP_SIZE, T5_REGDUMP_SIZE); 481248925Snp regs.data = calloc(1, len); 482222900Snp if (regs.data == NULL) { 483222900Snp warnc(ENOMEM, "regdump"); 484222900Snp return (ENOMEM); 485222900Snp } 486222900Snp 487248925Snp regs.len = len; 488222900Snp rc = doit(CHELSIO_T4_REGDUMP, ®s); 489222900Snp if (rc != 0) 490222900Snp return (rc); 491222900Snp 492222900Snp vers = get_card_vers(regs.version); 493222900Snp revision = (regs.version >> 10) & 0x3f; 494222900Snp 495222900Snp if (vers == 4) { 496222900Snp if (revision == 0x3f) 497222900Snp rc = dump_regs_t4vf(argc, argv, regs.data); 498222900Snp else 499222900Snp rc = dump_regs_t4(argc, argv, regs.data); 500296471Snp } else if (vers == 5) { 501296471Snp if (revision == 0x3f) 502296471Snp rc = dump_regs_t5vf(argc, argv, regs.data); 503296471Snp else 504296471Snp rc = dump_regs_t5(argc, argv, regs.data); 505296471Snp } else if (vers == 6) { 506296471Snp if (revision == 0x3f) 507296471Snp rc = dump_regs_t6vf(argc, argv, regs.data); 508296471Snp else 509296471Snp rc = dump_regs_t6(argc, argv, regs.data); 510296471Snp } else { 511248925Snp warnx("%s (type %d, rev %d) is not a known card.", 512222900Snp nexus, vers, revision); 513222900Snp return (ENOTSUP); 514222900Snp } 515222900Snp 516222900Snp free(regs.data); 517222900Snp return (rc); 518222900Snp} 519222900Snp 520222900Snpstatic void 521222900Snpdo_show_info_header(uint32_t mode) 522222900Snp{ 523222900Snp uint32_t i; 524222900Snp 525296236Snp printf("%4s %8s", "Idx", "Hits"); 526222900Snp for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) { 527222900Snp switch (mode & i) { 528222900Snp case T4_FILTER_FCoE: 529296236Snp printf(" FCoE"); 530222900Snp break; 531222900Snp 532222900Snp case T4_FILTER_PORT: 533296236Snp printf(" Port"); 534222900Snp break; 535222900Snp 536228561Snp case T4_FILTER_VNIC: 537296481Snp if (mode & T4_FILTER_IC_VNIC) 538296481Snp printf(" VFvld:PF:VF"); 539296481Snp else 540296481Snp printf(" vld:oVLAN"); 541222900Snp break; 542222900Snp 543228561Snp case T4_FILTER_VLAN: 544296236Snp printf(" vld:VLAN"); 545222900Snp break; 546222900Snp 547222900Snp case T4_FILTER_IP_TOS: 548296236Snp printf(" TOS"); 549222900Snp break; 550222900Snp 551222900Snp case T4_FILTER_IP_PROTO: 552296236Snp printf(" Prot"); 553222900Snp break; 554222900Snp 555222900Snp case T4_FILTER_ETH_TYPE: 556296236Snp printf(" EthType"); 557222900Snp break; 558222900Snp 559222900Snp case T4_FILTER_MAC_IDX: 560296236Snp printf(" MACIdx"); 561222900Snp break; 562222900Snp 563222900Snp case T4_FILTER_MPS_HIT_TYPE: 564296236Snp printf(" MPS"); 565222900Snp break; 566222900Snp 567222900Snp case T4_FILTER_IP_FRAGMENT: 568296236Snp printf(" Frag"); 569222900Snp break; 570222900Snp 571222900Snp default: 572222900Snp /* compressed filter field not enabled */ 573222900Snp break; 574222900Snp } 575222900Snp } 576222900Snp printf(" %20s %20s %9s %9s %s\n", 577222900Snp "DIP", "SIP", "DPORT", "SPORT", "Action"); 578222900Snp} 579222900Snp 580222900Snp/* 581222900Snp * Parse an argument sub-vector as a { <parameter name> <value>[:<mask>] } 582222900Snp * ordered tuple. If the parameter name in the argument sub-vector does not 583222900Snp * match the passed in parameter name, then a zero is returned for the 584222900Snp * function and no parsing is performed. If there is a match, then the value 585222900Snp * and optional mask are parsed and returned in the provided return value 586222900Snp * pointers. If no optional mask is specified, then a default mask of all 1s 587222900Snp * will be returned. 588222900Snp * 589222900Snp * An error in parsing the value[:mask] will result in an error message and 590222900Snp * program termination. 591222900Snp */ 592222900Snpstatic int 593222900Snpparse_val_mask(const char *param, const char *args[], uint32_t *val, 594222900Snp uint32_t *mask) 595222900Snp{ 596222900Snp char *p; 597222900Snp 598222900Snp if (strcmp(param, args[0]) != 0) 599222900Snp return (EINVAL); 600222900Snp 601222900Snp *val = strtoul(args[1], &p, 0); 602222900Snp if (p > args[1]) { 603222900Snp if (p[0] == 0) { 604222900Snp *mask = ~0; 605222900Snp return (0); 606222900Snp } 607222900Snp 608222900Snp if (p[0] == ':' && p[1] != 0) { 609222900Snp *mask = strtoul(p+1, &p, 0); 610222900Snp if (p[0] == 0) 611222900Snp return (0); 612222900Snp } 613222900Snp } 614222900Snp 615222900Snp warnx("parameter \"%s\" has bad \"value[:mask]\" %s", 616222900Snp args[0], args[1]); 617222900Snp 618222900Snp return (EINVAL); 619222900Snp} 620222900Snp 621222900Snp/* 622222900Snp * Parse an argument sub-vector as a { <parameter name> <addr>[/<mask>] } 623222900Snp * ordered tuple. If the parameter name in the argument sub-vector does not 624222900Snp * match the passed in parameter name, then a zero is returned for the 625222900Snp * function and no parsing is performed. If there is a match, then the value 626222900Snp * and optional mask are parsed and returned in the provided return value 627222900Snp * pointers. If no optional mask is specified, then a default mask of all 1s 628222900Snp * will be returned. 629222900Snp * 630222900Snp * The value return parameter "afp" is used to specify the expected address 631222900Snp * family -- IPv4 or IPv6 -- of the address[/mask] and return its actual 632222900Snp * format. A passed in value of AF_UNSPEC indicates that either IPv4 or IPv6 633222900Snp * is acceptable; AF_INET means that only IPv4 addresses are acceptable; and 634222900Snp * AF_INET6 means that only IPv6 are acceptable. AF_INET is returned for IPv4 635222900Snp * and AF_INET6 for IPv6 addresses, respectively. IPv4 address/mask pairs are 636222900Snp * returned in the first four bytes of the address and mask return values with 637222900Snp * the address A.B.C.D returned with { A, B, C, D } returned in addresses { 0, 638222900Snp * 1, 2, 3}, respectively. 639222900Snp * 640222900Snp * An error in parsing the value[:mask] will result in an error message and 641222900Snp * program termination. 642222900Snp */ 643222900Snpstatic int 644222900Snpparse_ipaddr(const char *param, const char *args[], int *afp, uint8_t addr[], 645222900Snp uint8_t mask[]) 646222900Snp{ 647222900Snp const char *colon, *afn; 648222900Snp char *slash; 649222900Snp uint8_t *m; 650222900Snp int af, ret; 651222900Snp unsigned int masksize; 652222900Snp 653222900Snp /* 654222900Snp * Is this our parameter? 655222900Snp */ 656222900Snp if (strcmp(param, args[0]) != 0) 657222900Snp return (EINVAL); 658222900Snp 659222900Snp /* 660222900Snp * Fundamental IPv4 versus IPv6 selection. 661222900Snp */ 662222900Snp colon = strchr(args[1], ':'); 663222900Snp if (!colon) { 664222900Snp afn = "IPv4"; 665222900Snp af = AF_INET; 666222900Snp masksize = 32; 667222900Snp } else { 668222900Snp afn = "IPv6"; 669222900Snp af = AF_INET6; 670222900Snp masksize = 128; 671222900Snp } 672222900Snp if (*afp == AF_UNSPEC) 673222900Snp *afp = af; 674222900Snp else if (*afp != af) { 675222900Snp warnx("address %s is not of expected family %s", 676222900Snp args[1], *afp == AF_INET ? "IP" : "IPv6"); 677222900Snp return (EINVAL); 678222900Snp } 679222900Snp 680222900Snp /* 681222900Snp * Parse address (temporarily stripping off any "/mask" 682222900Snp * specification). 683222900Snp */ 684222900Snp slash = strchr(args[1], '/'); 685222900Snp if (slash) 686222900Snp *slash = 0; 687222900Snp ret = inet_pton(af, args[1], addr); 688222900Snp if (slash) 689222900Snp *slash = '/'; 690222900Snp if (ret <= 0) { 691222900Snp warnx("Cannot parse %s %s address %s", param, afn, args[1]); 692222900Snp return (EINVAL); 693222900Snp } 694222900Snp 695222900Snp /* 696222900Snp * Parse optional mask specification. 697222900Snp */ 698222900Snp if (slash) { 699222900Snp char *p; 700222900Snp unsigned int prefix = strtoul(slash + 1, &p, 10); 701222900Snp 702222900Snp if (p == slash + 1) { 703222900Snp warnx("missing address prefix for %s", param); 704222900Snp return (EINVAL); 705222900Snp } 706222900Snp if (*p) { 707222900Snp warnx("%s is not a valid address prefix", slash + 1); 708222900Snp return (EINVAL); 709222900Snp } 710222900Snp if (prefix > masksize) { 711222900Snp warnx("prefix %u is too long for an %s address", 712222900Snp prefix, afn); 713222900Snp return (EINVAL); 714222900Snp } 715222900Snp memset(mask, 0, masksize / 8); 716222900Snp masksize = prefix; 717222900Snp } 718222900Snp 719222900Snp /* 720222900Snp * Fill in mask. 721222900Snp */ 722222900Snp for (m = mask; masksize >= 8; m++, masksize -= 8) 723222900Snp *m = ~0; 724222900Snp if (masksize) 725222900Snp *m = ~0 << (8 - masksize); 726222900Snp 727222900Snp return (0); 728222900Snp} 729222900Snp 730222900Snp/* 731222900Snp * Parse an argument sub-vector as a { <parameter name> <value> } ordered 732222900Snp * tuple. If the parameter name in the argument sub-vector does not match the 733222900Snp * passed in parameter name, then a zero is returned for the function and no 734222900Snp * parsing is performed. If there is a match, then the value is parsed and 735222900Snp * returned in the provided return value pointer. 736222900Snp */ 737222900Snpstatic int 738222900Snpparse_val(const char *param, const char *args[], uint32_t *val) 739222900Snp{ 740222900Snp char *p; 741222900Snp 742222900Snp if (strcmp(param, args[0]) != 0) 743222900Snp return (EINVAL); 744222900Snp 745222900Snp *val = strtoul(args[1], &p, 0); 746222900Snp if (p > args[1] && p[0] == 0) 747222900Snp return (0); 748222900Snp 749222900Snp warnx("parameter \"%s\" has bad \"value\" %s", args[0], args[1]); 750222900Snp return (EINVAL); 751222900Snp} 752222900Snp 753222900Snpstatic void 754222900Snpfilters_show_ipaddr(int type, uint8_t *addr, uint8_t *addrm) 755222900Snp{ 756222900Snp int noctets, octet; 757222900Snp 758222900Snp printf(" "); 759222900Snp if (type == 0) { 760222900Snp noctets = 4; 761222900Snp printf("%3s", " "); 762222900Snp } else 763222900Snp noctets = 16; 764222900Snp 765222900Snp for (octet = 0; octet < noctets; octet++) 766222900Snp printf("%02x", addr[octet]); 767222900Snp printf("/"); 768222900Snp for (octet = 0; octet < noctets; octet++) 769222900Snp printf("%02x", addrm[octet]); 770222900Snp} 771222900Snp 772222900Snpstatic void 773222900Snpdo_show_one_filter_info(struct t4_filter *t, uint32_t mode) 774222900Snp{ 775222900Snp uint32_t i; 776222900Snp 777222900Snp printf("%4d", t->idx); 778222900Snp if (t->hits == UINT64_MAX) 779222900Snp printf(" %8s", "-"); 780222900Snp else 781222900Snp printf(" %8ju", t->hits); 782222900Snp 783222900Snp /* 784222900Snp * Compressed header portion of filter. 785222900Snp */ 786222900Snp for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) { 787222900Snp switch (mode & i) { 788222900Snp case T4_FILTER_FCoE: 789222900Snp printf(" %1d/%1d", t->fs.val.fcoe, t->fs.mask.fcoe); 790222900Snp break; 791222900Snp 792222900Snp case T4_FILTER_PORT: 793222900Snp printf(" %1d/%1d", t->fs.val.iport, t->fs.mask.iport); 794222900Snp break; 795222900Snp 796228561Snp case T4_FILTER_VNIC: 797296481Snp if (mode & T4_FILTER_IC_VNIC) { 798296481Snp printf(" %1d:%1x:%02x/%1d:%1x:%02x", 799296481Snp t->fs.val.pfvf_vld, 800296481Snp (t->fs.val.vnic >> 13) & 0x7, 801296481Snp t->fs.val.vnic & 0x1fff, 802296481Snp t->fs.mask.pfvf_vld, 803296481Snp (t->fs.mask.vnic >> 13) & 0x7, 804296481Snp t->fs.mask.vnic & 0x1fff); 805296481Snp } else { 806296481Snp printf(" %1d:%04x/%1d:%04x", 807296481Snp t->fs.val.ovlan_vld, t->fs.val.vnic, 808296481Snp t->fs.mask.ovlan_vld, t->fs.mask.vnic); 809296481Snp } 810222900Snp break; 811222900Snp 812228561Snp case T4_FILTER_VLAN: 813222900Snp printf(" %1d:%04x/%1d:%04x", 814228561Snp t->fs.val.vlan_vld, t->fs.val.vlan, 815228561Snp t->fs.mask.vlan_vld, t->fs.mask.vlan); 816222900Snp break; 817222900Snp 818222900Snp case T4_FILTER_IP_TOS: 819222900Snp printf(" %02x/%02x", t->fs.val.tos, t->fs.mask.tos); 820222900Snp break; 821222900Snp 822222900Snp case T4_FILTER_IP_PROTO: 823222900Snp printf(" %02x/%02x", t->fs.val.proto, t->fs.mask.proto); 824222900Snp break; 825222900Snp 826222900Snp case T4_FILTER_ETH_TYPE: 827222900Snp printf(" %04x/%04x", t->fs.val.ethtype, 828222900Snp t->fs.mask.ethtype); 829222900Snp break; 830222900Snp 831222900Snp case T4_FILTER_MAC_IDX: 832222900Snp printf(" %03x/%03x", t->fs.val.macidx, 833222900Snp t->fs.mask.macidx); 834222900Snp break; 835222900Snp 836222900Snp case T4_FILTER_MPS_HIT_TYPE: 837222900Snp printf(" %1x/%1x", t->fs.val.matchtype, 838222900Snp t->fs.mask.matchtype); 839222900Snp break; 840222900Snp 841222900Snp case T4_FILTER_IP_FRAGMENT: 842222900Snp printf(" %1d/%1d", t->fs.val.frag, t->fs.mask.frag); 843222900Snp break; 844222900Snp 845222900Snp default: 846222900Snp /* compressed filter field not enabled */ 847222900Snp break; 848222900Snp } 849222900Snp } 850222900Snp 851222900Snp /* 852222900Snp * Fixed portion of filter. 853222900Snp */ 854222900Snp filters_show_ipaddr(t->fs.type, t->fs.val.dip, t->fs.mask.dip); 855222900Snp filters_show_ipaddr(t->fs.type, t->fs.val.sip, t->fs.mask.sip); 856222900Snp printf(" %04x/%04x %04x/%04x", 857222900Snp t->fs.val.dport, t->fs.mask.dport, 858222900Snp t->fs.val.sport, t->fs.mask.sport); 859222900Snp 860222900Snp /* 861222900Snp * Variable length filter action. 862222900Snp */ 863222900Snp if (t->fs.action == FILTER_DROP) 864222900Snp printf(" Drop"); 865222900Snp else if (t->fs.action == FILTER_SWITCH) { 866222900Snp printf(" Switch: port=%d", t->fs.eport); 867222900Snp if (t->fs.newdmac) 868222900Snp printf( 869222900Snp ", dmac=%02x:%02x:%02x:%02x:%02x:%02x " 870222900Snp ", l2tidx=%d", 871222900Snp t->fs.dmac[0], t->fs.dmac[1], 872222900Snp t->fs.dmac[2], t->fs.dmac[3], 873222900Snp t->fs.dmac[4], t->fs.dmac[5], 874222900Snp t->l2tidx); 875222900Snp if (t->fs.newsmac) 876222900Snp printf( 877222900Snp ", smac=%02x:%02x:%02x:%02x:%02x:%02x " 878222900Snp ", smtidx=%d", 879222900Snp t->fs.smac[0], t->fs.smac[1], 880222900Snp t->fs.smac[2], t->fs.smac[3], 881222900Snp t->fs.smac[4], t->fs.smac[5], 882222900Snp t->smtidx); 883222900Snp if (t->fs.newvlan == VLAN_REMOVE) 884222900Snp printf(", vlan=none"); 885222900Snp else if (t->fs.newvlan == VLAN_INSERT) 886222900Snp printf(", vlan=insert(%x)", t->fs.vlan); 887222900Snp else if (t->fs.newvlan == VLAN_REWRITE) 888222900Snp printf(", vlan=rewrite(%x)", t->fs.vlan); 889222900Snp } else { 890222900Snp printf(" Pass: Q="); 891222900Snp if (t->fs.dirsteer == 0) { 892222900Snp printf("RSS"); 893222900Snp if (t->fs.maskhash) 894222900Snp printf("(TCB=hash)"); 895222900Snp } else { 896222900Snp printf("%d", t->fs.iq); 897222900Snp if (t->fs.dirsteerhash == 0) 898222900Snp printf("(QID)"); 899222900Snp else 900222900Snp printf("(hash)"); 901222900Snp } 902222900Snp } 903222900Snp if (t->fs.prio) 904222900Snp printf(" Prio"); 905222900Snp if (t->fs.rpttid) 906222900Snp printf(" RptTID"); 907222900Snp printf("\n"); 908222900Snp} 909222900Snp 910222900Snpstatic int 911222900Snpshow_filters(void) 912222900Snp{ 913222900Snp uint32_t mode = 0, header = 0; 914222900Snp struct t4_filter t; 915222900Snp int rc; 916222900Snp 917222900Snp /* Get the global filter mode first */ 918222900Snp rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode); 919222900Snp if (rc != 0) 920222900Snp return (rc); 921222900Snp 922222900Snp t.idx = 0; 923222900Snp for (t.idx = 0; ; t.idx++) { 924222900Snp rc = doit(CHELSIO_T4_GET_FILTER, &t); 925222900Snp if (rc != 0 || t.idx == 0xffffffff) 926222900Snp break; 927222900Snp 928222900Snp if (!header) { 929222900Snp do_show_info_header(mode); 930222900Snp header = 1; 931222900Snp } 932222900Snp do_show_one_filter_info(&t, mode); 933222900Snp }; 934222900Snp 935222900Snp return (rc); 936222900Snp} 937222900Snp 938222900Snpstatic int 939222900Snpget_filter_mode(void) 940222900Snp{ 941222900Snp uint32_t mode = 0; 942222900Snp int rc; 943222900Snp 944222900Snp rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode); 945222900Snp if (rc != 0) 946222900Snp return (rc); 947222900Snp 948222900Snp if (mode & T4_FILTER_IPv4) 949222900Snp printf("ipv4 "); 950222900Snp 951222900Snp if (mode & T4_FILTER_IPv6) 952222900Snp printf("ipv6 "); 953222900Snp 954222900Snp if (mode & T4_FILTER_IP_SADDR) 955222900Snp printf("sip "); 956296236Snp 957222900Snp if (mode & T4_FILTER_IP_DADDR) 958222900Snp printf("dip "); 959222900Snp 960222900Snp if (mode & T4_FILTER_IP_SPORT) 961222900Snp printf("sport "); 962222900Snp 963222900Snp if (mode & T4_FILTER_IP_DPORT) 964222900Snp printf("dport "); 965222900Snp 966249368Snp if (mode & T4_FILTER_IP_FRAGMENT) 967249368Snp printf("frag "); 968249368Snp 969222900Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 970222900Snp printf("matchtype "); 971222900Snp 972222900Snp if (mode & T4_FILTER_MAC_IDX) 973222900Snp printf("macidx "); 974222900Snp 975222900Snp if (mode & T4_FILTER_ETH_TYPE) 976222900Snp printf("ethtype "); 977222900Snp 978222900Snp if (mode & T4_FILTER_IP_PROTO) 979222900Snp printf("proto "); 980222900Snp 981222900Snp if (mode & T4_FILTER_IP_TOS) 982222900Snp printf("tos "); 983222900Snp 984228561Snp if (mode & T4_FILTER_VLAN) 985228561Snp printf("vlan "); 986222900Snp 987296481Snp if (mode & T4_FILTER_VNIC) { 988296481Snp if (mode & T4_FILTER_IC_VNIC) 989296481Snp printf("vnic_id "); 990296481Snp else 991296481Snp printf("ovlan "); 992296481Snp } 993222900Snp 994222900Snp if (mode & T4_FILTER_PORT) 995222900Snp printf("iport "); 996222900Snp 997222900Snp if (mode & T4_FILTER_FCoE) 998222900Snp printf("fcoe "); 999222900Snp 1000222900Snp printf("\n"); 1001222900Snp 1002222900Snp return (0); 1003222900Snp} 1004222900Snp 1005222900Snpstatic int 1006222900Snpset_filter_mode(int argc, const char *argv[]) 1007222900Snp{ 1008222900Snp uint32_t mode = 0; 1009296481Snp int vnic = 0, ovlan = 0; 1010222900Snp 1011222900Snp for (; argc; argc--, argv++) { 1012249368Snp if (!strcmp(argv[0], "frag")) 1013249368Snp mode |= T4_FILTER_IP_FRAGMENT; 1014249368Snp 1015222900Snp if (!strcmp(argv[0], "matchtype")) 1016222900Snp mode |= T4_FILTER_MPS_HIT_TYPE; 1017222900Snp 1018222900Snp if (!strcmp(argv[0], "macidx")) 1019222900Snp mode |= T4_FILTER_MAC_IDX; 1020222900Snp 1021222900Snp if (!strcmp(argv[0], "ethtype")) 1022222900Snp mode |= T4_FILTER_ETH_TYPE; 1023222900Snp 1024222900Snp if (!strcmp(argv[0], "proto")) 1025222900Snp mode |= T4_FILTER_IP_PROTO; 1026222900Snp 1027222900Snp if (!strcmp(argv[0], "tos")) 1028222900Snp mode |= T4_FILTER_IP_TOS; 1029222900Snp 1030228561Snp if (!strcmp(argv[0], "vlan")) 1031228561Snp mode |= T4_FILTER_VLAN; 1032222900Snp 1033296481Snp if (!strcmp(argv[0], "ovlan")) { 1034228561Snp mode |= T4_FILTER_VNIC; 1035296481Snp ovlan++; 1036296481Snp } 1037222900Snp 1038296481Snp if (!strcmp(argv[0], "vnic_id")) { 1039296481Snp mode |= T4_FILTER_VNIC; 1040296481Snp mode |= T4_FILTER_IC_VNIC; 1041296481Snp vnic++; 1042296481Snp } 1043296481Snp 1044222900Snp if (!strcmp(argv[0], "iport")) 1045222900Snp mode |= T4_FILTER_PORT; 1046222900Snp 1047222900Snp if (!strcmp(argv[0], "fcoe")) 1048222900Snp mode |= T4_FILTER_FCoE; 1049222900Snp } 1050222900Snp 1051296481Snp if (vnic > 0 && ovlan > 0) { 1052296481Snp warnx("\"vnic_id\" and \"ovlan\" are mutually exclusive."); 1053296481Snp return (EINVAL); 1054296481Snp } 1055296481Snp 1056222900Snp return doit(CHELSIO_T4_SET_FILTER_MODE, &mode); 1057222900Snp} 1058222900Snp 1059222900Snpstatic int 1060222900Snpdel_filter(uint32_t idx) 1061222900Snp{ 1062222900Snp struct t4_filter t; 1063222900Snp 1064222900Snp t.idx = idx; 1065222900Snp 1066222900Snp return doit(CHELSIO_T4_DEL_FILTER, &t); 1067222900Snp} 1068222900Snp 1069222900Snpstatic int 1070222900Snpset_filter(uint32_t idx, int argc, const char *argv[]) 1071222900Snp{ 1072222900Snp int af = AF_UNSPEC, start_arg = 0; 1073222900Snp struct t4_filter t; 1074222900Snp 1075222900Snp if (argc < 2) { 1076222900Snp warnc(EINVAL, "%s", __func__); 1077222900Snp return (EINVAL); 1078222900Snp }; 1079222900Snp bzero(&t, sizeof (t)); 1080222900Snp t.idx = idx; 1081252470Snp t.fs.hitcnts = 1; 1082222900Snp 1083222900Snp for (start_arg = 0; start_arg + 2 <= argc; start_arg += 2) { 1084222900Snp const char **args = &argv[start_arg]; 1085222900Snp uint32_t val, mask; 1086222900Snp 1087222900Snp if (!strcmp(argv[start_arg], "type")) { 1088222900Snp int newaf; 1089222900Snp if (!strcasecmp(argv[start_arg + 1], "ipv4")) 1090222900Snp newaf = AF_INET; 1091222900Snp else if (!strcasecmp(argv[start_arg + 1], "ipv6")) 1092222900Snp newaf = AF_INET6; 1093222900Snp else { 1094222900Snp warnx("invalid type \"%s\"; " 1095222900Snp "must be one of \"ipv4\" or \"ipv6\"", 1096222900Snp argv[start_arg + 1]); 1097222900Snp return (EINVAL); 1098222900Snp } 1099222900Snp 1100222900Snp if (af != AF_UNSPEC && af != newaf) { 1101222900Snp warnx("conflicting IPv4/IPv6 specifications."); 1102222900Snp return (EINVAL); 1103222900Snp } 1104222900Snp af = newaf; 1105222900Snp } else if (!parse_val_mask("fcoe", args, &val, &mask)) { 1106222900Snp t.fs.val.fcoe = val; 1107222900Snp t.fs.mask.fcoe = mask; 1108222900Snp } else if (!parse_val_mask("iport", args, &val, &mask)) { 1109222900Snp t.fs.val.iport = val; 1110222900Snp t.fs.mask.iport = mask; 1111222900Snp } else if (!parse_val_mask("ovlan", args, &val, &mask)) { 1112228561Snp t.fs.val.vnic = val; 1113228561Snp t.fs.mask.vnic = mask; 1114296481Snp t.fs.val.ovlan_vld = 1; 1115296481Snp t.fs.mask.ovlan_vld = 1; 1116245520Snp } else if (!parse_val_mask("ivlan", args, &val, &mask)) { 1117228561Snp t.fs.val.vlan = val; 1118228561Snp t.fs.mask.vlan = mask; 1119228561Snp t.fs.val.vlan_vld = 1; 1120228561Snp t.fs.mask.vlan_vld = 1; 1121296481Snp } else if (!parse_val_mask("pf", args, &val, &mask)) { 1122296481Snp t.fs.val.vnic &= 0x1fff; 1123296481Snp t.fs.val.vnic |= (val & 0x7) << 13; 1124296481Snp t.fs.mask.vnic &= 0x1fff; 1125296481Snp t.fs.mask.vnic |= (mask & 0x7) << 13; 1126296481Snp t.fs.val.pfvf_vld = 1; 1127296481Snp t.fs.mask.pfvf_vld = 1; 1128296481Snp } else if (!parse_val_mask("vf", args, &val, &mask)) { 1129296481Snp t.fs.val.vnic &= 0xe000; 1130296481Snp t.fs.val.vnic |= val & 0x1fff; 1131296481Snp t.fs.mask.vnic &= 0xe000; 1132296481Snp t.fs.mask.vnic |= mask & 0x1fff; 1133296481Snp t.fs.val.pfvf_vld = 1; 1134296481Snp t.fs.mask.pfvf_vld = 1; 1135222900Snp } else if (!parse_val_mask("tos", args, &val, &mask)) { 1136222900Snp t.fs.val.tos = val; 1137222900Snp t.fs.mask.tos = mask; 1138222900Snp } else if (!parse_val_mask("proto", args, &val, &mask)) { 1139222900Snp t.fs.val.proto = val; 1140222900Snp t.fs.mask.proto = mask; 1141222900Snp } else if (!parse_val_mask("ethtype", args, &val, &mask)) { 1142222900Snp t.fs.val.ethtype = val; 1143222900Snp t.fs.mask.ethtype = mask; 1144222900Snp } else if (!parse_val_mask("macidx", args, &val, &mask)) { 1145222900Snp t.fs.val.macidx = val; 1146222900Snp t.fs.mask.macidx = mask; 1147222900Snp } else if (!parse_val_mask("matchtype", args, &val, &mask)) { 1148222900Snp t.fs.val.matchtype = val; 1149222900Snp t.fs.mask.matchtype = mask; 1150222900Snp } else if (!parse_val_mask("frag", args, &val, &mask)) { 1151222900Snp t.fs.val.frag = val; 1152222900Snp t.fs.mask.frag = mask; 1153222900Snp } else if (!parse_val_mask("dport", args, &val, &mask)) { 1154222900Snp t.fs.val.dport = val; 1155222900Snp t.fs.mask.dport = mask; 1156222900Snp } else if (!parse_val_mask("sport", args, &val, &mask)) { 1157222900Snp t.fs.val.sport = val; 1158222900Snp t.fs.mask.sport = mask; 1159222900Snp } else if (!parse_ipaddr("dip", args, &af, t.fs.val.dip, 1160222900Snp t.fs.mask.dip)) { 1161222900Snp /* nada */; 1162222900Snp } else if (!parse_ipaddr("sip", args, &af, t.fs.val.sip, 1163222900Snp t.fs.mask.sip)) { 1164222900Snp /* nada */; 1165222900Snp } else if (!strcmp(argv[start_arg], "action")) { 1166222900Snp if (!strcmp(argv[start_arg + 1], "pass")) 1167222900Snp t.fs.action = FILTER_PASS; 1168222900Snp else if (!strcmp(argv[start_arg + 1], "drop")) 1169222900Snp t.fs.action = FILTER_DROP; 1170222900Snp else if (!strcmp(argv[start_arg + 1], "switch")) 1171222900Snp t.fs.action = FILTER_SWITCH; 1172222900Snp else { 1173222900Snp warnx("invalid action \"%s\"; must be one of" 1174222900Snp " \"pass\", \"drop\" or \"switch\"", 1175222900Snp argv[start_arg + 1]); 1176222900Snp return (EINVAL); 1177222900Snp } 1178222900Snp } else if (!parse_val("hitcnts", args, &val)) { 1179222900Snp t.fs.hitcnts = val; 1180222900Snp } else if (!parse_val("prio", args, &val)) { 1181222900Snp t.fs.prio = val; 1182222900Snp } else if (!parse_val("rpttid", args, &val)) { 1183222900Snp t.fs.rpttid = 1; 1184222900Snp } else if (!parse_val("queue", args, &val)) { 1185222900Snp t.fs.dirsteer = 1; 1186222900Snp t.fs.iq = val; 1187222900Snp } else if (!parse_val("tcbhash", args, &val)) { 1188222900Snp t.fs.maskhash = 1; 1189222900Snp t.fs.dirsteerhash = 1; 1190222900Snp } else if (!parse_val("eport", args, &val)) { 1191222900Snp t.fs.eport = val; 1192222900Snp } else if (!strcmp(argv[start_arg], "dmac")) { 1193222900Snp struct ether_addr *daddr; 1194222900Snp 1195222900Snp daddr = ether_aton(argv[start_arg + 1]); 1196222900Snp if (daddr == NULL) { 1197222900Snp warnx("invalid dmac address \"%s\"", 1198222900Snp argv[start_arg + 1]); 1199222900Snp return (EINVAL); 1200222900Snp } 1201222900Snp memcpy(t.fs.dmac, daddr, ETHER_ADDR_LEN); 1202222900Snp t.fs.newdmac = 1; 1203222900Snp } else if (!strcmp(argv[start_arg], "smac")) { 1204222900Snp struct ether_addr *saddr; 1205222900Snp 1206222900Snp saddr = ether_aton(argv[start_arg + 1]); 1207222900Snp if (saddr == NULL) { 1208222900Snp warnx("invalid smac address \"%s\"", 1209222900Snp argv[start_arg + 1]); 1210222900Snp return (EINVAL); 1211222900Snp } 1212222900Snp memcpy(t.fs.smac, saddr, ETHER_ADDR_LEN); 1213222900Snp t.fs.newsmac = 1; 1214222900Snp } else if (!strcmp(argv[start_arg], "vlan")) { 1215222900Snp char *p; 1216222900Snp if (!strcmp(argv[start_arg + 1], "none")) { 1217222900Snp t.fs.newvlan = VLAN_REMOVE; 1218222900Snp } else if (argv[start_arg + 1][0] == '=') { 1219222900Snp t.fs.newvlan = VLAN_REWRITE; 1220222900Snp } else if (argv[start_arg + 1][0] == '+') { 1221222900Snp t.fs.newvlan = VLAN_INSERT; 1222245520Snp } else if (isdigit(argv[start_arg + 1][0]) && 1223245520Snp !parse_val_mask("vlan", args, &val, &mask)) { 1224245520Snp t.fs.val.vlan = val; 1225245520Snp t.fs.mask.vlan = mask; 1226245520Snp t.fs.val.vlan_vld = 1; 1227245520Snp t.fs.mask.vlan_vld = 1; 1228222900Snp } else { 1229222900Snp warnx("unknown vlan parameter \"%s\"; must" 1230245520Snp " be one of \"none\", \"=<vlan>\", " 1231245520Snp " \"+<vlan>\", or \"<vlan>\"", 1232245520Snp argv[start_arg + 1]); 1233222900Snp return (EINVAL); 1234222900Snp } 1235222900Snp if (t.fs.newvlan == VLAN_REWRITE || 1236222900Snp t.fs.newvlan == VLAN_INSERT) { 1237222900Snp t.fs.vlan = strtoul(argv[start_arg + 1] + 1, 1238222900Snp &p, 0); 1239222900Snp if (p == argv[start_arg + 1] + 1 || p[0] != 0) { 1240222900Snp warnx("invalid vlan \"%s\"", 1241222900Snp argv[start_arg + 1]); 1242222900Snp return (EINVAL); 1243222900Snp } 1244222900Snp } 1245222900Snp } else { 1246222900Snp warnx("invalid parameter \"%s\"", argv[start_arg]); 1247222900Snp return (EINVAL); 1248222900Snp } 1249222900Snp } 1250222900Snp if (start_arg != argc) { 1251222900Snp warnx("no value for \"%s\"", argv[start_arg]); 1252222900Snp return (EINVAL); 1253222900Snp } 1254222900Snp 1255222900Snp /* 1256222900Snp * Check basic sanity of option combinations. 1257222900Snp */ 1258222900Snp if (t.fs.action != FILTER_SWITCH && 1259222900Snp (t.fs.eport || t.fs.newdmac || t.fs.newsmac || t.fs.newvlan)) { 1260222900Snp warnx("prio, port dmac, smac and vlan only make sense with" 1261222900Snp " \"action switch\""); 1262222900Snp return (EINVAL); 1263222900Snp } 1264222900Snp if (t.fs.action != FILTER_PASS && 1265222900Snp (t.fs.rpttid || t.fs.dirsteer || t.fs.maskhash)) { 1266222900Snp warnx("rpttid, queue and tcbhash don't make sense with" 1267222900Snp " action \"drop\" or \"switch\""); 1268222900Snp return (EINVAL); 1269222900Snp } 1270296481Snp if (t.fs.val.ovlan_vld && t.fs.val.pfvf_vld) { 1271296481Snp warnx("ovlan and vnic_id (pf/vf) are mutually exclusive"); 1272296481Snp return (EINVAL); 1273296481Snp } 1274222900Snp 1275222900Snp t.fs.type = (af == AF_INET6 ? 1 : 0); /* default IPv4 */ 1276222900Snp return doit(CHELSIO_T4_SET_FILTER, &t); 1277222900Snp} 1278222900Snp 1279222900Snpstatic int 1280222900Snpfilter_cmd(int argc, const char *argv[]) 1281222900Snp{ 1282222900Snp long long val; 1283222900Snp uint32_t idx; 1284222900Snp char *s; 1285222900Snp 1286222900Snp if (argc == 0) { 1287222900Snp warnx("filter: no arguments."); 1288222900Snp return (EINVAL); 1289222900Snp }; 1290222900Snp 1291222900Snp /* list */ 1292222900Snp if (strcmp(argv[0], "list") == 0) { 1293222900Snp if (argc != 1) 1294222900Snp warnx("trailing arguments after \"list\" ignored."); 1295222900Snp 1296222900Snp return show_filters(); 1297222900Snp } 1298222900Snp 1299222900Snp /* mode */ 1300222900Snp if (argc == 1 && strcmp(argv[0], "mode") == 0) 1301222900Snp return get_filter_mode(); 1302222900Snp 1303222900Snp /* mode <mode> */ 1304222900Snp if (strcmp(argv[0], "mode") == 0) 1305222900Snp return set_filter_mode(argc - 1, argv + 1); 1306222900Snp 1307222900Snp /* <idx> ... */ 1308222900Snp s = str_to_number(argv[0], NULL, &val); 1309222900Snp if (*s || val > 0xffffffffU) { 1310222900Snp warnx("\"%s\" is neither an index nor a filter subcommand.", 1311222900Snp argv[0]); 1312222900Snp return (EINVAL); 1313222900Snp } 1314222900Snp idx = (uint32_t) val; 1315222900Snp 1316222900Snp /* <idx> delete|clear */ 1317222900Snp if (argc == 2 && 1318222900Snp (strcmp(argv[1], "delete") == 0 || strcmp(argv[1], "clear") == 0)) { 1319222900Snp return del_filter(idx); 1320222900Snp } 1321222900Snp 1322222900Snp /* <idx> [<param> <val>] ... */ 1323222900Snp return set_filter(idx, argc - 1, argv + 1); 1324222900Snp} 1325222900Snp 1326222974Snp/* 1327222974Snp * Shows the fields of a multi-word structure. The structure is considered to 1328222974Snp * consist of @nwords 32-bit words (i.e, it's an (@nwords * 32)-bit structure) 1329222974Snp * whose fields are described by @fd. The 32-bit words are given in @words 1330222974Snp * starting with the least significant 32-bit word. 1331222974Snp */ 1332222974Snpstatic void 1333222974Snpshow_struct(const uint32_t *words, int nwords, const struct field_desc *fd) 1334222974Snp{ 1335222974Snp unsigned int w = 0; 1336222974Snp const struct field_desc *p; 1337222974Snp 1338222974Snp for (p = fd; p->name; p++) 1339222974Snp w = max(w, strlen(p->name)); 1340222974Snp 1341222974Snp while (fd->name) { 1342222974Snp unsigned long long data; 1343222974Snp int first_word = fd->start / 32; 1344222974Snp int shift = fd->start % 32; 1345222974Snp int width = fd->end - fd->start + 1; 1346222974Snp unsigned long long mask = (1ULL << width) - 1; 1347222974Snp 1348222974Snp data = (words[first_word] >> shift) | 1349222974Snp ((uint64_t)words[first_word + 1] << (32 - shift)); 1350222974Snp if (shift) 1351222974Snp data |= ((uint64_t)words[first_word + 2] << (64 - shift)); 1352222974Snp data &= mask; 1353222974Snp if (fd->islog2) 1354222974Snp data = 1 << data; 1355222974Snp printf("%-*s ", w, fd->name); 1356222974Snp printf(fd->hex ? "%#llx\n" : "%llu\n", data << fd->shift); 1357222974Snp fd++; 1358222974Snp } 1359222974Snp} 1360222974Snp 1361222974Snp#define FIELD(name, start, end) { name, start, end, 0, 0, 0 } 1362222974Snp#define FIELD1(name, start) FIELD(name, start, start) 1363222974Snp 1364222974Snpstatic void 1365306137Snpshow_t5t6_ctxt(const struct t4_sge_context *p, int vers) 1366222974Snp{ 1367284984Snp static struct field_desc egress_t5[] = { 1368284984Snp FIELD("DCA_ST:", 181, 191), 1369222974Snp FIELD1("StatusPgNS:", 180), 1370222974Snp FIELD1("StatusPgRO:", 179), 1371222974Snp FIELD1("FetchNS:", 178), 1372222974Snp FIELD1("FetchRO:", 177), 1373222974Snp FIELD1("Valid:", 176), 1374222974Snp FIELD("PCIeDataChannel:", 174, 175), 1375284984Snp FIELD1("StatusPgTPHintEn:", 173), 1376284984Snp FIELD("StatusPgTPHint:", 171, 172), 1377284984Snp FIELD1("FetchTPHintEn:", 170), 1378284984Snp FIELD("FetchTPHint:", 168, 169), 1379284984Snp FIELD1("FCThreshOverride:", 167), 1380284984Snp { "WRLength:", 162, 166, 9, 0, 1 }, 1381284984Snp FIELD1("WRLengthKnown:", 161), 1382284984Snp FIELD1("ReschedulePending:", 160), 1383284984Snp FIELD1("OnChipQueue:", 159), 1384284984Snp FIELD1("FetchSizeMode:", 158), 1385284984Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1386284984Snp FIELD1("FLMPacking:", 155), 1387284984Snp FIELD("FetchBurstMax:", 153, 154), 1388284984Snp FIELD("uPToken:", 133, 152), 1389284984Snp FIELD1("uPTokenEn:", 132), 1390284984Snp FIELD1("UserModeIO:", 131), 1391284984Snp FIELD("uPFLCredits:", 123, 130), 1392284984Snp FIELD1("uPFLCreditEn:", 122), 1393284984Snp FIELD("FID:", 111, 121), 1394284984Snp FIELD("HostFCMode:", 109, 110), 1395284984Snp FIELD1("HostFCOwner:", 108), 1396284984Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1397284984Snp FIELD("CIDX:", 89, 104), 1398284984Snp FIELD("PIDX:", 73, 88), 1399284984Snp { "BaseAddress:", 18, 72, 9, 1 }, 1400284984Snp FIELD("QueueSize:", 2, 17), 1401284984Snp FIELD1("QueueType:", 1), 1402284984Snp FIELD1("CachePriority:", 0), 1403284984Snp { NULL } 1404284984Snp }; 1405306137Snp static struct field_desc egress_t6[] = { 1406306137Snp FIELD("DCA_ST:", 181, 191), 1407306137Snp FIELD1("StatusPgNS:", 180), 1408306137Snp FIELD1("StatusPgRO:", 179), 1409306137Snp FIELD1("FetchNS:", 178), 1410306137Snp FIELD1("FetchRO:", 177), 1411306137Snp FIELD1("Valid:", 176), 1412306137Snp FIELD1("ReschedulePending_1:", 175), 1413306137Snp FIELD1("PCIeDataChannel:", 174), 1414306137Snp FIELD1("StatusPgTPHintEn:", 173), 1415306137Snp FIELD("StatusPgTPHint:", 171, 172), 1416306137Snp FIELD1("FetchTPHintEn:", 170), 1417306137Snp FIELD("FetchTPHint:", 168, 169), 1418306137Snp FIELD1("FCThreshOverride:", 167), 1419306137Snp { "WRLength:", 162, 166, 9, 0, 1 }, 1420306137Snp FIELD1("WRLengthKnown:", 161), 1421306137Snp FIELD1("ReschedulePending:", 160), 1422306137Snp FIELD("TimerIx:", 157, 159), 1423306137Snp FIELD1("FetchBurstMin:", 156), 1424306137Snp FIELD1("FLMPacking:", 155), 1425306137Snp FIELD("FetchBurstMax:", 153, 154), 1426306137Snp FIELD("uPToken:", 133, 152), 1427306137Snp FIELD1("uPTokenEn:", 132), 1428306137Snp FIELD1("UserModeIO:", 131), 1429306137Snp FIELD("uPFLCredits:", 123, 130), 1430306137Snp FIELD1("uPFLCreditEn:", 122), 1431306137Snp FIELD("FID:", 111, 121), 1432306137Snp FIELD("HostFCMode:", 109, 110), 1433306137Snp FIELD1("HostFCOwner:", 108), 1434306137Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1435306137Snp FIELD("CIDX:", 89, 104), 1436306137Snp FIELD("PIDX:", 73, 88), 1437306137Snp { "BaseAddress:", 18, 72, 9, 1 }, 1438306137Snp FIELD("QueueSize:", 2, 17), 1439306137Snp FIELD1("QueueType:", 1), 1440306137Snp FIELD1("FetchSizeMode:", 0), 1441306137Snp { NULL } 1442306137Snp }; 1443284984Snp static struct field_desc fl_t5[] = { 1444284984Snp FIELD("DCA_ST:", 181, 191), 1445284984Snp FIELD1("StatusPgNS:", 180), 1446284984Snp FIELD1("StatusPgRO:", 179), 1447284984Snp FIELD1("FetchNS:", 178), 1448284984Snp FIELD1("FetchRO:", 177), 1449284984Snp FIELD1("Valid:", 176), 1450284984Snp FIELD("PCIeDataChannel:", 174, 175), 1451284984Snp FIELD1("StatusPgTPHintEn:", 173), 1452284984Snp FIELD("StatusPgTPHint:", 171, 172), 1453284984Snp FIELD1("FetchTPHintEn:", 170), 1454284984Snp FIELD("FetchTPHint:", 168, 169), 1455284984Snp FIELD1("FCThreshOverride:", 167), 1456284984Snp FIELD1("ReschedulePending:", 160), 1457284984Snp FIELD1("OnChipQueue:", 159), 1458284984Snp FIELD1("FetchSizeMode:", 158), 1459284984Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1460284984Snp FIELD1("FLMPacking:", 155), 1461284984Snp FIELD("FetchBurstMax:", 153, 154), 1462284984Snp FIELD1("FLMcongMode:", 152), 1463284984Snp FIELD("MaxuPFLCredits:", 144, 151), 1464284984Snp FIELD("FLMcontextID:", 133, 143), 1465284984Snp FIELD1("uPTokenEn:", 132), 1466284984Snp FIELD1("UserModeIO:", 131), 1467284984Snp FIELD("uPFLCredits:", 123, 130), 1468284984Snp FIELD1("uPFLCreditEn:", 122), 1469284984Snp FIELD("FID:", 111, 121), 1470284984Snp FIELD("HostFCMode:", 109, 110), 1471284984Snp FIELD1("HostFCOwner:", 108), 1472284984Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1473284984Snp FIELD("CIDX:", 89, 104), 1474284984Snp FIELD("PIDX:", 73, 88), 1475284984Snp { "BaseAddress:", 18, 72, 9, 1 }, 1476284984Snp FIELD("QueueSize:", 2, 17), 1477284984Snp FIELD1("QueueType:", 1), 1478284984Snp FIELD1("CachePriority:", 0), 1479284984Snp { NULL } 1480284984Snp }; 1481284984Snp static struct field_desc ingress_t5[] = { 1482284984Snp FIELD("DCA_ST:", 143, 153), 1483284984Snp FIELD1("ISCSICoalescing:", 142), 1484284984Snp FIELD1("Queue_Valid:", 141), 1485284984Snp FIELD1("TimerPending:", 140), 1486284984Snp FIELD1("DropRSS:", 139), 1487284984Snp FIELD("PCIeChannel:", 137, 138), 1488284984Snp FIELD1("SEInterruptArmed:", 136), 1489284984Snp FIELD1("CongestionMgtEnable:", 135), 1490284984Snp FIELD1("NoSnoop:", 134), 1491284984Snp FIELD1("RelaxedOrdering:", 133), 1492284984Snp FIELD1("GTSmode:", 132), 1493284984Snp FIELD1("TPHintEn:", 131), 1494284984Snp FIELD("TPHint:", 129, 130), 1495284984Snp FIELD1("UpdateScheduling:", 128), 1496284984Snp FIELD("UpdateDelivery:", 126, 127), 1497284984Snp FIELD1("InterruptSent:", 125), 1498284984Snp FIELD("InterruptIDX:", 114, 124), 1499284984Snp FIELD1("InterruptDestination:", 113), 1500284984Snp FIELD1("InterruptArmed:", 112), 1501284984Snp FIELD("RxIntCounter:", 106, 111), 1502284984Snp FIELD("RxIntCounterThreshold:", 104, 105), 1503284984Snp FIELD1("Generation:", 103), 1504284984Snp { "BaseAddress:", 48, 102, 9, 1 }, 1505284984Snp FIELD("PIDX:", 32, 47), 1506284984Snp FIELD("CIDX:", 16, 31), 1507284984Snp { "QueueSize:", 4, 15, 4, 0 }, 1508284984Snp { "QueueEntrySize:", 2, 3, 4, 0, 1 }, 1509284984Snp FIELD1("QueueEntryOverride:", 1), 1510284984Snp FIELD1("CachePriority:", 0), 1511284984Snp { NULL } 1512284984Snp }; 1513306137Snp static struct field_desc ingress_t6[] = { 1514306137Snp FIELD1("SP_NS:", 158), 1515306137Snp FIELD1("SP_RO:", 157), 1516306137Snp FIELD1("SP_TPHintEn:", 156), 1517306137Snp FIELD("SP_TPHint:", 154, 155), 1518306137Snp FIELD("DCA_ST:", 143, 153), 1519306137Snp FIELD1("ISCSICoalescing:", 142), 1520306137Snp FIELD1("Queue_Valid:", 141), 1521306137Snp FIELD1("TimerPending:", 140), 1522306137Snp FIELD1("DropRSS:", 139), 1523306137Snp FIELD("PCIeChannel:", 137, 138), 1524306137Snp FIELD1("SEInterruptArmed:", 136), 1525306137Snp FIELD1("CongestionMgtEnable:", 135), 1526306137Snp FIELD1("NoSnoop:", 134), 1527306137Snp FIELD1("RelaxedOrdering:", 133), 1528306137Snp FIELD1("GTSmode:", 132), 1529306137Snp FIELD1("TPHintEn:", 131), 1530306137Snp FIELD("TPHint:", 129, 130), 1531306137Snp FIELD1("UpdateScheduling:", 128), 1532306137Snp FIELD("UpdateDelivery:", 126, 127), 1533306137Snp FIELD1("InterruptSent:", 125), 1534306137Snp FIELD("InterruptIDX:", 114, 124), 1535306137Snp FIELD1("InterruptDestination:", 113), 1536306137Snp FIELD1("InterruptArmed:", 112), 1537306137Snp FIELD("RxIntCounter:", 106, 111), 1538306137Snp FIELD("RxIntCounterThreshold:", 104, 105), 1539306137Snp FIELD1("Generation:", 103), 1540306137Snp { "BaseAddress:", 48, 102, 9, 1 }, 1541306137Snp FIELD("PIDX:", 32, 47), 1542306137Snp FIELD("CIDX:", 16, 31), 1543306137Snp { "QueueSize:", 4, 15, 4, 0 }, 1544306137Snp { "QueueEntrySize:", 2, 3, 4, 0, 1 }, 1545306137Snp FIELD1("QueueEntryOverride:", 1), 1546306137Snp FIELD1("CachePriority:", 0), 1547306137Snp { NULL } 1548306137Snp }; 1549284984Snp static struct field_desc flm_t5[] = { 1550284984Snp FIELD1("Valid:", 89), 1551284984Snp FIELD("SplitLenMode:", 87, 88), 1552284984Snp FIELD1("TPHintEn:", 86), 1553284984Snp FIELD("TPHint:", 84, 85), 1554284984Snp FIELD1("NoSnoop:", 83), 1555284984Snp FIELD1("RelaxedOrdering:", 82), 1556284984Snp FIELD("DCA_ST:", 71, 81), 1557284984Snp FIELD("EQid:", 54, 70), 1558284984Snp FIELD("SplitEn:", 52, 53), 1559284984Snp FIELD1("PadEn:", 51), 1560284984Snp FIELD1("PackEn:", 50), 1561284984Snp FIELD1("Cache_Lock :", 49), 1562284984Snp FIELD1("CongDrop:", 48), 1563284984Snp FIELD("PackOffset:", 16, 47), 1564284984Snp FIELD("CIDX:", 8, 15), 1565284984Snp FIELD("PIDX:", 0, 7), 1566284984Snp { NULL } 1567284984Snp }; 1568306137Snp static struct field_desc flm_t6[] = { 1569306137Snp FIELD1("Valid:", 89), 1570306137Snp FIELD("SplitLenMode:", 87, 88), 1571306137Snp FIELD1("TPHintEn:", 86), 1572306137Snp FIELD("TPHint:", 84, 85), 1573306137Snp FIELD1("NoSnoop:", 83), 1574306137Snp FIELD1("RelaxedOrdering:", 82), 1575306137Snp FIELD("DCA_ST:", 71, 81), 1576306137Snp FIELD("EQid:", 54, 70), 1577306137Snp FIELD("SplitEn:", 52, 53), 1578306137Snp FIELD1("PadEn:", 51), 1579306137Snp FIELD1("PackEn:", 50), 1580306137Snp FIELD1("Cache_Lock :", 49), 1581306137Snp FIELD1("CongDrop:", 48), 1582306138Snp FIELD1("Inflight:", 47), 1583306137Snp FIELD1("CongEn:", 46), 1584306137Snp FIELD1("CongMode:", 45), 1585306137Snp FIELD("PackOffset:", 20, 39), 1586306137Snp FIELD("CIDX:", 8, 15), 1587306137Snp FIELD("PIDX:", 0, 7), 1588306137Snp { NULL } 1589306137Snp }; 1590284984Snp static struct field_desc conm_t5[] = { 1591284984Snp FIELD1("CngMPSEnable:", 21), 1592284984Snp FIELD("CngTPMode:", 19, 20), 1593284984Snp FIELD1("CngDBPHdr:", 18), 1594284984Snp FIELD1("CngDBPData:", 17), 1595284984Snp FIELD1("CngIMSG:", 16), 1596284984Snp { "CngChMap:", 0, 15, 0, 1, 0 }, 1597284984Snp { NULL } 1598284984Snp }; 1599284984Snp 1600306137Snp if (p->mem_id == SGE_CONTEXT_EGRESS) { 1601306137Snp if (p->data[0] & 2) 1602306137Snp show_struct(p->data, 6, fl_t5); 1603306137Snp else if (vers == 5) 1604306137Snp show_struct(p->data, 6, egress_t5); 1605306137Snp else 1606306137Snp show_struct(p->data, 6, egress_t6); 1607306137Snp } else if (p->mem_id == SGE_CONTEXT_FLM) 1608306137Snp show_struct(p->data, 3, vers == 5 ? flm_t5 : flm_t6); 1609284984Snp else if (p->mem_id == SGE_CONTEXT_INGRESS) 1610306137Snp show_struct(p->data, 5, vers == 5 ? ingress_t5 : ingress_t6); 1611284984Snp else if (p->mem_id == SGE_CONTEXT_CNM) 1612284984Snp show_struct(p->data, 1, conm_t5); 1613284984Snp} 1614284984Snp 1615284984Snpstatic void 1616284984Snpshow_t4_ctxt(const struct t4_sge_context *p) 1617284984Snp{ 1618284984Snp static struct field_desc egress_t4[] = { 1619284984Snp FIELD1("StatusPgNS:", 180), 1620284984Snp FIELD1("StatusPgRO:", 179), 1621284984Snp FIELD1("FetchNS:", 178), 1622284984Snp FIELD1("FetchRO:", 177), 1623284984Snp FIELD1("Valid:", 176), 1624284984Snp FIELD("PCIeDataChannel:", 174, 175), 1625222974Snp FIELD1("DCAEgrQEn:", 173), 1626222974Snp FIELD("DCACPUID:", 168, 172), 1627222974Snp FIELD1("FCThreshOverride:", 167), 1628222974Snp FIELD("WRLength:", 162, 166), 1629222974Snp FIELD1("WRLengthKnown:", 161), 1630222974Snp FIELD1("ReschedulePending:", 160), 1631222974Snp FIELD1("OnChipQueue:", 159), 1632222974Snp FIELD1("FetchSizeMode", 158), 1633222974Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1634222974Snp { "FetchBurstMax:", 153, 154, 6, 0, 1 }, 1635222974Snp FIELD("uPToken:", 133, 152), 1636222974Snp FIELD1("uPTokenEn:", 132), 1637222974Snp FIELD1("UserModeIO:", 131), 1638222974Snp FIELD("uPFLCredits:", 123, 130), 1639222974Snp FIELD1("uPFLCreditEn:", 122), 1640222974Snp FIELD("FID:", 111, 121), 1641222974Snp FIELD("HostFCMode:", 109, 110), 1642222974Snp FIELD1("HostFCOwner:", 108), 1643222974Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1644222974Snp FIELD("CIDX:", 89, 104), 1645222974Snp FIELD("PIDX:", 73, 88), 1646222974Snp { "BaseAddress:", 18, 72, 9, 1 }, 1647222974Snp FIELD("QueueSize:", 2, 17), 1648222974Snp FIELD1("QueueType:", 1), 1649222974Snp FIELD1("CachePriority:", 0), 1650222974Snp { NULL } 1651222974Snp }; 1652284984Snp static struct field_desc fl_t4[] = { 1653222974Snp FIELD1("StatusPgNS:", 180), 1654222974Snp FIELD1("StatusPgRO:", 179), 1655222974Snp FIELD1("FetchNS:", 178), 1656222974Snp FIELD1("FetchRO:", 177), 1657222974Snp FIELD1("Valid:", 176), 1658222974Snp FIELD("PCIeDataChannel:", 174, 175), 1659222974Snp FIELD1("DCAEgrQEn:", 173), 1660222974Snp FIELD("DCACPUID:", 168, 172), 1661222974Snp FIELD1("FCThreshOverride:", 167), 1662222974Snp FIELD1("ReschedulePending:", 160), 1663222974Snp FIELD1("OnChipQueue:", 159), 1664222974Snp FIELD1("FetchSizeMode", 158), 1665222974Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1666222974Snp { "FetchBurstMax:", 153, 154, 6, 0, 1 }, 1667222974Snp FIELD1("FLMcongMode:", 152), 1668222974Snp FIELD("MaxuPFLCredits:", 144, 151), 1669222974Snp FIELD("FLMcontextID:", 133, 143), 1670222974Snp FIELD1("uPTokenEn:", 132), 1671222974Snp FIELD1("UserModeIO:", 131), 1672222974Snp FIELD("uPFLCredits:", 123, 130), 1673222974Snp FIELD1("uPFLCreditEn:", 122), 1674222974Snp FIELD("FID:", 111, 121), 1675222974Snp FIELD("HostFCMode:", 109, 110), 1676222974Snp FIELD1("HostFCOwner:", 108), 1677222974Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1678222974Snp FIELD("CIDX:", 89, 104), 1679222974Snp FIELD("PIDX:", 73, 88), 1680222974Snp { "BaseAddress:", 18, 72, 9, 1 }, 1681222974Snp FIELD("QueueSize:", 2, 17), 1682222974Snp FIELD1("QueueType:", 1), 1683222974Snp FIELD1("CachePriority:", 0), 1684222974Snp { NULL } 1685222974Snp }; 1686284984Snp static struct field_desc ingress_t4[] = { 1687222974Snp FIELD1("NoSnoop:", 145), 1688222974Snp FIELD1("RelaxedOrdering:", 144), 1689222974Snp FIELD1("GTSmode:", 143), 1690222974Snp FIELD1("ISCSICoalescing:", 142), 1691222974Snp FIELD1("Valid:", 141), 1692222974Snp FIELD1("TimerPending:", 140), 1693222974Snp FIELD1("DropRSS:", 139), 1694222974Snp FIELD("PCIeChannel:", 137, 138), 1695222974Snp FIELD1("SEInterruptArmed:", 136), 1696222974Snp FIELD1("CongestionMgtEnable:", 135), 1697222974Snp FIELD1("DCAIngQEnable:", 134), 1698222974Snp FIELD("DCACPUID:", 129, 133), 1699222974Snp FIELD1("UpdateScheduling:", 128), 1700222974Snp FIELD("UpdateDelivery:", 126, 127), 1701222974Snp FIELD1("InterruptSent:", 125), 1702222974Snp FIELD("InterruptIDX:", 114, 124), 1703222974Snp FIELD1("InterruptDestination:", 113), 1704222974Snp FIELD1("InterruptArmed:", 112), 1705222974Snp FIELD("RxIntCounter:", 106, 111), 1706222974Snp FIELD("RxIntCounterThreshold:", 104, 105), 1707222974Snp FIELD1("Generation:", 103), 1708222974Snp { "BaseAddress:", 48, 102, 9, 1 }, 1709222974Snp FIELD("PIDX:", 32, 47), 1710222974Snp FIELD("CIDX:", 16, 31), 1711222974Snp { "QueueSize:", 4, 15, 4, 0 }, 1712222974Snp { "QueueEntrySize:", 2, 3, 4, 0, 1 }, 1713222974Snp FIELD1("QueueEntryOverride:", 1), 1714222974Snp FIELD1("CachePriority:", 0), 1715222974Snp { NULL } 1716222974Snp }; 1717284984Snp static struct field_desc flm_t4[] = { 1718222974Snp FIELD1("NoSnoop:", 79), 1719222974Snp FIELD1("RelaxedOrdering:", 78), 1720222974Snp FIELD1("Valid:", 77), 1721222974Snp FIELD("DCACPUID:", 72, 76), 1722222974Snp FIELD1("DCAFLEn:", 71), 1723222974Snp FIELD("EQid:", 54, 70), 1724222974Snp FIELD("SplitEn:", 52, 53), 1725222974Snp FIELD1("PadEn:", 51), 1726222974Snp FIELD1("PackEn:", 50), 1727222974Snp FIELD1("DBpriority:", 48), 1728222974Snp FIELD("PackOffset:", 16, 47), 1729222974Snp FIELD("CIDX:", 8, 15), 1730222974Snp FIELD("PIDX:", 0, 7), 1731222974Snp { NULL } 1732222974Snp }; 1733284984Snp static struct field_desc conm_t4[] = { 1734222974Snp FIELD1("CngDBPHdr:", 6), 1735222974Snp FIELD1("CngDBPData:", 5), 1736222974Snp FIELD1("CngIMSG:", 4), 1737261534Snp { "CngChMap:", 0, 3, 0, 1, 0}, 1738222974Snp { NULL } 1739222974Snp }; 1740222974Snp 1741222974Snp if (p->mem_id == SGE_CONTEXT_EGRESS) 1742284984Snp show_struct(p->data, 6, (p->data[0] & 2) ? fl_t4 : egress_t4); 1743222974Snp else if (p->mem_id == SGE_CONTEXT_FLM) 1744284984Snp show_struct(p->data, 3, flm_t4); 1745222974Snp else if (p->mem_id == SGE_CONTEXT_INGRESS) 1746284984Snp show_struct(p->data, 5, ingress_t4); 1747222974Snp else if (p->mem_id == SGE_CONTEXT_CNM) 1748284984Snp show_struct(p->data, 1, conm_t4); 1749222974Snp} 1750222974Snp 1751222974Snp#undef FIELD 1752222974Snp#undef FIELD1 1753222974Snp 1754222900Snpstatic int 1755222974Snpget_sge_context(int argc, const char *argv[]) 1756222974Snp{ 1757222974Snp int rc; 1758222974Snp char *p; 1759222974Snp long cid; 1760222974Snp struct t4_sge_context cntxt = {0}; 1761222974Snp 1762222974Snp if (argc != 2) { 1763222974Snp warnx("sge_context: incorrect number of arguments."); 1764222974Snp return (EINVAL); 1765222974Snp } 1766222974Snp 1767222974Snp if (!strcmp(argv[0], "egress")) 1768222974Snp cntxt.mem_id = SGE_CONTEXT_EGRESS; 1769222974Snp else if (!strcmp(argv[0], "ingress")) 1770222974Snp cntxt.mem_id = SGE_CONTEXT_INGRESS; 1771222974Snp else if (!strcmp(argv[0], "fl")) 1772222974Snp cntxt.mem_id = SGE_CONTEXT_FLM; 1773222974Snp else if (!strcmp(argv[0], "cong")) 1774222974Snp cntxt.mem_id = SGE_CONTEXT_CNM; 1775222974Snp else { 1776222974Snp warnx("unknown context type \"%s\"; known types are egress, " 1777222974Snp "ingress, fl, and cong.", argv[0]); 1778222974Snp return (EINVAL); 1779222974Snp } 1780222974Snp 1781222974Snp p = str_to_number(argv[1], &cid, NULL); 1782222974Snp if (*p) { 1783222974Snp warnx("invalid context id \"%s\"", argv[1]); 1784222974Snp return (EINVAL); 1785222974Snp } 1786222974Snp cntxt.cid = cid; 1787222974Snp 1788222974Snp rc = doit(CHELSIO_T4_GET_SGE_CONTEXT, &cntxt); 1789222974Snp if (rc != 0) 1790222974Snp return (rc); 1791222974Snp 1792284984Snp if (chip_id == 4) 1793284984Snp show_t4_ctxt(&cntxt); 1794284984Snp else 1795306137Snp show_t5t6_ctxt(&cntxt, chip_id); 1796284984Snp 1797222974Snp return (0); 1798222974Snp} 1799222974Snp 1800222974Snpstatic int 1801228594Snploadfw(int argc, const char *argv[]) 1802228594Snp{ 1803228594Snp int rc, fd; 1804228594Snp struct t4_data data = {0}; 1805228594Snp const char *fname = argv[0]; 1806228594Snp struct stat st = {0}; 1807228594Snp 1808228594Snp if (argc != 1) { 1809228594Snp warnx("loadfw: incorrect number of arguments."); 1810228594Snp return (EINVAL); 1811228594Snp } 1812228594Snp 1813228594Snp fd = open(fname, O_RDONLY); 1814228594Snp if (fd < 0) { 1815228594Snp warn("open(%s)", fname); 1816228594Snp return (errno); 1817228594Snp } 1818228594Snp 1819228594Snp if (fstat(fd, &st) < 0) { 1820228594Snp warn("fstat"); 1821228594Snp close(fd); 1822228594Snp return (errno); 1823228594Snp } 1824228594Snp 1825228594Snp data.len = st.st_size; 1826273360Snp data.data = mmap(0, data.len, PROT_READ, MAP_PRIVATE, fd, 0); 1827228594Snp if (data.data == MAP_FAILED) { 1828228594Snp warn("mmap"); 1829228594Snp close(fd); 1830228594Snp return (errno); 1831228594Snp } 1832228594Snp 1833228594Snp rc = doit(CHELSIO_T4_LOAD_FW, &data); 1834228594Snp munmap(data.data, data.len); 1835228594Snp close(fd); 1836228594Snp return (rc); 1837228594Snp} 1838228594Snp 1839228594Snpstatic int 1840306823Snploadcfg(int argc, const char *argv[]) 1841306823Snp{ 1842306823Snp int rc, fd; 1843306823Snp struct t4_data data = {0}; 1844306823Snp const char *fname = argv[0]; 1845306823Snp struct stat st = {0}; 1846306823Snp 1847306823Snp if (argc != 1) { 1848306823Snp warnx("loadcfg: incorrect number of arguments."); 1849306823Snp return (EINVAL); 1850306823Snp } 1851306823Snp 1852306823Snp if (strcmp(fname, "clear") == 0) 1853306823Snp return (doit(CHELSIO_T4_LOAD_CFG, &data)); 1854306823Snp 1855306823Snp fd = open(fname, O_RDONLY); 1856306823Snp if (fd < 0) { 1857306823Snp warn("open(%s)", fname); 1858306823Snp return (errno); 1859306823Snp } 1860306823Snp 1861306823Snp if (fstat(fd, &st) < 0) { 1862306823Snp warn("fstat"); 1863306823Snp close(fd); 1864306823Snp return (errno); 1865306823Snp } 1866306823Snp 1867306823Snp data.len = st.st_size; 1868306823Snp data.len &= ~3; /* Clip off to make it a multiple of 4 */ 1869306823Snp data.data = mmap(0, data.len, PROT_READ, MAP_PRIVATE, fd, 0); 1870306823Snp if (data.data == MAP_FAILED) { 1871306823Snp warn("mmap"); 1872306823Snp close(fd); 1873306823Snp return (errno); 1874306823Snp } 1875306823Snp 1876306823Snp rc = doit(CHELSIO_T4_LOAD_CFG, &data); 1877306823Snp munmap(data.data, data.len); 1878306823Snp close(fd); 1879306823Snp return (rc); 1880306823Snp} 1881306823Snp 1882306823Snpstatic int 1883228594Snpread_mem(uint32_t addr, uint32_t len, void (*output)(uint32_t *, uint32_t)) 1884228594Snp{ 1885228594Snp int rc; 1886228594Snp struct t4_mem_range mr; 1887228594Snp 1888228594Snp mr.addr = addr; 1889228594Snp mr.len = len; 1890228594Snp mr.data = malloc(mr.len); 1891228594Snp 1892228594Snp if (mr.data == 0) { 1893228594Snp warn("read_mem: malloc"); 1894228594Snp return (errno); 1895228594Snp } 1896228594Snp 1897228594Snp rc = doit(CHELSIO_T4_GET_MEM, &mr); 1898228594Snp if (rc != 0) 1899228594Snp goto done; 1900228594Snp 1901228594Snp if (output) 1902228594Snp (*output)(mr.data, mr.len); 1903228594Snpdone: 1904228594Snp free(mr.data); 1905228594Snp return (rc); 1906228594Snp} 1907228594Snp 1908228594Snp/* 1909228594Snp * Display memory as list of 'n' 4-byte values per line. 1910228594Snp */ 1911228594Snpstatic void 1912228594Snpshow_mem(uint32_t *buf, uint32_t len) 1913228594Snp{ 1914228594Snp const char *s; 1915228594Snp int i, n = 8; 1916228594Snp 1917228594Snp while (len) { 1918228594Snp for (i = 0; len && i < n; i++, buf++, len -= 4) { 1919228594Snp s = i ? " " : ""; 1920228594Snp printf("%s%08x", s, htonl(*buf)); 1921228594Snp } 1922228594Snp printf("\n"); 1923228594Snp } 1924228594Snp} 1925228594Snp 1926228594Snpstatic int 1927228594Snpmemdump(int argc, const char *argv[]) 1928228594Snp{ 1929228594Snp char *p; 1930228594Snp long l; 1931228594Snp uint32_t addr, len; 1932228594Snp 1933228594Snp if (argc != 2) { 1934228594Snp warnx("incorrect number of arguments."); 1935228594Snp return (EINVAL); 1936228594Snp } 1937228594Snp 1938228594Snp p = str_to_number(argv[0], &l, NULL); 1939228594Snp if (*p) { 1940228594Snp warnx("invalid address \"%s\"", argv[0]); 1941228594Snp return (EINVAL); 1942228594Snp } 1943228594Snp addr = l; 1944228594Snp 1945228594Snp p = str_to_number(argv[1], &l, NULL); 1946228594Snp if (*p) { 1947228594Snp warnx("memdump: invalid length \"%s\"", argv[1]); 1948228594Snp return (EINVAL); 1949228594Snp } 1950228594Snp len = l; 1951228594Snp 1952228594Snp return (read_mem(addr, len, show_mem)); 1953228594Snp} 1954228594Snp 1955228594Snp/* 1956228594Snp * Display TCB as list of 'n' 4-byte values per line. 1957228594Snp */ 1958228594Snpstatic void 1959228594Snpshow_tcb(uint32_t *buf, uint32_t len) 1960228594Snp{ 1961228594Snp const char *s; 1962228594Snp int i, n = 8; 1963228594Snp 1964228594Snp while (len) { 1965228594Snp for (i = 0; len && i < n; i++, buf++, len -= 4) { 1966228594Snp s = i ? " " : ""; 1967228594Snp printf("%s%08x", s, htonl(*buf)); 1968228594Snp } 1969228594Snp printf("\n"); 1970228594Snp } 1971228594Snp} 1972228594Snp 1973228594Snp#define A_TP_CMM_TCB_BASE 0x7d10 1974228594Snp#define TCB_SIZE 128 1975228594Snpstatic int 1976228594Snpread_tcb(int argc, const char *argv[]) 1977228594Snp{ 1978228594Snp char *p; 1979228594Snp long l; 1980228594Snp long long val; 1981228594Snp unsigned int tid; 1982228594Snp uint32_t addr; 1983228594Snp int rc; 1984228594Snp 1985228594Snp if (argc != 1) { 1986228594Snp warnx("incorrect number of arguments."); 1987228594Snp return (EINVAL); 1988228594Snp } 1989228594Snp 1990228594Snp p = str_to_number(argv[0], &l, NULL); 1991228594Snp if (*p) { 1992228594Snp warnx("invalid tid \"%s\"", argv[0]); 1993228594Snp return (EINVAL); 1994228594Snp } 1995228594Snp tid = l; 1996228594Snp 1997228594Snp rc = read_reg(A_TP_CMM_TCB_BASE, 4, &val); 1998228594Snp if (rc != 0) 1999228594Snp return (rc); 2000228594Snp 2001228594Snp addr = val + tid * TCB_SIZE; 2002228594Snp 2003228594Snp return (read_mem(addr, TCB_SIZE, show_tcb)); 2004228594Snp} 2005228594Snp 2006228594Snpstatic int 2007241401Snpread_i2c(int argc, const char *argv[]) 2008241401Snp{ 2009241401Snp char *p; 2010241401Snp long l; 2011241401Snp struct t4_i2c_data i2cd; 2012241401Snp int rc, i; 2013241401Snp 2014241401Snp if (argc < 3 || argc > 4) { 2015241401Snp warnx("incorrect number of arguments."); 2016241401Snp return (EINVAL); 2017241401Snp } 2018241401Snp 2019241401Snp p = str_to_number(argv[0], &l, NULL); 2020241401Snp if (*p || l > UCHAR_MAX) { 2021241401Snp warnx("invalid port id \"%s\"", argv[0]); 2022241401Snp return (EINVAL); 2023241401Snp } 2024241401Snp i2cd.port_id = l; 2025241401Snp 2026241401Snp p = str_to_number(argv[1], &l, NULL); 2027241401Snp if (*p || l > UCHAR_MAX) { 2028241401Snp warnx("invalid i2c device address \"%s\"", argv[1]); 2029241401Snp return (EINVAL); 2030241401Snp } 2031241401Snp i2cd.dev_addr = l; 2032241401Snp 2033241401Snp p = str_to_number(argv[2], &l, NULL); 2034241401Snp if (*p || l > UCHAR_MAX) { 2035241401Snp warnx("invalid byte offset \"%s\"", argv[2]); 2036241401Snp return (EINVAL); 2037241401Snp } 2038241401Snp i2cd.offset = l; 2039241401Snp 2040241401Snp if (argc == 4) { 2041241401Snp p = str_to_number(argv[3], &l, NULL); 2042241401Snp if (*p || l > sizeof(i2cd.data)) { 2043241401Snp warnx("invalid number of bytes \"%s\"", argv[3]); 2044241401Snp return (EINVAL); 2045241401Snp } 2046241401Snp i2cd.len = l; 2047241401Snp } else 2048241401Snp i2cd.len = 1; 2049241401Snp 2050241401Snp rc = doit(CHELSIO_T4_GET_I2C, &i2cd); 2051241401Snp if (rc != 0) 2052241401Snp return (rc); 2053241401Snp 2054241401Snp for (i = 0; i < i2cd.len; i++) 2055241401Snp printf("0x%x [%u]\n", i2cd.data[i], i2cd.data[i]); 2056241401Snp 2057241401Snp return (0); 2058241401Snp} 2059241401Snp 2060241401Snpstatic int 2061241416Snpclearstats(int argc, const char *argv[]) 2062241416Snp{ 2063241416Snp char *p; 2064241416Snp long l; 2065241416Snp uint32_t port; 2066241416Snp 2067241416Snp if (argc != 1) { 2068241416Snp warnx("incorrect number of arguments."); 2069241416Snp return (EINVAL); 2070241416Snp } 2071241416Snp 2072241416Snp p = str_to_number(argv[0], &l, NULL); 2073241416Snp if (*p) { 2074241416Snp warnx("invalid port id \"%s\"", argv[0]); 2075241416Snp return (EINVAL); 2076241416Snp } 2077241416Snp port = l; 2078241416Snp 2079241416Snp return doit(CHELSIO_T4_CLEAR_STATS, &port); 2080241416Snp} 2081241416Snp 2082241416Snpstatic int 2083253691Snpshow_tracers(void) 2084253691Snp{ 2085253691Snp struct t4_tracer t; 2086253691Snp char *s; 2087253691Snp int rc, port_idx, i; 2088253691Snp long long val; 2089253691Snp 2090253691Snp /* Magic values: MPS_TRC_CFG = 0x9800. MPS_TRC_CFG[1:1] = TrcEn */ 2091253691Snp rc = read_reg(0x9800, 4, &val); 2092253691Snp if (rc != 0) 2093253691Snp return (rc); 2094253691Snp printf("tracing is %s\n", val & 2 ? "ENABLED" : "DISABLED"); 2095253691Snp 2096253691Snp t.idx = 0; 2097253691Snp for (t.idx = 0; ; t.idx++) { 2098253691Snp rc = doit(CHELSIO_T4_GET_TRACER, &t); 2099253691Snp if (rc != 0 || t.idx == 0xff) 2100253691Snp break; 2101253691Snp 2102253691Snp if (t.tp.port < 4) { 2103253691Snp s = "Rx"; 2104253691Snp port_idx = t.tp.port; 2105253691Snp } else if (t.tp.port < 8) { 2106253691Snp s = "Tx"; 2107253691Snp port_idx = t.tp.port - 4; 2108253691Snp } else if (t.tp.port < 12) { 2109253691Snp s = "loopback"; 2110253691Snp port_idx = t.tp.port - 8; 2111253691Snp } else if (t.tp.port < 16) { 2112253691Snp s = "MPS Rx"; 2113253691Snp port_idx = t.tp.port - 12; 2114253691Snp } else if (t.tp.port < 20) { 2115253691Snp s = "MPS Tx"; 2116253691Snp port_idx = t.tp.port - 16; 2117253691Snp } else { 2118253691Snp s = "unknown"; 2119253691Snp port_idx = t.tp.port; 2120253691Snp } 2121253691Snp 2122253691Snp printf("\ntracer %u (currently %s) captures ", t.idx, 2123253691Snp t.enabled ? "ENABLED" : "DISABLED"); 2124253691Snp if (t.tp.port < 8) 2125253691Snp printf("port %u %s, ", port_idx, s); 2126253691Snp else 2127253691Snp printf("%s %u, ", s, port_idx); 2128253691Snp printf("snap length: %u, min length: %u\n", t.tp.snap_len, 2129253691Snp t.tp.min_len); 2130253691Snp printf("packets captured %smatch filter\n", 2131253691Snp t.tp.invert ? "do not " : ""); 2132253691Snp if (t.tp.skip_ofst) { 2133253691Snp printf("filter pattern: "); 2134253691Snp for (i = 0; i < t.tp.skip_ofst * 2; i += 2) 2135253691Snp printf("%08x%08x", t.tp.data[i], 2136253691Snp t.tp.data[i + 1]); 2137253691Snp printf("/"); 2138253691Snp for (i = 0; i < t.tp.skip_ofst * 2; i += 2) 2139253691Snp printf("%08x%08x", t.tp.mask[i], 2140253691Snp t.tp.mask[i + 1]); 2141253691Snp printf("@0\n"); 2142253691Snp } 2143253691Snp printf("filter pattern: "); 2144253691Snp for (i = t.tp.skip_ofst * 2; i < T4_TRACE_LEN / 4; i += 2) 2145253691Snp printf("%08x%08x", t.tp.data[i], t.tp.data[i + 1]); 2146253691Snp printf("/"); 2147253691Snp for (i = t.tp.skip_ofst * 2; i < T4_TRACE_LEN / 4; i += 2) 2148253691Snp printf("%08x%08x", t.tp.mask[i], t.tp.mask[i + 1]); 2149253691Snp printf("@%u\n", (t.tp.skip_ofst + t.tp.skip_len) * 8); 2150253691Snp } 2151253691Snp 2152253691Snp return (rc); 2153253691Snp} 2154253691Snp 2155253691Snpstatic int 2156253691Snptracer_onoff(uint8_t idx, int enabled) 2157253691Snp{ 2158253691Snp struct t4_tracer t; 2159253691Snp 2160253691Snp t.idx = idx; 2161253691Snp t.enabled = enabled; 2162253691Snp t.valid = 0; 2163253691Snp 2164253691Snp return doit(CHELSIO_T4_SET_TRACER, &t); 2165253691Snp} 2166253691Snp 2167253691Snpstatic void 2168253691Snpcreate_tracing_ifnet() 2169253691Snp{ 2170253691Snp char *cmd[] = { 2171253691Snp "/sbin/ifconfig", __DECONST(char *, nexus), "create", NULL 2172253691Snp }; 2173253691Snp char *env[] = {NULL}; 2174253691Snp 2175253691Snp if (vfork() == 0) { 2176253691Snp close(STDERR_FILENO); 2177253691Snp execve(cmd[0], cmd, env); 2178253691Snp _exit(0); 2179253691Snp } 2180253691Snp} 2181253691Snp 2182253691Snp/* 2183253691Snp * XXX: Allow user to specify snaplen, minlen, and pattern (including inverted 2184253691Snp * matching). Right now this is a quick-n-dirty implementation that traces the 2185253691Snp * first 128B of all tx or rx on a port 2186253691Snp */ 2187253691Snpstatic int 2188253691Snpset_tracer(uint8_t idx, int argc, const char *argv[]) 2189253691Snp{ 2190253691Snp struct t4_tracer t; 2191253691Snp int len, port; 2192253691Snp 2193253691Snp bzero(&t, sizeof (t)); 2194253691Snp t.idx = idx; 2195253691Snp t.enabled = 1; 2196253691Snp t.valid = 1; 2197253691Snp 2198253691Snp if (argc != 1) { 2199253691Snp warnx("must specify tx<n> or rx<n>."); 2200253691Snp return (EINVAL); 2201253691Snp } 2202253691Snp 2203253691Snp len = strlen(argv[0]); 2204253691Snp if (len != 3) { 2205253691Snp warnx("argument must be 3 characters (tx<n> or rx<n>)"); 2206253691Snp return (EINVAL); 2207253691Snp } 2208253691Snp 2209253691Snp if (strncmp(argv[0], "tx", 2) == 0) { 2210253691Snp port = argv[0][2] - '0'; 2211253691Snp if (port < 0 || port > 3) { 2212253691Snp warnx("'%c' in %s is invalid", argv[0][2], argv[0]); 2213253691Snp return (EINVAL); 2214253691Snp } 2215253691Snp port += 4; 2216253691Snp } else if (strncmp(argv[0], "rx", 2) == 0) { 2217253691Snp port = argv[0][2] - '0'; 2218253691Snp if (port < 0 || port > 3) { 2219253691Snp warnx("'%c' in %s is invalid", argv[0][2], argv[0]); 2220253691Snp return (EINVAL); 2221253691Snp } 2222253691Snp } else { 2223253691Snp warnx("argument '%s' isn't tx<n> or rx<n>", argv[0]); 2224253691Snp return (EINVAL); 2225253691Snp } 2226253691Snp 2227253691Snp t.tp.snap_len = 128; 2228253691Snp t.tp.min_len = 0; 2229253691Snp t.tp.skip_ofst = 0; 2230253691Snp t.tp.skip_len = 0; 2231253691Snp t.tp.invert = 0; 2232253691Snp t.tp.port = port; 2233253691Snp 2234253691Snp create_tracing_ifnet(); 2235253691Snp return doit(CHELSIO_T4_SET_TRACER, &t); 2236253691Snp} 2237253691Snp 2238253691Snpstatic int 2239259048Snptracer_cmd(int argc, const char *argv[]) 2240259048Snp{ 2241259048Snp long long val; 2242259048Snp uint8_t idx; 2243259048Snp char *s; 2244259048Snp 2245259048Snp if (argc == 0) { 2246259048Snp warnx("tracer: no arguments."); 2247259048Snp return (EINVAL); 2248259048Snp }; 2249259048Snp 2250259048Snp /* list */ 2251259048Snp if (strcmp(argv[0], "list") == 0) { 2252259048Snp if (argc != 1) 2253259048Snp warnx("trailing arguments after \"list\" ignored."); 2254259048Snp 2255259048Snp return show_tracers(); 2256259048Snp } 2257259048Snp 2258259048Snp /* <idx> ... */ 2259259048Snp s = str_to_number(argv[0], NULL, &val); 2260259048Snp if (*s || val > 0xff) { 2261259048Snp warnx("\"%s\" is neither an index nor a tracer subcommand.", 2262259048Snp argv[0]); 2263259048Snp return (EINVAL); 2264259048Snp } 2265259048Snp idx = (int8_t)val; 2266259048Snp 2267259048Snp /* <idx> disable */ 2268259048Snp if (argc == 2 && strcmp(argv[1], "disable") == 0) 2269259048Snp return tracer_onoff(idx, 0); 2270259048Snp 2271259048Snp /* <idx> enable */ 2272259048Snp if (argc == 2 && strcmp(argv[1], "enable") == 0) 2273259048Snp return tracer_onoff(idx, 1); 2274259048Snp 2275259048Snp /* <idx> ... */ 2276259048Snp return set_tracer(idx, argc - 1, argv + 1); 2277259048Snp} 2278259048Snp 2279259048Snpstatic int 2280269106Snpmodinfo_raw(int port_id) 2281269106Snp{ 2282269106Snp uint8_t offset; 2283269106Snp struct t4_i2c_data i2cd; 2284269106Snp int rc; 2285269106Snp 2286269106Snp for (offset = 0; offset < 96; offset += sizeof(i2cd.data)) { 2287269106Snp bzero(&i2cd, sizeof(i2cd)); 2288269106Snp i2cd.port_id = port_id; 2289269106Snp i2cd.dev_addr = 0xa0; 2290269106Snp i2cd.offset = offset; 2291269106Snp i2cd.len = sizeof(i2cd.data); 2292269106Snp rc = doit(CHELSIO_T4_GET_I2C, &i2cd); 2293269106Snp if (rc != 0) 2294269106Snp return (rc); 2295269106Snp printf("%02x: %02x %02x %02x %02x %02x %02x %02x %02x", 2296269106Snp offset, i2cd.data[0], i2cd.data[1], i2cd.data[2], 2297269106Snp i2cd.data[3], i2cd.data[4], i2cd.data[5], i2cd.data[6], 2298269106Snp i2cd.data[7]); 2299269106Snp 2300269106Snp printf(" %c%c%c%c %c%c%c%c\n", 2301269106Snp isprint(i2cd.data[0]) ? i2cd.data[0] : '.', 2302269106Snp isprint(i2cd.data[1]) ? i2cd.data[1] : '.', 2303269106Snp isprint(i2cd.data[2]) ? i2cd.data[2] : '.', 2304269106Snp isprint(i2cd.data[3]) ? i2cd.data[3] : '.', 2305269106Snp isprint(i2cd.data[4]) ? i2cd.data[4] : '.', 2306269106Snp isprint(i2cd.data[5]) ? i2cd.data[5] : '.', 2307269106Snp isprint(i2cd.data[6]) ? i2cd.data[6] : '.', 2308269106Snp isprint(i2cd.data[7]) ? i2cd.data[7] : '.'); 2309269106Snp } 2310269106Snp 2311269106Snp return (0); 2312269106Snp} 2313269106Snp 2314269106Snpstatic int 2315258698Snpmodinfo(int argc, const char *argv[]) 2316258698Snp{ 2317258698Snp long port; 2318258698Snp char string[16], *p; 2319258698Snp struct t4_i2c_data i2cd; 2320258698Snp int rc, i; 2321258698Snp uint16_t temp, vcc, tx_bias, tx_power, rx_power; 2322258698Snp 2323269106Snp if (argc < 1) { 2324258698Snp warnx("must supply a port"); 2325258698Snp return (EINVAL); 2326258698Snp } 2327258698Snp 2328269106Snp if (argc > 2) { 2329269106Snp warnx("too many arguments"); 2330269106Snp return (EINVAL); 2331269106Snp } 2332269106Snp 2333258698Snp p = str_to_number(argv[0], &port, NULL); 2334258698Snp if (*p || port > UCHAR_MAX) { 2335258698Snp warnx("invalid port id \"%s\"", argv[0]); 2336258698Snp return (EINVAL); 2337258698Snp } 2338258698Snp 2339269106Snp if (argc == 2) { 2340269106Snp if (!strcmp(argv[1], "raw")) 2341269106Snp return (modinfo_raw(port)); 2342269106Snp else { 2343269106Snp warnx("second argument can only be \"raw\""); 2344269106Snp return (EINVAL); 2345269106Snp } 2346269106Snp } 2347269106Snp 2348258698Snp bzero(&i2cd, sizeof(i2cd)); 2349258698Snp i2cd.len = 1; 2350258698Snp i2cd.port_id = port; 2351258698Snp i2cd.dev_addr = SFF_8472_BASE; 2352258698Snp 2353258698Snp i2cd.offset = SFF_8472_ID; 2354258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2355258698Snp goto fail; 2356258698Snp 2357258698Snp if (i2cd.data[0] > SFF_8472_ID_LAST) 2358258698Snp printf("Unknown ID\n"); 2359258698Snp else 2360258698Snp printf("ID: %s\n", sff_8472_id[i2cd.data[0]]); 2361258698Snp 2362258698Snp bzero(&string, sizeof(string)); 2363258698Snp for (i = SFF_8472_VENDOR_START; i < SFF_8472_VENDOR_END; i++) { 2364258698Snp i2cd.offset = i; 2365258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2366258698Snp goto fail; 2367258698Snp string[i - SFF_8472_VENDOR_START] = i2cd.data[0]; 2368258698Snp } 2369258698Snp printf("Vendor %s\n", string); 2370258698Snp 2371258698Snp bzero(&string, sizeof(string)); 2372258698Snp for (i = SFF_8472_SN_START; i < SFF_8472_SN_END; i++) { 2373258698Snp i2cd.offset = i; 2374258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2375258698Snp goto fail; 2376258698Snp string[i - SFF_8472_SN_START] = i2cd.data[0]; 2377258698Snp } 2378258698Snp printf("SN %s\n", string); 2379258698Snp 2380258698Snp bzero(&string, sizeof(string)); 2381258698Snp for (i = SFF_8472_PN_START; i < SFF_8472_PN_END; i++) { 2382258698Snp i2cd.offset = i; 2383258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2384258698Snp goto fail; 2385258698Snp string[i - SFF_8472_PN_START] = i2cd.data[0]; 2386258698Snp } 2387258698Snp printf("PN %s\n", string); 2388258698Snp 2389258698Snp bzero(&string, sizeof(string)); 2390258698Snp for (i = SFF_8472_REV_START; i < SFF_8472_REV_END; i++) { 2391258698Snp i2cd.offset = i; 2392258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2393258698Snp goto fail; 2394258698Snp string[i - SFF_8472_REV_START] = i2cd.data[0]; 2395258698Snp } 2396258698Snp printf("Rev %s\n", string); 2397258698Snp 2398258698Snp i2cd.offset = SFF_8472_DIAG_TYPE; 2399258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2400258698Snp goto fail; 2401258698Snp 2402258698Snp if ((char )i2cd.data[0] & (SFF_8472_DIAG_IMPL | 2403258698Snp SFF_8472_DIAG_INTERNAL)) { 2404258698Snp 2405258698Snp /* Switch to reading from the Diagnostic address. */ 2406258698Snp i2cd.dev_addr = SFF_8472_DIAG; 2407258698Snp i2cd.len = 1; 2408258698Snp 2409258698Snp i2cd.offset = SFF_8472_TEMP; 2410258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2411258698Snp goto fail; 2412258698Snp temp = i2cd.data[0] << 8; 2413258698Snp printf("Temp: "); 2414258698Snp if ((temp & SFF_8472_TEMP_SIGN) == SFF_8472_TEMP_SIGN) 2415258698Snp printf("-"); 2416258698Snp else 2417258698Snp printf("+"); 2418258698Snp printf("%dC\n", (temp & SFF_8472_TEMP_MSK) >> 2419258698Snp SFF_8472_TEMP_SHIFT); 2420258698Snp 2421258698Snp i2cd.offset = SFF_8472_VCC; 2422258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2423258698Snp goto fail; 2424258698Snp vcc = i2cd.data[0] << 8; 2425258698Snp printf("Vcc %fV\n", vcc / SFF_8472_VCC_FACTOR); 2426258698Snp 2427258698Snp i2cd.offset = SFF_8472_TX_BIAS; 2428258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2429258698Snp goto fail; 2430258698Snp tx_bias = i2cd.data[0] << 8; 2431258698Snp printf("TX Bias %fuA\n", tx_bias / SFF_8472_BIAS_FACTOR); 2432258698Snp 2433258698Snp i2cd.offset = SFF_8472_TX_POWER; 2434258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2435258698Snp goto fail; 2436258698Snp tx_power = i2cd.data[0] << 8; 2437258698Snp printf("TX Power %fmW\n", tx_power / SFF_8472_POWER_FACTOR); 2438258698Snp 2439258698Snp i2cd.offset = SFF_8472_RX_POWER; 2440258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2441258698Snp goto fail; 2442258698Snp rx_power = i2cd.data[0] << 8; 2443258698Snp printf("RX Power %fmW\n", rx_power / SFF_8472_POWER_FACTOR); 2444258698Snp 2445258698Snp } else 2446258698Snp printf("Diagnostics not supported.\n"); 2447258698Snp 2448258698Snp return(0); 2449258698Snp 2450258698Snpfail: 2451258698Snp if (rc == EPERM) 2452258698Snp warnx("No module/cable in port %ld", port); 2453258698Snp return (rc); 2454258698Snp 2455258698Snp} 2456258698Snp 2457259048Snp/* XXX: pass in a low/high and do range checks as well */ 2458258698Snpstatic int 2459259048Snpget_sched_param(const char *param, const char *args[], long *val) 2460253691Snp{ 2461259048Snp char *p; 2462253691Snp 2463259048Snp if (strcmp(param, args[0]) != 0) 2464259048Snp return (EINVAL); 2465259048Snp 2466259048Snp p = str_to_number(args[1], val, NULL); 2467259048Snp if (*p) { 2468259048Snp warnx("parameter \"%s\" has bad value \"%s\"", args[0], 2469259048Snp args[1]); 2470259048Snp return (EINVAL); 2471259048Snp } 2472259048Snp 2473259048Snp return (0); 2474259048Snp} 2475259048Snp 2476259048Snpstatic int 2477259048Snpsched_class(int argc, const char *argv[]) 2478259048Snp{ 2479259048Snp struct t4_sched_params op; 2480259048Snp int errs, i; 2481259048Snp 2482259048Snp memset(&op, 0xff, sizeof(op)); 2483259048Snp op.subcmd = -1; 2484259048Snp op.type = -1; 2485253691Snp if (argc == 0) { 2486259048Snp warnx("missing scheduling sub-command"); 2487253691Snp return (EINVAL); 2488259048Snp } 2489259048Snp if (!strcmp(argv[0], "config")) { 2490259048Snp op.subcmd = SCHED_CLASS_SUBCMD_CONFIG; 2491259048Snp op.u.config.minmax = -1; 2492259048Snp } else if (!strcmp(argv[0], "params")) { 2493259048Snp op.subcmd = SCHED_CLASS_SUBCMD_PARAMS; 2494259048Snp op.u.params.level = op.u.params.mode = op.u.params.rateunit = 2495259048Snp op.u.params.ratemode = op.u.params.channel = 2496259048Snp op.u.params.cl = op.u.params.minrate = op.u.params.maxrate = 2497259048Snp op.u.params.weight = op.u.params.pktsize = -1; 2498259048Snp } else { 2499259048Snp warnx("invalid scheduling sub-command \"%s\"", argv[0]); 2500259048Snp return (EINVAL); 2501259048Snp } 2502253691Snp 2503259048Snp /* Decode remaining arguments ... */ 2504259048Snp errs = 0; 2505259048Snp for (i = 1; i < argc; i += 2) { 2506259048Snp const char **args = &argv[i]; 2507259048Snp long l; 2508253691Snp 2509259048Snp if (i + 1 == argc) { 2510259048Snp warnx("missing argument for \"%s\"", args[0]); 2511259048Snp errs++; 2512259048Snp break; 2513259048Snp } 2514259048Snp 2515259048Snp if (!strcmp(args[0], "type")) { 2516259048Snp if (!strcmp(args[1], "packet")) 2517259048Snp op.type = SCHED_CLASS_TYPE_PACKET; 2518259048Snp else { 2519259048Snp warnx("invalid type parameter \"%s\"", args[1]); 2520259048Snp errs++; 2521259048Snp } 2522259048Snp 2523259048Snp continue; 2524259048Snp } 2525259048Snp 2526259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_CONFIG) { 2527259048Snp if(!get_sched_param("minmax", args, &l)) 2528259048Snp op.u.config.minmax = (int8_t)l; 2529259048Snp else { 2530259048Snp warnx("unknown scheduler config parameter " 2531259048Snp "\"%s\"", args[0]); 2532259048Snp errs++; 2533259048Snp } 2534259048Snp 2535259048Snp continue; 2536259048Snp } 2537259048Snp 2538259048Snp /* Rest applies only to SUBCMD_PARAMS */ 2539259048Snp if (op.subcmd != SCHED_CLASS_SUBCMD_PARAMS) 2540259048Snp continue; 2541259048Snp 2542259048Snp if (!strcmp(args[0], "level")) { 2543259048Snp if (!strcmp(args[1], "cl-rl")) 2544259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CL_RL; 2545259048Snp else if (!strcmp(args[1], "cl-wrr")) 2546259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CL_WRR; 2547259048Snp else if (!strcmp(args[1], "ch-rl")) 2548259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CH_RL; 2549259048Snp else { 2550259048Snp warnx("invalid level parameter \"%s\"", 2551259048Snp args[1]); 2552259048Snp errs++; 2553259048Snp } 2554259048Snp } else if (!strcmp(args[0], "mode")) { 2555259048Snp if (!strcmp(args[1], "class")) 2556259048Snp op.u.params.mode = SCHED_CLASS_MODE_CLASS; 2557259048Snp else if (!strcmp(args[1], "flow")) 2558259048Snp op.u.params.mode = SCHED_CLASS_MODE_FLOW; 2559259048Snp else { 2560259048Snp warnx("invalid mode parameter \"%s\"", args[1]); 2561259048Snp errs++; 2562259048Snp } 2563259048Snp } else if (!strcmp(args[0], "rate-unit")) { 2564259048Snp if (!strcmp(args[1], "bits")) 2565259048Snp op.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS; 2566259048Snp else if (!strcmp(args[1], "pkts")) 2567259048Snp op.u.params.rateunit = SCHED_CLASS_RATEUNIT_PKTS; 2568259048Snp else { 2569259048Snp warnx("invalid rate-unit parameter \"%s\"", 2570259048Snp args[1]); 2571259048Snp errs++; 2572259048Snp } 2573259048Snp } else if (!strcmp(args[0], "rate-mode")) { 2574259048Snp if (!strcmp(args[1], "relative")) 2575259048Snp op.u.params.ratemode = SCHED_CLASS_RATEMODE_REL; 2576259048Snp else if (!strcmp(args[1], "absolute")) 2577259048Snp op.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS; 2578259048Snp else { 2579259048Snp warnx("invalid rate-mode parameter \"%s\"", 2580259048Snp args[1]); 2581259048Snp errs++; 2582259048Snp } 2583259048Snp } else if (!get_sched_param("channel", args, &l)) 2584259048Snp op.u.params.channel = (int8_t)l; 2585259048Snp else if (!get_sched_param("class", args, &l)) 2586259048Snp op.u.params.cl = (int8_t)l; 2587259048Snp else if (!get_sched_param("min-rate", args, &l)) 2588259048Snp op.u.params.minrate = (int32_t)l; 2589259048Snp else if (!get_sched_param("max-rate", args, &l)) 2590259048Snp op.u.params.maxrate = (int32_t)l; 2591259048Snp else if (!get_sched_param("weight", args, &l)) 2592259048Snp op.u.params.weight = (int16_t)l; 2593259048Snp else if (!get_sched_param("pkt-size", args, &l)) 2594259048Snp op.u.params.pktsize = (int16_t)l; 2595259048Snp else { 2596259048Snp warnx("unknown scheduler parameter \"%s\"", args[0]); 2597259048Snp errs++; 2598259048Snp } 2599253691Snp } 2600253691Snp 2601259048Snp /* 2602259048Snp * Catch some logical fallacies in terms of argument combinations here 2603259048Snp * so we can offer more than just the EINVAL return from the driver. 2604259048Snp * The driver will be able to catch a lot more issues since it knows 2605259048Snp * the specifics of the device hardware capabilities like how many 2606259048Snp * channels, classes, etc. the device supports. 2607259048Snp */ 2608259048Snp if (op.type < 0) { 2609259048Snp warnx("sched \"type\" parameter missing"); 2610259048Snp errs++; 2611259048Snp } 2612259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_CONFIG) { 2613259048Snp if (op.u.config.minmax < 0) { 2614259048Snp warnx("sched config \"minmax\" parameter missing"); 2615259048Snp errs++; 2616259048Snp } 2617259048Snp } 2618259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_PARAMS) { 2619259048Snp if (op.u.params.level < 0) { 2620259048Snp warnx("sched params \"level\" parameter missing"); 2621259048Snp errs++; 2622259048Snp } 2623259048Snp if (op.u.params.mode < 0) { 2624259048Snp warnx("sched params \"mode\" parameter missing"); 2625259048Snp errs++; 2626259048Snp } 2627259048Snp if (op.u.params.rateunit < 0) { 2628259048Snp warnx("sched params \"rate-unit\" parameter missing"); 2629259048Snp errs++; 2630259048Snp } 2631259048Snp if (op.u.params.ratemode < 0) { 2632259048Snp warnx("sched params \"rate-mode\" parameter missing"); 2633259048Snp errs++; 2634259048Snp } 2635259048Snp if (op.u.params.channel < 0) { 2636259048Snp warnx("sched params \"channel\" missing"); 2637259048Snp errs++; 2638259048Snp } 2639259048Snp if (op.u.params.cl < 0) { 2640259048Snp warnx("sched params \"class\" missing"); 2641259048Snp errs++; 2642259048Snp } 2643259048Snp if (op.u.params.maxrate < 0 && 2644259048Snp (op.u.params.level == SCHED_CLASS_LEVEL_CL_RL || 2645259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CH_RL)) { 2646259048Snp warnx("sched params \"max-rate\" missing for " 2647259048Snp "rate-limit level"); 2648259048Snp errs++; 2649259048Snp } 2650259048Snp if (op.u.params.weight < 0 && 2651259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CL_WRR) { 2652259048Snp warnx("sched params \"weight\" missing for " 2653259048Snp "weighted-round-robin level"); 2654259048Snp errs++; 2655259048Snp } 2656259048Snp if (op.u.params.pktsize < 0 && 2657259048Snp (op.u.params.level == SCHED_CLASS_LEVEL_CL_RL || 2658259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CH_RL)) { 2659259048Snp warnx("sched params \"pkt-size\" missing for " 2660259048Snp "rate-limit level"); 2661259048Snp errs++; 2662259048Snp } 2663259048Snp if (op.u.params.mode == SCHED_CLASS_MODE_FLOW && 2664259048Snp op.u.params.ratemode != SCHED_CLASS_RATEMODE_ABS) { 2665259048Snp warnx("sched params mode flow needs rate-mode absolute"); 2666259048Snp errs++; 2667259048Snp } 2668259048Snp if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_REL && 2669259048Snp !in_range(op.u.params.maxrate, 1, 100)) { 2670259048Snp warnx("sched params \"max-rate\" takes " 2671259048Snp "percentage value(1-100) for rate-mode relative"); 2672259048Snp errs++; 2673259048Snp } 2674259048Snp if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_ABS && 2675301516Snp !in_range(op.u.params.maxrate, 1, 100000000)) { 2676259048Snp warnx("sched params \"max-rate\" takes " 2677301516Snp "value(1-100000000) for rate-mode absolute"); 2678259048Snp errs++; 2679259048Snp } 2680259048Snp if (op.u.params.maxrate > 0 && 2681259048Snp op.u.params.maxrate < op.u.params.minrate) { 2682259048Snp warnx("sched params \"max-rate\" is less than " 2683259048Snp "\"min-rate\""); 2684259048Snp errs++; 2685259048Snp } 2686259048Snp } 2687259048Snp 2688259048Snp if (errs > 0) { 2689259048Snp warnx("%d error%s in sched-class command", errs, 2690259048Snp errs == 1 ? "" : "s"); 2691253691Snp return (EINVAL); 2692253691Snp } 2693253691Snp 2694259048Snp return doit(CHELSIO_T4_SCHED_CLASS, &op); 2695259048Snp} 2696253691Snp 2697259048Snpstatic int 2698259048Snpsched_queue(int argc, const char *argv[]) 2699259048Snp{ 2700259048Snp struct t4_sched_queue op = {0}; 2701259048Snp char *p; 2702259048Snp long val; 2703253691Snp 2704259048Snp if (argc != 3) { 2705259048Snp /* need "<port> <queue> <class> */ 2706259048Snp warnx("incorrect number of arguments."); 2707259048Snp return (EINVAL); 2708259048Snp } 2709259048Snp 2710259048Snp p = str_to_number(argv[0], &val, NULL); 2711259048Snp if (*p || val > UCHAR_MAX) { 2712259048Snp warnx("invalid port id \"%s\"", argv[0]); 2713259048Snp return (EINVAL); 2714259048Snp } 2715259048Snp op.port = (uint8_t)val; 2716259048Snp 2717259048Snp if (!strcmp(argv[1], "all") || !strcmp(argv[1], "*")) 2718259048Snp op.queue = -1; 2719259048Snp else { 2720259048Snp p = str_to_number(argv[1], &val, NULL); 2721259048Snp if (*p || val < -1) { 2722259048Snp warnx("invalid queue \"%s\"", argv[1]); 2723259048Snp return (EINVAL); 2724259048Snp } 2725259048Snp op.queue = (int8_t)val; 2726259048Snp } 2727259048Snp 2728259048Snp if (!strcmp(argv[2], "unbind") || !strcmp(argv[2], "clear")) 2729259048Snp op.cl = -1; 2730259048Snp else { 2731259048Snp p = str_to_number(argv[2], &val, NULL); 2732259048Snp if (*p || val < -1) { 2733259048Snp warnx("invalid class \"%s\"", argv[2]); 2734259048Snp return (EINVAL); 2735259048Snp } 2736259048Snp op.cl = (int8_t)val; 2737259048Snp } 2738259048Snp 2739259048Snp return doit(CHELSIO_T4_SCHED_QUEUE, &op); 2740253691Snp} 2741253691Snp 2742253691Snpstatic int 2743222900Snprun_cmd(int argc, const char *argv[]) 2744222900Snp{ 2745222900Snp int rc = -1; 2746222900Snp const char *cmd = argv[0]; 2747222900Snp 2748222900Snp /* command */ 2749222900Snp argc--; 2750222900Snp argv++; 2751222900Snp 2752222900Snp if (!strcmp(cmd, "reg") || !strcmp(cmd, "reg32")) 2753222900Snp rc = register_io(argc, argv, 4); 2754222900Snp else if (!strcmp(cmd, "reg64")) 2755222900Snp rc = register_io(argc, argv, 8); 2756222900Snp else if (!strcmp(cmd, "regdump")) 2757222900Snp rc = dump_regs(argc, argv); 2758222900Snp else if (!strcmp(cmd, "filter")) 2759222900Snp rc = filter_cmd(argc, argv); 2760222974Snp else if (!strcmp(cmd, "context")) 2761222974Snp rc = get_sge_context(argc, argv); 2762228594Snp else if (!strcmp(cmd, "loadfw")) 2763228594Snp rc = loadfw(argc, argv); 2764228594Snp else if (!strcmp(cmd, "memdump")) 2765228594Snp rc = memdump(argc, argv); 2766228594Snp else if (!strcmp(cmd, "tcb")) 2767228594Snp rc = read_tcb(argc, argv); 2768241401Snp else if (!strcmp(cmd, "i2c")) 2769241401Snp rc = read_i2c(argc, argv); 2770241416Snp else if (!strcmp(cmd, "clearstats")) 2771241416Snp rc = clearstats(argc, argv); 2772253691Snp else if (!strcmp(cmd, "tracer")) 2773253691Snp rc = tracer_cmd(argc, argv); 2774258698Snp else if (!strcmp(cmd, "modinfo")) 2775258698Snp rc = modinfo(argc, argv); 2776259048Snp else if (!strcmp(cmd, "sched-class")) 2777259048Snp rc = sched_class(argc, argv); 2778259048Snp else if (!strcmp(cmd, "sched-queue")) 2779259048Snp rc = sched_queue(argc, argv); 2780306823Snp else if (!strcmp(cmd, "loadcfg")) 2781306823Snp rc = loadcfg(argc, argv); 2782222900Snp else { 2783222900Snp rc = EINVAL; 2784222900Snp warnx("invalid command \"%s\"", cmd); 2785222900Snp } 2786222900Snp 2787222900Snp return (rc); 2788222900Snp} 2789222900Snp 2790222900Snp#define MAX_ARGS 15 2791222900Snpstatic int 2792222900Snprun_cmd_loop(void) 2793222900Snp{ 2794222900Snp int i, rc = 0; 2795222900Snp char buffer[128], *buf; 2796222900Snp const char *args[MAX_ARGS + 1]; 2797222900Snp 2798222900Snp /* 2799222900Snp * Simple loop: displays a "> " prompt and processes any input as a 2800222900Snp * cxgbetool command. You're supposed to enter only the part after 2801222900Snp * "cxgbetool t4nexX". Use "quit" or "exit" to exit. 2802222900Snp */ 2803222900Snp for (;;) { 2804222900Snp fprintf(stdout, "> "); 2805222900Snp fflush(stdout); 2806222900Snp buf = fgets(buffer, sizeof(buffer), stdin); 2807222900Snp if (buf == NULL) { 2808222900Snp if (ferror(stdin)) { 2809222900Snp warn("stdin error"); 2810222900Snp rc = errno; /* errno from fgets */ 2811222900Snp } 2812222900Snp break; 2813222900Snp } 2814222900Snp 2815222900Snp i = 0; 2816222900Snp while ((args[i] = strsep(&buf, " \t\n")) != NULL) { 2817222900Snp if (args[i][0] != 0 && ++i == MAX_ARGS) 2818222900Snp break; 2819222900Snp } 2820222900Snp args[i] = 0; 2821222900Snp 2822222900Snp if (i == 0) 2823222900Snp continue; /* skip empty line */ 2824222900Snp 2825222900Snp if (!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) 2826222900Snp break; 2827222900Snp 2828222900Snp rc = run_cmd(i, args); 2829222900Snp } 2830222900Snp 2831222900Snp /* rc normally comes from the last command (not including quit/exit) */ 2832222900Snp return (rc); 2833222900Snp} 2834222900Snp 2835222900Snpint 2836222900Snpmain(int argc, const char *argv[]) 2837222900Snp{ 2838222900Snp int rc = -1; 2839222900Snp 2840222900Snp progname = argv[0]; 2841222900Snp 2842222900Snp if (argc == 2) { 2843222900Snp if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 2844222900Snp usage(stdout); 2845222900Snp exit(0); 2846222900Snp } 2847222900Snp } 2848222900Snp 2849222900Snp if (argc < 3) { 2850222900Snp usage(stderr); 2851222900Snp exit(EINVAL); 2852222900Snp } 2853222900Snp 2854222900Snp nexus = argv[1]; 2855222900Snp 2856222900Snp /* progname and nexus */ 2857222900Snp argc -= 2; 2858222900Snp argv += 2; 2859222900Snp 2860222900Snp if (argc == 1 && !strcmp(argv[0], "stdio")) 2861222900Snp rc = run_cmd_loop(); 2862222900Snp else 2863222900Snp rc = run_cmd(argc, argv); 2864222900Snp 2865222900Snp return (rc); 2866222900Snp} 2867