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