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