xref: /illumos-gate/usr/src/uts/common/io/igb/igb_gld.c (revision 9164a50bf932130cbb5097a16f6986873ce0e6e5)
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(c) 2007-2010 Intel Corporation. All rights reserved.
24  */
25 
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
29  * Copyright 2014 Pluribus Networks Inc.
30  * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
31  * Copyright (c) 2017, Joyent, Inc.
32  * Copyright 2023 Oxide Computer Company
33  */
34 
35 #include "igb_sw.h"
36 
37 int
38 igb_m_stat(void *arg, uint_t stat, uint64_t *val)
39 {
40 	igb_t *igb = (igb_t *)arg;
41 	struct e1000_hw *hw = &igb->hw;
42 	igb_stat_t *igb_ks;
43 	uint32_t low_val, high_val;
44 
45 	igb_ks = (igb_stat_t *)igb->igb_ks->ks_data;
46 
47 	mutex_enter(&igb->gen_lock);
48 
49 	if (igb->igb_state & IGB_SUSPENDED) {
50 		mutex_exit(&igb->gen_lock);
51 		return (ECANCELED);
52 	}
53 
54 	switch (stat) {
55 	case MAC_STAT_IFSPEED:
56 		*val = igb->link_speed * 1000000ull;
57 		break;
58 
59 	case MAC_STAT_MULTIRCV:
60 		igb->stat_mprc += E1000_READ_REG(hw, E1000_MPRC);
61 		*val = igb->stat_mprc;
62 		break;
63 
64 	case MAC_STAT_BRDCSTRCV:
65 		igb->stat_bprc += E1000_READ_REG(hw, E1000_BPRC);
66 		*val = igb->stat_bprc;
67 		break;
68 
69 	case MAC_STAT_MULTIXMT:
70 		igb->stat_mptc += E1000_READ_REG(hw, E1000_MPTC);
71 		*val = igb->stat_mptc;
72 		break;
73 
74 	case MAC_STAT_BRDCSTXMT:
75 		igb->stat_bptc += E1000_READ_REG(hw, E1000_BPTC);
76 		*val = igb->stat_bptc;
77 		break;
78 
79 	case MAC_STAT_NORCVBUF:
80 		igb->stat_rnbc += E1000_READ_REG(hw, E1000_RNBC);
81 		*val = igb->stat_rnbc;
82 		break;
83 
84 	case MAC_STAT_IERRORS:
85 		igb->stat_rxerrc += E1000_READ_REG(hw, E1000_RXERRC);
86 		igb->stat_algnerrc += E1000_READ_REG(hw, E1000_ALGNERRC);
87 		igb_ks->rlec.value.ui64 +=
88 		    E1000_READ_REG(hw, E1000_RLEC);
89 		igb->stat_crcerrs += E1000_READ_REG(hw, E1000_CRCERRS);
90 		igb->stat_cexterr += E1000_READ_REG(hw, E1000_CEXTERR);
91 		*val = igb->stat_rxerrc +
92 		    igb->stat_algnerrc +
93 		    igb_ks->rlec.value.ui64 +
94 		    igb->stat_crcerrs +
95 		    igb->stat_cexterr;
96 		break;
97 
98 	case MAC_STAT_NOXMTBUF:
99 		*val = 0;
100 		break;
101 
102 	case MAC_STAT_OERRORS:
103 		igb->stat_ecol += E1000_READ_REG(hw, E1000_ECOL);
104 		*val = igb->stat_ecol;
105 		break;
106 
107 	case MAC_STAT_COLLISIONS:
108 		igb->stat_colc += E1000_READ_REG(hw, E1000_COLC);
109 		*val = igb->stat_colc;
110 		break;
111 
112 	case MAC_STAT_RBYTES:
113 		/*
114 		 * The 64-bit register will reset whenever the upper
115 		 * 32 bits are read. So we need to read the lower
116 		 * 32 bits first, then read the upper 32 bits.
117 		 */
118 		low_val = E1000_READ_REG(hw, E1000_TORL);
119 		high_val = E1000_READ_REG(hw, E1000_TORH);
120 		igb->stat_tor += (uint64_t)high_val << 32 | (uint64_t)low_val;
121 		*val = igb->stat_tor;
122 		break;
123 
124 	case MAC_STAT_IPACKETS:
125 		igb->stat_tpr += E1000_READ_REG(hw, E1000_TPR);
126 		*val = igb->stat_tpr;
127 		break;
128 
129 	case MAC_STAT_OBYTES:
130 		/*
131 		 * The 64-bit register will reset whenever the upper
132 		 * 32 bits are read. So we need to read the lower
133 		 * 32 bits first, then read the upper 32 bits.
134 		 */
135 		low_val = E1000_READ_REG(hw, E1000_TOTL);
136 		high_val = E1000_READ_REG(hw, E1000_TOTH);
137 		igb->stat_tot += (uint64_t)high_val << 32 | (uint64_t)low_val;
138 		*val = igb->stat_tot;
139 		break;
140 
141 	case MAC_STAT_OPACKETS:
142 		igb->stat_tpt += E1000_READ_REG(hw, E1000_TPT);
143 		*val = igb->stat_tpt;
144 		break;
145 
146 	/* RFC 1643 stats */
147 	case ETHER_STAT_ALIGN_ERRORS:
148 		igb->stat_algnerrc += E1000_READ_REG(hw, E1000_ALGNERRC);
149 		*val = igb->stat_algnerrc;
150 		break;
151 
152 	case ETHER_STAT_FCS_ERRORS:
153 		igb->stat_crcerrs += E1000_READ_REG(hw, E1000_CRCERRS);
154 		*val = igb->stat_crcerrs;
155 		break;
156 
157 	case ETHER_STAT_FIRST_COLLISIONS:
158 		igb->stat_scc += E1000_READ_REG(hw, E1000_SCC);
159 		*val = igb->stat_scc;
160 		break;
161 
162 	case ETHER_STAT_MULTI_COLLISIONS:
163 		igb->stat_mcc += E1000_READ_REG(hw, E1000_MCC);
164 		*val = igb->stat_mcc;
165 		break;
166 
167 	case ETHER_STAT_SQE_ERRORS:
168 		igb->stat_sec += E1000_READ_REG(hw, E1000_SEC);
169 		*val = igb->stat_sec;
170 		break;
171 
172 	case ETHER_STAT_DEFER_XMTS:
173 		igb->stat_dc += E1000_READ_REG(hw, E1000_DC);
174 		*val = igb->stat_dc;
175 		break;
176 
177 	case ETHER_STAT_TX_LATE_COLLISIONS:
178 		igb->stat_latecol += E1000_READ_REG(hw, E1000_LATECOL);
179 		*val = igb->stat_latecol;
180 		break;
181 
182 	case ETHER_STAT_EX_COLLISIONS:
183 		igb->stat_ecol += E1000_READ_REG(hw, E1000_ECOL);
184 		*val = igb->stat_ecol;
185 		break;
186 
187 	case ETHER_STAT_MACXMT_ERRORS:
188 		igb->stat_ecol += E1000_READ_REG(hw, E1000_ECOL);
189 		*val = igb->stat_ecol;
190 		break;
191 
192 	case ETHER_STAT_CARRIER_ERRORS:
193 		igb->stat_cexterr += E1000_READ_REG(hw, E1000_CEXTERR);
194 		*val = igb->stat_cexterr;
195 		break;
196 
197 	case ETHER_STAT_TOOLONG_ERRORS:
198 		igb->stat_roc += E1000_READ_REG(hw, E1000_ROC);
199 		*val = igb->stat_roc;
200 		break;
201 
202 	case ETHER_STAT_MACRCV_ERRORS:
203 		igb->stat_rxerrc += E1000_READ_REG(hw, E1000_RXERRC);
204 		*val = igb->stat_rxerrc;
205 		break;
206 
207 	/* MII/GMII stats */
208 	case ETHER_STAT_XCVR_ADDR:
209 		*val = hw->phy.addr;
210 		break;
211 
212 	case ETHER_STAT_XCVR_ID:
213 		*val = hw->phy.id | hw->phy.revision;
214 		break;
215 
216 	case ETHER_STAT_XCVR_INUSE:
217 		*val = (uint64_t)e1000_link_to_media(hw, igb->link_speed);
218 		break;
219 
220 	case ETHER_STAT_CAP_1000FDX:
221 		*val = igb->param_1000fdx_cap;
222 		break;
223 
224 	case ETHER_STAT_CAP_1000HDX:
225 		*val = igb->param_1000hdx_cap;
226 		break;
227 
228 	case ETHER_STAT_CAP_100FDX:
229 		*val = igb->param_100fdx_cap;
230 		break;
231 
232 	case ETHER_STAT_CAP_100HDX:
233 		*val = igb->param_100hdx_cap;
234 		break;
235 
236 	case ETHER_STAT_CAP_10FDX:
237 		*val = igb->param_10fdx_cap;
238 		break;
239 
240 	case ETHER_STAT_CAP_10HDX:
241 		*val = igb->param_10hdx_cap;
242 		break;
243 
244 	case ETHER_STAT_CAP_ASMPAUSE:
245 		*val = igb->param_asym_pause_cap;
246 		break;
247 
248 	case ETHER_STAT_CAP_PAUSE:
249 		*val = igb->param_pause_cap;
250 		break;
251 
252 	case ETHER_STAT_CAP_AUTONEG:
253 		*val = igb->param_autoneg_cap;
254 		break;
255 
256 	case ETHER_STAT_ADV_CAP_1000FDX:
257 		*val = igb->param_adv_1000fdx_cap;
258 		break;
259 
260 	case ETHER_STAT_ADV_CAP_1000HDX:
261 		*val = igb->param_adv_1000hdx_cap;
262 		break;
263 
264 	case ETHER_STAT_ADV_CAP_100FDX:
265 		*val = igb->param_adv_100fdx_cap;
266 		break;
267 
268 	case ETHER_STAT_ADV_CAP_100HDX:
269 		*val = igb->param_adv_100hdx_cap;
270 		break;
271 
272 	case ETHER_STAT_ADV_CAP_10FDX:
273 		*val = igb->param_adv_10fdx_cap;
274 		break;
275 
276 	case ETHER_STAT_ADV_CAP_10HDX:
277 		*val = igb->param_adv_10hdx_cap;
278 		break;
279 
280 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
281 		*val = igb->param_adv_asym_pause_cap;
282 		break;
283 
284 	case ETHER_STAT_ADV_CAP_PAUSE:
285 		*val = igb->param_adv_pause_cap;
286 		break;
287 
288 	case ETHER_STAT_ADV_CAP_AUTONEG:
289 		*val = hw->mac.autoneg;
290 		break;
291 
292 	case ETHER_STAT_LP_CAP_1000FDX:
293 		*val = igb->param_lp_1000fdx_cap;
294 		break;
295 
296 	case ETHER_STAT_LP_CAP_1000HDX:
297 		*val = igb->param_lp_1000hdx_cap;
298 		break;
299 
300 	case ETHER_STAT_LP_CAP_100FDX:
301 		*val = igb->param_lp_100fdx_cap;
302 		break;
303 
304 	case ETHER_STAT_LP_CAP_100HDX:
305 		*val = igb->param_lp_100hdx_cap;
306 		break;
307 
308 	case ETHER_STAT_LP_CAP_10FDX:
309 		*val = igb->param_lp_10fdx_cap;
310 		break;
311 
312 	case ETHER_STAT_LP_CAP_10HDX:
313 		*val = igb->param_lp_10hdx_cap;
314 		break;
315 
316 	case ETHER_STAT_LP_CAP_ASMPAUSE:
317 		*val = igb->param_lp_asym_pause_cap;
318 		break;
319 
320 	case ETHER_STAT_LP_CAP_PAUSE:
321 		*val = igb->param_lp_pause_cap;
322 		break;
323 
324 	case ETHER_STAT_LP_CAP_AUTONEG:
325 		*val = igb->param_lp_autoneg_cap;
326 		break;
327 
328 	case ETHER_STAT_LINK_ASMPAUSE:
329 		*val = igb->param_asym_pause_cap;
330 		break;
331 
332 	case ETHER_STAT_LINK_PAUSE:
333 		*val = igb->param_pause_cap;
334 		break;
335 
336 	case ETHER_STAT_LINK_AUTONEG:
337 		*val = hw->mac.autoneg;
338 		break;
339 
340 	case ETHER_STAT_LINK_DUPLEX:
341 		*val = (igb->link_duplex == FULL_DUPLEX) ?
342 		    LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
343 		break;
344 
345 	case ETHER_STAT_TOOSHORT_ERRORS:
346 		igb->stat_ruc += E1000_READ_REG(hw, E1000_RUC);
347 		*val = igb->stat_ruc;
348 		break;
349 
350 	case ETHER_STAT_CAP_REMFAULT:
351 		*val = igb->param_rem_fault;
352 		break;
353 
354 	case ETHER_STAT_ADV_REMFAULT:
355 		*val = igb->param_adv_rem_fault;
356 		break;
357 
358 	case ETHER_STAT_LP_REMFAULT:
359 		*val = igb->param_lp_rem_fault;
360 		break;
361 
362 	case ETHER_STAT_JABBER_ERRORS:
363 		igb->stat_rjc += E1000_READ_REG(hw, E1000_RJC);
364 		*val = igb->stat_rjc;
365 		break;
366 
367 	case ETHER_STAT_CAP_100T4:
368 		*val = igb->param_100t4_cap;
369 		break;
370 
371 	case ETHER_STAT_ADV_CAP_100T4:
372 		*val = igb->param_adv_100t4_cap;
373 		break;
374 
375 	case ETHER_STAT_LP_CAP_100T4:
376 		*val = igb->param_lp_100t4_cap;
377 		break;
378 
379 	default:
380 		mutex_exit(&igb->gen_lock);
381 		return (ENOTSUP);
382 	}
383 
384 	mutex_exit(&igb->gen_lock);
385 
386 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
387 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
388 		return (EIO);
389 	}
390 
391 	return (0);
392 }
393 
394 /*
395  * Bring the device out of the reset/quiesced state that it
396  * was in when the interface was registered.
397  */
398 int
399 igb_m_start(void *arg)
400 {
401 	igb_t *igb = (igb_t *)arg;
402 
403 	mutex_enter(&igb->gen_lock);
404 
405 	if (igb->igb_state & IGB_SUSPENDED) {
406 		mutex_exit(&igb->gen_lock);
407 		return (ECANCELED);
408 	}
409 
410 	if (igb_start(igb, B_TRUE) != IGB_SUCCESS) {
411 		mutex_exit(&igb->gen_lock);
412 		return (EIO);
413 	}
414 
415 	atomic_or_32(&igb->igb_state, IGB_STARTED);
416 
417 	mutex_exit(&igb->gen_lock);
418 
419 	/*
420 	 * Enable and start the watchdog timer
421 	 */
422 	igb_enable_watchdog_timer(igb);
423 
424 	return (0);
425 }
426 
427 /*
428  * Stop the device and put it in a reset/quiesced state such
429  * that the interface can be unregistered.
430  */
431 void
432 igb_m_stop(void *arg)
433 {
434 	igb_t *igb = (igb_t *)arg;
435 
436 	mutex_enter(&igb->gen_lock);
437 
438 	if (igb->igb_state & IGB_SUSPENDED) {
439 		mutex_exit(&igb->gen_lock);
440 		return;
441 	}
442 
443 	atomic_and_32(&igb->igb_state, ~IGB_STARTED);
444 
445 	igb_stop(igb, B_TRUE);
446 
447 	mutex_exit(&igb->gen_lock);
448 
449 	/*
450 	 * Disable and stop the watchdog timer
451 	 */
452 	igb_disable_watchdog_timer(igb);
453 }
454 
455 /*
456  * Set the promiscuity of the device.
457  */
458 int
459 igb_m_promisc(void *arg, boolean_t on)
460 {
461 	igb_t *igb = (igb_t *)arg;
462 	uint32_t reg_val;
463 
464 	mutex_enter(&igb->gen_lock);
465 
466 	if (igb->igb_state & IGB_SUSPENDED) {
467 		mutex_exit(&igb->gen_lock);
468 		return (ECANCELED);
469 	}
470 
471 	reg_val = E1000_READ_REG(&igb->hw, E1000_RCTL);
472 
473 	if (on)
474 		reg_val |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
475 	else
476 		reg_val &= (~(E1000_RCTL_UPE | E1000_RCTL_MPE));
477 
478 	E1000_WRITE_REG(&igb->hw, E1000_RCTL, reg_val);
479 
480 	mutex_exit(&igb->gen_lock);
481 
482 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
483 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
484 		return (EIO);
485 	}
486 
487 	return (0);
488 }
489 
490 /*
491  * Add/remove the addresses to/from the set of multicast
492  * addresses for which the device will receive packets.
493  */
494 int
495 igb_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
496 {
497 	igb_t *igb = (igb_t *)arg;
498 	int result;
499 
500 	mutex_enter(&igb->gen_lock);
501 
502 	if (igb->igb_state & IGB_SUSPENDED) {
503 		mutex_exit(&igb->gen_lock);
504 		return (ECANCELED);
505 	}
506 
507 	result = (add) ? igb_multicst_add(igb, mcst_addr)
508 	    : igb_multicst_remove(igb, mcst_addr);
509 
510 	mutex_exit(&igb->gen_lock);
511 
512 	return (result);
513 }
514 
515 /*
516  * Pass on M_IOCTL messages passed to the DLD, and support
517  * private IOCTLs for debugging and ndd.
518  */
519 void
520 igb_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
521 {
522 	igb_t *igb = (igb_t *)arg;
523 	struct iocblk *iocp;
524 	enum ioc_reply status;
525 
526 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
527 	iocp->ioc_error = 0;
528 
529 	mutex_enter(&igb->gen_lock);
530 	if (igb->igb_state & IGB_SUSPENDED) {
531 		mutex_exit(&igb->gen_lock);
532 		miocnak(q, mp, 0, EINVAL);
533 		return;
534 	}
535 	mutex_exit(&igb->gen_lock);
536 
537 	switch (iocp->ioc_cmd) {
538 	case LB_GET_INFO_SIZE:
539 	case LB_GET_INFO:
540 	case LB_GET_MODE:
541 	case LB_SET_MODE:
542 		status = igb_loopback_ioctl(igb, iocp, mp);
543 		break;
544 
545 	default:
546 		status = IOC_INVAL;
547 		break;
548 	}
549 
550 	/*
551 	 * Decide how to reply
552 	 */
553 	switch (status) {
554 	default:
555 	case IOC_INVAL:
556 		/*
557 		 * Error, reply with a NAK and EINVAL or the specified error
558 		 */
559 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
560 		    EINVAL : iocp->ioc_error);
561 		break;
562 
563 	case IOC_DONE:
564 		/*
565 		 * OK, reply already sent
566 		 */
567 		break;
568 
569 	case IOC_ACK:
570 		/*
571 		 * OK, reply with an ACK
572 		 */
573 		miocack(q, mp, 0, 0);
574 		break;
575 
576 	case IOC_REPLY:
577 		/*
578 		 * OK, send prepared reply as ACK or NAK
579 		 */
580 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
581 		    M_IOCACK : M_IOCNAK;
582 		qreply(q, mp);
583 		break;
584 	}
585 }
586 
587 /*
588  * Add a MAC address to the target RX group.
589  */
590 static int
591 igb_addmac(void *arg, const uint8_t *mac_addr)
592 {
593 	igb_rx_group_t *rx_group = (igb_rx_group_t *)arg;
594 	igb_t *igb = rx_group->igb;
595 	struct e1000_hw *hw = &igb->hw;
596 	int i, slot;
597 
598 	mutex_enter(&igb->gen_lock);
599 
600 	if (igb->igb_state & IGB_SUSPENDED) {
601 		mutex_exit(&igb->gen_lock);
602 		return (ECANCELED);
603 	}
604 
605 	if (igb->unicst_avail == 0) {
606 		/* no slots available */
607 		mutex_exit(&igb->gen_lock);
608 		return (ENOSPC);
609 	}
610 
611 	/*
612 	 * The slots from 0 to igb->num_rx_groups are reserved slots which
613 	 * are 1 to 1 mapped with group index directly. The other slots are
614 	 * shared between the all of groups. While adding a MAC address,
615 	 * it will try to set the reserved slots first, then the shared slots.
616 	 */
617 	slot = -1;
618 	if (igb->unicst_addr[rx_group->index].mac.set == 1) {
619 		/*
620 		 * The reserved slot for current group is used, find the free
621 		 * slots in the shared slots.
622 		 */
623 		for (i = igb->num_rx_groups; i < igb->unicst_total; i++) {
624 			if (igb->unicst_addr[i].mac.set == 0) {
625 				slot = i;
626 				break;
627 			}
628 		}
629 	} else
630 		slot = rx_group->index;
631 
632 	if (slot == -1) {
633 		/* no slots available in the shared slots */
634 		mutex_exit(&igb->gen_lock);
635 		return (ENOSPC);
636 	}
637 
638 	/* Set VMDq according to the mode supported by hardware. */
639 	e1000_rar_set_vmdq(hw, mac_addr, slot, igb->vmdq_mode, rx_group->index);
640 
641 	bcopy(mac_addr, igb->unicst_addr[slot].mac.addr, ETHERADDRL);
642 	igb->unicst_addr[slot].mac.group_index = rx_group->index;
643 	igb->unicst_addr[slot].mac.set = 1;
644 	igb->unicst_avail--;
645 
646 	mutex_exit(&igb->gen_lock);
647 
648 	return (0);
649 }
650 
651 /*
652  * Remove a MAC address from the specified RX group.
653  */
654 static int
655 igb_remmac(void *arg, const uint8_t *mac_addr)
656 {
657 	igb_rx_group_t *rx_group = (igb_rx_group_t *)arg;
658 	igb_t *igb = rx_group->igb;
659 	struct e1000_hw *hw = &igb->hw;
660 	int slot;
661 
662 	mutex_enter(&igb->gen_lock);
663 
664 	if (igb->igb_state & IGB_SUSPENDED) {
665 		mutex_exit(&igb->gen_lock);
666 		return (ECANCELED);
667 	}
668 
669 	slot = igb_unicst_find(igb, mac_addr);
670 	if (slot == -1) {
671 		mutex_exit(&igb->gen_lock);
672 		return (EINVAL);
673 	}
674 
675 	if (igb->unicst_addr[slot].mac.set == 0) {
676 		mutex_exit(&igb->gen_lock);
677 		return (EINVAL);
678 	}
679 
680 	/* Clear the MAC ddress in the slot */
681 	e1000_rar_clear(hw, slot);
682 	igb->unicst_addr[slot].mac.set = 0;
683 	igb->unicst_avail++;
684 
685 	mutex_exit(&igb->gen_lock);
686 
687 	return (0);
688 }
689 
690 /*
691  * Enable interrupt on the specificed rx ring.
692  */
693 int
694 igb_rx_ring_intr_enable(mac_intr_handle_t intrh)
695 {
696 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)intrh;
697 	igb_t *igb = rx_ring->igb;
698 	struct e1000_hw *hw = &igb->hw;
699 	uint32_t index = rx_ring->index;
700 
701 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
702 		/* Interrupt enabling for MSI-X */
703 		igb->eims_mask |= (E1000_EICR_RX_QUEUE0 << index);
704 		E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
705 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
706 	} else {
707 		ASSERT(index == 0);
708 		/* Interrupt enabling for MSI and legacy */
709 		igb->ims_mask |= E1000_IMS_RXT0;
710 		E1000_WRITE_REG(hw, E1000_IMS, igb->ims_mask);
711 	}
712 
713 	E1000_WRITE_FLUSH(hw);
714 
715 	return (0);
716 }
717 
718 /*
719  * Disable interrupt on the specificed rx ring.
720  */
721 int
722 igb_rx_ring_intr_disable(mac_intr_handle_t intrh)
723 {
724 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)intrh;
725 	igb_t *igb = rx_ring->igb;
726 	struct e1000_hw *hw = &igb->hw;
727 	uint32_t index = rx_ring->index;
728 
729 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
730 		/* Interrupt disabling for MSI-X */
731 		igb->eims_mask &= ~(E1000_EICR_RX_QUEUE0 << index);
732 		E1000_WRITE_REG(hw, E1000_EIMC,
733 		    (E1000_EICR_RX_QUEUE0 << index));
734 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
735 	} else {
736 		ASSERT(index == 0);
737 		/* Interrupt disabling for MSI and legacy */
738 		igb->ims_mask &= ~E1000_IMS_RXT0;
739 		E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_RXT0);
740 	}
741 
742 	E1000_WRITE_FLUSH(hw);
743 
744 	return (0);
745 }
746 
747 /*
748  * Get the global ring index by a ring index within a group.
749  */
750 int
751 igb_get_rx_ring_index(igb_t *igb, int gindex, int rindex)
752 {
753 	igb_rx_ring_t *rx_ring;
754 	int i;
755 
756 	for (i = 0; i < igb->num_rx_rings; i++) {
757 		rx_ring = &igb->rx_rings[i];
758 		if (rx_ring->group_index == gindex)
759 			rindex--;
760 		if (rindex < 0)
761 			return (i);
762 	}
763 
764 	return (-1);
765 }
766 
767 static int
768 igb_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
769 {
770 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)rh;
771 
772 	mutex_enter(&rx_ring->rx_lock);
773 	rx_ring->ring_gen_num = mr_gen_num;
774 	mutex_exit(&rx_ring->rx_lock);
775 	return (0);
776 }
777 
778 /*
779  * Callback funtion for MAC layer to register all rings.
780  */
781 /* ARGSUSED */
782 void
783 igb_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
784     const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
785 {
786 	igb_t *igb = (igb_t *)arg;
787 	mac_intr_t *mintr = &infop->mri_intr;
788 
789 	switch (rtype) {
790 	case MAC_RING_TYPE_RX: {
791 		igb_rx_ring_t *rx_ring;
792 		int global_index;
793 
794 		/*
795 		 * 'index' is the ring index within the group.
796 		 * We need the global ring index by searching in group.
797 		 */
798 		global_index = igb_get_rx_ring_index(igb, rg_index, index);
799 
800 		ASSERT(global_index >= 0);
801 
802 		rx_ring = &igb->rx_rings[global_index];
803 		rx_ring->ring_handle = rh;
804 
805 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
806 		infop->mri_start = igb_ring_start;
807 		infop->mri_stop = NULL;
808 		infop->mri_poll = (mac_ring_poll_t)igb_rx_ring_poll;
809 		infop->mri_stat = igb_rx_ring_stat;
810 
811 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
812 		mintr->mi_enable = igb_rx_ring_intr_enable;
813 		mintr->mi_disable = igb_rx_ring_intr_disable;
814 		if (igb->intr_type & (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
815 			mintr->mi_ddi_handle =
816 			    igb->htable[rx_ring->intr_vector];
817 		}
818 		break;
819 	}
820 	case MAC_RING_TYPE_TX: {
821 		ASSERT(index < igb->num_tx_rings);
822 
823 		igb_tx_ring_t *tx_ring = &igb->tx_rings[index];
824 		tx_ring->ring_handle = rh;
825 
826 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
827 		infop->mri_start = NULL;
828 		infop->mri_stop = NULL;
829 		infop->mri_tx = igb_tx_ring_send;
830 		infop->mri_stat = igb_tx_ring_stat;
831 		if (igb->intr_type & (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
832 			mintr->mi_ddi_handle =
833 			    igb->htable[tx_ring->intr_vector];
834 		}
835 		break;
836 	}
837 	default:
838 		break;
839 	}
840 }
841 
842 void
843 igb_fill_group(void *arg, mac_ring_type_t rtype, const int index,
844     mac_group_info_t *infop, mac_group_handle_t gh)
845 {
846 	igb_t *igb = (igb_t *)arg;
847 
848 	switch (rtype) {
849 	case MAC_RING_TYPE_RX: {
850 		igb_rx_group_t *rx_group;
851 
852 		ASSERT((index >= 0) && (index < igb->num_rx_groups));
853 
854 		rx_group = &igb->rx_groups[index];
855 		rx_group->group_handle = gh;
856 
857 		infop->mgi_driver = (mac_group_driver_t)rx_group;
858 		infop->mgi_start = NULL;
859 		infop->mgi_stop = NULL;
860 		infop->mgi_addmac = igb_addmac;
861 		infop->mgi_remmac = igb_remmac;
862 		infop->mgi_count = (igb->num_rx_rings / igb->num_rx_groups);
863 
864 		break;
865 	}
866 	case MAC_RING_TYPE_TX:
867 		break;
868 	default:
869 		break;
870 	}
871 }
872 
873 static int
874 igb_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
875 {
876 	igb_t *igb = arg;
877 
878 	if (flags != 0)
879 		return (EINVAL);
880 
881 	if (mode != MAC_LED_DEFAULT &&
882 	    mode != MAC_LED_IDENT &&
883 	    mode != MAC_LED_OFF &&
884 	    mode != MAC_LED_ON)
885 		return (ENOTSUP);
886 
887 	if (mode != MAC_LED_DEFAULT && !igb->igb_led_setup) {
888 		if (e1000_setup_led(&igb->hw) != E1000_SUCCESS)
889 			return (EIO);
890 
891 		igb->igb_led_setup = B_TRUE;
892 	}
893 
894 	switch (mode) {
895 	case MAC_LED_DEFAULT:
896 		if (igb->igb_led_setup) {
897 			if (e1000_cleanup_led(&igb->hw) != E1000_SUCCESS)
898 				return (EIO);
899 			igb->igb_led_setup = B_FALSE;
900 		}
901 		break;
902 	case MAC_LED_IDENT:
903 		if (e1000_blink_led(&igb->hw) != E1000_SUCCESS)
904 			return (EIO);
905 		break;
906 	case MAC_LED_OFF:
907 		if (e1000_led_off(&igb->hw) != E1000_SUCCESS)
908 			return (EIO);
909 		break;
910 	case MAC_LED_ON:
911 		if (e1000_led_on(&igb->hw) != E1000_SUCCESS)
912 			return (EIO);
913 		break;
914 	default:
915 		return (ENOTSUP);
916 	}
917 
918 	return (0);
919 }
920 
921 /*
922  * Obtain the MAC's capabilities and associated data from
923  * the driver.
924  */
925 boolean_t
926 igb_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
927 {
928 	igb_t *igb = (igb_t *)arg;
929 
930 	switch (cap) {
931 	case MAC_CAPAB_HCKSUM: {
932 		uint32_t *tx_hcksum_flags = cap_data;
933 
934 		/*
935 		 * We advertise our capabilities only if tx hcksum offload is
936 		 * enabled.  On receive, the stack will accept checksummed
937 		 * packets anyway, even if we haven't said we can deliver
938 		 * them.
939 		 */
940 		if (!igb->tx_hcksum_enable)
941 			return (B_FALSE);
942 
943 		*tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
944 		break;
945 	}
946 	case MAC_CAPAB_LSO: {
947 		mac_capab_lso_t *cap_lso = cap_data;
948 
949 		if (igb->lso_enable) {
950 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4 |
951 			    LSO_TX_BASIC_TCP_IPV6;
952 			cap_lso->lso_basic_tcp_ipv4.lso_max = IGB_LSO_MAXLEN;
953 			cap_lso->lso_basic_tcp_ipv6.lso_max = IGB_LSO_MAXLEN;
954 			break;
955 		} else {
956 			return (B_FALSE);
957 		}
958 	}
959 	case MAC_CAPAB_RINGS: {
960 		mac_capab_rings_t *cap_rings = cap_data;
961 
962 		switch (cap_rings->mr_type) {
963 		case MAC_RING_TYPE_RX:
964 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
965 			cap_rings->mr_rnum = igb->num_rx_rings;
966 			cap_rings->mr_gnum = igb->num_rx_groups;
967 			cap_rings->mr_rget = igb_fill_ring;
968 			cap_rings->mr_gget = igb_fill_group;
969 			cap_rings->mr_gaddring = NULL;
970 			cap_rings->mr_gremring = NULL;
971 
972 			break;
973 		case MAC_RING_TYPE_TX:
974 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
975 			cap_rings->mr_rnum = igb->num_tx_rings;
976 			cap_rings->mr_gnum = 0;
977 			cap_rings->mr_rget = igb_fill_ring;
978 			cap_rings->mr_gget = NULL;
979 
980 			break;
981 		default:
982 			break;
983 		}
984 		break;
985 	}
986 
987 	case MAC_CAPAB_LED: {
988 		mac_capab_led_t *cap_led = cap_data;
989 
990 		cap_led->mcl_flags = 0;
991 		cap_led->mcl_modes = MAC_LED_DEFAULT;
992 		if (igb->hw.mac.ops.blink_led != NULL &&
993 		    igb->hw.mac.ops.blink_led != e1000_null_ops_generic) {
994 			cap_led->mcl_modes |= MAC_LED_IDENT;
995 		}
996 		if (igb->hw.mac.ops.led_off != NULL &&
997 		    igb->hw.mac.ops.led_off != e1000_null_ops_generic) {
998 			cap_led->mcl_modes |= MAC_LED_OFF;
999 		}
1000 		if (igb->hw.mac.ops.led_on != NULL &&
1001 		    igb->hw.mac.ops.led_on != e1000_null_ops_generic) {
1002 			cap_led->mcl_modes |= MAC_LED_ON;
1003 		}
1004 		cap_led->mcl_set = igb_led_set;
1005 		break;
1006 	}
1007 
1008 	default:
1009 		return (B_FALSE);
1010 	}
1011 	return (B_TRUE);
1012 }
1013 
1014 int
1015 igb_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1016     uint_t pr_valsize, const void *pr_val)
1017 {
1018 	igb_t *igb = (igb_t *)arg;
1019 	struct e1000_hw *hw = &igb->hw;
1020 	int err = 0;
1021 	uint32_t flow_control;
1022 	uint32_t cur_mtu, new_mtu;
1023 	uint32_t rx_size;
1024 	uint32_t tx_size;
1025 
1026 	mutex_enter(&igb->gen_lock);
1027 	if (igb->igb_state & IGB_SUSPENDED) {
1028 		mutex_exit(&igb->gen_lock);
1029 		return (ECANCELED);
1030 	}
1031 
1032 	if (igb->loopback_mode != IGB_LB_NONE && igb_param_locked(pr_num)) {
1033 		/*
1034 		 * All en_* parameters are locked (read-only)
1035 		 * while the device is in any sort of loopback mode.
1036 		 */
1037 		mutex_exit(&igb->gen_lock);
1038 		return (EBUSY);
1039 	}
1040 
1041 	switch (pr_num) {
1042 	case MAC_PROP_EN_1000FDX_CAP:
1043 		/* read/write on copper, read-only on serdes */
1044 		if (hw->phy.media_type != e1000_media_type_copper) {
1045 			err = ENOTSUP;
1046 			break;
1047 		}
1048 		igb->param_en_1000fdx_cap = *(uint8_t *)pr_val;
1049 		igb->param_adv_1000fdx_cap = *(uint8_t *)pr_val;
1050 		goto setup_link;
1051 	case MAC_PROP_EN_100FDX_CAP:
1052 		if (hw->phy.media_type != e1000_media_type_copper) {
1053 			err = ENOTSUP;
1054 			break;
1055 		}
1056 		igb->param_en_100fdx_cap = *(uint8_t *)pr_val;
1057 		igb->param_adv_100fdx_cap = *(uint8_t *)pr_val;
1058 		goto setup_link;
1059 	case MAC_PROP_EN_100HDX_CAP:
1060 		if (hw->phy.media_type != e1000_media_type_copper) {
1061 			err = ENOTSUP;
1062 			break;
1063 		}
1064 		igb->param_en_100hdx_cap = *(uint8_t *)pr_val;
1065 		igb->param_adv_100hdx_cap = *(uint8_t *)pr_val;
1066 		goto setup_link;
1067 	case MAC_PROP_EN_10FDX_CAP:
1068 		if (hw->phy.media_type != e1000_media_type_copper) {
1069 			err = ENOTSUP;
1070 			break;
1071 		}
1072 		igb->param_en_10fdx_cap = *(uint8_t *)pr_val;
1073 		igb->param_adv_10fdx_cap = *(uint8_t *)pr_val;
1074 		goto setup_link;
1075 	case MAC_PROP_EN_10HDX_CAP:
1076 		if (hw->phy.media_type != e1000_media_type_copper) {
1077 			err = ENOTSUP;
1078 			break;
1079 		}
1080 		igb->param_en_10hdx_cap = *(uint8_t *)pr_val;
1081 		igb->param_adv_10hdx_cap = *(uint8_t *)pr_val;
1082 		goto setup_link;
1083 	case MAC_PROP_AUTONEG:
1084 		if (hw->phy.media_type != e1000_media_type_copper) {
1085 			err = ENOTSUP;
1086 			break;
1087 		}
1088 		igb->param_adv_autoneg_cap = *(uint8_t *)pr_val;
1089 		goto setup_link;
1090 	case MAC_PROP_FLOWCTRL:
1091 		bcopy(pr_val, &flow_control, sizeof (flow_control));
1092 
1093 		switch (flow_control) {
1094 		default:
1095 			err = EINVAL;
1096 			break;
1097 		case LINK_FLOWCTRL_NONE:
1098 			hw->fc.requested_mode = e1000_fc_none;
1099 			break;
1100 		case LINK_FLOWCTRL_RX:
1101 			hw->fc.requested_mode = e1000_fc_rx_pause;
1102 			break;
1103 		case LINK_FLOWCTRL_TX:
1104 			hw->fc.requested_mode = e1000_fc_tx_pause;
1105 			break;
1106 		case LINK_FLOWCTRL_BI:
1107 			hw->fc.requested_mode = e1000_fc_full;
1108 			break;
1109 		}
1110 setup_link:
1111 		if (err == 0) {
1112 			if (igb_setup_link(igb, B_TRUE) != IGB_SUCCESS)
1113 				err = EINVAL;
1114 		}
1115 		break;
1116 	case MAC_PROP_ADV_1000FDX_CAP:
1117 	case MAC_PROP_ADV_1000HDX_CAP:
1118 	case MAC_PROP_ADV_100T4_CAP:
1119 	case MAC_PROP_ADV_100FDX_CAP:
1120 	case MAC_PROP_ADV_100HDX_CAP:
1121 	case MAC_PROP_ADV_10FDX_CAP:
1122 	case MAC_PROP_ADV_10HDX_CAP:
1123 	case MAC_PROP_EN_1000HDX_CAP:
1124 	case MAC_PROP_EN_100T4_CAP:
1125 	case MAC_PROP_STATUS:
1126 	case MAC_PROP_SPEED:
1127 	case MAC_PROP_DUPLEX:
1128 	case MAC_PROP_MEDIA:
1129 		err = ENOTSUP; /* read-only prop. Can't set this. */
1130 		break;
1131 	case MAC_PROP_MTU:
1132 		/* adapter must be stopped for an MTU change */
1133 		if (igb->igb_state & IGB_STARTED) {
1134 			err = EBUSY;
1135 			break;
1136 		}
1137 
1138 		cur_mtu = igb->default_mtu;
1139 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
1140 		if (new_mtu == cur_mtu) {
1141 			err = 0;
1142 			break;
1143 		}
1144 
1145 		if (new_mtu < MIN_MTU || new_mtu > MAX_MTU) {
1146 			err = EINVAL;
1147 			break;
1148 		}
1149 
1150 		err = mac_maxsdu_update(igb->mac_hdl, new_mtu);
1151 		if (err == 0) {
1152 			igb->default_mtu = new_mtu;
1153 			igb->max_frame_size = igb->default_mtu +
1154 			    sizeof (struct ether_vlan_header) + ETHERFCSL;
1155 
1156 			/*
1157 			 * Set rx buffer size
1158 			 */
1159 			rx_size = igb->max_frame_size + IPHDR_ALIGN_ROOM;
1160 			igb->rx_buf_size = ((rx_size >> 10) + ((rx_size &
1161 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
1162 
1163 			/*
1164 			 * Set tx buffer size
1165 			 */
1166 			tx_size = igb->max_frame_size;
1167 			igb->tx_buf_size = ((tx_size >> 10) + ((tx_size &
1168 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
1169 		}
1170 		break;
1171 	case MAC_PROP_PRIVATE:
1172 		err = igb_set_priv_prop(igb, pr_name, pr_valsize, pr_val);
1173 		break;
1174 	default:
1175 		err = ENOTSUP;
1176 		break;
1177 	}
1178 
1179 	mutex_exit(&igb->gen_lock);
1180 
1181 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
1182 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
1183 		return (EIO);
1184 	}
1185 
1186 	return (err);
1187 }
1188 
1189 int
1190 igb_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1191     uint_t pr_valsize, void *pr_val)
1192 {
1193 	igb_t *igb = (igb_t *)arg;
1194 	struct e1000_hw *hw = &igb->hw;
1195 	int err = 0;
1196 	uint32_t flow_control;
1197 	uint64_t tmp = 0;
1198 
1199 	switch (pr_num) {
1200 	case MAC_PROP_DUPLEX:
1201 		ASSERT(pr_valsize >= sizeof (link_duplex_t));
1202 		bcopy(&igb->link_duplex, pr_val, sizeof (link_duplex_t));
1203 		break;
1204 	case MAC_PROP_SPEED:
1205 		ASSERT(pr_valsize >= sizeof (uint64_t));
1206 		tmp = igb->link_speed * 1000000ull;
1207 		bcopy(&tmp, pr_val, sizeof (tmp));
1208 		break;
1209 	case MAC_PROP_AUTONEG:
1210 		ASSERT(pr_valsize >= sizeof (uint8_t));
1211 		*(uint8_t *)pr_val = igb->param_adv_autoneg_cap;
1212 		break;
1213 	case MAC_PROP_FLOWCTRL:
1214 		ASSERT(pr_valsize >= sizeof (uint32_t));
1215 		switch (hw->fc.requested_mode) {
1216 			case e1000_fc_none:
1217 				flow_control = LINK_FLOWCTRL_NONE;
1218 				break;
1219 			case e1000_fc_rx_pause:
1220 				flow_control = LINK_FLOWCTRL_RX;
1221 				break;
1222 			case e1000_fc_tx_pause:
1223 				flow_control = LINK_FLOWCTRL_TX;
1224 				break;
1225 			case e1000_fc_full:
1226 				flow_control = LINK_FLOWCTRL_BI;
1227 				break;
1228 		}
1229 		bcopy(&flow_control, pr_val, sizeof (flow_control));
1230 		break;
1231 	case MAC_PROP_ADV_1000FDX_CAP:
1232 		*(uint8_t *)pr_val = igb->param_adv_1000fdx_cap;
1233 		break;
1234 	case MAC_PROP_EN_1000FDX_CAP:
1235 		*(uint8_t *)pr_val = igb->param_en_1000fdx_cap;
1236 		break;
1237 	case MAC_PROP_ADV_1000HDX_CAP:
1238 		*(uint8_t *)pr_val = igb->param_adv_1000hdx_cap;
1239 		break;
1240 	case MAC_PROP_EN_1000HDX_CAP:
1241 		*(uint8_t *)pr_val = igb->param_en_1000hdx_cap;
1242 		break;
1243 	case MAC_PROP_ADV_100T4_CAP:
1244 		*(uint8_t *)pr_val = igb->param_adv_100t4_cap;
1245 		break;
1246 	case MAC_PROP_EN_100T4_CAP:
1247 		*(uint8_t *)pr_val = igb->param_en_100t4_cap;
1248 		break;
1249 	case MAC_PROP_ADV_100FDX_CAP:
1250 		*(uint8_t *)pr_val = igb->param_adv_100fdx_cap;
1251 		break;
1252 	case MAC_PROP_EN_100FDX_CAP:
1253 		*(uint8_t *)pr_val = igb->param_en_100fdx_cap;
1254 		break;
1255 	case MAC_PROP_ADV_100HDX_CAP:
1256 		*(uint8_t *)pr_val = igb->param_adv_100hdx_cap;
1257 		break;
1258 	case MAC_PROP_EN_100HDX_CAP:
1259 		*(uint8_t *)pr_val = igb->param_en_100hdx_cap;
1260 		break;
1261 	case MAC_PROP_ADV_10FDX_CAP:
1262 		*(uint8_t *)pr_val = igb->param_adv_10fdx_cap;
1263 		break;
1264 	case MAC_PROP_EN_10FDX_CAP:
1265 		*(uint8_t *)pr_val = igb->param_en_10fdx_cap;
1266 		break;
1267 	case MAC_PROP_ADV_10HDX_CAP:
1268 		*(uint8_t *)pr_val = igb->param_adv_10hdx_cap;
1269 		break;
1270 	case MAC_PROP_EN_10HDX_CAP:
1271 		*(uint8_t *)pr_val = igb->param_en_10hdx_cap;
1272 		break;
1273 	case MAC_PROP_MEDIA:
1274 		*(mac_ether_media_t *)pr_val = e1000_link_to_media(hw,
1275 		    igb->link_speed);
1276 		break;
1277 	case MAC_PROP_PRIVATE:
1278 		err = igb_get_priv_prop(igb, pr_name, pr_valsize, pr_val);
1279 		break;
1280 	default:
1281 		err = ENOTSUP;
1282 		break;
1283 	}
1284 	return (err);
1285 }
1286 
1287 void
1288 igb_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1289     mac_prop_info_handle_t prh)
1290 {
1291 	igb_t *igb = (igb_t *)arg;
1292 	struct e1000_hw *hw = &igb->hw;
1293 	uint16_t phy_status, phy_ext_status;
1294 
1295 	switch (pr_num) {
1296 	case MAC_PROP_DUPLEX:
1297 	case MAC_PROP_SPEED:
1298 	case MAC_PROP_ADV_1000FDX_CAP:
1299 	case MAC_PROP_ADV_1000HDX_CAP:
1300 	case MAC_PROP_EN_1000HDX_CAP:
1301 	case MAC_PROP_ADV_100T4_CAP:
1302 	case MAC_PROP_EN_100T4_CAP:
1303 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1304 		break;
1305 
1306 	case MAC_PROP_EN_1000FDX_CAP:
1307 		if (hw->phy.media_type != e1000_media_type_copper) {
1308 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1309 		} else {
1310 			(void) e1000_read_phy_reg(hw, PHY_EXT_STATUS,
1311 			    &phy_ext_status);
1312 			mac_prop_info_set_default_uint8(prh,
1313 			    ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
1314 			    (phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0);
1315 		}
1316 		break;
1317 
1318 	case MAC_PROP_ADV_100FDX_CAP:
1319 	case MAC_PROP_EN_100FDX_CAP:
1320 		if (hw->phy.media_type != e1000_media_type_copper) {
1321 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1322 		} else {
1323 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1324 			mac_prop_info_set_default_uint8(prh,
1325 			    ((phy_status & MII_SR_100X_FD_CAPS) ||
1326 			    (phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0);
1327 		}
1328 		break;
1329 
1330 	case MAC_PROP_ADV_100HDX_CAP:
1331 	case MAC_PROP_EN_100HDX_CAP:
1332 		if (hw->phy.media_type != e1000_media_type_copper) {
1333 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1334 		} else {
1335 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1336 			mac_prop_info_set_default_uint8(prh,
1337 			    ((phy_status & MII_SR_100X_HD_CAPS) ||
1338 			    (phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0);
1339 		}
1340 		break;
1341 
1342 	case MAC_PROP_ADV_10FDX_CAP:
1343 	case MAC_PROP_EN_10FDX_CAP:
1344 		if (hw->phy.media_type != e1000_media_type_copper) {
1345 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1346 		} else {
1347 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1348 			mac_prop_info_set_default_uint8(prh,
1349 			    (phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0);
1350 		}
1351 		break;
1352 
1353 	case MAC_PROP_ADV_10HDX_CAP:
1354 	case MAC_PROP_EN_10HDX_CAP:
1355 		if (hw->phy.media_type != e1000_media_type_copper) {
1356 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1357 		} else {
1358 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1359 			mac_prop_info_set_default_uint8(prh,
1360 			    (phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0);
1361 		}
1362 		break;
1363 
1364 	case MAC_PROP_AUTONEG:
1365 		if (hw->phy.media_type != e1000_media_type_copper) {
1366 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1367 		} else {
1368 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1369 			mac_prop_info_set_default_uint8(prh,
1370 			    (phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0);
1371 		}
1372 		break;
1373 
1374 	case MAC_PROP_FLOWCTRL:
1375 		mac_prop_info_set_default_link_flowctrl(prh, LINK_FLOWCTRL_BI);
1376 		break;
1377 
1378 	case MAC_PROP_MTU:
1379 		mac_prop_info_set_range_uint32(prh, MIN_MTU, MAX_MTU);
1380 		break;
1381 
1382 	case MAC_PROP_PRIVATE:
1383 		igb_priv_prop_info(igb, pr_name, prh);
1384 		break;
1385 	}
1386 
1387 }
1388 
1389 boolean_t
1390 igb_param_locked(mac_prop_id_t pr_num)
1391 {
1392 	/*
1393 	 * All en_* parameters are locked (read-only) while
1394 	 * the device is in any sort of loopback mode ...
1395 	 */
1396 	switch (pr_num) {
1397 		case MAC_PROP_EN_1000FDX_CAP:
1398 		case MAC_PROP_EN_1000HDX_CAP:
1399 		case MAC_PROP_EN_100T4_CAP:
1400 		case MAC_PROP_EN_100FDX_CAP:
1401 		case MAC_PROP_EN_100HDX_CAP:
1402 		case MAC_PROP_EN_10FDX_CAP:
1403 		case MAC_PROP_EN_10HDX_CAP:
1404 		case MAC_PROP_AUTONEG:
1405 		case MAC_PROP_FLOWCTRL:
1406 			return (B_TRUE);
1407 	}
1408 	return (B_FALSE);
1409 }
1410 
1411 /* ARGSUSED */
1412 int
1413 igb_set_priv_prop(igb_t *igb, const char *pr_name,
1414     uint_t pr_valsize, const void *pr_val)
1415 {
1416 	int err = 0;
1417 	long result;
1418 	struct e1000_hw *hw = &igb->hw;
1419 	int i;
1420 
1421 	if (strcmp(pr_name, "_eee_support") == 0) {
1422 		if (pr_val == NULL)
1423 			return (EINVAL);
1424 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1425 		switch (result) {
1426 		case 0:
1427 		case 1:
1428 			/*
1429 			 * For now, only supported on I350/I354.
1430 			 * Add new mac.type values (or use < instead)
1431 			 * as new cards offer up EEE.
1432 			 */
1433 			switch (hw->mac.type) {
1434 			case e1000_i350:
1435 				/* Must set this prior to the set call. */
1436 				hw->dev_spec._82575.eee_disable = !result;
1437 				if (e1000_set_eee_i350(hw, result,
1438 				    result) != E1000_SUCCESS)
1439 					err = EIO;
1440 				break;
1441 			case e1000_i354:
1442 				/* Must set this prior to the set call. */
1443 				hw->dev_spec._82575.eee_disable = !result;
1444 				if (e1000_set_eee_i354(hw, result,
1445 				    result) != E1000_SUCCESS)
1446 					err = EIO;
1447 				break;
1448 			default:
1449 				return (ENXIO);
1450 			}
1451 			break;
1452 		default:
1453 			err = EINVAL;
1454 			/* FALLTHRU */
1455 		}
1456 		return (err);
1457 	}
1458 	if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
1459 		if (pr_val == NULL) {
1460 			err = EINVAL;
1461 			return (err);
1462 		}
1463 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1464 		if (result < MIN_TX_COPY_THRESHOLD ||
1465 		    result > MAX_TX_COPY_THRESHOLD)
1466 			err = EINVAL;
1467 		else {
1468 			igb->tx_copy_thresh = (uint32_t)result;
1469 		}
1470 		return (err);
1471 	}
1472 	if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
1473 		if (pr_val == NULL) {
1474 			err = EINVAL;
1475 			return (err);
1476 		}
1477 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1478 		if (result < MIN_TX_RECYCLE_THRESHOLD ||
1479 		    result > MAX_TX_RECYCLE_THRESHOLD)
1480 			err = EINVAL;
1481 		else {
1482 			igb->tx_recycle_thresh = (uint32_t)result;
1483 		}
1484 		return (err);
1485 	}
1486 	if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
1487 		if (pr_val == NULL) {
1488 			err = EINVAL;
1489 			return (err);
1490 		}
1491 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1492 		if (result < MIN_TX_OVERLOAD_THRESHOLD ||
1493 		    result > MAX_TX_OVERLOAD_THRESHOLD)
1494 			err = EINVAL;
1495 		else {
1496 			igb->tx_overload_thresh = (uint32_t)result;
1497 		}
1498 		return (err);
1499 	}
1500 	if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
1501 		if (pr_val == NULL) {
1502 			err = EINVAL;
1503 			return (err);
1504 		}
1505 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1506 		if (result < MIN_TX_RESCHED_THRESHOLD ||
1507 		    result > MAX_TX_RESCHED_THRESHOLD ||
1508 		    result > igb->tx_ring_size)
1509 			err = EINVAL;
1510 		else {
1511 			igb->tx_resched_thresh = (uint32_t)result;
1512 		}
1513 		return (err);
1514 	}
1515 	if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
1516 		if (pr_val == NULL) {
1517 			err = EINVAL;
1518 			return (err);
1519 		}
1520 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1521 		if (result < MIN_RX_COPY_THRESHOLD ||
1522 		    result > MAX_RX_COPY_THRESHOLD)
1523 			err = EINVAL;
1524 		else {
1525 			igb->rx_copy_thresh = (uint32_t)result;
1526 		}
1527 		return (err);
1528 	}
1529 	if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
1530 		if (pr_val == NULL) {
1531 			err = EINVAL;
1532 			return (err);
1533 		}
1534 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1535 		if (result < MIN_RX_LIMIT_PER_INTR ||
1536 		    result > MAX_RX_LIMIT_PER_INTR)
1537 			err = EINVAL;
1538 		else {
1539 			igb->rx_limit_per_intr = (uint32_t)result;
1540 		}
1541 		return (err);
1542 	}
1543 	if (strcmp(pr_name, "_intr_throttling") == 0) {
1544 		if (pr_val == NULL) {
1545 			err = EINVAL;
1546 			return (err);
1547 		}
1548 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1549 
1550 		if (result < igb->capab->min_intr_throttle ||
1551 		    result > igb->capab->max_intr_throttle)
1552 			err = EINVAL;
1553 		else {
1554 			igb->intr_throttling[0] = (uint32_t)result;
1555 
1556 			for (i = 0; i < MAX_NUM_EITR; i++)
1557 				igb->intr_throttling[i] =
1558 				    igb->intr_throttling[0];
1559 
1560 			/* Set interrupt throttling rate */
1561 			for (i = 0; i < igb->intr_cnt; i++)
1562 				E1000_WRITE_REG(hw, E1000_EITR(i),
1563 				    igb->intr_throttling[i]);
1564 		}
1565 		return (err);
1566 	}
1567 	return (ENOTSUP);
1568 }
1569 
1570 int
1571 igb_get_priv_prop(igb_t *igb, const char *pr_name, uint_t pr_valsize,
1572     void *pr_val)
1573 {
1574 	int value;
1575 
1576 	if (strcmp(pr_name, "_adv_pause_cap") == 0) {
1577 		value = igb->param_adv_pause_cap;
1578 	} else if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
1579 		value = igb->param_adv_asym_pause_cap;
1580 	} else if (strcmp(pr_name, "_eee_support") == 0) {
1581 		/*
1582 		 * For now, only supported on I350.  Add new mac.type values
1583 		 * (or use < instead) as new cards offer up EEE.
1584 		 */
1585 		switch (igb->hw.mac.type) {
1586 		case e1000_i350:
1587 		case e1000_i354:
1588 			value = !(igb->hw.dev_spec._82575.eee_disable);
1589 			break;
1590 		default:
1591 			value = 0;
1592 		}
1593 	} else if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
1594 		value = igb->tx_copy_thresh;
1595 	} else if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
1596 		value = igb->tx_recycle_thresh;
1597 	} else if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
1598 		value = igb->tx_overload_thresh;
1599 	} else if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
1600 		value = igb->tx_resched_thresh;
1601 	} else if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
1602 		value = igb->rx_copy_thresh;
1603 	} else if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
1604 		value = igb->rx_limit_per_intr;
1605 	} else if (strcmp(pr_name, "_intr_throttling") == 0) {
1606 		value = igb->intr_throttling[0];
1607 	} else {
1608 		return (ENOTSUP);
1609 	}
1610 
1611 	(void) snprintf(pr_val, pr_valsize, "%d", value);
1612 	return (0);
1613 }
1614 
1615 void
1616 igb_priv_prop_info(igb_t *igb, const char *pr_name, mac_prop_info_handle_t prh)
1617 {
1618 	char valstr[64];
1619 	int value;
1620 
1621 	if (strcmp(pr_name, "_adv_pause_cap") == 0 ||
1622 	    strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
1623 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1624 		return;
1625 	} else if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
1626 		value = DEFAULT_TX_COPY_THRESHOLD;
1627 	} else if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
1628 		value = DEFAULT_TX_RECYCLE_THRESHOLD;
1629 	} else if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
1630 		value = DEFAULT_TX_OVERLOAD_THRESHOLD;
1631 	} else if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
1632 		value = DEFAULT_TX_RESCHED_THRESHOLD;
1633 	} else if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
1634 		value = DEFAULT_RX_COPY_THRESHOLD;
1635 	} else if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
1636 		value = DEFAULT_RX_LIMIT_PER_INTR;
1637 	} else if (strcmp(pr_name, "_intr_throttling") == 0) {
1638 		value = igb->capab->def_intr_throttle;
1639 	} else {
1640 		return;
1641 	}
1642 
1643 	(void) snprintf(valstr, sizeof (valstr), "%d", value);
1644 	mac_prop_info_set_default_str(prh, valstr);
1645 }
1646