xref: /freebsd-12.1/sys/dev/bnxt/bnxt_sysctl.c (revision c3545222)
1 /*-
2  * Broadcom NetXtreme-C/E network driver.
3  *
4  * Copyright (c) 2016 Broadcom, All Rights Reserved.
5  * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
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  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/types.h>
33 #include <sys/sysctl.h>
34 
35 #include "bnxt.h"
36 #include "bnxt_hwrm.h"
37 #include "bnxt_sysctl.h"
38 
39 static int bnxt_vlan_only_sysctl(SYSCTL_HANDLER_ARGS);
40 /*
41  * We want to create:
42  * dev.bnxt.0.hwstats.txq0
43  * dev.bnxt.0.hwstats.txq0.txmbufs
44  * dev.bnxt.0.hwstats.rxq0
45  * dev.bnxt.0.hwstats.txq0.rxmbufs
46  * so the hwstats ctx list needs to be created in attach_post and populated
47  * during init.
48  *
49  * Then, it needs to be cleaned up in stop.
50  */
51 
52 int
53 bnxt_init_sysctl_ctx(struct bnxt_softc *softc)
54 {
55 	struct sysctl_ctx_list *ctx;
56 
57 	sysctl_ctx_init(&softc->hw_stats);
58 	ctx = device_get_sysctl_ctx(softc->dev);
59 	softc->hw_stats_oid = SYSCTL_ADD_NODE(ctx,
60 	    SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev)), OID_AUTO,
61 	    "hwstats", CTLFLAG_RD, 0, "hardware statistics");
62 	if (!softc->hw_stats_oid) {
63 		sysctl_ctx_free(&softc->hw_stats);
64 		return ENOMEM;
65 	}
66 
67 	sysctl_ctx_init(&softc->ver_info->ver_ctx);
68 	ctx = device_get_sysctl_ctx(softc->dev);
69 	softc->ver_info->ver_oid = SYSCTL_ADD_NODE(ctx,
70 	    SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev)), OID_AUTO,
71 	    "ver", CTLFLAG_RD, 0, "hardware/firmware version information");
72 	if (!softc->ver_info->ver_oid) {
73 		sysctl_ctx_free(&softc->ver_info->ver_ctx);
74 		return ENOMEM;
75 	}
76 
77 	sysctl_ctx_init(&softc->nvm_info->nvm_ctx);
78 	ctx = device_get_sysctl_ctx(softc->dev);
79 	softc->nvm_info->nvm_oid = SYSCTL_ADD_NODE(ctx,
80 	    SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev)), OID_AUTO,
81 	    "nvram", CTLFLAG_RD, 0, "nvram information");
82 	if (!softc->nvm_info->nvm_oid) {
83 		sysctl_ctx_free(&softc->nvm_info->nvm_ctx);
84 		return ENOMEM;
85 	}
86 
87 	return 0;
88 }
89 
90 int
91 bnxt_free_sysctl_ctx(struct bnxt_softc *softc)
92 {
93 	int orc;
94 	int rc = 0;
95 
96 	if (softc->hw_stats_oid != NULL) {
97 		orc = sysctl_ctx_free(&softc->hw_stats);
98 		if (orc)
99 			rc = orc;
100 		else
101 			softc->hw_stats_oid = NULL;
102 	}
103 	if (softc->ver_info->ver_oid != NULL) {
104 		orc = sysctl_ctx_free(&softc->ver_info->ver_ctx);
105 		if (orc)
106 			rc = orc;
107 		else
108 			softc->ver_info->ver_oid = NULL;
109 	}
110 	if (softc->nvm_info->nvm_oid != NULL) {
111 		orc = sysctl_ctx_free(&softc->nvm_info->nvm_ctx);
112 		if (orc)
113 			rc = orc;
114 		else
115 			softc->nvm_info->nvm_oid = NULL;
116 	}
117 
118 	return rc;
119 }
120 
121 int
122 bnxt_create_tx_sysctls(struct bnxt_softc *softc, int txr)
123 {
124 	struct sysctl_oid *oid;
125 	struct ctx_hw_stats *tx_stats = (void *)softc->tx_stats.idi_vaddr;
126 	char	name[32];
127 	char	desc[64];
128 
129 	sprintf(name, "txq%d", txr);
130 	sprintf(desc, "transmit queue %d", txr);
131 	oid = SYSCTL_ADD_NODE(&softc->hw_stats,
132 	    SYSCTL_CHILDREN(softc->hw_stats_oid), OID_AUTO, name, CTLFLAG_RD, 0,
133 	    desc);
134 	if (!oid)
135 		return ENOMEM;
136 
137 
138 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
139 	    "ucast_pkts", CTLFLAG_RD, &tx_stats[txr].tx_ucast_pkts,
140 	    "unicast packets sent");
141 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
142 	    "mcast_pkts", CTLFLAG_RD, &tx_stats[txr].tx_mcast_pkts,
143 	    "multicast packets sent");
144 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
145 	    "bcast_pkts", CTLFLAG_RD, &tx_stats[txr].tx_bcast_pkts,
146 	    "broadcast packets sent");
147 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
148 	    "discard_pkts", CTLFLAG_RD,
149 	    &tx_stats[txr].tx_discard_pkts, "discarded transmit packets");
150 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
151 	    "drop_pkts", CTLFLAG_RD, &tx_stats[txr].tx_drop_pkts,
152 	    "dropped transmit packets");
153 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
154 	    "ucast_bytes", CTLFLAG_RD, &tx_stats[txr].tx_ucast_bytes,
155 	    "unicast bytes sent");
156 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
157 	    "mcast_bytes", CTLFLAG_RD, &tx_stats[txr].tx_mcast_bytes,
158 	    "multicast bytes sent");
159 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
160 	    "bcast_bytes", CTLFLAG_RD, &tx_stats[txr].tx_bcast_bytes,
161 	    "broadcast bytes sent");
162 
163 	return 0;
164 }
165 
166 int
167 bnxt_create_rx_sysctls(struct bnxt_softc *softc, int rxr)
168 {
169 	struct sysctl_oid *oid;
170 	struct ctx_hw_stats *rx_stats = (void *)softc->rx_stats.idi_vaddr;
171 	char	name[32];
172 	char	desc[64];
173 
174 	sprintf(name, "rxq%d", rxr);
175 	sprintf(desc, "receive queue %d", rxr);
176 	oid = SYSCTL_ADD_NODE(&softc->hw_stats,
177 	    SYSCTL_CHILDREN(softc->hw_stats_oid), OID_AUTO, name, CTLFLAG_RD, 0,
178 	    desc);
179 	if (!oid)
180 		return ENOMEM;
181 
182 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
183 	    "ucast_pkts", CTLFLAG_RD, &rx_stats[rxr].rx_ucast_pkts,
184 	    "unicast packets received");
185 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
186 	    "mcast_pkts", CTLFLAG_RD, &rx_stats[rxr].rx_mcast_pkts,
187 	    "multicast packets received");
188 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
189 	    "bcast_pkts", CTLFLAG_RD, &rx_stats[rxr].rx_bcast_pkts,
190 	    "broadcast packets received");
191 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
192 	    "discard_pkts", CTLFLAG_RD,
193 	    &rx_stats[rxr].rx_discard_pkts, "discarded receive packets");
194 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
195 	    "drop_pkts", CTLFLAG_RD, &rx_stats[rxr].rx_drop_pkts,
196 	    "dropped receive packets");
197 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
198 	    "ucast_bytes", CTLFLAG_RD, &rx_stats[rxr].rx_ucast_bytes,
199 	    "unicast bytes received");
200 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
201 	    "mcast_bytes", CTLFLAG_RD, &rx_stats[rxr].rx_mcast_bytes,
202 	    "multicast bytes received");
203 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
204 	    "bcast_bytes", CTLFLAG_RD, &rx_stats[rxr].rx_bcast_bytes,
205 	    "broadcast bytes received");
206 
207 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
208 	    "tpa_pkts", CTLFLAG_RD, &rx_stats[rxr].tpa_pkts,
209 	    "TPA packets");
210 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
211 	    "tpa_bytes", CTLFLAG_RD, &rx_stats[rxr].tpa_bytes,
212 	    "TPA bytes");
213 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
214 	    "tpa_events", CTLFLAG_RD, &rx_stats[rxr].tpa_events,
215 	    "TPA events");
216 	SYSCTL_ADD_QUAD(&softc->hw_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
217 	    "tpa_aborts", CTLFLAG_RD, &rx_stats[rxr].tpa_aborts,
218 	    "TPA aborts");
219 
220 	return 0;
221 }
222 
223 static char *bnxt_chip_type[] = {
224 	"ASIC",
225 	"FPGA",
226 	"Palladium",
227 	"Unknown"
228 };
229 #define MAX_CHIP_TYPE 3
230 
231 static int
232 bnxt_package_ver_sysctl(SYSCTL_HANDLER_ARGS)
233 {
234 	struct bnxt_softc *softc = arg1;
235 	struct iflib_dma_info dma_data;
236 	char *pkglog = NULL;
237 	char *p;
238 	char *next;
239 	char unk[] = "<unknown>";
240 	char *buf = unk;
241 	int rc;
242 	int field;
243 	uint16_t ordinal = BNX_DIR_ORDINAL_FIRST;
244 	uint16_t index;
245 	uint32_t data_len;
246 
247 	rc = bnxt_hwrm_nvm_find_dir_entry(softc, BNX_DIR_TYPE_PKG_LOG,
248 	    &ordinal, BNX_DIR_EXT_NONE, &index, false,
249 	    HWRM_NVM_FIND_DIR_ENTRY_INPUT_OPT_ORDINAL_EQ,
250 	    &data_len, NULL, NULL);
251 	dma_data.idi_vaddr = NULL;
252 	if (rc == 0 && data_len) {
253 		rc = iflib_dma_alloc(softc->ctx, data_len, &dma_data,
254 		    BUS_DMA_NOWAIT);
255 		if (rc == 0) {
256 			rc = bnxt_hwrm_nvm_read(softc, index, 0, data_len,
257 			    &dma_data);
258 			if (rc == 0) {
259 				pkglog = dma_data.idi_vaddr;
260 				/* NULL terminate (removes last \n) */
261 				pkglog[data_len-1] = 0;
262 
263 				/* Set p = start of last line */
264 				p = strrchr(pkglog, '\n');
265 				if (p == NULL)
266 					p = pkglog;
267 
268 				/* Now find the correct tab delimited field */
269 				for (field = 0, next = p,
270 				    p = strsep(&next, "\t");
271 				    field <
272 				    BNX_PKG_LOG_FIELD_IDX_PKG_VERSION && p;
273 				    p = strsep(&next, "\t")) {
274 					field++;
275 				}
276 				if (field == BNX_PKG_LOG_FIELD_IDX_PKG_VERSION)
277 					buf = p;
278 			}
279 		}
280 		else
281 			dma_data.idi_vaddr = NULL;
282 	}
283 
284 	rc = sysctl_handle_string(oidp, buf, 0, req);
285 	if (dma_data.idi_vaddr)
286 		iflib_dma_free(&dma_data);
287 	return rc;
288 }
289 
290 static int
291 bnxt_hwrm_min_ver_sysctl(SYSCTL_HANDLER_ARGS)
292 {
293 	struct bnxt_softc *softc = arg1;
294 	char buf[16];
295 	uint8_t	newver[3];
296 	int rc;
297 
298 	sprintf(buf, "%hhu.%hhu.%hhu", softc->ver_info->hwrm_min_major,
299 	    softc->ver_info->hwrm_min_minor, softc->ver_info->hwrm_min_update);
300 
301 	rc = sysctl_handle_string(oidp, buf, sizeof(buf), req);
302 	if (rc || req->newptr == NULL)
303 		return rc;
304 	if (sscanf(buf, "%hhu.%hhu.%hhu%*c", &newver[0], &newver[1],
305 	    &newver[2]) != 3)
306 		return EINVAL;
307 	softc->ver_info->hwrm_min_major = newver[0];
308 	softc->ver_info->hwrm_min_minor = newver[1];
309 	softc->ver_info->hwrm_min_update = newver[2];
310 	bnxt_check_hwrm_version(softc);
311 
312 	return rc;
313 }
314 
315 int
316 bnxt_create_ver_sysctls(struct bnxt_softc *softc)
317 {
318 	struct bnxt_ver_info *vi = softc->ver_info;
319 	struct sysctl_oid *oid = vi->ver_oid;
320 
321 	if (!oid)
322 		return ENOMEM;
323 
324 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
325 	    "hwrm_if", CTLFLAG_RD, vi->hwrm_if_ver, 0,
326 	    "HWRM interface version");
327 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
328 	    "driver_hwrm_if", CTLFLAG_RD, vi->driver_hwrm_if_ver, 0,
329 	    "HWRM firmware version");
330 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
331 	    "hwrm_fw", CTLFLAG_RD, vi->hwrm_fw_ver, 0,
332 	    "HWRM firmware version");
333 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
334 	    "mgmt_fw", CTLFLAG_RD, vi->mgmt_fw_ver, 0,
335 	    "management firmware version");
336 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
337 	    "netctrl_fw", CTLFLAG_RD, vi->netctrl_fw_ver, 0,
338 	    "network control firmware version");
339 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
340 	    "roce_fw", CTLFLAG_RD, vi->roce_fw_ver, 0,
341 	    "RoCE firmware version");
342 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
343 	    "phy", CTLFLAG_RD, vi->phy_ver, 0,
344 	    "PHY version");
345 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
346 	    "hwrm_fw_name", CTLFLAG_RD, vi->hwrm_fw_name, 0,
347 	    "HWRM firmware name");
348 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
349 	    "mgmt_fw_name", CTLFLAG_RD, vi->mgmt_fw_name, 0,
350 	    "management firmware name");
351 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
352 	    "netctrl_fw_name", CTLFLAG_RD, vi->netctrl_fw_name, 0,
353 	    "network control firmware name");
354 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
355 	    "roce_fw_name", CTLFLAG_RD, vi->roce_fw_name, 0,
356 	    "RoCE firmware name");
357 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
358 	    "phy_vendor", CTLFLAG_RD, vi->phy_vendor, 0,
359 	    "PHY vendor name");
360 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
361 	    "phy_partnumber", CTLFLAG_RD, vi->phy_partnumber, 0,
362 	    "PHY vendor part number");
363 	SYSCTL_ADD_U16(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
364 	    "chip_num", CTLFLAG_RD, &vi->chip_num, 0, "chip number");
365 	SYSCTL_ADD_U8(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
366 	    "chip_rev", CTLFLAG_RD, &vi->chip_rev, 0, "chip revision");
367 	SYSCTL_ADD_U8(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
368 	    "chip_metal", CTLFLAG_RD, &vi->chip_metal, 0, "chip metal number");
369 	SYSCTL_ADD_U8(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
370 	    "chip_bond_id", CTLFLAG_RD, &vi->chip_bond_id, 0,
371 	    "chip bond id");
372 	SYSCTL_ADD_STRING(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
373 	    "chip_type", CTLFLAG_RD, vi->chip_type > MAX_CHIP_TYPE ?
374 	    bnxt_chip_type[MAX_CHIP_TYPE] : bnxt_chip_type[vi->chip_type], 0,
375 	    "RoCE firmware name");
376 	SYSCTL_ADD_PROC(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
377 	    "package_ver", CTLTYPE_STRING|CTLFLAG_RD, softc, 0,
378 	    bnxt_package_ver_sysctl, "A",
379 	    "currently installed package version");
380 	SYSCTL_ADD_PROC(&vi->ver_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
381 	    "hwrm_min_ver", CTLTYPE_STRING|CTLFLAG_RWTUN, softc, 0,
382 	    bnxt_hwrm_min_ver_sysctl, "A",
383 	    "minimum hwrm API vesion to support");
384 
385 	return 0;
386 }
387 
388 int
389 bnxt_create_nvram_sysctls(struct bnxt_nvram_info *ni)
390 {
391 	struct sysctl_oid *oid = ni->nvm_oid;
392 
393 	if (!oid)
394 		return ENOMEM;
395 
396 	SYSCTL_ADD_U16(&ni->nvm_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
397 	    "mfg_id", CTLFLAG_RD, &ni->mfg_id, 0, "manufacturer id");
398 	SYSCTL_ADD_U16(&ni->nvm_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
399 	    "device_id", CTLFLAG_RD, &ni->device_id, 0, "device id");
400 	SYSCTL_ADD_U32(&ni->nvm_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
401 	    "sector_size", CTLFLAG_RD, &ni->sector_size, 0, "sector size");
402 	SYSCTL_ADD_U32(&ni->nvm_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
403 	    "size", CTLFLAG_RD, &ni->size, 0, "nvram total size");
404 	SYSCTL_ADD_U32(&ni->nvm_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
405 	    "reserved_size", CTLFLAG_RD, &ni->reserved_size, 0,
406 	    "total reserved space");
407 	SYSCTL_ADD_U32(&ni->nvm_ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
408 	    "available_size", CTLFLAG_RD, &ni->available_size, 0,
409 	    "total available space");
410 
411 	return 0;
412 }
413 
414 static int
415 bnxt_rss_key_sysctl(SYSCTL_HANDLER_ARGS)
416 {
417 	struct bnxt_softc *softc = arg1;
418 	char buf[HW_HASH_KEY_SIZE*2+1] = {0};
419 	char *p;
420 	int i;
421 	int rc;
422 
423 	for (p = buf, i=0; i<HW_HASH_KEY_SIZE; i++)
424 		p += sprintf(p, "%02x", softc->vnic_info.rss_hash_key[i]);
425 
426 	rc = sysctl_handle_string(oidp, buf, sizeof(buf), req);
427 	if (rc || req->newptr == NULL)
428 		return rc;
429 
430 	if (strspn(buf, "0123456789abcdefABCDEF") != (HW_HASH_KEY_SIZE * 2))
431 		return EINVAL;
432 
433 	for (p = buf, i=0; i<HW_HASH_KEY_SIZE; i++) {
434 		if (sscanf(p, "%02hhx", &softc->vnic_info.rss_hash_key[i]) != 1)
435 			return EINVAL;
436 		p += 2;
437 	}
438 
439 	if (if_getdrvflags(iflib_get_ifp(softc->ctx)) & IFF_DRV_RUNNING)
440 		bnxt_hwrm_rss_cfg(softc, &softc->vnic_info,
441 		    softc->vnic_info.rss_hash_type);
442 
443 	return rc;
444 }
445 
446 static const char *bnxt_hash_types[] = {"ipv4", "tcp_ipv4", "udp_ipv4", "ipv6",
447     "tcp_ipv6", "udp_ipv6", NULL};
448 
449 static int bnxt_get_rss_type_str_bit(char *str)
450 {
451 	int i;
452 
453 	for (i=0; bnxt_hash_types[i]; i++)
454 		if (strcmp(bnxt_hash_types[i], str) == 0)
455 			return i;
456 
457 	return -1;
458 }
459 
460 static int
461 bnxt_rss_type_sysctl(SYSCTL_HANDLER_ARGS)
462 {
463 	struct bnxt_softc *softc = arg1;
464 	char buf[256] = {0};
465 	char *p;
466 	char *next;
467 	int rc;
468 	int type;
469 	int bit;
470 
471 	for (type = softc->vnic_info.rss_hash_type; type;
472 	    type &= ~(1<<bit)) {
473 		bit = ffs(type) - 1;
474 		if (bit >= sizeof(bnxt_hash_types) / sizeof(const char *))
475 			continue;
476 		if (type != softc->vnic_info.rss_hash_type)
477 			strcat(buf, ",");
478 		strcat(buf, bnxt_hash_types[bit]);
479 	}
480 
481 	rc = sysctl_handle_string(oidp, buf, sizeof(buf), req);
482 	if (rc || req->newptr == NULL)
483 		return rc;
484 
485 	for (type = 0, next = buf, p = strsep(&next, " ,"); p;
486 	    p = strsep(&next, " ,")) {
487 		bit = bnxt_get_rss_type_str_bit(p);
488 		if (bit == -1)
489 			return EINVAL;
490 		type |= 1<<bit;
491 	}
492 	if (type != softc->vnic_info.rss_hash_type) {
493 		softc->vnic_info.rss_hash_type = type;
494 		if (if_getdrvflags(iflib_get_ifp(softc->ctx)) & IFF_DRV_RUNNING)
495 			bnxt_hwrm_rss_cfg(softc, &softc->vnic_info,
496 			    softc->vnic_info.rss_hash_type);
497 	}
498 
499 	return rc;
500 }
501 
502 static int
503 bnxt_rx_stall_sysctl(SYSCTL_HANDLER_ARGS) {
504 	struct bnxt_softc *softc = arg1;
505 	int rc;
506 	int val;
507 
508 	if (softc == NULL)
509 		return EBUSY;
510 
511 	val = (bool)(softc->vnic_info.flags & BNXT_VNIC_FLAG_BD_STALL);
512 	rc = sysctl_handle_int(oidp, &val, 0, req);
513 	if (rc || !req->newptr)
514 		return rc;
515 
516 	if (val)
517 		softc->vnic_info.flags |= BNXT_VNIC_FLAG_BD_STALL;
518 	else
519 		softc->vnic_info.flags &= ~BNXT_VNIC_FLAG_BD_STALL;
520 
521 	if (if_getdrvflags(iflib_get_ifp(softc->ctx)) & IFF_DRV_RUNNING)
522 		rc = bnxt_hwrm_vnic_cfg(softc, &softc->vnic_info);
523 
524 	return rc;
525 }
526 
527 static int
528 bnxt_vlan_strip_sysctl(SYSCTL_HANDLER_ARGS) {
529 	struct bnxt_softc *softc = arg1;
530 	int rc;
531 	int val;
532 
533 	if (softc == NULL)
534 		return EBUSY;
535 
536 	val = (bool)(softc->vnic_info.flags & BNXT_VNIC_FLAG_VLAN_STRIP);
537 	rc = sysctl_handle_int(oidp, &val, 0, req);
538 	if (rc || !req->newptr)
539 		return rc;
540 
541 	if (val)
542 		softc->vnic_info.flags |= BNXT_VNIC_FLAG_VLAN_STRIP;
543 	else
544 		softc->vnic_info.flags &= ~BNXT_VNIC_FLAG_VLAN_STRIP;
545 
546 	if (if_getdrvflags(iflib_get_ifp(softc->ctx)) & IFF_DRV_RUNNING)
547 		rc = bnxt_hwrm_vnic_cfg(softc, &softc->vnic_info);
548 
549 	return rc;
550 }
551 
552 static int
553 bnxt_set_coal_rx_usecs(SYSCTL_HANDLER_ARGS) {
554 	struct bnxt_softc *softc = arg1;
555 	int rc;
556 	int val;
557 
558 	if (softc == NULL)
559 		return EBUSY;
560 
561 	val = softc->rx_coal_usecs;
562 	rc = sysctl_handle_int(oidp, &val, 0, req);
563 	if (rc || !req->newptr)
564 		return rc;
565 
566 	softc->rx_coal_usecs = val;
567 	rc = bnxt_hwrm_set_coal(softc);
568 
569 	return rc;
570 }
571 
572 static int
573 bnxt_set_coal_rx_frames(SYSCTL_HANDLER_ARGS) {
574 	struct bnxt_softc *softc = arg1;
575 	int rc;
576 	int val;
577 
578 	if (softc == NULL)
579 		return EBUSY;
580 
581 	val = softc->rx_coal_frames;
582 	rc = sysctl_handle_int(oidp, &val, 0, req);
583 	if (rc || !req->newptr)
584 		return rc;
585 
586 	softc->rx_coal_frames = val;
587 	rc = bnxt_hwrm_set_coal(softc);
588 
589 	return rc;
590 }
591 
592 static int
593 bnxt_set_coal_rx_usecs_irq(SYSCTL_HANDLER_ARGS) {
594 	struct bnxt_softc *softc = arg1;
595 	int rc;
596 	int val;
597 
598 	if (softc == NULL)
599 		return EBUSY;
600 
601 	val = softc->rx_coal_usecs_irq;
602 	rc = sysctl_handle_int(oidp, &val, 0, req);
603 	if (rc || !req->newptr)
604 		return rc;
605 
606 	softc->rx_coal_usecs_irq = val;
607 	rc = bnxt_hwrm_set_coal(softc);
608 
609 	return rc;
610 }
611 
612 static int
613 bnxt_set_coal_rx_frames_irq(SYSCTL_HANDLER_ARGS) {
614 	struct bnxt_softc *softc = arg1;
615 	int rc;
616 	int val;
617 
618 	if (softc == NULL)
619 		return EBUSY;
620 
621 	val = softc->rx_coal_frames_irq;
622 	rc = sysctl_handle_int(oidp, &val, 0, req);
623 	if (rc || !req->newptr)
624 		return rc;
625 
626 	softc->rx_coal_frames_irq = val;
627 	rc = bnxt_hwrm_set_coal(softc);
628 
629 	return rc;
630 }
631 
632 static int
633 bnxt_set_coal_tx_usecs(SYSCTL_HANDLER_ARGS) {
634 	struct bnxt_softc *softc = arg1;
635 	int rc;
636 	int val;
637 
638 	if (softc == NULL)
639 		return EBUSY;
640 
641 	val = softc->tx_coal_usecs;
642 	rc = sysctl_handle_int(oidp, &val, 0, req);
643 	if (rc || !req->newptr)
644 		return rc;
645 
646 	softc->tx_coal_usecs = val;
647 	rc = bnxt_hwrm_set_coal(softc);
648 
649 	return rc;
650 }
651 
652 static int
653 bnxt_set_coal_tx_frames(SYSCTL_HANDLER_ARGS) {
654 	struct bnxt_softc *softc = arg1;
655 	int rc;
656 	int val;
657 
658 	if (softc == NULL)
659 		return EBUSY;
660 
661 	val = softc->tx_coal_frames;
662 	rc = sysctl_handle_int(oidp, &val, 0, req);
663 	if (rc || !req->newptr)
664 		return rc;
665 
666 	softc->tx_coal_frames = val;
667 	rc = bnxt_hwrm_set_coal(softc);
668 
669 	return rc;
670 }
671 
672 static int
673 bnxt_set_coal_tx_usecs_irq(SYSCTL_HANDLER_ARGS) {
674 	struct bnxt_softc *softc = arg1;
675 	int rc;
676 	int val;
677 
678 	if (softc == NULL)
679 		return EBUSY;
680 
681 	val = softc->tx_coal_usecs_irq;
682 	rc = sysctl_handle_int(oidp, &val, 0, req);
683 	if (rc || !req->newptr)
684 		return rc;
685 
686 	softc->tx_coal_usecs_irq = val;
687 	rc = bnxt_hwrm_set_coal(softc);
688 
689 	return rc;
690 }
691 
692 static int
693 bnxt_set_coal_tx_frames_irq(SYSCTL_HANDLER_ARGS) {
694 	struct bnxt_softc *softc = arg1;
695 	int rc;
696 	int val;
697 
698 	if (softc == NULL)
699 		return EBUSY;
700 
701 	val = softc->tx_coal_frames_irq;
702 	rc = sysctl_handle_int(oidp, &val, 0, req);
703 	if (rc || !req->newptr)
704 		return rc;
705 
706 	softc->tx_coal_frames_irq = val;
707 	rc = bnxt_hwrm_set_coal(softc);
708 
709 	return rc;
710 }
711 
712 int
713 bnxt_create_config_sysctls_pre(struct bnxt_softc *softc)
714 {
715 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(softc->dev);
716 	struct sysctl_oid_list *children;
717 
718 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev));;
719 
720 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rss_key",
721 	    CTLTYPE_STRING|CTLFLAG_RWTUN, softc, 0, bnxt_rss_key_sysctl, "A",
722 	    "RSS key");
723 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rss_type",
724 	    CTLTYPE_STRING|CTLFLAG_RWTUN, softc, 0, bnxt_rss_type_sysctl, "A",
725 	    "RSS type bits");
726 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_stall",
727 	    CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_rx_stall_sysctl, "I",
728 	    "buffer rx packets in hardware until the host posts new buffers");
729 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "vlan_strip",
730 	    CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_vlan_strip_sysctl, "I",
731 	    "strip VLAN tag in the RX path");
732 	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "if_name", CTLFLAG_RD,
733 		iflib_get_ifp(softc->ctx)->if_xname, 0, "interface name");
734 
735         SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_rx_usecs",
736                         CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_rx_usecs,
737 			"I", "interrupt coalescing Rx Usecs");
738         SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_rx_frames",
739                         CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_rx_frames,
740 			"I", "interrupt coalescing Rx Frames");
741         SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_rx_usecs_irq",
742                         CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_rx_usecs_irq,
743 			"I", "interrupt coalescing Rx Usecs IRQ");
744         SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_rx_frames_irq",
745                         CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_rx_frames_irq,
746 			"I", "interrupt coalescing Rx Frames IRQ");
747         SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_usecs",
748                         CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_tx_usecs,
749 			"I", "interrupt coalescing Tx Usces");
750         SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_frames",
751                         CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_tx_frames,
752 			"I", "interrupt coalescing Tx Frames");
753         SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_usecs_irq",
754                         CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_tx_usecs_irq,
755 			"I", "interrupt coalescing Tx Usecs IRQ");
756         SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "intr_coal_tx_frames_irq",
757                         CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_set_coal_tx_frames_irq,
758 			"I", "interrupt coalescing Tx Frames IRQ");
759 
760 	return 0;
761 }
762 
763 static int
764 bnxt_vlan_only_sysctl(SYSCTL_HANDLER_ARGS) {
765 	struct bnxt_softc *softc = arg1;
766 	int rc;
767 	int val;
768 
769 	if (softc == NULL)
770 		return EBUSY;
771 
772 	val = softc->vnic_info.vlan_only;
773 	rc = sysctl_handle_int(oidp, &val, 0, req);
774 	if (rc || !req->newptr)
775 		return rc;
776 
777 	if (val)
778 		val = 1;
779 
780 	if (val != softc->vnic_info.vlan_only) {
781 		softc->vnic_info.vlan_only = val;
782 		if (if_getdrvflags(iflib_get_ifp(softc->ctx)) & IFF_DRV_RUNNING)
783 			rc = bnxt_hwrm_cfa_l2_set_rx_mask(softc,
784 			    &softc->vnic_info);
785 	}
786 
787 	return rc;
788 }
789 
790 int
791 bnxt_create_config_sysctls_post(struct bnxt_softc *softc)
792 {
793 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(softc->dev);
794 	struct sysctl_oid_list *children;
795 
796 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev));;
797 
798 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "vlan_only",
799 	    CTLTYPE_INT|CTLFLAG_RWTUN, softc, 0, bnxt_vlan_only_sysctl, "I",
800 	    "require vlan tag on received packets when vlan is enabled");
801 
802 	return 0;
803 }
804