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