1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2018 Joyent, Inc.
14  */
15 
16 #include <mdb/mdb_ctf.h>
17 #include <sys/mdb_modapi.h>
18 #include "i40e_sw.h"
19 
20 #define	RSRC_MAX	0x13
21 static const char *i40e_switch_rsrc_names[] = {
22 	"VEBs",
23 	"VSIs",
24 	"Perfect Match MAC Addresses",
25 	"S-Tags",
26 	"Reserved",
27 	"Multicast Hash Entries",
28 	"Reserved",
29 	"VLANs",
30 	"VSI Lists",
31 	"Reserved",
32 	"VLAN Stat pools",
33 	"Mirror rules",
34 	"Queue sets",
35 	"Inner VLAN Forwarding",
36 	"Reserved",
37 	"Inner MACs",
38 	"IPs",
39 	"GRE/VN1 Keys",
40 	"VN2 Keys",
41 	"Tunnelling Ports"
42 };
43 
44 /*
45  * i40e mdb dcmds
46  */
47 /* ARGSUSED */
48 static int
i40e_switch_rsrcs_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)49 i40e_switch_rsrcs_dcmd(uintptr_t addr, uint_t flags, int argc,
50     const mdb_arg_t *argv)
51 {
52 	i40e_t i40e;
53 	int i;
54 
55 	if (!(flags & DCMD_ADDRSPEC)) {
56 		mdb_warn("::i40e_switch_rsrcs does not operate globally\n");
57 		return (DCMD_USAGE);
58 	}
59 
60 	if (mdb_vread(&i40e, sizeof (i40e_t), addr) != sizeof (i40e_t)) {
61 		mdb_warn("failed to read i40e_t at %p", addr);
62 		return (DCMD_ERR);
63 	}
64 
65 	mdb_printf("%-28s %-12s %-8s %-8s %s\n", "TYPE", "GUARANTEE",
66 	    "TOTAL", "USED", "UNALLOCED");
67 
68 	for (i = 0; i < i40e.i40e_switch_rsrc_actual; i++) {
69 		i40e_switch_rsrc_t rsrc;
70 		uintptr_t raddr = (uintptr_t)i40e.i40e_switch_rsrcs +
71 		    i * sizeof (i40e_switch_rsrc_t);
72 		const char *name;
73 
74 		if (mdb_vread(&rsrc, sizeof (i40e_switch_rsrc_t), raddr) !=
75 		    sizeof (i40e_switch_rsrc_t)) {
76 			mdb_warn("failed to read i40e_switch_rsrc_t %d at %p",
77 			    i, raddr);
78 			return (DCMD_ERR);
79 		}
80 
81 		if (rsrc.resource_type <= RSRC_MAX) {
82 			name = i40e_switch_rsrc_names[rsrc.resource_type];
83 		} else {
84 			char *buf;
85 			size_t s = mdb_snprintf(NULL, 0, "Unknown type (%d)",
86 			    rsrc.resource_type);
87 			buf = mdb_alloc(s + 1, UM_GC | UM_SLEEP);
88 			(void) mdb_snprintf(buf, s + 1, "Unknown type (%d)",
89 			    rsrc.resource_type);
90 			name = buf;
91 		}
92 
93 		mdb_printf("%-28s %-12d %-8d %-8d %d\n", name,
94 		    LE_16(rsrc.guaranteed), LE_16(rsrc.total), LE_16(rsrc.used),
95 		    LE_16(rsrc.total_unalloced));
96 	}
97 
98 	return (DCMD_OK);
99 }
100 
101 typedef struct mdb_i40e_trqpair {
102 	uint32_t		itrq_tx_ring_size;
103 	uint32_t		itrq_desc_free;
104 	uint32_t 		*itrq_desc_wbhead;
105 	uint32_t		itrq_desc_head;
106 	uint32_t		itrq_desc_tail;
107 	i40e_tx_desc_t		*itrq_desc_ring;
108 	i40e_tx_control_block_t	**itrq_tcb_work_list;
109 } mdb_i40e_trqpair_t;
110 
111 static void
i40e_tx_ring_help()112 i40e_tx_ring_help()
113 {
114 	mdb_printf(
115 	    "\t -a dump all ring entries\n"
116 	    "\t or\n"
117 	    "\t combine -b [start index] with -e [end index] to specify a \n"
118 	    "\t range of ring entries to print\n");
119 }
120 
121 static int
i40e_tx_ring_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)122 i40e_tx_ring_dcmd(uintptr_t addr, uint_t flags, int argc,
123     const mdb_arg_t *argv)
124 {
125 	mdb_i40e_trqpair_t trq;
126 	i40e_tx_desc_t *descring;
127 	i40e_tx_control_block_t **wklist;
128 	uint32_t wbhead;
129 	size_t ringsz, wklistsz;
130 	boolean_t opt_a = B_FALSE;
131 	char *opt_b = NULL, *opt_e = NULL;
132 	uint64_t begin = UINT64_MAX, end = UINT64_MAX;
133 
134 	if (!(flags & DCMD_ADDRSPEC)) {
135 		mdb_warn("::i40e_tx_ring does not operate globally\n");
136 		return (DCMD_USAGE);
137 	}
138 
139 	if (mdb_getopts(argc, argv,
140 	    'a', MDB_OPT_SETBITS, B_TRUE, &opt_a,
141 	    'b', MDB_OPT_STR, &opt_b,
142 	    'e', MDB_OPT_STR, &opt_e, NULL) != argc)
143 		return (DCMD_USAGE);
144 
145 	/*
146 	 * Verify that a legal combination of -a/-b/-e were used.
147 	 */
148 	if (opt_a && (opt_b != NULL || opt_e != NULL)) {
149 		mdb_warn("-a and -b/-e are mutually exclusive\n");
150 		return (DCMD_USAGE);
151 	}
152 	if (argc > 0 && ! opt_a && (opt_b == NULL || opt_e == NULL)) {
153 		mdb_warn("-b/-e must both be specified\n");
154 		return (DCMD_USAGE);
155 	}
156 
157 	if (mdb_ctf_vread(&trq, "i40e_trqpair_t", "mdb_i40e_trqpair_t", addr,
158 	    0) == -1) {
159 		mdb_warn("failed to read i40e_trqpair_t at %p", addr);
160 		return (DCMD_ERR);
161 	}
162 
163 	if (opt_b != NULL)
164 		begin = mdb_strtoull(opt_b);
165 	if (opt_e != NULL)
166 		end = mdb_strtoull(opt_e);
167 	if (opt_a) {
168 		begin = 0;
169 		end = trq.itrq_tx_ring_size - 1;
170 	}
171 
172 	/*
173 	 * Verify that the requested range of ring entries makes sense.
174 	 */
175 	if (argc > 0 && (end < begin || begin >= trq.itrq_tx_ring_size ||
176 	    end >= trq.itrq_tx_ring_size)) {
177 		mdb_warn("invalid range specified\n");
178 		return (DCMD_USAGE);
179 	}
180 
181 	if (mdb_vread(&wbhead, sizeof (uint32_t),
182 	    (uintptr_t)trq.itrq_desc_wbhead) != sizeof (uint32_t)) {
183 		mdb_warn("failed to read trq.itrq_desc_wbhead");
184 		return (DCMD_ERR);
185 	}
186 	mdb_printf("%-20s%d\n", "Ring Size:", trq.itrq_tx_ring_size);
187 	mdb_printf("%-20s%d\n", "Free Descriptors:", trq.itrq_desc_free);
188 	mdb_printf("%-20s%d\n", "Writeback Head:", wbhead);
189 	mdb_printf("%-20s%d\n", "Head:", trq.itrq_desc_head);
190 	mdb_printf("%-20s%d\n", "Tail:", trq.itrq_desc_tail);
191 
192 	/*
193 	 * No arguments were specified, so we're done.
194 	 */
195 	if (argc == 0)
196 		return (DCMD_OK);
197 
198 	/*
199 	 * Allocate memory and read in the entire TX descriptor ring and
200 	 * TCB work list.
201 	 */
202 	ringsz = sizeof (i40e_tx_desc_t) * trq.itrq_tx_ring_size;
203 	descring = mdb_alloc(ringsz, UM_SLEEP);
204 	if (mdb_vread(descring, ringsz, (uintptr_t)trq.itrq_desc_ring) !=
205 	    ringsz) {
206 		mdb_warn("Failed to read in TX decriptor ring\n");
207 		mdb_free(descring, ringsz);
208 		return (DCMD_ERR);
209 	}
210 	wklistsz = sizeof (i40e_tx_control_block_t *) * trq.itrq_tx_ring_size;
211 	wklist = mdb_alloc(wklistsz, UM_SLEEP);
212 	if (mdb_vread(wklist, wklistsz, (uintptr_t)trq.itrq_tcb_work_list) !=
213 	    wklistsz) {
214 		mdb_warn("Failed to read in TX TCB work list\n");
215 		mdb_free(descring, ringsz);
216 		mdb_free(wklist, wklistsz);
217 		return (DCMD_ERR);
218 	}
219 
220 	mdb_printf("\n%-10s %-10s %-16s %-16s %-10s\n", "Index", "Desc Type",
221 	    "Desc Ptr", "TCB Ptr", "Other");
222 	for (uint64_t i = begin; i <= end; i++) {
223 		const char *dtype;
224 		char dother[17];
225 		i40e_tx_desc_t *dptr;
226 		i40e_tx_control_block_t *tcbptr;
227 		uint64_t ctob;
228 
229 		dptr = &descring[i];
230 		tcbptr = wklist[i];
231 		ctob = LE_64(dptr->cmd_type_offset_bsz);
232 		if (ctob == 0) {
233 			dtype = "FREE";
234 		} else {
235 			switch (ctob & I40E_TXD_QW1_DTYPE_MASK) {
236 			case (I40E_TX_DESC_DTYPE_CONTEXT):
237 				dtype = "CONTEXT";
238 				break;
239 			case (I40E_TX_DESC_DTYPE_DATA):
240 				dtype = "DATA";
241 				break;
242 			case (I40E_TX_DESC_DTYPE_FILTER_PROG):
243 				dtype = "FILTER";
244 				break;
245 			default:
246 				dtype = "UNKNOWN";
247 			}
248 		}
249 		dother[0] = '\0';
250 		if (i == wbhead)
251 			(void) strcat(dother, "WBHEAD");
252 
253 		if (i == trq.itrq_desc_head)
254 			(void) strcat(dother,
255 			    strlen(dother) > 0 ? " HEAD" : "HEAD");
256 
257 		if (i == trq.itrq_desc_tail)
258 			(void) strcat(dother,
259 			    strlen(dother) > 0 ? " TAIL" : "TAIL");
260 
261 		mdb_printf("%-10d %-10s %-16p %-16p %-10s\n", i, dtype, dptr,
262 		    tcbptr, dother);
263 	}
264 
265 	mdb_free(descring, ringsz);
266 	mdb_free(wklist, wklistsz);
267 	return (DCMD_OK);
268 }
269 
270 static const mdb_dcmd_t i40e_dcmds[] = {
271 	{ "i40e_switch_rsrcs", NULL, "print switch resources",
272 	    i40e_switch_rsrcs_dcmd, NULL },
273 	{ "i40e_tx_ring", "[-a] -b [start index] -e [end index]\n",
274 	    "dump TX descriptor ring state", i40e_tx_ring_dcmd,
275 	    i40e_tx_ring_help },
276 	{ NULL }
277 };
278 
279 static const mdb_modinfo_t i40e_modinfo = {
280 	MDB_API_VERSION, i40e_dcmds, NULL
281 };
282 
283 const mdb_modinfo_t *
_mdb_init(void)284 _mdb_init(void)
285 {
286 	return (&i40e_modinfo);
287 }
288