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