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