xref: /titanic_52/usr/src/uts/common/io/nge/nge_kstats.c (revision 2f79bea12c9814c8829dad82312f3c944423bcce)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "nge.h"
30 
31 #undef	NGE_DBG
32 #define	NGE_DBG		NGE_DBG_STATS	/* debug flag for this code	*/
33 
34 /*
35  * Table of Hardware-defined Statistics Block Offsets and Names
36  */
37 #define	KS_NAME(s)			{ KS_ ## s, #s }
38 
39 const nge_ksindex_t nge_statistics[] = {
40 
41 	KS_NAME(ifHOutOctets),
42 	KS_NAME(ifHOutZeroRetranCount),
43 	KS_NAME(ifHOutOneRetranCount),
44 	KS_NAME(ifHOutMoreRetranCount),
45 	KS_NAME(ifHOutColCount),
46 	KS_NAME(ifHOutFifoovCount),
47 	KS_NAME(ifHOutLOCCount),
48 	KS_NAME(ifHOutExDecCount),
49 	KS_NAME(ifHOutRetryCount),
50 	KS_NAME(ifHInFrameErrCount),
51 	KS_NAME(ifHInExtraOctErrCount),
52 	KS_NAME(ifHInLColErrCount),
53 	KS_NAME(ifHInOversizeErrCount),
54 	KS_NAME(ifHInFovErrCount),
55 	KS_NAME(ifHInFCSErrCount),
56 	KS_NAME(ifHInAlignErrCount),
57 	KS_NAME(ifHInLenErrCount),
58 	KS_NAME(ifHInUniPktsCount),
59 	KS_NAME(ifHInBroadPksCount),
60 	KS_NAME(ifHInMulPksCount),
61 	{ KS_STATS_SIZE, NULL }
62 };
63 
64 /*
65  * Local datatype for defining tables of (Offset, Name) pairs
66  */
67 static int
68 nge_statistics_update(kstat_t *ksp, int flag)
69 {
70 	uint32_t regno;
71 	nge_t *ngep;
72 	nge_statistics_t *istp;
73 	nge_hw_statistics_t *hw_stp;
74 	kstat_named_t *knp;
75 	const nge_ksindex_t *ksip;
76 
77 	if (flag != KSTAT_READ)
78 		return (EACCES);
79 
80 	ngep = ksp->ks_private;
81 	istp = &ngep->statistics;
82 	hw_stp = &istp->hw_statistics;
83 	knp = ksp->ks_data;
84 
85 	/*
86 	 * Transfer the statistics values from the hardware statistics regs
87 	 */
88 	for (ksip = nge_statistics; ksip->name != NULL; ++knp, ++ksip) {
89 		regno = KS_BASE + ksip->index * sizeof (uint32_t);
90 		hw_stp->a[ksip->index] += nge_reg_get32(ngep, regno);
91 		knp->value.ui64 = hw_stp->a[ksip->index];
92 	}
93 
94 	return (0);
95 }
96 
97 
98 static const nge_ksindex_t nge_chipinfo[] = {
99 	{ 0,				"businfo"		},
100 	{ 1,				"command"		},
101 	{ 2,				"vendor_id"		},
102 	{ 3,				"device_id"		},
103 	{ 4,				"subsystem_vendor_id"	},
104 	{ 5,				"subsystem_device_id"	},
105 	{ 6,				"revision_id"		},
106 	{ 7,				"cache_line_size"	},
107 	{ 8,				"latency_timer"		},
108 	{ 9,				"phy_mode"		},
109 	{ 10,				"phy_id"		},
110 	{ 11,				"hw_mac_addr"		},
111 	{ 12,				"&bus_type"		},
112 	{ 13,				"&bus_speed"		},
113 	{ 14,				"&bus_size"		},
114 	{ -1,				NULL 			}
115 };
116 
117 static const nge_ksindex_t nge_debuginfo[] = {
118 	{ 0,				"rx_realloc"		},
119 	{ 1,				"rx_realloc_fails"	},
120 	{ 2,				"rx_realloc_DMA_fails"	},
121 	{ 3,				"rx_realloc_MP_fails"	},
122 	{ 4,				"rx_rcfree"		},
123 	{ 5,				"context_switch"	},
124 	{ 6,				"ip_hsum_err"		},
125 	{ 7,				"tcp_hsum_err"		},
126 	{ 8,				"tc_next"		},
127 	{ 9,				"tx_next"		},
128 	{ 10,				"tx_free"		},
129 	{ 11,				"tx_flow"		},
130 	{ 12,				"rx_prod"		},
131 	{ 13,				"rx_hold"		},
132 	{ 14,				"rx_nobuf"		},
133 	{ 15,				"rx_err"		},
134 	{16,				"tx_err"		},
135 	{17,				"tx_stall"		},
136 	{ -1,				NULL 			}
137 };
138 
139 static int
140 nge_chipinfo_update(kstat_t *ksp, int flag)
141 {
142 	nge_t *ngep;
143 	kstat_named_t *knp;
144 	chip_info_t *infop;
145 
146 	if (flag != KSTAT_READ)
147 		return (EACCES);
148 
149 	ngep = ksp->ks_private;
150 	infop = &ngep->chipinfo;
151 	knp = ksp->ks_data;
152 
153 	(knp++)->value.ui64 = infop->businfo;
154 	(knp++)->value.ui64 = infop->command;
155 	(knp++)->value.ui64 = infop->vendor;
156 	(knp++)->value.ui64 = infop->device;
157 	(knp++)->value.ui64 = infop->subven;
158 	(knp++)->value.ui64 = infop->subdev;
159 	(knp++)->value.ui64 = infop->revision;
160 	(knp++)->value.ui64 = infop->clsize;
161 	(knp++)->value.ui64 = infop->latency;
162 	(knp++)->value.ui64 = ngep->phy_mode;
163 	(knp++)->value.ui64 = ngep->phy_id;
164 	(knp++)->value.ui64 = infop->hw_mac_addr;
165 	return (0);
166 }
167 
168 static int
169 nge_debuginfo_update(kstat_t *ksp, int flag)
170 {
171 	nge_t *ngep;
172 	kstat_named_t *knp;
173 	nge_sw_statistics_t *sw_stp;
174 
175 	if (flag != KSTAT_READ)
176 		return (EACCES);
177 
178 	ngep = ksp->ks_private;
179 	sw_stp = &ngep->statistics.sw_statistics;
180 	knp = ksp->ks_data;
181 
182 	(knp++)->value.ui64 = sw_stp->recv_realloc;
183 	(knp++)->value.ui64 = sw_stp->kmem_alloc_err;
184 	(knp++)->value.ui64 = sw_stp->dma_alloc_err;
185 	(knp++)->value.ui64 = sw_stp->mp_alloc_err;
186 	(knp++)->value.ui64 = sw_stp->recy_free;
187 	(knp++)->value.ui64 = sw_stp->load_context;
188 	(knp++)->value.ui64 = sw_stp->ip_hwsum_err;
189 	(knp++)->value.ui64 = sw_stp->tcp_hwsum_err;
190 	(knp++)->value.ui64 = ngep->send->tc_next;
191 	(knp++)->value.ui64 = ngep->send->tx_next;
192 	(knp++)->value.ui64 = ngep->send->tx_free;
193 	(knp++)->value.ui64 = ngep->send->tx_flow;
194 	(knp++)->value.ui64 = ngep->recv->prod_index;
195 	(knp++)->value.ui64 = ngep->buff->rx_hold;
196 	(knp++)->value.ui64 = sw_stp->rx_nobuffer;
197 	(knp++)->value.ui64 = sw_stp->rx_err;
198 	(knp++)->value.ui64 = sw_stp->tx_stop_err;
199 	(knp++)->value.ui64 = sw_stp->tx_stall;
200 	return (0);
201 }
202 
203 static kstat_t *
204 nge_setup_named_kstat(nge_t *ngep, int instance, char *name,
205 	const nge_ksindex_t *ksip, size_t size, int (*update)(kstat_t *, int))
206 {
207 	kstat_t *ksp;
208 	kstat_named_t *knp;
209 	char *np;
210 	int type;
211 
212 	size /= sizeof (nge_ksindex_t);
213 	ksp = kstat_create(NGE_DRIVER_NAME, instance, name, "net",
214 	    KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_PERSISTENT);
215 	if (ksp == NULL)
216 		return (NULL);
217 
218 	ksp->ks_private = ngep;
219 	ksp->ks_update = update;
220 	for (knp = ksp->ks_data; (np = ksip->name) != NULL; ++knp, ++ksip) {
221 		switch (*np) {
222 		default:
223 			type = KSTAT_DATA_UINT64;
224 			break;
225 		case '%':
226 			np += 1;
227 			type = KSTAT_DATA_UINT32;
228 			break;
229 
230 		case '$':
231 			np ++;
232 			type = KSTAT_DATA_STRING;
233 			break;
234 		case '&':
235 			np ++;
236 			type = KSTAT_DATA_CHAR;
237 			break;
238 		}
239 		kstat_named_init(knp, np, type);
240 	}
241 	kstat_install(ksp);
242 
243 	return (ksp);
244 }
245 
246 /*
247  * Create kstats corresponding to NDD parameters
248  */
249 static kstat_t *
250 nge_setup_params_kstat(nge_t *ngep, int instance, char *name,
251 	int (*update)(kstat_t *, int))
252 {
253 	kstat_t *ksp;
254 	kstat_named_t *knp;
255 	int i;
256 
257 	ksp = kstat_create(NGE_DRIVER_NAME, instance, name, "net",
258 	    KSTAT_TYPE_NAMED, PARAM_COUNT, KSTAT_FLAG_PERSISTENT);
259 	if (ksp != NULL) {
260 		ksp->ks_private = ngep;
261 		ksp->ks_update = update;
262 		for (knp = ksp->ks_data, i = 0; i < PARAM_COUNT; ++knp, ++i)
263 			kstat_named_init(knp, ngep->nd_params[i].ndp_name+1,
264 			    KSTAT_DATA_UINT64);
265 		kstat_install(ksp);
266 	}
267 
268 	return (ksp);
269 }
270 
271 void
272 nge_init_kstats(nge_t *ngep, int instance)
273 {
274 	NGE_TRACE(("nge_init_kstats($%p, %d)", (void *)ngep, instance));
275 
276 	ngep->nge_kstats[NGE_KSTAT_STATS] = nge_setup_named_kstat(ngep,
277 	    instance, "statistics", nge_statistics,
278 	    sizeof (nge_statistics), nge_statistics_update);
279 
280 	ngep->nge_kstats[NGE_KSTAT_CHIPID] = nge_setup_named_kstat(ngep,
281 	    instance, "chipinfo", nge_chipinfo,
282 	    sizeof (nge_chipinfo), nge_chipinfo_update);
283 
284 	ngep->nge_kstats[NGE_KSTAT_DEBUG] = nge_setup_named_kstat(ngep,
285 	    instance, "driver-debug", nge_debuginfo,
286 	    sizeof (nge_debuginfo), nge_debuginfo_update);
287 
288 }
289 
290 void
291 nge_fini_kstats(nge_t *ngep)
292 {
293 	int i;
294 
295 	NGE_TRACE(("nge_fini_kstats($%p)", (void *)ngep));
296 	for (i = NGE_KSTAT_COUNT;  --i >= 0; )
297 		if (ngep->nge_kstats[i] != NULL)
298 			kstat_delete(ngep->nge_kstats[i]);
299 }
300 
301 int
302 nge_m_stat(void *arg, uint_t stat, uint64_t *val)
303 {
304 	nge_t *ngep = arg;
305 	uint32_t regno;
306 	nge_statistics_t *nstp = &ngep->statistics;
307 	nge_hw_statistics_t *hw_stp = &nstp->hw_statistics;
308 	nge_sw_statistics_t *sw_stp = &nstp->sw_statistics;
309 
310 	switch (stat) {
311 	case MAC_STAT_IFSPEED:
312 		*val = ngep->param_link_speed * 1000000ull;
313 		break;
314 
315 	case MAC_STAT_MULTIRCV:
316 		regno = KS_BASE + KS_ifHInMulPksCount * sizeof (uint32_t);
317 		hw_stp->s.InMulPksCount += nge_reg_get32(ngep, regno);
318 		*val = hw_stp->s.InMulPksCount;
319 		break;
320 
321 	case MAC_STAT_BRDCSTRCV:
322 		regno = KS_BASE +  KS_ifHInBroadPksCount * sizeof (uint32_t);
323 		hw_stp->s.InBroadPksCount += nge_reg_get32(ngep, regno);
324 		*val = hw_stp->s.InBroadPksCount;
325 		break;
326 
327 	case MAC_STAT_NORCVBUF:
328 		*val = sw_stp->rx_nobuffer;
329 		break;
330 
331 	case MAC_STAT_IERRORS:
332 		regno = KS_BASE + KS_ifHInFrameErrCount * sizeof (uint32_t);
333 		hw_stp->s.InFrameErrCount += nge_reg_get32(ngep, regno);
334 		regno = KS_BASE + KS_ifHInExtraOctErrCount * sizeof (uint32_t);
335 		hw_stp->s.InExtraOctErrCount += nge_reg_get32(ngep, regno);
336 		regno = KS_BASE + KS_ifHInLColErrCount * sizeof (uint32_t);
337 		hw_stp->s.InLColErrCount += nge_reg_get32(ngep, regno);
338 		regno = KS_BASE + KS_ifHInOversizeErrCount * sizeof (uint32_t);
339 		hw_stp->s.InOversizeErrCount += nge_reg_get32(ngep, regno);
340 		regno = KS_BASE + KS_ifHInFovErrCount * sizeof (uint32_t);
341 		hw_stp->s.InFovErrCount += nge_reg_get32(ngep, regno);
342 		regno = KS_BASE + KS_ifHInFCSErrCount * sizeof (uint32_t);
343 		hw_stp->s.InFCSErrCount += nge_reg_get32(ngep, regno);
344 		regno = KS_BASE + KS_ifHInAlignErrCount * sizeof (uint32_t);
345 		hw_stp->s.InAlignErrCount += nge_reg_get32(ngep, regno);
346 		regno = KS_BASE + KS_ifHInLenErrCount * sizeof (uint32_t);
347 		hw_stp->s.InLenErrCount += nge_reg_get32(ngep, regno);
348 		*val = hw_stp->s.InFrameErrCount +
349 		    hw_stp->s.InExtraOctErrCount +
350 		    hw_stp->s.InLColErrCount +
351 		    hw_stp->s.InOversizeErrCount +
352 		    hw_stp->s.InFovErrCount +
353 		    hw_stp->s.InFCSErrCount +
354 		    hw_stp->s.InAlignErrCount +
355 		    hw_stp->s.InLenErrCount;
356 		break;
357 
358 	case MAC_STAT_OERRORS:
359 		regno = KS_BASE + KS_ifHOutFifoovCount * sizeof (uint32_t);
360 		hw_stp->s.OutFifoovCount += nge_reg_get32(ngep, regno);
361 		regno = KS_BASE + KS_ifHOutLOCCount * sizeof (uint32_t);
362 		hw_stp->s.OutLOCCount += nge_reg_get32(ngep, regno);
363 		regno = KS_BASE + KS_ifHOutExDecCount * sizeof (uint32_t);
364 		hw_stp->s.OutExDecCount += nge_reg_get32(ngep, regno);
365 		regno = KS_BASE + KS_ifHOutRetryCount * sizeof (uint32_t);
366 		hw_stp->s.OutRetryCount += nge_reg_get32(ngep, regno);
367 		*val = hw_stp->s.OutFifoovCount +
368 		    hw_stp->s.OutLOCCount +
369 		    hw_stp->s.OutExDecCount +
370 		    hw_stp->s.OutRetryCount;
371 		break;
372 
373 	case MAC_STAT_COLLISIONS:
374 		regno = KS_BASE + KS_ifHOutColCount * sizeof (uint32_t);
375 		hw_stp->s.OutColCount += nge_reg_get32(ngep, regno);
376 		*val = hw_stp->s.OutColCount;
377 		break;
378 
379 	case MAC_STAT_RBYTES:
380 		*val = sw_stp->rbytes;
381 		break;
382 
383 	case MAC_STAT_IPACKETS:
384 		*val = sw_stp->recv_count;
385 		break;
386 
387 	case MAC_STAT_OBYTES:
388 		*val = sw_stp->obytes;
389 		break;
390 
391 	case MAC_STAT_OPACKETS:
392 		*val = sw_stp->xmit_count;
393 		break;
394 
395 	case ETHER_STAT_ALIGN_ERRORS:
396 		regno = KS_BASE + KS_ifHInAlignErrCount * sizeof (uint32_t);
397 		hw_stp->s.InAlignErrCount += nge_reg_get32(ngep, regno);
398 		*val = hw_stp->s.InAlignErrCount;
399 		break;
400 
401 	case ETHER_STAT_FCS_ERRORS:
402 		regno = KS_BASE + KS_ifHInFCSErrCount * sizeof (uint32_t);
403 		hw_stp->s.InFCSErrCount += nge_reg_get32(ngep, regno);
404 		*val = hw_stp->s.InFCSErrCount;
405 		break;
406 
407 	case ETHER_STAT_FIRST_COLLISIONS:
408 		regno = KS_BASE + KS_ifHOutZeroRetranCount * sizeof (uint32_t);
409 		hw_stp->s.OutZeroRetranCount += nge_reg_get32(ngep, regno);
410 		*val = hw_stp->s.OutZeroRetranCount;
411 		break;
412 
413 	case ETHER_STAT_MULTI_COLLISIONS:
414 		regno = KS_BASE + KS_ifHOutOneRetranCount * sizeof (uint32_t);
415 		hw_stp->s.OutOneRetranCount += nge_reg_get32(ngep, regno);
416 		regno = KS_BASE + KS_ifHOutMoreRetranCount * sizeof (uint32_t);
417 		hw_stp->s.OutMoreRetranCount += nge_reg_get32(ngep, regno);
418 		*val =  hw_stp->s.OutOneRetranCount +
419 		    hw_stp->s.OutMoreRetranCount;
420 		break;
421 
422 	case ETHER_STAT_DEFER_XMTS:
423 		regno = KS_BASE + KS_ifHOutExDecCount * sizeof (uint32_t);
424 		hw_stp->s.OutExDecCount += nge_reg_get32(ngep, regno);
425 		*val = hw_stp->s.OutExDecCount;
426 		break;
427 
428 	case ETHER_STAT_TX_LATE_COLLISIONS:
429 		regno = KS_BASE + KS_ifHOutColCount * sizeof (uint32_t);
430 		hw_stp->s.OutColCount += nge_reg_get32(ngep, regno);
431 		*val = hw_stp->s.OutColCount;
432 		break;
433 
434 	case ETHER_STAT_EX_COLLISIONS:
435 		regno = KS_BASE + KS_ifHOutOneRetranCount * sizeof (uint32_t);
436 		hw_stp->s.OutOneRetranCount += nge_reg_get32(ngep, regno);
437 		*val = hw_stp->s.OutOneRetranCount;
438 		break;
439 
440 	case ETHER_STAT_CARRIER_ERRORS:
441 		regno = KS_BASE + KS_ifHOutLOCCount * sizeof (uint32_t);
442 		hw_stp->s.OutLOCCount += nge_reg_get32(ngep, regno);
443 		*val = hw_stp->s.OutLOCCount;
444 		break;
445 
446 	case ETHER_STAT_TOOLONG_ERRORS:
447 		regno = KS_BASE + KS_ifHInOversizeErrCount * sizeof (uint32_t);
448 		hw_stp->s.InOversizeErrCount += nge_reg_get32(ngep, regno);
449 		*val = hw_stp->s.InOversizeErrCount;
450 		break;
451 
452 	case ETHER_STAT_XCVR_ADDR:
453 		*val = ngep->phy_xmii_addr;
454 		break;
455 
456 	case ETHER_STAT_XCVR_ID:
457 		*val = ngep->phy_id;
458 		break;
459 
460 	case ETHER_STAT_XCVR_INUSE:
461 		*val = XCVR_1000T;
462 		break;
463 
464 	case ETHER_STAT_CAP_1000FDX:
465 		*val = 1;
466 		break;
467 
468 	case ETHER_STAT_CAP_1000HDX:
469 		*val = 0;
470 		break;
471 
472 	case ETHER_STAT_CAP_100FDX:
473 		*val = 1;
474 		break;
475 
476 	case ETHER_STAT_CAP_100HDX:
477 		*val = 1;
478 		break;
479 
480 	case ETHER_STAT_CAP_10FDX:
481 		*val = 1;
482 		break;
483 
484 	case ETHER_STAT_CAP_10HDX:
485 		*val = 1;
486 		break;
487 
488 	case ETHER_STAT_CAP_ASMPAUSE:
489 		*val = 1;
490 		break;
491 
492 	case ETHER_STAT_CAP_PAUSE:
493 		*val = 1;
494 		break;
495 
496 	case ETHER_STAT_CAP_AUTONEG:
497 		*val = 1;
498 		break;
499 
500 	case ETHER_STAT_ADV_CAP_1000FDX:
501 		*val = ngep->param_adv_1000fdx;
502 		break;
503 
504 	case ETHER_STAT_ADV_CAP_1000HDX:
505 		*val = ngep->param_adv_1000hdx;
506 		break;
507 
508 	case ETHER_STAT_ADV_CAP_100FDX:
509 		*val = ngep->param_adv_100fdx;
510 		break;
511 
512 	case ETHER_STAT_ADV_CAP_100HDX:
513 		*val = ngep->param_adv_100hdx;
514 		break;
515 
516 	case ETHER_STAT_ADV_CAP_10FDX:
517 		*val = ngep->param_adv_10fdx;
518 		break;
519 
520 	case ETHER_STAT_ADV_CAP_10HDX:
521 		*val = ngep->param_adv_10hdx;
522 		break;
523 
524 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
525 		*val = ngep->param_adv_asym_pause;
526 		break;
527 
528 	case ETHER_STAT_ADV_CAP_PAUSE:
529 		*val = ngep->param_adv_pause;
530 		break;
531 
532 	case ETHER_STAT_ADV_CAP_AUTONEG:
533 		*val = ngep->param_adv_autoneg;
534 		break;
535 
536 	case ETHER_STAT_LP_CAP_1000FDX:
537 		*val = ngep->param_lp_1000fdx;
538 		break;
539 
540 	case ETHER_STAT_LP_CAP_1000HDX:
541 		*val = ngep->param_lp_1000hdx;
542 		break;
543 
544 	case ETHER_STAT_LP_CAP_100FDX:
545 		*val = ngep->param_lp_100fdx;
546 		break;
547 
548 	case ETHER_STAT_LP_CAP_100HDX:
549 		*val = ngep->param_lp_100hdx;
550 		break;
551 
552 	case ETHER_STAT_LP_CAP_10FDX:
553 		*val = ngep->param_lp_10fdx;
554 		break;
555 
556 	case ETHER_STAT_LP_CAP_10HDX:
557 		*val = ngep->param_lp_10hdx;
558 		break;
559 
560 	case ETHER_STAT_LP_CAP_ASMPAUSE:
561 		*val = ngep->param_lp_asym_pause;
562 		break;
563 
564 	case ETHER_STAT_LP_CAP_PAUSE:
565 		*val = ngep->param_lp_pause;
566 		break;
567 
568 	case ETHER_STAT_LP_CAP_AUTONEG:
569 		*val = ngep->param_lp_autoneg;
570 		break;
571 
572 	case ETHER_STAT_LINK_ASMPAUSE:
573 		*val = ngep->param_adv_asym_pause &&
574 		    ngep->param_lp_asym_pause &&
575 		    ngep->param_adv_pause != ngep->param_lp_pause;
576 		break;
577 
578 	case ETHER_STAT_LINK_PAUSE:
579 		*val = ngep->param_link_rx_pause;
580 		break;
581 
582 	case ETHER_STAT_LINK_AUTONEG:
583 		*val = ngep->param_link_autoneg;
584 		break;
585 
586 	case ETHER_STAT_LINK_DUPLEX:
587 		*val = ngep->param_link_duplex;
588 		break;
589 
590 	default:
591 		return (ENOTSUP);
592 	}
593 
594 	return (0);
595 }
596