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