cxgbtool.c revision 194928
1/**************************************************************************
2
3Copyright (c) 2007-2009, Chelsio Inc.
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are met:
8
9 1. Redistributions of source code must retain the above copyright notice,
10    this list of conditions and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15
16 3. Neither the name of the Chelsio Corporation nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30POSSIBILITY OF SUCH DAMAGE.
31
32
33***************************************************************************/
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/usr.sbin/cxgbtool/cxgbtool.c 194928 2009-06-24 22:28:48Z np $");
36
37#include <stdlib.h>
38#include <stdio.h>
39#include <stdint.h>
40#include <string.h>
41#include <unistd.h>
42#include <fcntl.h>
43#include <err.h>
44#include <errno.h>
45#include <inttypes.h>
46#include <sys/param.h>
47#include <sys/time.h>
48#include <sys/ioctl.h>
49#include <sys/socket.h>
50
51#include <netinet/in.h>
52#include <arpa/inet.h>
53
54#include <net/if.h>
55#include <net/if_var.h>
56#include <net/if_types.h>
57#include <sys/endian.h>
58
59#define NMTUS 16
60#define TCB_SIZE 128
61#define TCB_WORDS (TCB_SIZE / 4)
62#define PROTO_SRAM_LINES 128
63#define PROTO_SRAM_LINE_BITS 132
64#define PROTO_SRAM_LINE_NIBBLES (132 / 4)
65#define PROTO_SRAM_SIZE (PROTO_SRAM_LINE_NIBBLES * PROTO_SRAM_LINES / 2)
66#define PROTO_SRAM_EEPROM_ADDR 4096
67
68#include <cxgb_ioctl.h>
69#include <common/cxgb_regs.h>
70#include "version.h"
71
72struct reg_info {
73        const char *name;
74        uint16_t addr;
75        uint16_t len;
76};
77
78
79#include "reg_defs.c"
80#if defined(CONFIG_T3_REGS)
81# include "reg_defs_t3.c"
82# include "reg_defs_t3b.c"
83# include "reg_defs_t3c.c"
84#endif
85
86static const char *progname;
87
88static void __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
123static int
124doit(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
139static 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
151static uint32_t
152read_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
163static void
164write_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
175static 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
203static 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
233static inline uint32_t xtract(uint32_t val, int shift, int len)
234{
235	return (val >> shift) & ((1 << len) - 1);
236}
237
238static 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
257static 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)
295static 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
356static 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
417static 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
479static int
480dump_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
517static 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
595static 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
615static 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
652static 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
670static 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
683static 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
697static 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
713static 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
753static 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
799static 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
838static 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
857static 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
887static 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
910static 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
923static 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
965static 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
996static 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
1027static 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
1057static 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
1065static 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
1087static 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
1098static 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 */
1116static 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 */
1146static 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
1159static 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
1165static 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
1241static 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
1250static 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
1296static 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
1336static 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
1345static 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
1375static 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
1411static int
1412run_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
1465static int
1466run_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
1515int
1516main(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}
1544