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