]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/axgbe/xgbe-sysctl.c
Merge commit '7a590c074ceede12b2b6e794f8703d6fa5749918'
[FreeBSD/FreeBSD.git] / sys / dev / axgbe / xgbe-sysctl.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2020 Advanced Micro Devices, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * Contact Information :
28  * Rajesh Kumar <rajesh1.kumar@amd.com>
29  * Arpan Palit <Arpan.Palit@amd.com>
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/sysctl.h>
37 #include <sys/sbuf.h>
38
39 #include "xgbe.h"
40 #include "xgbe-common.h"
41
42 #define SYSCTL_BUF_LEN 64
43
44 typedef enum{
45         /* Coalesce flag */
46         rx_coalesce_usecs = 1,
47         rx_max_coalesced_frames,
48         rx_coalesce_usecs_irq,
49         rx_max_coalesced_frames_irq,
50         tx_coalesce_usecs,
51         tx_max_coalesced_frames,
52         tx_coalesce_usecs_irq,
53         tx_max_coalesced_frames_irq,
54         stats_block_coalesce_usecs,
55         use_adaptive_rx_coalesce,
56         use_adaptive_tx_coalesce,
57         pkt_rate_low,
58         rx_coalesce_usecs_low,
59         rx_max_coalesced_frames_low,
60         tx_coalesce_usecs_low,
61         tx_max_coalesced_frames_low,
62         pkt_rate_high,
63         rx_coalesce_usecs_high,
64         rx_max_coalesced_frames_high,
65         tx_coalesce_usecs_high,
66         tx_max_coalesced_frames_high,
67         rate_sample_interval,
68
69         /* Pasue flag */
70         autoneg,
71         tx_pause,
72         rx_pause,
73
74         /* link settings */
75         speed,
76         duplex,
77
78         /* Ring settings */
79         rx_pending,
80         rx_mini_pending,
81         rx_jumbo_pending,
82         tx_pending,
83
84         /* Channels settings */
85         rx_count,
86         tx_count,
87         other_count,
88         combined_count,
89 } sysctl_variable_t;
90
91 typedef enum {
92         SYSL_NONE,
93         SYSL_BOOL,
94         SYSL_S32,
95         SYSL_U8,
96         SYSL_U16,
97         SYSL_U32,
98         SYSL_U64,
99         SYSL_BE16,
100         SYSL_IP4,
101         SYSL_STR,
102         SYSL_FLAG,
103         SYSL_MAC,
104 } sysctl_type_t;
105
106 struct sysctl_info {
107         uint8_t name[32];
108         sysctl_type_t type;
109         sysctl_variable_t flag;
110         uint8_t support[16];
111 };
112
113 struct sysctl_op {
114         /* Coalesce options */
115         unsigned int rx_coalesce_usecs;
116         unsigned int rx_max_coalesced_frames;
117         unsigned int rx_coalesce_usecs_irq;
118         unsigned int rx_max_coalesced_frames_irq;
119         unsigned int tx_coalesce_usecs;
120         unsigned int tx_max_coalesced_frames;
121         unsigned int tx_coalesce_usecs_irq;
122         unsigned int tx_max_coalesced_frames_irq;
123         unsigned int stats_block_coalesce_usecs;
124         unsigned int use_adaptive_rx_coalesce;
125         unsigned int use_adaptive_tx_coalesce;
126         unsigned int pkt_rate_low;
127         unsigned int rx_coalesce_usecs_low;
128         unsigned int rx_max_coalesced_frames_low;
129         unsigned int tx_coalesce_usecs_low;
130         unsigned int tx_max_coalesced_frames_low;
131         unsigned int pkt_rate_high;
132         unsigned int rx_coalesce_usecs_high;
133         unsigned int rx_max_coalesced_frames_high;
134         unsigned int tx_coalesce_usecs_high;
135         unsigned int tx_max_coalesced_frames_high;
136         unsigned int rate_sample_interval;
137
138         /* Pasue options */
139         unsigned int autoneg;
140         unsigned int tx_pause;
141         unsigned int rx_pause;
142
143         /* Link settings options */
144         unsigned int speed;
145         unsigned int duplex;
146
147         /* Ring param options */
148         unsigned int rx_max_pending;
149         unsigned int rx_mini_max_pending;
150         unsigned int rx_jumbo_max_pending;
151         unsigned int tx_max_pending;
152         unsigned int rx_pending;
153         unsigned int rx_mini_pending;
154         unsigned int rx_jumbo_pending;
155         unsigned int tx_pending;
156
157         /* Channels options */
158         unsigned int max_rx;
159         unsigned int max_tx;
160         unsigned int max_other;
161         unsigned int max_combined;
162         unsigned int rx_count;
163         unsigned int tx_count;
164         unsigned int other_count;
165         unsigned int combined_count;
166 } sys_op;
167
168 #define GSTRING_LEN 32
169
170 struct xgbe_stats {
171         char stat_string[GSTRING_LEN];
172         int stat_size;
173         int stat_offset;
174 };
175
176 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
177
178 #define XGMAC_MMC_STAT(_string, _var)                      \
179         { _string,                                            \
180           FIELD_SIZEOF(struct xgbe_mmc_stats, _var),        \
181           offsetof(struct xgbe_prv_data, mmc_stats._var),       \
182         }
183
184 #define XGMAC_EXT_STAT(_string, _var)                      \
185         { _string,                                            \
186           FIELD_SIZEOF(struct xgbe_ext_stats, _var),        \
187           offsetof(struct xgbe_prv_data, ext_stats._var),       \
188         }
189 static const struct xgbe_stats xgbe_gstring_stats[] = {
190         XGMAC_MMC_STAT("tx_bytes", txoctetcount_gb),
191         XGMAC_MMC_STAT("tx_packets", txframecount_gb),
192         XGMAC_MMC_STAT("tx_unicast_packets", txunicastframes_gb),
193         XGMAC_MMC_STAT("tx_broadcast_packets", txbroadcastframes_gb),
194         XGMAC_MMC_STAT("tx_multicast_packets", txmulticastframes_gb),
195         XGMAC_MMC_STAT("tx_vlan_packets", txvlanframes_g),
196         XGMAC_EXT_STAT("tx_vxlan_packets", tx_vxlan_packets),
197         XGMAC_EXT_STAT("tx_tso_packets", tx_tso_packets),
198         XGMAC_MMC_STAT("tx_64_byte_packets", tx64octets_gb),
199         XGMAC_MMC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb),
200         XGMAC_MMC_STAT("tx_128_to_255_byte_packets", tx128to255octets_gb),
201         XGMAC_MMC_STAT("tx_256_to_511_byte_packets", tx256to511octets_gb),
202         XGMAC_MMC_STAT("tx_512_to_1023_byte_packets", tx512to1023octets_gb),
203         XGMAC_MMC_STAT("tx_1024_to_max_byte_packets", tx1024tomaxoctets_gb),
204         XGMAC_MMC_STAT("tx_underflow_errors", txunderflowerror),
205         XGMAC_MMC_STAT("tx_pause_frames", txpauseframes),
206
207         XGMAC_MMC_STAT("rx_bytes", rxoctetcount_gb),
208         XGMAC_MMC_STAT("rx_packets", rxframecount_gb),
209         XGMAC_MMC_STAT("rx_unicast_packets", rxunicastframes_g),
210         XGMAC_MMC_STAT("rx_broadcast_packets", rxbroadcastframes_g),
211         XGMAC_MMC_STAT("rx_multicast_packets", rxmulticastframes_g),
212         XGMAC_MMC_STAT("rx_vlan_packets", rxvlanframes_gb),
213         XGMAC_EXT_STAT("rx_vxlan_packets", rx_vxlan_packets),
214         XGMAC_MMC_STAT("rx_64_byte_packets", rx64octets_gb),
215         XGMAC_MMC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb),
216         XGMAC_MMC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb),
217         XGMAC_MMC_STAT("rx_256_to_511_byte_packets", rx256to511octets_gb),
218         XGMAC_MMC_STAT("rx_512_to_1023_byte_packets", rx512to1023octets_gb),
219         XGMAC_MMC_STAT("rx_1024_to_max_byte_packets", rx1024tomaxoctets_gb),
220         XGMAC_MMC_STAT("rx_undersize_packets", rxundersize_g),
221         XGMAC_MMC_STAT("rx_oversize_packets", rxoversize_g),
222         XGMAC_MMC_STAT("rx_crc_errors", rxcrcerror),
223         XGMAC_MMC_STAT("rx_crc_errors_small_packets", rxrunterror),
224         XGMAC_MMC_STAT("rx_crc_errors_giant_packets", rxjabbererror),
225         XGMAC_MMC_STAT("rx_length_errors", rxlengtherror),
226         XGMAC_MMC_STAT("rx_out_of_range_errors", rxoutofrangetype),
227         XGMAC_MMC_STAT("rx_fifo_overflow_errors", rxfifooverflow),
228         XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
229         XGMAC_EXT_STAT("rx_csum_errors", rx_csum_errors),
230         XGMAC_EXT_STAT("rx_vxlan_csum_errors", rx_vxlan_csum_errors),
231         XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
232         XGMAC_EXT_STAT("rx_split_header_packets", rx_split_header_packets),
233         XGMAC_EXT_STAT("rx_buffer_unavailable", rx_buffer_unavailable),
234 };
235
236 #define XGBE_STATS_COUNT        ARRAY_SIZE(xgbe_gstring_stats)
237
238 char** alloc_sysctl_buffer(void);
239 void get_val(char *buf, char **op, char **val, int *n_op);
240 void fill_data(struct sysctl_op *sys_op, int flag, unsigned int value);
241
242 static int
243 exit_bad_op(void)
244 {
245
246         printf("SYSCTL: bad command line option (s)\n");
247         return(-EINVAL);
248 }
249
250 static inline unsigned
251 fls_long(unsigned long l)
252 {
253
254         if (sizeof(l) == 4)
255                 return (fls(l));
256         return (fls64(l));
257 }
258
259 static inline __attribute__((const))
260 unsigned long __rounddown_pow_of_two(unsigned long n)
261 {
262
263         return (1UL << (fls_long(n) - 1));
264 }
265
266 static inline int
267 get_ubuf(struct sysctl_req *req, char *ubuf)
268 {
269         int rc;
270
271         printf("%s: len:0x%li idx:0x%li\n", __func__, req->newlen,
272             req->newidx);
273         if (req->newlen >= SYSCTL_BUF_LEN)
274                 return (-EINVAL);
275
276         rc = SYSCTL_IN(req, ubuf, req->newlen);
277         if (rc)
278                 return (rc);
279         ubuf[req->newlen] = '\0';
280
281         return (0);
282 }
283
284 char**
285 alloc_sysctl_buffer(void)
286 {
287         char **buffer;
288         int i;
289
290         buffer = malloc(sizeof(char *)*32, M_AXGBE, M_WAITOK | M_ZERO);
291         for(i = 0; i < 32; i++)
292                 buffer[i] = malloc(sizeof(char)*32, M_AXGBE, M_WAITOK | M_ZERO);
293
294         return (buffer);
295 }
296
297 void
298 get_val(char *buf, char **op, char **val, int *n_op)
299 {
300         int blen = strlen(buf);
301         int count = 0;
302         int i, j;
303
304         *n_op = 0;
305         for (i = 0; i < blen; i++) {
306                 count++;
307                 /* Get sysctl command option */
308                 for (j = 0; buf[i] != ' '; j++) {
309                         if (i >= blen)
310                                 break;
311                         op[*n_op][j] = buf[i++];
312                 }
313                 op[*n_op][j+1] = '\0';
314                 if (i >= strlen(buf))
315                         goto out;
316
317                 /* Get sysctl value*/
318                 i++;
319                 for (j = 0; buf[i] != ' '; j++) {
320                         if (i >= blen)
321                                 break;
322                         val[*n_op][j] = buf[i++]; 
323                 }
324                 val[*n_op][j+1] = '\0';
325                 if (i >= strlen(buf))
326                         goto out;
327
328                 *n_op = count;
329         }
330
331 out:
332         *n_op = count;
333 }
334
335 void
336 fill_data(struct sysctl_op *sys_op, int flag, unsigned int value)
337 {
338
339         switch(flag) {
340         case 1:
341         sys_op->rx_coalesce_usecs = value;
342         break;
343         case 2:
344         sys_op->rx_max_coalesced_frames = value;
345         break;
346         case 3:
347         sys_op->rx_coalesce_usecs_irq = value;
348         break;
349         case 4:
350         sys_op->rx_max_coalesced_frames_irq = value;
351         break;
352         case 5:
353         sys_op->tx_coalesce_usecs = value;
354         break;
355         case 6:
356         sys_op->tx_max_coalesced_frames = value;
357         break;
358         case 7:
359         sys_op->tx_coalesce_usecs_irq = value;
360         break;
361         case 8:
362         sys_op->tx_max_coalesced_frames_irq = value;
363         break;
364         case 9:
365         sys_op->stats_block_coalesce_usecs = value;
366         break;
367         case 10:
368         sys_op->use_adaptive_rx_coalesce = value;
369         break;
370         case 11:
371         sys_op->use_adaptive_tx_coalesce = value;
372         break;
373         case 12:
374         sys_op->pkt_rate_low = value;
375         break;
376         case 13:
377         sys_op->rx_coalesce_usecs_low = value;
378         break;
379         case 14:
380         sys_op->rx_max_coalesced_frames_low = value;
381         break;
382         case 15:
383         sys_op->tx_coalesce_usecs_low = value;
384         break;
385         case 16:
386         sys_op->tx_max_coalesced_frames_low = value;
387         break;
388         case 17:
389         sys_op->pkt_rate_high = value;
390         break;
391         case 18:
392         sys_op->rx_coalesce_usecs_high = value;
393         break;
394         case 19:
395         sys_op->rx_max_coalesced_frames_high = value;
396         break;
397         case 20:
398         sys_op->tx_coalesce_usecs_high = value;
399         break;
400         case 21:
401         sys_op->tx_max_coalesced_frames_high = value;
402         break;
403         case 22:
404         sys_op->rate_sample_interval = value;
405         break;
406         case 23:
407         sys_op->autoneg = value;
408         break;
409         case 24:
410         sys_op->rx_pause = value;
411         break;
412         case 25:
413         sys_op->tx_pause = value;
414         break;
415         case 26:
416         sys_op->speed = value;
417         break;
418         case 27:
419         sys_op->duplex = value;
420         break;
421         case 28:
422         sys_op->rx_pending = value;
423         break;
424         case 29:
425         sys_op->rx_mini_pending = value;
426         break;
427         case 30:
428         sys_op->rx_jumbo_pending = value;
429         break;
430         case 31:
431         sys_op->tx_pending = value;
432         break;
433         default:
434                 printf("Option error\n");
435         }
436 }
437
438 static int
439 parse_generic_sysctl(struct xgbe_prv_data *pdata, char *buf,
440     struct sysctl_info *info, unsigned int n_info)
441 {
442         struct sysctl_op *sys_op = pdata->sys_op;
443         unsigned int value;
444         char **op, **val;
445         int n_op = 0;
446         int rc = 0;
447         int i, idx;
448
449         op = alloc_sysctl_buffer();
450         val = alloc_sysctl_buffer();
451         get_val(buf, op, val, &n_op);
452
453         for (i = 0; i < n_op; i++) {
454                 for (idx = 0; idx < n_info; idx++) {
455                         if (strcmp(info[idx].name, op[i]) == 0) {
456                                 if (strcmp(info[idx].support,
457                                     "not-supported") == 0){
458                                         axgbe_printf(1, "ignoring not-supported "
459                                             "option \"%s\"\n", info[idx].name);
460                                         break;
461                                 }
462                                 switch(info[idx].type) {
463                                 case SYSL_BOOL: {
464                                         if (!strcmp(val[i], "on"))
465                                                 fill_data(sys_op,
466                                                     info[idx].flag, 1);
467                                         else if (!strcmp(val[i], "off"))
468                                                 fill_data(sys_op,
469                                                     info[idx].flag, 0);
470                                         else
471                                                 rc = exit_bad_op();
472                                         break;
473                                 }
474                                 case SYSL_S32:
475                                         sscanf(val[i], "%u", &value);
476                                         fill_data(sys_op, info[idx].flag, value);
477                                         break;
478                                 case SYSL_U8:
479                                         if (!strcmp(val[i], "half"))
480                                                 fill_data(sys_op,
481                                                     info[idx].flag, DUPLEX_HALF);
482                                         else if (!strcmp(val[i], "full"))
483                                                 fill_data(sys_op,
484                                                     info[idx].flag, DUPLEX_FULL);
485                                         else
486                                                 exit_bad_op();
487                                 default:
488                                         rc = exit_bad_op();
489                                 }
490                         }
491                 }
492         }
493
494         for(i = 0; i < 32; i++)
495                 free(op[i], M_AXGBE);
496         free(op, M_AXGBE);
497
498         for(i = 0; i < 32; i++)
499                 free(val[i], M_AXGBE);
500         free(val, M_AXGBE);
501         return (rc);
502 }
503
504
505 static int
506 sysctl_xgmac_reg_addr_handler(SYSCTL_HANDLER_ARGS)
507 {
508         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
509         ssize_t buf_size = 64;
510         char buf[buf_size];
511         struct sbuf *sb;
512         unsigned int reg;
513         int rc = 0;
514
515         if (req->newptr == NULL) {
516                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
517                 if (sb == NULL) {
518                         rc = sb->s_error;
519                         return (rc);
520                 }
521
522                 axgbe_printf(2, "READ: %s: sysctl_xgmac_reg: 0x%x\n",  __func__,
523                     pdata->sysctl_xgmac_reg);
524                 sbuf_printf(sb, "\nXGMAC reg_addr:      0x%x\n",
525                     pdata->sysctl_xgmac_reg);
526                 rc = sbuf_finish(sb);
527                 sbuf_delete(sb);
528                 return (rc);
529         }
530
531         rc = get_ubuf(req, buf);
532         if (rc == 0) {
533                 sscanf(buf, "%x", &reg);
534                 axgbe_printf(2, "WRITE: %s: reg: 0x%x\n",  __func__, reg);
535                 pdata->sysctl_xgmac_reg = reg;
536         }
537
538         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
539         return (rc);
540 }
541
542 static int
543 sysctl_get_drv_info_handler(SYSCTL_HANDLER_ARGS)
544 {
545         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
546         struct xgbe_hw_features *hw_feat = &pdata->hw_feat;
547         ssize_t buf_size = 64;
548         struct sbuf *sb;
549         int rc = 0;
550
551         if (req->newptr == NULL) {
552                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
553                 if (sb == NULL) {
554                         rc = sb->s_error;
555                         return (rc);
556                 }
557
558                 sbuf_printf(sb, "\ndriver:      %s", XGBE_DRV_NAME);
559                 sbuf_printf(sb, "\nversion: %s", XGBE_DRV_VERSION);
560                 sbuf_printf(sb, "\nfirmware-version: %d.%d.%d",
561                     XGMAC_GET_BITS(hw_feat->version, MAC_VR, USERVER),
562                     XGMAC_GET_BITS(hw_feat->version, MAC_VR, DEVID),
563                     XGMAC_GET_BITS(hw_feat->version, MAC_VR, SNPSVER));
564                 sbuf_printf(sb, "\nbus-info: %04d:%02d:%02d",
565                     pdata->pcie_bus, pdata->pcie_device, pdata->pcie_func);
566
567                 rc = sbuf_finish(sb);
568                 sbuf_delete(sb);
569                 return (rc);
570         }
571
572         return (-EINVAL);
573 }
574
575 static int
576 sysctl_get_link_info_handler(SYSCTL_HANDLER_ARGS)
577 {
578         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
579         ssize_t buf_size = 64;
580         struct sbuf *sb;
581         int rc = 0;
582
583         if (req->newptr == NULL) {
584                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
585                 if (sb == NULL) {
586                         rc = sb->s_error;
587                         return (rc);
588                 }
589                 
590                 sbuf_printf(sb, "\nLink is %s", pdata->phy.link ? "Up" : "Down");
591                 rc = sbuf_finish(sb);
592                 sbuf_delete(sb);
593                 return (0);
594         }
595
596         return (-EINVAL);
597 }
598
599 #define COALESCE_SYSCTL_INFO(__coalop)                                                  \
600 {                                                                                       \
601         { "adaptive-rx", SYSL_BOOL, use_adaptive_rx_coalesce, "not-supported" },        \
602         { "adaptive-tx", SYSL_BOOL, use_adaptive_tx_coalesce, "not-supported" },        \
603         { "sample-interval", SYSL_S32, rate_sample_interval, "not-supported" },         \
604         { "stats-block-usecs", SYSL_S32, stats_block_coalesce_usecs, "not-supported" }, \
605         { "pkt-rate-low", SYSL_S32, pkt_rate_low, "not-supported" },                    \
606         { "pkt-rate-high", SYSL_S32, pkt_rate_high, "not-supported" },                  \
607         { "rx-usecs", SYSL_S32, rx_coalesce_usecs, "supported" },                       \
608         { "rx-frames", SYSL_S32, rx_max_coalesced_frames, "supported" },                \
609         { "rx-usecs-irq", SYSL_S32, rx_coalesce_usecs_irq, "not-supported" },           \
610         { "rx-frames-irq", SYSL_S32, rx_max_coalesced_frames_irq, "not-supported" },    \
611         { "tx-usecs", SYSL_S32, tx_coalesce_usecs, "not-supported" },                   \
612         { "tx-frames", SYSL_S32, tx_max_coalesced_frames, "supported" },                \
613         { "tx-usecs-irq", SYSL_S32, tx_coalesce_usecs_irq, "not-supported" },           \
614         { "tx-frames-irq", SYSL_S32, tx_max_coalesced_frames_irq, "not-supported" },    \
615         { "rx-usecs-low", SYSL_S32, rx_coalesce_usecs_low, "not-supported" },           \
616         { "rx-frames-low", SYSL_S32, rx_max_coalesced_frames_low, "not-supported"},     \
617         { "tx-usecs-low", SYSL_S32, tx_coalesce_usecs_low, "not-supported" },           \
618         { "tx-frames-low", SYSL_S32, tx_max_coalesced_frames_low, "not-supported" },    \
619         { "rx-usecs-high", SYSL_S32, rx_coalesce_usecs_high, "not-supported" },         \
620         { "rx-frames-high", SYSL_S32, rx_max_coalesced_frames_high, "not-supported" },  \
621         { "tx-usecs-high", SYSL_S32, tx_coalesce_usecs_high, "not-supported" },         \
622         { "tx-frames-high", SYSL_S32, tx_max_coalesced_frames_high, "not-supported" },  \
623 }
624
625 static int
626 sysctl_coalesce_handler(SYSCTL_HANDLER_ARGS)
627 {
628         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
629         struct xgbe_hw_if *hw_if = &pdata->hw_if;
630         struct sysctl_op *sys_op = pdata->sys_op;
631         struct sysctl_info sysctl_coalesce[] = COALESCE_SYSCTL_INFO(coalop);
632         unsigned int rx_frames, rx_riwt, rx_usecs;
633         unsigned int tx_frames;
634         ssize_t buf_size = 64;
635         char buf[buf_size];
636         struct sbuf *sb;
637         int rc = 0;
638
639         if (req->newptr == NULL) {
640                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
641                 if (sb == NULL) {
642                         rc = sb->s_error;
643                         return (rc);
644                 }
645                 sys_op->rx_coalesce_usecs = pdata->rx_usecs;
646                 sys_op->rx_max_coalesced_frames = pdata->rx_frames;
647                 sys_op->tx_max_coalesced_frames = pdata->tx_frames;
648
649                 sbuf_printf(sb, "\nAdaptive RX: %s  TX: %s\n",
650                     sys_op->use_adaptive_rx_coalesce ? "on" : "off",
651                     sys_op->use_adaptive_tx_coalesce ? "on" : "off");
652
653                 sbuf_printf(sb, "stats-block-usecs: %u\n"
654                     "sample-interval: %u\n"
655                     "pkt-rate-low: %u\n"
656                     "pkt-rate-high: %u\n"
657                     "\n"
658                     "rx-usecs: %u\n"
659                     "rx-frames: %u\n"
660                     "rx-usecs-irq: %u\n"
661                     "rx-frames-irq: %u\n"
662                     "\n"
663                     "tx-usecs: %u\n"
664                     "tx-frames: %u\n"
665                     "tx-usecs-irq: %u\n"
666                     "tx-frames-irq: %u\n"
667                     "\n"
668                     "rx-usecs-low: %u\n"
669                     "rx-frames-low: %u\n"
670                     "tx-usecs-low: %u\n"
671                     "tx-frames-low: %u\n"
672                     "\n"
673                     "rx-usecs-high: %u\n"
674                     "rx-frames-high: %u\n"
675                     "tx-usecs-high: %u\n"
676                     "tx-frames-high: %u\n",
677                     sys_op->stats_block_coalesce_usecs,
678                     sys_op->rate_sample_interval,
679                     sys_op->pkt_rate_low,
680                     sys_op->pkt_rate_high,
681
682                     sys_op->rx_coalesce_usecs,
683                     sys_op->rx_max_coalesced_frames,
684                     sys_op->rx_coalesce_usecs_irq,
685                     sys_op->rx_max_coalesced_frames_irq,
686
687                     sys_op->tx_coalesce_usecs,
688                     sys_op->tx_max_coalesced_frames,
689                     sys_op->tx_coalesce_usecs_irq,
690                     sys_op->tx_max_coalesced_frames_irq,
691
692                     sys_op->rx_coalesce_usecs_low,
693                     sys_op->rx_max_coalesced_frames_low,
694                     sys_op->tx_coalesce_usecs_low,
695                     sys_op->tx_max_coalesced_frames_low,
696
697                     sys_op->rx_coalesce_usecs_high,
698                     sys_op->rx_max_coalesced_frames_high,
699                     sys_op->tx_coalesce_usecs_high,
700                     sys_op->tx_max_coalesced_frames_high);
701
702                 rc = sbuf_finish(sb);
703                 sbuf_delete(sb);
704                 return (0);
705         }
706
707         rc = get_ubuf(req, buf);
708         if (rc == 0) {
709                 parse_generic_sysctl(pdata, buf, sysctl_coalesce,
710                     ARRAY_SIZE(sysctl_coalesce)); 
711
712                 rx_riwt = hw_if->usec_to_riwt(pdata, sys_op->rx_coalesce_usecs);
713                 rx_usecs = sys_op->rx_coalesce_usecs;
714                 rx_frames = sys_op->rx_max_coalesced_frames;
715
716                 /* Use smallest possible value if conversion resulted in zero */
717                 if (rx_usecs && !rx_riwt)
718                         rx_riwt = 1;
719
720                 /* Check the bounds of values for Rx */
721                 if (rx_riwt > XGMAC_MAX_DMA_RIWT) {
722                         axgbe_printf(2, "rx-usec is limited to %d usecs\n",
723                             hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT));
724                         return (-EINVAL);
725                 }
726                 if (rx_frames > pdata->rx_desc_count) {
727                         axgbe_printf(2, "rx-frames is limited to %d frames\n",
728                             pdata->rx_desc_count);
729                         return (-EINVAL);
730                 }
731
732                 tx_frames = sys_op->tx_max_coalesced_frames;
733
734                 /* Check the bounds of values for Tx */
735                 if (tx_frames > pdata->tx_desc_count) {
736                         axgbe_printf(2, "tx-frames is limited to %d frames\n",
737                             pdata->tx_desc_count);
738                         return (-EINVAL);
739                 }
740
741                 pdata->rx_riwt = rx_riwt;
742                 pdata->rx_usecs = rx_usecs;
743                 pdata->rx_frames = rx_frames;
744                 hw_if->config_rx_coalesce(pdata);
745
746                 pdata->tx_frames = tx_frames;
747                 hw_if->config_tx_coalesce(pdata);
748         }
749
750         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
751
752         return (rc);
753 }
754
755 static int
756 sysctl_pauseparam_handler(SYSCTL_HANDLER_ARGS)
757 {
758         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
759         struct sysctl_op *sys_op = pdata->sys_op;
760         struct sysctl_info sysctl_pauseparam[] = {
761                 { "autoneg", SYSL_BOOL, autoneg, "supported" },
762                 { "rx", SYSL_BOOL, rx_pause, "supported" },
763                 { "tx", SYSL_BOOL, tx_pause, "supported" },
764         };
765         ssize_t buf_size = 512;
766         char buf[buf_size];
767         struct sbuf *sb;
768         int rc = 0;
769
770         if (req->newptr == NULL) {
771                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
772                 if (sb == NULL) {
773                         rc = sb->s_error;
774                         return (rc);
775                 }
776                 sys_op->autoneg = pdata->phy.pause_autoneg;
777                 sys_op->tx_pause = pdata->phy.tx_pause;
778                 sys_op->rx_pause = pdata->phy.rx_pause;
779
780                 sbuf_printf(sb,
781                     "\nAutonegotiate:   %s\n"
782                     "RX:                %s\n"
783                     "TX:                %s\n",
784                     sys_op->autoneg ? "on" : "off",
785                     sys_op->rx_pause ? "on" : "off",
786                     sys_op->tx_pause ? "on" : "off");
787
788                 if (pdata->phy.lp_advertising) {
789                         int an_rx = 0, an_tx = 0;
790
791                         if (pdata->phy.advertising & pdata->phy.lp_advertising &
792                             ADVERTISED_Pause) {
793                                 an_tx = 1;
794                                 an_rx = 1;
795                         } else if (pdata->phy.advertising &
796                             pdata->phy.lp_advertising & ADVERTISED_Asym_Pause) {
797                                 if (pdata->phy.advertising & ADVERTISED_Pause)
798                                         an_rx = 1;
799                                 else if (pdata->phy.lp_advertising &
800                                     ADVERTISED_Pause)
801                                 an_tx = 1;
802                         }
803                         sbuf_printf(sb,
804                             "\n->\nRX negotiated:       %s\n"
805                             "TX negotiated:     %s\n",
806                             an_rx ? "on" : "off",
807                             an_tx ? "on" : "off");
808                 }
809                 rc = sbuf_finish(sb);
810                 sbuf_delete(sb);
811                 return (0);
812         }
813
814         rc = get_ubuf(req, buf);
815         if (rc == 0) {
816                 parse_generic_sysctl(pdata, buf, sysctl_pauseparam,
817                     ARRAY_SIZE(sysctl_pauseparam));
818
819                 if (sys_op->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) {
820                         axgbe_error("autoneg disabled, pause autoneg not available\n");
821                         return (-EINVAL);
822                 }
823
824                 pdata->phy.pause_autoneg = sys_op->autoneg;
825                 pdata->phy.tx_pause = sys_op->tx_pause;
826                 pdata->phy.rx_pause = sys_op->rx_pause;
827
828                 XGBE_CLR_ADV(&pdata->phy, Pause);
829                 XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
830
831                 if (sys_op->rx_pause) {
832                         XGBE_SET_ADV(&pdata->phy, Pause);
833                         XGBE_SET_ADV(&pdata->phy, Asym_Pause);
834                 }
835
836                 if (sys_op->tx_pause) {
837                         /* Equivalent to XOR of Asym_Pause */
838                         if (XGBE_ADV(&pdata->phy, Asym_Pause))
839                                 XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
840                         else
841                                 XGBE_SET_ADV(&pdata->phy, Asym_Pause);
842                 }
843
844                 if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
845                         rc = pdata->phy_if.phy_config_aneg(pdata);
846
847         }
848
849         return (rc);
850 }
851
852 static int
853 sysctl_link_ksettings_handler(SYSCTL_HANDLER_ARGS)
854 {
855         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
856         struct sysctl_op *sys_op = pdata->sys_op;
857         struct sysctl_info sysctl_linksettings[] = {
858                 { "autoneg", SYSL_BOOL, autoneg, "supported" },
859                 { "speed", SYSL_U32, speed, "supported" },
860                 { "duplex", SYSL_U8, duplex, "supported" },
861         };
862         ssize_t buf_size = 512;
863         char buf[buf_size], link_modes[16], speed_modes[16];
864         struct sbuf *sb;
865         uint32_t speed;
866         int rc = 0;
867
868         if (req->newptr == NULL) {
869                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
870                 if (sb == NULL) {
871                         rc = sb->s_error;
872                         return (rc);
873                 }
874                 sys_op->autoneg = pdata->phy.autoneg;
875                 sys_op->speed = pdata->phy.speed;
876                 sys_op->duplex = pdata->phy.duplex;
877
878                 XGBE_LM_COPY(&pdata->phy, supported, &pdata->phy, supported);
879                 XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, advertising);
880                 XGBE_LM_COPY(&pdata->phy, lp_advertising, &pdata->phy, lp_advertising);
881
882                 switch (sys_op->speed) {
883                 case 1:
884                         strcpy(link_modes, "Unknown");
885                         strcpy(speed_modes, "Unknown");
886                         break;
887                 case 2:
888                         strcpy(link_modes, "10Gbps/Full");
889                         strcpy(speed_modes, "10000");
890                         break;
891                 case 3: 
892                         strcpy(link_modes, "2.5Gbps/Full");
893                         strcpy(speed_modes, "2500");
894                         break;
895                 case 4: 
896                         strcpy(link_modes, "1Gbps/Full");
897                         strcpy(speed_modes, "1000");
898                         break;
899                 case 5: 
900                         strcpy(link_modes, "100Mbps/Full");
901                         strcpy(speed_modes, "100");
902                         break;
903                 case 6:
904                         strcpy(link_modes, "10Mbps/Full");
905                         strcpy(speed_modes, "10");
906                         break;
907                 }
908                         
909                 sbuf_printf(sb,
910                     "\nlink_modes: %s\n"
911                     "autonegotiation: %s\n"
912                     "speed: %sMbps\n",
913                     link_modes,
914                     (sys_op->autoneg == AUTONEG_DISABLE) ? "off" : "on",
915                     speed_modes);
916
917                 switch (sys_op->duplex) {
918                         case DUPLEX_HALF:
919                                 sbuf_printf(sb, "Duplex: Half\n");
920                                 break;
921                         case DUPLEX_FULL:
922                                 sbuf_printf(sb, "Duplex: Full\n");
923                                 break;
924                         default:
925                                 sbuf_printf(sb, "Duplex: Unknown\n");
926                                 break;
927                 }
928                 rc = sbuf_finish(sb);
929                 sbuf_delete(sb);
930                 return (0);
931         }
932
933         rc = get_ubuf(req, buf);
934         if (rc == 0) {
935                 parse_generic_sysctl(pdata, buf, sysctl_linksettings,
936                     ARRAY_SIZE(sysctl_linksettings));
937
938                 speed = sys_op->speed;
939
940                 if ((sys_op->autoneg != AUTONEG_ENABLE) &&
941                     (sys_op->autoneg != AUTONEG_DISABLE)) {
942                         axgbe_error("unsupported autoneg %hhu\n",
943                             (unsigned char)sys_op->autoneg);
944                         return (-EINVAL);
945                 }
946
947                 if (sys_op->autoneg == AUTONEG_DISABLE) {
948                         if (!pdata->phy_if.phy_valid_speed(pdata, speed)) {
949                                 axgbe_error("unsupported speed %u\n", speed);
950                                 return (-EINVAL);
951                         }
952
953                         if (sys_op->duplex != DUPLEX_FULL) {
954                                 axgbe_error("unsupported duplex %hhu\n",
955                                     (unsigned char)sys_op->duplex);
956                                 return (-EINVAL);
957                         }
958                 }
959
960                 pdata->phy.autoneg = sys_op->autoneg;
961                 pdata->phy.speed = speed;
962                 pdata->phy.duplex = sys_op->duplex;
963
964                 if (sys_op->autoneg == AUTONEG_ENABLE)
965                         XGBE_SET_ADV(&pdata->phy, Autoneg);
966                 else
967                         XGBE_CLR_ADV(&pdata->phy, Autoneg);
968
969                 if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
970                         rc = pdata->phy_if.phy_config_aneg(pdata);
971         }
972
973         return (rc);
974 }
975
976 static int
977 sysctl_ringparam_handler(SYSCTL_HANDLER_ARGS)
978 {
979         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
980         struct sysctl_op *sys_op = pdata->sys_op;
981         struct sysctl_info sysctl_ringparam[] = {
982                 { "rx", SYSL_S32, rx_pending, "supported" },
983                 { "rx-mini", SYSL_S32, rx_mini_pending, "supported" },
984                 { "rx-jumbo", SYSL_S32, rx_jumbo_pending, "supported" },
985                 { "tx", SYSL_S32, tx_pending, "supported" },
986         };
987         ssize_t buf_size = 512;
988         unsigned int rx, tx;
989         char buf[buf_size];
990         struct sbuf *sb;
991         int rc = 0;
992
993         if (req->newptr == NULL) {
994                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
995                 if (sb == NULL) {
996                         rc = sb->s_error;
997                         return (rc);
998                 }
999                 sys_op->rx_max_pending = XGBE_RX_DESC_CNT_MAX;
1000                 sys_op->tx_max_pending = XGBE_TX_DESC_CNT_MAX;
1001                 sys_op->rx_pending = pdata->rx_desc_count;
1002                 sys_op->tx_pending = pdata->tx_desc_count;
1003
1004                 sbuf_printf(sb,
1005                     "\nPre-set maximums:\n"
1006                     "RX:                %u\n"
1007                     "RX Mini:   %u\n"
1008                     "RX Jumbo:  %u\n"
1009                     "TX:                %u\n",
1010                     sys_op->rx_max_pending,
1011                     sys_op->rx_mini_max_pending,
1012                     sys_op->rx_jumbo_max_pending,
1013                     sys_op->tx_max_pending);
1014
1015                 sbuf_printf(sb,
1016                     "\nCurrent hardware settings:\n"
1017                     "RX:                %u\n"
1018                     "RX Mini:   %u\n"
1019                     "RX Jumbo:  %u\n"
1020                     "TX:                %u\n",
1021                     sys_op->rx_pending,
1022                     sys_op->rx_mini_pending,
1023                     sys_op->rx_jumbo_pending,
1024                     sys_op->tx_pending);
1025
1026                 rc = sbuf_finish(sb);
1027                 sbuf_delete(sb);
1028                 return (0);
1029         }
1030
1031         rc = get_ubuf(req, buf);
1032         if (rc == 0) {
1033                 parse_generic_sysctl(pdata, buf, sysctl_ringparam,
1034                     ARRAY_SIZE(sysctl_ringparam));
1035
1036                 if (sys_op->rx_mini_pending || sys_op->rx_jumbo_pending) {
1037                         axgbe_error("unsupported ring parameter\n");
1038                         return (-EINVAL);
1039                 }
1040
1041                 if ((sys_op->rx_pending < XGBE_RX_DESC_CNT_MIN) ||
1042                                 (sys_op->rx_pending > XGBE_RX_DESC_CNT_MAX)) {
1043                         axgbe_error("rx ring param must be between %u and %u\n",
1044                             XGBE_RX_DESC_CNT_MIN, XGBE_RX_DESC_CNT_MAX);
1045                         return (-EINVAL);
1046                 }
1047
1048                 if ((sys_op->tx_pending < XGBE_TX_DESC_CNT_MIN) ||
1049                                 (sys_op->tx_pending > XGBE_TX_DESC_CNT_MAX)) {
1050                         axgbe_error("tx ring param must be between %u and %u\n",
1051                             XGBE_TX_DESC_CNT_MIN, XGBE_TX_DESC_CNT_MAX);
1052                         return (-EINVAL);
1053                 }
1054
1055                 rx = __rounddown_pow_of_two(sys_op->rx_pending);
1056                 if (rx != sys_op->rx_pending)
1057                         axgbe_printf(1, "rx ring param rounded to power of 2: %u\n",
1058                             rx);
1059
1060                 tx = __rounddown_pow_of_two(sys_op->tx_pending);
1061                 if (tx != sys_op->tx_pending)
1062                         axgbe_printf(1, "tx ring param rounded to power of 2: %u\n",
1063                             tx);
1064
1065                 if ((rx == pdata->rx_desc_count) &&
1066                     (tx == pdata->tx_desc_count))
1067                         goto out;
1068
1069                 pdata->rx_desc_count = rx;
1070                 pdata->tx_desc_count = tx;
1071
1072                 /* TODO - restart dev */
1073         }
1074
1075 out:
1076         return (0);
1077 }
1078
1079 static int
1080 sysctl_channels_handler(SYSCTL_HANDLER_ARGS)
1081 {
1082         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1083         struct sysctl_op *sys_op = pdata->sys_op;
1084         struct sysctl_info sysctl_channels[] = {
1085                 { "rx", SYSL_S32, rx_count, "supported" },
1086                 { "tx", SYSL_S32, tx_count, "supported" },
1087                 { "other", SYSL_S32, other_count, "supported" },
1088                 { "combined", SYSL_S32, combined_count, "supported" },
1089         };
1090         unsigned int rx, tx, combined;
1091         ssize_t buf_size = 512;
1092         char buf[buf_size];
1093         struct sbuf *sb;
1094         int rc = 0;
1095
1096         if (req->newptr == NULL) {
1097                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1098                 if (sb == NULL) {
1099                         rc = sb->s_error;
1100                         return (rc);
1101                 }
1102                 rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count);
1103                 rx = min(rx, pdata->channel_irq_count);
1104                 tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count);
1105                 tx = min(tx, pdata->channel_irq_count);
1106                 tx = min(tx, pdata->tx_max_q_count);
1107
1108                 combined = min(rx, tx);
1109
1110                 sys_op->max_combined = combined;
1111                 sys_op->max_rx = rx ? rx - 1 : 0;
1112                 sys_op->max_tx = tx ? tx - 1 : 0;
1113
1114                 /* Get current settings based on device state */
1115                 rx = pdata->rx_ring_count;
1116                 tx = pdata->tx_ring_count;
1117
1118                 combined = min(rx, tx);
1119                 rx -= combined;
1120                 tx -= combined;
1121
1122                 sys_op->combined_count = combined;
1123                 sys_op->rx_count = rx;
1124                 sys_op->tx_count = tx;
1125
1126                 sbuf_printf(sb,
1127                     "\nPre-set maximums:\n"
1128                     "RX:                %u\n"
1129                     "TX:                %u\n"
1130                     "Other:             %u\n"
1131                     "Combined:  %u\n",
1132                     sys_op->max_rx, sys_op->max_tx,
1133                     sys_op->max_other,
1134                     sys_op->max_combined);
1135
1136                 sbuf_printf(sb,
1137                     "\nCurrent hardware settings:\n"
1138                     "RX:                %u\n"
1139                     "TX:                %u\n"
1140                     "Other:             %u\n"
1141                     "Combined:  %u\n",
1142                     sys_op->rx_count, sys_op->tx_count,
1143                     sys_op->other_count,
1144                     sys_op->combined_count);
1145
1146                 rc = sbuf_finish(sb);
1147                 sbuf_delete(sb);
1148                 return (0);
1149         }
1150
1151         rc = get_ubuf(req, buf);
1152         if (rc == 0) {
1153                 parse_generic_sysctl(pdata, buf, sysctl_channels,
1154                     ARRAY_SIZE(sysctl_channels));
1155
1156                 axgbe_error( "channel inputs: combined=%u, rx-only=%u,"
1157                     " tx-only=%u\n", sys_op->combined_count,
1158                     sys_op->rx_count, sys_op->tx_count);
1159         }
1160
1161         return (rc);
1162 }
1163
1164
1165 static int
1166 sysctl_mac_stats_handler(SYSCTL_HANDLER_ARGS)
1167 {
1168         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1169         ssize_t buf_size = 64;
1170         struct sbuf *sb;
1171         int rc = 0;
1172         int i;
1173
1174         if (req->newptr == NULL) {
1175                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1176                 if (sb == NULL) {
1177                         rc = sb->s_error;
1178                         return (rc);
1179                 }
1180
1181                 pdata->hw_if.read_mmc_stats(pdata);
1182                 for (i = 0; i < XGBE_STATS_COUNT; i++) {
1183                 sbuf_printf(sb, "\n %s: %lu",
1184                     xgbe_gstring_stats[i].stat_string,
1185                     *(uint64_t *)((uint8_t *)pdata + xgbe_gstring_stats[i].stat_offset));
1186                 }
1187                 for (i = 0; i < pdata->tx_ring_count; i++) {
1188                         sbuf_printf(sb,
1189                             "\n txq_packets[%d]: %lu"
1190                             "\n txq_bytes[%d]: %lu",
1191                             i, pdata->ext_stats.txq_packets[i],
1192                             i, pdata->ext_stats.txq_bytes[i]);
1193                 }
1194                 for (i = 0; i < pdata->rx_ring_count; i++) {
1195                         sbuf_printf(sb,
1196                             "\n rxq_packets[%d]: %lu"
1197                             "\n rxq_bytes[%d]: %lu",
1198                             i, pdata->ext_stats.rxq_packets[i],
1199                             i, pdata->ext_stats.rxq_bytes[i]);
1200                 }
1201
1202                 rc = sbuf_finish(sb);
1203                 sbuf_delete(sb);
1204                 return (rc);
1205         }
1206
1207         return (-EINVAL);
1208 }
1209
1210 static int
1211 sysctl_xgmac_reg_value_handler(SYSCTL_HANDLER_ARGS)
1212 {
1213         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1214         ssize_t buf_size = 64;
1215         char buf[buf_size];
1216         unsigned int value;
1217         struct sbuf *sb;
1218         int rc = 0;
1219
1220         if (req->newptr == NULL) {
1221                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1222                 if (sb == NULL) {
1223                         rc = sb->s_error;
1224                         return (rc);
1225                 }
1226
1227                 value = XGMAC_IOREAD(pdata, pdata->sysctl_xgmac_reg);
1228                 axgbe_printf(2, "READ: %s: value: 0x%x\n",  __func__, value);
1229                 sbuf_printf(sb, "\nXGMAC reg_value:     0x%x\n", value);
1230                 rc = sbuf_finish(sb);
1231                 sbuf_delete(sb);
1232                 return (rc);
1233         }
1234
1235         rc = get_ubuf(req, buf);
1236         if (rc == 0) {
1237                 sscanf(buf, "%x", &value);
1238                 axgbe_printf(2, "WRITE: %s: value: 0x%x\n",  __func__, value);
1239                 XGMAC_IOWRITE(pdata, pdata->sysctl_xgmac_reg, value);
1240         }
1241
1242         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1243         return (rc);
1244 }
1245
1246 static int
1247 sysctl_xpcs_mmd_reg_handler(SYSCTL_HANDLER_ARGS)
1248 {
1249         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1250         ssize_t buf_size = 64;
1251         char buf[buf_size];
1252         struct sbuf *sb;
1253         unsigned int reg;
1254         int rc = 0;
1255
1256         if (req->newptr == NULL) {
1257                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1258                 if (sb == NULL) {
1259                         rc = sb->s_error;
1260                         return (rc);
1261                 }
1262
1263                 axgbe_printf(2, "READ: %s: xpcs_mmd: 0x%x\n",  __func__,
1264                     pdata->sysctl_xpcs_mmd);
1265                 sbuf_printf(sb, "\nXPCS mmd_reg:        0x%x\n",
1266                     pdata->sysctl_xpcs_mmd);
1267                 rc = sbuf_finish(sb);
1268                 sbuf_delete(sb);
1269                 return (rc);
1270         }
1271
1272         rc = get_ubuf(req, buf);
1273         if (rc == 0) {
1274                 sscanf(buf, "%x", &reg);
1275                 axgbe_printf(2, "WRITE: %s: mmd_reg: 0x%x\n",  __func__, reg);
1276                 pdata->sysctl_xpcs_mmd = reg;
1277         }
1278
1279         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1280         return (rc);
1281 }
1282
1283 static int
1284 sysctl_xpcs_reg_addr_handler(SYSCTL_HANDLER_ARGS)
1285 {
1286         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1287         ssize_t buf_size = 64;
1288         char buf[buf_size];
1289         struct sbuf *sb;
1290         unsigned int reg;
1291         int rc = 0;
1292
1293         if (req->newptr == NULL) {
1294                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1295                 if (sb == NULL) {
1296                         rc = sb->s_error;
1297                         return (rc);
1298                 }
1299
1300                 axgbe_printf(2, "READ: %s: sysctl_xpcs_reg: 0x%x\n",  __func__,
1301                     pdata->sysctl_xpcs_reg);
1302                 sbuf_printf(sb, "\nXPCS reg_addr:       0x%x\n",
1303                     pdata->sysctl_xpcs_reg);
1304                 rc = sbuf_finish(sb);
1305                 sbuf_delete(sb);
1306                 return (rc);
1307         }
1308
1309         rc = get_ubuf(req, buf);
1310         if (rc == 0) {
1311                 sscanf(buf, "%x", &reg);
1312                 axgbe_printf(2, "WRITE: %s: reg: 0x%x\n",  __func__, reg);
1313                 pdata->sysctl_xpcs_reg = reg;
1314         }
1315
1316         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1317         return (rc);
1318 }
1319
1320 static int
1321 sysctl_xpcs_reg_value_handler(SYSCTL_HANDLER_ARGS)
1322 {
1323         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1324         ssize_t buf_size = 64;
1325         char buf[buf_size];
1326         unsigned int value;
1327         struct sbuf *sb;
1328         int rc = 0;
1329
1330         if (req->newptr == NULL) {
1331                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1332                 if (sb == NULL) {
1333                         rc = sb->s_error;
1334                         return (rc);
1335                 }
1336
1337                 value = XMDIO_READ(pdata, pdata->sysctl_xpcs_mmd,
1338                     pdata->sysctl_xpcs_reg);
1339                 axgbe_printf(2, "READ: %s: value: 0x%x\n",  __func__, value);
1340                 sbuf_printf(sb, "\nXPCS reg_value:      0x%x\n", value);
1341                 rc = sbuf_finish(sb);
1342                 sbuf_delete(sb);
1343                 return (rc);
1344         }
1345
1346         rc = get_ubuf(req, buf);
1347         if (rc == 0) {
1348                 sscanf(buf, "%x", &value);
1349                 axgbe_printf(2, "WRITE: %s: value: 0x%x\n",  __func__, value);
1350                 XMDIO_WRITE(pdata, pdata->sysctl_xpcs_mmd,
1351                     pdata->sysctl_xpcs_reg, value);
1352         }
1353
1354         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1355         return (rc);
1356 }
1357
1358 static int
1359 sysctl_xprop_reg_addr_handler(SYSCTL_HANDLER_ARGS)
1360 {
1361         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1362         ssize_t buf_size = 64;
1363         char buf[buf_size];
1364         struct sbuf *sb;
1365         unsigned int reg;
1366         int rc = 0;
1367
1368         if (req->newptr == NULL) {
1369                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1370                 if (sb == NULL) {
1371                         rc = sb->s_error;
1372                         return (rc);
1373                 }
1374
1375                 axgbe_printf(2, "READ: %s: sysctl_xprop_reg: 0x%x\n",  __func__,
1376                     pdata->sysctl_xprop_reg);
1377                 sbuf_printf(sb, "\nXPROP reg_addr:      0x%x\n",
1378                     pdata->sysctl_xprop_reg);
1379                 rc = sbuf_finish(sb);
1380                 sbuf_delete(sb);
1381                 return (rc);
1382         }
1383
1384         rc = get_ubuf(req, buf);
1385         if (rc == 0) {
1386                 sscanf(buf, "%x", &reg);
1387                 axgbe_printf(2, "WRITE: %s: reg: 0x%x\n",  __func__, reg);
1388                 pdata->sysctl_xprop_reg = reg;
1389         }
1390
1391         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1392         return (rc);
1393 }
1394
1395 static int
1396 sysctl_xprop_reg_value_handler(SYSCTL_HANDLER_ARGS)
1397 {
1398         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1399         ssize_t buf_size = 64;
1400         char buf[buf_size];
1401         unsigned int value;
1402         struct sbuf *sb;
1403         int rc = 0;
1404
1405         if (req->newptr == NULL) {
1406                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1407                 if (sb == NULL) {
1408                         rc = sb->s_error;
1409                         return (rc);
1410                 }
1411
1412                 value = XP_IOREAD(pdata, pdata->sysctl_xprop_reg);
1413                 axgbe_printf(2, "READ: %s: value: 0x%x\n",  __func__, value);
1414                 sbuf_printf(sb, "\nXPROP reg_value:     0x%x\n", value);
1415                 rc = sbuf_finish(sb);
1416                 sbuf_delete(sb);
1417                 return (rc);
1418         }
1419
1420         rc = get_ubuf(req, buf);
1421         if (rc == 0) {
1422                 sscanf(buf, "%x", &value);
1423                 axgbe_printf(2, "WRITE: %s: value: 0x%x\n",  __func__, value);
1424                 XP_IOWRITE(pdata, pdata->sysctl_xprop_reg, value);
1425         }
1426
1427         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1428         return (rc);
1429 }
1430
1431 static int
1432 sysctl_xi2c_reg_addr_handler(SYSCTL_HANDLER_ARGS)
1433 {
1434         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1435         ssize_t buf_size = 64;
1436         char buf[buf_size];
1437         struct sbuf *sb;
1438         unsigned int reg;
1439         int rc = 0;
1440
1441         if (req->newptr == NULL) {
1442                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1443                 if (sb == NULL) {
1444                         rc = sb->s_error;
1445                         return (rc);
1446                 }
1447
1448                 axgbe_printf(2, "READ: %s: sysctl_xi2c_reg: 0x%x\n",  __func__,
1449                     pdata->sysctl_xi2c_reg);
1450                 sbuf_printf(sb, "\nXI2C reg_addr:       0x%x\n",
1451                     pdata->sysctl_xi2c_reg);
1452                 rc = sbuf_finish(sb);
1453                 sbuf_delete(sb);
1454                 return (rc);
1455         }
1456
1457         rc = get_ubuf(req, buf);
1458         if (rc == 0) {
1459                 sscanf(buf, "%x", &reg);
1460                 axgbe_printf(2, "WRITE: %s: reg: 0x%x\n",  __func__, reg);
1461                 pdata->sysctl_xi2c_reg = reg;
1462         }
1463
1464         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1465         return (rc);
1466 }
1467
1468 static int
1469 sysctl_xi2c_reg_value_handler(SYSCTL_HANDLER_ARGS)
1470 {
1471         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1472         ssize_t buf_size = 64;
1473         char buf[buf_size];
1474         unsigned int value;
1475         struct sbuf *sb;
1476         int rc = 0;
1477
1478         if (req->newptr == NULL) {
1479                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1480                 if (sb == NULL) {
1481                         rc = sb->s_error;
1482                         return (rc);
1483                 }
1484
1485                 value = XI2C_IOREAD(pdata, pdata->sysctl_xi2c_reg);
1486                 axgbe_printf(2, "READ: %s: value: 0x%x\n",  __func__, value);
1487                 sbuf_printf(sb, "\nXI2C reg_value:      0x%x\n", value);
1488                 rc = sbuf_finish(sb);
1489                 sbuf_delete(sb);
1490                 return (rc);
1491         }
1492
1493         rc = get_ubuf(req, buf);
1494         if (rc == 0) {
1495                 sscanf(buf, "%x", &value);
1496                 axgbe_printf(2, "WRITE: %s: value: 0x%x\n",  __func__, value);
1497                 XI2C_IOWRITE(pdata, pdata->sysctl_xi2c_reg, value);
1498         }
1499
1500         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1501         return (rc);
1502 }
1503
1504 static int
1505 sysctl_an_cdr_wr_handler(SYSCTL_HANDLER_ARGS)
1506 {
1507         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1508         unsigned int an_cdr_wr = 0;
1509         ssize_t buf_size = 64;
1510         char buf[buf_size];
1511         struct sbuf *sb;
1512         int rc = 0;
1513
1514         if (req->newptr == NULL) {
1515                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1516                 if (sb == NULL) {
1517                         rc = sb->s_error;
1518                         return (rc);
1519                 }
1520
1521                 axgbe_printf(2, "READ: %s: an_cdr_wr: %d\n",  __func__,
1522                     pdata->sysctl_an_cdr_workaround);
1523                 sbuf_printf(sb, "%d\n", pdata->sysctl_an_cdr_workaround);
1524                 rc = sbuf_finish(sb);
1525                 sbuf_delete(sb);
1526                 return (rc);
1527         }
1528
1529         rc = get_ubuf(req, buf);
1530         if (rc == 0) {
1531                 sscanf(buf, "%u", &an_cdr_wr);
1532                 axgbe_printf(2, "WRITE: %s: an_cdr_wr: 0x%d\n",  __func__,
1533                     an_cdr_wr);
1534
1535                 if (an_cdr_wr)
1536                         pdata->sysctl_an_cdr_workaround = 1;
1537                 else
1538                         pdata->sysctl_an_cdr_workaround = 0;
1539         }
1540
1541         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1542         return (rc);
1543 }
1544
1545 static int
1546 sysctl_an_cdr_track_early_handler(SYSCTL_HANDLER_ARGS)
1547 {
1548         struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)arg1;
1549         unsigned int an_cdr_track_early = 0;
1550         ssize_t buf_size = 64;
1551         char buf[buf_size];
1552         struct sbuf *sb;
1553         int rc = 0;
1554
1555         if (req->newptr == NULL) {
1556                 sb = sbuf_new_for_sysctl(NULL, NULL, buf_size, req);
1557                 if (sb == NULL) {
1558                         rc = sb->s_error;
1559                         return (rc);
1560                 }
1561
1562                 axgbe_printf(2, "READ: %s: an_cdr_track_early %d\n",  __func__,
1563                     pdata->sysctl_an_cdr_track_early);
1564                 sbuf_printf(sb, "%d\n", pdata->sysctl_an_cdr_track_early);                      
1565                 rc = sbuf_finish(sb);
1566                 sbuf_delete(sb);
1567                 return (rc);
1568         }
1569
1570         rc = get_ubuf(req, buf);
1571         if (rc == 0) {
1572                 sscanf(buf, "%u", &an_cdr_track_early);
1573                 axgbe_printf(2, "WRITE: %s: an_cdr_track_early: %d\n",  __func__,
1574                     an_cdr_track_early);
1575
1576                 if (an_cdr_track_early)
1577                         pdata->sysctl_an_cdr_track_early = 1;
1578                 else
1579                         pdata->sysctl_an_cdr_track_early = 0;
1580         }
1581
1582         axgbe_printf(2, "%s: rc= %d\n",  __func__, rc);
1583         return (rc);
1584 }
1585
1586 void
1587 axgbe_sysctl_exit(struct xgbe_prv_data *pdata)
1588 {
1589
1590         if (pdata->sys_op)
1591                 free(pdata->sys_op, M_AXGBE);
1592 }
1593
1594 void 
1595 axgbe_sysctl_init(struct xgbe_prv_data *pdata)
1596 {
1597         struct sysctl_ctx_list *clist;
1598         struct sysctl_oid_list *top;
1599         struct sysctl_oid *parent; 
1600         struct sysctl_op *sys_op;
1601
1602         sys_op = malloc(sizeof(*sys_op), M_AXGBE, M_WAITOK | M_ZERO);
1603         pdata->sys_op = sys_op;
1604
1605         clist = device_get_sysctl_ctx(pdata->dev); 
1606         parent = device_get_sysctl_tree(pdata->dev);
1607         top = SYSCTL_CHILDREN(parent);
1608
1609         /* Set defaults */
1610         pdata->sysctl_xgmac_reg = 0;
1611         pdata->sysctl_xpcs_mmd = 1;
1612         pdata->sysctl_xpcs_reg = 0;
1613
1614         SYSCTL_ADD_UINT(clist, top, OID_AUTO, "axgbe_debug_level", CTLFLAG_RWTUN,
1615             &pdata->debug_level, 0, "axgbe log level -- higher is verbose");
1616
1617         SYSCTL_ADD_UINT(clist, top, OID_AUTO, "sph_enable",
1618             CTLFLAG_RDTUN, &pdata->sph_enable, 1,
1619             "shows the split header feature state (1 - enable, 0 - disable");
1620
1621         SYSCTL_ADD_UINT(clist, top, OID_AUTO, "link_workaround",
1622             CTLFLAG_RWTUN, &pdata->link_workaround, 0,
1623             "enable the workaround for link issue in coming up");
1624
1625         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xgmac_register",
1626             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1627             pdata, 0, sysctl_xgmac_reg_addr_handler, "IU",
1628             "xgmac register addr");
1629
1630         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xgmac_register_value",
1631             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1632             pdata, 0, sysctl_xgmac_reg_value_handler, "IU",
1633             "xgmac register value");
1634
1635         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xpcs_mmd",
1636             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1637             pdata, 0, sysctl_xpcs_mmd_reg_handler, "IU", "xpcs mmd register");
1638
1639         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xpcs_register",
1640             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1641             pdata, 0, sysctl_xpcs_reg_addr_handler, "IU", "xpcs register");
1642
1643         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xpcs_register_value",
1644             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1645             pdata, 0, sysctl_xpcs_reg_value_handler, "IU",
1646             "xpcs register value");
1647
1648         if (pdata->xpcs_res) {
1649                 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xprop_register",
1650                     CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1651                     pdata, 0, sysctl_xprop_reg_addr_handler,
1652                     "IU", "xprop register");
1653
1654                 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xprop_register_value",
1655                     CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1656                     pdata, 0, sysctl_xprop_reg_value_handler,
1657                     "IU", "xprop register value");
1658         }
1659
1660         if (pdata->xpcs_res) {
1661                 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xi2c_register",
1662                     CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1663                     pdata, 0, sysctl_xi2c_reg_addr_handler,
1664                     "IU", "xi2c register");
1665
1666                 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xi2c_register_value",
1667                     CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1668                     pdata, 0, sysctl_xi2c_reg_value_handler,
1669                     "IU", "xi2c register value");
1670         }
1671
1672         if (pdata->vdata->an_cdr_workaround) {
1673                 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "an_cdr_workaround",
1674                     CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1675                     pdata, 0, sysctl_an_cdr_wr_handler, "IU",
1676                     "an cdr workaround");
1677
1678                 SYSCTL_ADD_PROC(clist, top, OID_AUTO, "an_cdr_track_early",
1679                     CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1680                     pdata, 0, sysctl_an_cdr_track_early_handler, "IU",
1681                     "an cdr track early");
1682         }
1683
1684         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "drv_info",
1685             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1686             pdata, 0, sysctl_get_drv_info_handler, "IU",
1687             "xgbe drv info");
1688
1689         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "link_info",
1690             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1691             pdata, 0, sysctl_get_link_info_handler, "IU",
1692             "xgbe link info");
1693
1694         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "coalesce_info",
1695             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1696             pdata, 0, sysctl_coalesce_handler, "IU",
1697             "xgbe coalesce info");
1698
1699         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "pauseparam_info",
1700             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1701             pdata, 0, sysctl_pauseparam_handler, "IU",
1702             "xgbe pauseparam info");
1703
1704         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "link_ksettings_info",
1705             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1706             pdata, 0, sysctl_link_ksettings_handler, "IU",
1707             "xgbe link_ksettings info");
1708
1709         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "ringparam_info",
1710             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1711             pdata, 0, sysctl_ringparam_handler, "IU",
1712             "xgbe ringparam info");
1713
1714         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "channels_info",
1715             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1716             pdata, 0, sysctl_channels_handler, "IU",
1717             "xgbe channels info");
1718
1719         SYSCTL_ADD_PROC(clist, top, OID_AUTO, "mac_stats",
1720             CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1721             pdata, 0, sysctl_mac_stats_handler, "IU",
1722             "xgbe mac stats");
1723 }