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