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