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