]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bnxt/bnxt_sysctl.c
MFV r322223: 8378 crash due to bp in-memory modification of nopwrite block
[FreeBSD/FreeBSD.git] / sys / dev / bnxt / bnxt_sysctl.c
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 }