xref: /onnv-gate/usr/src/uts/common/io/igb/igb_gld.c (revision 12980:c2b4f6c2d38a)
15779Sxy150489 /*
25779Sxy150489  * CDDL HEADER START
35779Sxy150489  *
45779Sxy150489  * The contents of this file are subject to the terms of the
55779Sxy150489  * Common Development and Distribution License (the "License").
65779Sxy150489  * You may not use this file except in compliance with the License.
75779Sxy150489  *
88275SEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98275SEric Cheng  * or http://www.opensolaris.org/os/licensing.
105779Sxy150489  * See the License for the specific language governing permissions
115779Sxy150489  * and limitations under the License.
125779Sxy150489  *
138275SEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
148275SEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155779Sxy150489  * If applicable, add the following below this CDDL HEADER, with the
165779Sxy150489  * fields enclosed by brackets "[]" replaced with your own identifying
175779Sxy150489  * information: Portions Copyright [yyyy] [name of copyright owner]
185779Sxy150489  *
195779Sxy150489  * CDDL HEADER END
205779Sxy150489  */
215779Sxy150489 
225779Sxy150489 /*
23*12980SGuoqing.Zhu@Sun.COM  * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
245779Sxy150489  */
255779Sxy150489 
268275SEric Cheng /*
27*12980SGuoqing.Zhu@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
288275SEric Cheng  */
295779Sxy150489 
305779Sxy150489 #include "igb_sw.h"
315779Sxy150489 
325779Sxy150489 int
igb_m_stat(void * arg,uint_t stat,uint64_t * val)335779Sxy150489 igb_m_stat(void *arg, uint_t stat, uint64_t *val)
345779Sxy150489 {
355779Sxy150489 	igb_t *igb = (igb_t *)arg;
365779Sxy150489 	struct e1000_hw *hw = &igb->hw;
375779Sxy150489 	igb_stat_t *igb_ks;
385779Sxy150489 	uint32_t low_val, high_val;
395779Sxy150489 
405779Sxy150489 	igb_ks = (igb_stat_t *)igb->igb_ks->ks_data;
415779Sxy150489 
425779Sxy150489 	mutex_enter(&igb->gen_lock);
435779Sxy150489 
445779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
455779Sxy150489 		mutex_exit(&igb->gen_lock);
465779Sxy150489 		return (ECANCELED);
475779Sxy150489 	}
485779Sxy150489 
495779Sxy150489 	switch (stat) {
505779Sxy150489 	case MAC_STAT_IFSPEED:
515779Sxy150489 		*val = igb->link_speed * 1000000ull;
525779Sxy150489 		break;
535779Sxy150489 
545779Sxy150489 	case MAC_STAT_MULTIRCV:
555779Sxy150489 		igb_ks->mprc.value.ui64 +=
565779Sxy150489 		    E1000_READ_REG(hw, E1000_MPRC);
575779Sxy150489 		*val = igb_ks->mprc.value.ui64;
585779Sxy150489 		break;
595779Sxy150489 
605779Sxy150489 	case MAC_STAT_BRDCSTRCV:
615779Sxy150489 		igb_ks->bprc.value.ui64 +=
625779Sxy150489 		    E1000_READ_REG(hw, E1000_BPRC);
635779Sxy150489 		*val = igb_ks->bprc.value.ui64;
645779Sxy150489 		break;
655779Sxy150489 
665779Sxy150489 	case MAC_STAT_MULTIXMT:
675779Sxy150489 		igb_ks->mptc.value.ui64 +=
685779Sxy150489 		    E1000_READ_REG(hw, E1000_MPTC);
695779Sxy150489 		*val = igb_ks->mptc.value.ui64;
705779Sxy150489 		break;
715779Sxy150489 
725779Sxy150489 	case MAC_STAT_BRDCSTXMT:
735779Sxy150489 		igb_ks->bptc.value.ui64 +=
745779Sxy150489 		    E1000_READ_REG(hw, E1000_BPTC);
755779Sxy150489 		*val = igb_ks->bptc.value.ui64;
765779Sxy150489 		break;
775779Sxy150489 
785779Sxy150489 	case MAC_STAT_NORCVBUF:
795779Sxy150489 		igb_ks->rnbc.value.ui64 +=
805779Sxy150489 		    E1000_READ_REG(hw, E1000_RNBC);
815779Sxy150489 		*val = igb_ks->rnbc.value.ui64;
825779Sxy150489 		break;
835779Sxy150489 
845779Sxy150489 	case MAC_STAT_IERRORS:
855779Sxy150489 		igb_ks->rxerrc.value.ui64 +=
865779Sxy150489 		    E1000_READ_REG(hw, E1000_RXERRC);
875779Sxy150489 		igb_ks->algnerrc.value.ui64 +=
885779Sxy150489 		    E1000_READ_REG(hw, E1000_ALGNERRC);
895779Sxy150489 		igb_ks->rlec.value.ui64 +=
905779Sxy150489 		    E1000_READ_REG(hw, E1000_RLEC);
915779Sxy150489 		igb_ks->crcerrs.value.ui64 +=
925779Sxy150489 		    E1000_READ_REG(hw, E1000_CRCERRS);
935779Sxy150489 		igb_ks->cexterr.value.ui64 +=
945779Sxy150489 		    E1000_READ_REG(hw, E1000_CEXTERR);
955779Sxy150489 		*val = igb_ks->rxerrc.value.ui64 +
965779Sxy150489 		    igb_ks->algnerrc.value.ui64 +
975779Sxy150489 		    igb_ks->rlec.value.ui64 +
985779Sxy150489 		    igb_ks->crcerrs.value.ui64 +
995779Sxy150489 		    igb_ks->cexterr.value.ui64;
1005779Sxy150489 		break;
1015779Sxy150489 
1025779Sxy150489 	case MAC_STAT_NOXMTBUF:
1035779Sxy150489 		*val = 0;
1045779Sxy150489 		break;
1055779Sxy150489 
1065779Sxy150489 	case MAC_STAT_OERRORS:
1075779Sxy150489 		igb_ks->ecol.value.ui64 +=
1085779Sxy150489 		    E1000_READ_REG(hw, E1000_ECOL);
1095779Sxy150489 		*val = igb_ks->ecol.value.ui64;
1105779Sxy150489 		break;
1115779Sxy150489 
1125779Sxy150489 	case MAC_STAT_COLLISIONS:
1135779Sxy150489 		igb_ks->colc.value.ui64 +=
1145779Sxy150489 		    E1000_READ_REG(hw, E1000_COLC);
1155779Sxy150489 		*val = igb_ks->colc.value.ui64;
1165779Sxy150489 		break;
1175779Sxy150489 
1185779Sxy150489 	case MAC_STAT_RBYTES:
1195779Sxy150489 		/*
1205779Sxy150489 		 * The 64-bit register will reset whenever the upper
1215779Sxy150489 		 * 32 bits are read. So we need to read the lower
1225779Sxy150489 		 * 32 bits first, then read the upper 32 bits.
1235779Sxy150489 		 */
1245779Sxy150489 		low_val = E1000_READ_REG(hw, E1000_TORL);
1255779Sxy150489 		high_val = E1000_READ_REG(hw, E1000_TORH);
1265779Sxy150489 		igb_ks->tor.value.ui64 +=
1275779Sxy150489 		    (uint64_t)high_val << 32 | (uint64_t)low_val;
1285779Sxy150489 		*val = igb_ks->tor.value.ui64;
1295779Sxy150489 		break;
1305779Sxy150489 
1315779Sxy150489 	case MAC_STAT_IPACKETS:
1325779Sxy150489 		igb_ks->tpr.value.ui64 +=
1335779Sxy150489 		    E1000_READ_REG(hw, E1000_TPR);
1345779Sxy150489 		*val = igb_ks->tpr.value.ui64;
1355779Sxy150489 		break;
1365779Sxy150489 
1375779Sxy150489 	case MAC_STAT_OBYTES:
1385779Sxy150489 		/*
1395779Sxy150489 		 * The 64-bit register will reset whenever the upper
1405779Sxy150489 		 * 32 bits are read. So we need to read the lower
1415779Sxy150489 		 * 32 bits first, then read the upper 32 bits.
1425779Sxy150489 		 */
1435779Sxy150489 		low_val = E1000_READ_REG(hw, E1000_TOTL);
1445779Sxy150489 		high_val = E1000_READ_REG(hw, E1000_TOTH);
1455779Sxy150489 		igb_ks->tot.value.ui64 +=
1465779Sxy150489 		    (uint64_t)high_val << 32 | (uint64_t)low_val;
1475779Sxy150489 		*val = igb_ks->tot.value.ui64;
1485779Sxy150489 		break;
1495779Sxy150489 
1505779Sxy150489 	case MAC_STAT_OPACKETS:
1515779Sxy150489 		igb_ks->tpt.value.ui64 +=
1525779Sxy150489 		    E1000_READ_REG(hw, E1000_TPT);
1535779Sxy150489 		*val = igb_ks->tpt.value.ui64;
1545779Sxy150489 		break;
1555779Sxy150489 
1565779Sxy150489 	/* RFC 1643 stats */
1575779Sxy150489 	case ETHER_STAT_ALIGN_ERRORS:
1585779Sxy150489 		igb_ks->algnerrc.value.ui64 +=
1595779Sxy150489 		    E1000_READ_REG(hw, E1000_ALGNERRC);
1605779Sxy150489 		*val = igb_ks->algnerrc.value.ui64;
1615779Sxy150489 		break;
1625779Sxy150489 
1635779Sxy150489 	case ETHER_STAT_FCS_ERRORS:
1645779Sxy150489 		igb_ks->crcerrs.value.ui64 +=
1655779Sxy150489 		    E1000_READ_REG(hw, E1000_CRCERRS);
1665779Sxy150489 		*val = igb_ks->crcerrs.value.ui64;
1675779Sxy150489 		break;
1685779Sxy150489 
1695779Sxy150489 	case ETHER_STAT_FIRST_COLLISIONS:
1705779Sxy150489 		igb_ks->scc.value.ui64 +=
1715779Sxy150489 		    E1000_READ_REG(hw, E1000_SCC);
1725779Sxy150489 		*val = igb_ks->scc.value.ui64;
1735779Sxy150489 		break;
1745779Sxy150489 
1755779Sxy150489 	case ETHER_STAT_MULTI_COLLISIONS:
1765779Sxy150489 		igb_ks->mcc.value.ui64 +=
1775779Sxy150489 		    E1000_READ_REG(hw, E1000_MCC);
1785779Sxy150489 		*val = igb_ks->mcc.value.ui64;
1795779Sxy150489 		break;
1805779Sxy150489 
1815779Sxy150489 	case ETHER_STAT_SQE_ERRORS:
1825779Sxy150489 		igb_ks->sec.value.ui64 +=
1835779Sxy150489 		    E1000_READ_REG(hw, E1000_SEC);
1845779Sxy150489 		*val = igb_ks->sec.value.ui64;
1855779Sxy150489 		break;
1865779Sxy150489 
1875779Sxy150489 	case ETHER_STAT_DEFER_XMTS:
1885779Sxy150489 		igb_ks->dc.value.ui64 +=
1895779Sxy150489 		    E1000_READ_REG(hw, E1000_DC);
1905779Sxy150489 		*val = igb_ks->dc.value.ui64;
1915779Sxy150489 		break;
1925779Sxy150489 
1935779Sxy150489 	case ETHER_STAT_TX_LATE_COLLISIONS:
1945779Sxy150489 		igb_ks->latecol.value.ui64 +=
1955779Sxy150489 		    E1000_READ_REG(hw, E1000_LATECOL);
1965779Sxy150489 		*val = igb_ks->latecol.value.ui64;
1975779Sxy150489 		break;
1985779Sxy150489 
1995779Sxy150489 	case ETHER_STAT_EX_COLLISIONS:
2005779Sxy150489 		igb_ks->ecol.value.ui64 +=
2015779Sxy150489 		    E1000_READ_REG(hw, E1000_ECOL);
2025779Sxy150489 		*val = igb_ks->ecol.value.ui64;
2035779Sxy150489 		break;
2045779Sxy150489 
2055779Sxy150489 	case ETHER_STAT_MACXMT_ERRORS:
2065779Sxy150489 		igb_ks->ecol.value.ui64 +=
2075779Sxy150489 		    E1000_READ_REG(hw, E1000_ECOL);
2085779Sxy150489 		*val = igb_ks->ecol.value.ui64;
2095779Sxy150489 		break;
2105779Sxy150489 
2115779Sxy150489 	case ETHER_STAT_CARRIER_ERRORS:
2125779Sxy150489 		igb_ks->cexterr.value.ui64 +=
2135779Sxy150489 		    E1000_READ_REG(hw, E1000_CEXTERR);
2145779Sxy150489 		*val = igb_ks->cexterr.value.ui64;
2155779Sxy150489 		break;
2165779Sxy150489 
2175779Sxy150489 	case ETHER_STAT_TOOLONG_ERRORS:
2185779Sxy150489 		igb_ks->roc.value.ui64 +=
2195779Sxy150489 		    E1000_READ_REG(hw, E1000_ROC);
2205779Sxy150489 		*val = igb_ks->roc.value.ui64;
2215779Sxy150489 		break;
2225779Sxy150489 
2235779Sxy150489 	case ETHER_STAT_MACRCV_ERRORS:
2245779Sxy150489 		igb_ks->rxerrc.value.ui64 +=
2255779Sxy150489 		    E1000_READ_REG(hw, E1000_RXERRC);
2265779Sxy150489 		*val = igb_ks->rxerrc.value.ui64;
2275779Sxy150489 		break;
2285779Sxy150489 
2295779Sxy150489 	/* MII/GMII stats */
2305779Sxy150489 	case ETHER_STAT_XCVR_ADDR:
2315779Sxy150489 		/* The Internal PHY's MDI address for each MAC is 1 */
2325779Sxy150489 		*val = 1;
2335779Sxy150489 		break;
2345779Sxy150489 
2355779Sxy150489 	case ETHER_STAT_XCVR_ID:
2365779Sxy150489 		*val = hw->phy.id | hw->phy.revision;
2375779Sxy150489 		break;
2385779Sxy150489 
2395779Sxy150489 	case ETHER_STAT_XCVR_INUSE:
2405779Sxy150489 		switch (igb->link_speed) {
2415779Sxy150489 		case SPEED_1000:
2425779Sxy150489 			*val =
2435779Sxy150489 			    (hw->phy.media_type == e1000_media_type_copper) ?
2445779Sxy150489 			    XCVR_1000T : XCVR_1000X;
2455779Sxy150489 			break;
2465779Sxy150489 		case SPEED_100:
2475779Sxy150489 			*val =
2485779Sxy150489 			    (hw->phy.media_type == e1000_media_type_copper) ?
2495779Sxy150489 			    (igb->param_100t4_cap == 1) ?
2505779Sxy150489 			    XCVR_100T4 : XCVR_100T2 : XCVR_100X;
2515779Sxy150489 			break;
2525779Sxy150489 		case SPEED_10:
2535779Sxy150489 			*val = XCVR_10;
2545779Sxy150489 			break;
2555779Sxy150489 		default:
2565779Sxy150489 			*val = XCVR_NONE;
2575779Sxy150489 			break;
2585779Sxy150489 		}
2595779Sxy150489 		break;
2605779Sxy150489 
2615779Sxy150489 	case ETHER_STAT_CAP_1000FDX:
2625779Sxy150489 		*val = igb->param_1000fdx_cap;
2635779Sxy150489 		break;
2645779Sxy150489 
2655779Sxy150489 	case ETHER_STAT_CAP_1000HDX:
2665779Sxy150489 		*val = igb->param_1000hdx_cap;
2675779Sxy150489 		break;
2685779Sxy150489 
2695779Sxy150489 	case ETHER_STAT_CAP_100FDX:
2705779Sxy150489 		*val = igb->param_100fdx_cap;
2715779Sxy150489 		break;
2725779Sxy150489 
2735779Sxy150489 	case ETHER_STAT_CAP_100HDX:
2745779Sxy150489 		*val = igb->param_100hdx_cap;
2755779Sxy150489 		break;
2765779Sxy150489 
2775779Sxy150489 	case ETHER_STAT_CAP_10FDX:
2785779Sxy150489 		*val = igb->param_10fdx_cap;
2795779Sxy150489 		break;
2805779Sxy150489 
2815779Sxy150489 	case ETHER_STAT_CAP_10HDX:
2825779Sxy150489 		*val = igb->param_10hdx_cap;
2835779Sxy150489 		break;
2845779Sxy150489 
2855779Sxy150489 	case ETHER_STAT_CAP_ASMPAUSE:
2865779Sxy150489 		*val = igb->param_asym_pause_cap;
2875779Sxy150489 		break;
2885779Sxy150489 
2895779Sxy150489 	case ETHER_STAT_CAP_PAUSE:
2905779Sxy150489 		*val = igb->param_pause_cap;
2915779Sxy150489 		break;
2925779Sxy150489 
2935779Sxy150489 	case ETHER_STAT_CAP_AUTONEG:
2945779Sxy150489 		*val = igb->param_autoneg_cap;
2955779Sxy150489 		break;
2965779Sxy150489 
2975779Sxy150489 	case ETHER_STAT_ADV_CAP_1000FDX:
2985779Sxy150489 		*val = igb->param_adv_1000fdx_cap;
2995779Sxy150489 		break;
3005779Sxy150489 
3015779Sxy150489 	case ETHER_STAT_ADV_CAP_1000HDX:
3025779Sxy150489 		*val = igb->param_adv_1000hdx_cap;
3035779Sxy150489 		break;
3045779Sxy150489 
3055779Sxy150489 	case ETHER_STAT_ADV_CAP_100FDX:
3065779Sxy150489 		*val = igb->param_adv_100fdx_cap;
3075779Sxy150489 		break;
3085779Sxy150489 
3095779Sxy150489 	case ETHER_STAT_ADV_CAP_100HDX:
3105779Sxy150489 		*val = igb->param_adv_100hdx_cap;
3115779Sxy150489 		break;
3125779Sxy150489 
3135779Sxy150489 	case ETHER_STAT_ADV_CAP_10FDX:
3145779Sxy150489 		*val = igb->param_adv_10fdx_cap;
3155779Sxy150489 		break;
3165779Sxy150489 
3175779Sxy150489 	case ETHER_STAT_ADV_CAP_10HDX:
3185779Sxy150489 		*val = igb->param_adv_10hdx_cap;
3195779Sxy150489 		break;
3205779Sxy150489 
3215779Sxy150489 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
3225779Sxy150489 		*val = igb->param_adv_asym_pause_cap;
3235779Sxy150489 		break;
3245779Sxy150489 
3255779Sxy150489 	case ETHER_STAT_ADV_CAP_PAUSE:
3265779Sxy150489 		*val = igb->param_adv_pause_cap;
3275779Sxy150489 		break;
3285779Sxy150489 
3295779Sxy150489 	case ETHER_STAT_ADV_CAP_AUTONEG:
3305779Sxy150489 		*val = hw->mac.autoneg;
3315779Sxy150489 		break;
3325779Sxy150489 
3335779Sxy150489 	case ETHER_STAT_LP_CAP_1000FDX:
3345779Sxy150489 		*val = igb->param_lp_1000fdx_cap;
3355779Sxy150489 		break;
3365779Sxy150489 
3375779Sxy150489 	case ETHER_STAT_LP_CAP_1000HDX:
3385779Sxy150489 		*val = igb->param_lp_1000hdx_cap;
3395779Sxy150489 		break;
3405779Sxy150489 
3415779Sxy150489 	case ETHER_STAT_LP_CAP_100FDX:
3425779Sxy150489 		*val = igb->param_lp_100fdx_cap;
3435779Sxy150489 		break;
3445779Sxy150489 
3455779Sxy150489 	case ETHER_STAT_LP_CAP_100HDX:
3465779Sxy150489 		*val = igb->param_lp_100hdx_cap;
3475779Sxy150489 		break;
3485779Sxy150489 
3495779Sxy150489 	case ETHER_STAT_LP_CAP_10FDX:
3505779Sxy150489 		*val = igb->param_lp_10fdx_cap;
3515779Sxy150489 		break;
3525779Sxy150489 
3535779Sxy150489 	case ETHER_STAT_LP_CAP_10HDX:
3545779Sxy150489 		*val = igb->param_lp_10hdx_cap;
3555779Sxy150489 		break;
3565779Sxy150489 
3575779Sxy150489 	case ETHER_STAT_LP_CAP_ASMPAUSE:
3585779Sxy150489 		*val = igb->param_lp_asym_pause_cap;
3595779Sxy150489 		break;
3605779Sxy150489 
3615779Sxy150489 	case ETHER_STAT_LP_CAP_PAUSE:
3625779Sxy150489 		*val = igb->param_lp_pause_cap;
3635779Sxy150489 		break;
3645779Sxy150489 
3655779Sxy150489 	case ETHER_STAT_LP_CAP_AUTONEG:
3665779Sxy150489 		*val = igb->param_lp_autoneg_cap;
3675779Sxy150489 		break;
3685779Sxy150489 
3695779Sxy150489 	case ETHER_STAT_LINK_ASMPAUSE:
3705779Sxy150489 		*val = igb->param_asym_pause_cap;
3715779Sxy150489 		break;
3725779Sxy150489 
3735779Sxy150489 	case ETHER_STAT_LINK_PAUSE:
3745779Sxy150489 		*val = igb->param_pause_cap;
3755779Sxy150489 		break;
3765779Sxy150489 
3775779Sxy150489 	case ETHER_STAT_LINK_AUTONEG:
3785779Sxy150489 		*val = hw->mac.autoneg;
3795779Sxy150489 		break;
3805779Sxy150489 
3815779Sxy150489 	case ETHER_STAT_LINK_DUPLEX:
3825779Sxy150489 		*val = (igb->link_duplex == FULL_DUPLEX) ?
3835779Sxy150489 		    LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
3845779Sxy150489 		break;
3855779Sxy150489 
3865779Sxy150489 	case ETHER_STAT_TOOSHORT_ERRORS:
3875779Sxy150489 		igb_ks->ruc.value.ui64 +=
3885779Sxy150489 		    E1000_READ_REG(hw, E1000_RUC);
3895779Sxy150489 		*val = igb_ks->ruc.value.ui64;
3905779Sxy150489 		break;
3915779Sxy150489 
3925779Sxy150489 	case ETHER_STAT_CAP_REMFAULT:
3935779Sxy150489 		*val = igb->param_rem_fault;
3945779Sxy150489 		break;
3955779Sxy150489 
3965779Sxy150489 	case ETHER_STAT_ADV_REMFAULT:
3975779Sxy150489 		*val = igb->param_adv_rem_fault;
3985779Sxy150489 		break;
3995779Sxy150489 
4005779Sxy150489 	case ETHER_STAT_LP_REMFAULT:
4015779Sxy150489 		*val = igb->param_lp_rem_fault;
4025779Sxy150489 		break;
4035779Sxy150489 
4045779Sxy150489 	case ETHER_STAT_JABBER_ERRORS:
4055779Sxy150489 		igb_ks->rjc.value.ui64 +=
4065779Sxy150489 		    E1000_READ_REG(hw, E1000_RJC);
4075779Sxy150489 		*val = igb_ks->rjc.value.ui64;
4085779Sxy150489 		break;
4095779Sxy150489 
4105779Sxy150489 	case ETHER_STAT_CAP_100T4:
4115779Sxy150489 		*val = igb->param_100t4_cap;
4125779Sxy150489 		break;
4135779Sxy150489 
4145779Sxy150489 	case ETHER_STAT_ADV_CAP_100T4:
4155779Sxy150489 		*val = igb->param_adv_100t4_cap;
4165779Sxy150489 		break;
4175779Sxy150489 
4185779Sxy150489 	case ETHER_STAT_LP_CAP_100T4:
4195779Sxy150489 		*val = igb->param_lp_100t4_cap;
4205779Sxy150489 		break;
4215779Sxy150489 
4225779Sxy150489 	default:
4235779Sxy150489 		mutex_exit(&igb->gen_lock);
4245779Sxy150489 		return (ENOTSUP);
4255779Sxy150489 	}
4265779Sxy150489 
4275779Sxy150489 	mutex_exit(&igb->gen_lock);
4285779Sxy150489 
42911367SJason.Xu@Sun.COM 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
43011367SJason.Xu@Sun.COM 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
43111367SJason.Xu@Sun.COM 		return (EIO);
43211367SJason.Xu@Sun.COM 	}
4336624Sgl147354 
4345779Sxy150489 	return (0);
4355779Sxy150489 }
4365779Sxy150489 
4375779Sxy150489 /*
4385779Sxy150489  * Bring the device out of the reset/quiesced state that it
4395779Sxy150489  * was in when the interface was registered.
4405779Sxy150489  */
4415779Sxy150489 int
igb_m_start(void * arg)4425779Sxy150489 igb_m_start(void *arg)
4435779Sxy150489 {
4445779Sxy150489 	igb_t *igb = (igb_t *)arg;
4455779Sxy150489 
4465779Sxy150489 	mutex_enter(&igb->gen_lock);
4475779Sxy150489 
4485779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
4495779Sxy150489 		mutex_exit(&igb->gen_lock);
4505779Sxy150489 		return (ECANCELED);
4515779Sxy150489 	}
4525779Sxy150489 
45311502SChenlu.Chen@Sun.COM 	if (igb_start(igb, B_TRUE) != IGB_SUCCESS) {
4545779Sxy150489 		mutex_exit(&igb->gen_lock);
4555779Sxy150489 		return (EIO);
4565779Sxy150489 	}
4575779Sxy150489 
45811367SJason.Xu@Sun.COM 	atomic_or_32(&igb->igb_state, IGB_STARTED);
4595779Sxy150489 
4605779Sxy150489 	mutex_exit(&igb->gen_lock);
4615779Sxy150489 
4625779Sxy150489 	/*
4635779Sxy150489 	 * Enable and start the watchdog timer
4645779Sxy150489 	 */
4655779Sxy150489 	igb_enable_watchdog_timer(igb);
4665779Sxy150489 
4675779Sxy150489 	return (0);
4685779Sxy150489 }
4695779Sxy150489 
4705779Sxy150489 /*
4715779Sxy150489  * Stop the device and put it in a reset/quiesced state such
4725779Sxy150489  * that the interface can be unregistered.
4735779Sxy150489  */
4745779Sxy150489 void
igb_m_stop(void * arg)4755779Sxy150489 igb_m_stop(void *arg)
4765779Sxy150489 {
4775779Sxy150489 	igb_t *igb = (igb_t *)arg;
4785779Sxy150489 
4795779Sxy150489 	mutex_enter(&igb->gen_lock);
4805779Sxy150489 
4815779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
4825779Sxy150489 		mutex_exit(&igb->gen_lock);
4835779Sxy150489 		return;
4845779Sxy150489 	}
4855779Sxy150489 
48611367SJason.Xu@Sun.COM 	atomic_and_32(&igb->igb_state, ~IGB_STARTED);
4875779Sxy150489 
48811502SChenlu.Chen@Sun.COM 	igb_stop(igb, B_TRUE);
4895779Sxy150489 
4905779Sxy150489 	mutex_exit(&igb->gen_lock);
4915779Sxy150489 
4925779Sxy150489 	/*
4935779Sxy150489 	 * Disable and stop the watchdog timer
4945779Sxy150489 	 */
4955779Sxy150489 	igb_disable_watchdog_timer(igb);
4965779Sxy150489 }
4975779Sxy150489 
4985779Sxy150489 /*
4995779Sxy150489  * Set the promiscuity of the device.
5005779Sxy150489  */
5015779Sxy150489 int
igb_m_promisc(void * arg,boolean_t on)5025779Sxy150489 igb_m_promisc(void *arg, boolean_t on)
5035779Sxy150489 {
5045779Sxy150489 	igb_t *igb = (igb_t *)arg;
5055779Sxy150489 	uint32_t reg_val;
5065779Sxy150489 
5075779Sxy150489 	mutex_enter(&igb->gen_lock);
5085779Sxy150489 
5095779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
5105779Sxy150489 		mutex_exit(&igb->gen_lock);
5115779Sxy150489 		return (ECANCELED);
5125779Sxy150489 	}
5135779Sxy150489 
5145779Sxy150489 	reg_val = E1000_READ_REG(&igb->hw, E1000_RCTL);
5155779Sxy150489 
5165779Sxy150489 	if (on)
5175779Sxy150489 		reg_val |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
5185779Sxy150489 	else
5195779Sxy150489 		reg_val &= (~(E1000_RCTL_UPE | E1000_RCTL_MPE));
5205779Sxy150489 
5215779Sxy150489 	E1000_WRITE_REG(&igb->hw, E1000_RCTL, reg_val);
5225779Sxy150489 
5235779Sxy150489 	mutex_exit(&igb->gen_lock);
5245779Sxy150489 
5256624Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
5266624Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
5276624Sgl147354 		return (EIO);
5286624Sgl147354 	}
5296624Sgl147354 
5305779Sxy150489 	return (0);
5315779Sxy150489 }
5325779Sxy150489 
5335779Sxy150489 /*
5345779Sxy150489  * Add/remove the addresses to/from the set of multicast
5355779Sxy150489  * addresses for which the device will receive packets.
5365779Sxy150489  */
5375779Sxy150489 int
igb_m_multicst(void * arg,boolean_t add,const uint8_t * mcst_addr)5385779Sxy150489 igb_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
5395779Sxy150489 {
5405779Sxy150489 	igb_t *igb = (igb_t *)arg;
5415779Sxy150489 	int result;
5425779Sxy150489 
5435779Sxy150489 	mutex_enter(&igb->gen_lock);
5445779Sxy150489 
5455779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
5465779Sxy150489 		mutex_exit(&igb->gen_lock);
5475779Sxy150489 		return (ECANCELED);
5485779Sxy150489 	}
5495779Sxy150489 
5505779Sxy150489 	result = (add) ? igb_multicst_add(igb, mcst_addr)
5515779Sxy150489 	    : igb_multicst_remove(igb, mcst_addr);
5525779Sxy150489 
5535779Sxy150489 	mutex_exit(&igb->gen_lock);
5545779Sxy150489 
5555779Sxy150489 	return (result);
5565779Sxy150489 }
5575779Sxy150489 
5585779Sxy150489 /*
5595779Sxy150489  * Pass on M_IOCTL messages passed to the DLD, and support
5605779Sxy150489  * private IOCTLs for debugging and ndd.
5615779Sxy150489  */
5625779Sxy150489 void
igb_m_ioctl(void * arg,queue_t * q,mblk_t * mp)5635779Sxy150489 igb_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
5645779Sxy150489 {
5655779Sxy150489 	igb_t *igb = (igb_t *)arg;
5665779Sxy150489 	struct iocblk *iocp;
5675779Sxy150489 	enum ioc_reply status;
5685779Sxy150489 
5695779Sxy150489 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
5705779Sxy150489 	iocp->ioc_error = 0;
5715779Sxy150489 
57211502SChenlu.Chen@Sun.COM 	mutex_enter(&igb->gen_lock);
57311502SChenlu.Chen@Sun.COM 	if (igb->igb_state & IGB_SUSPENDED) {
57411502SChenlu.Chen@Sun.COM 		mutex_exit(&igb->gen_lock);
57511502SChenlu.Chen@Sun.COM 		miocnak(q, mp, 0, EINVAL);
57611502SChenlu.Chen@Sun.COM 		return;
57711502SChenlu.Chen@Sun.COM 	}
57811502SChenlu.Chen@Sun.COM 	mutex_exit(&igb->gen_lock);
57911502SChenlu.Chen@Sun.COM 
5805779Sxy150489 	switch (iocp->ioc_cmd) {
5815779Sxy150489 	case LB_GET_INFO_SIZE:
5825779Sxy150489 	case LB_GET_INFO:
5835779Sxy150489 	case LB_GET_MODE:
5845779Sxy150489 	case LB_SET_MODE:
5855779Sxy150489 		status = igb_loopback_ioctl(igb, iocp, mp);
5865779Sxy150489 		break;
5875779Sxy150489 
5885779Sxy150489 	default:
5895779Sxy150489 		status = IOC_INVAL;
5905779Sxy150489 		break;
5915779Sxy150489 	}
5925779Sxy150489 
5935779Sxy150489 	/*
5945779Sxy150489 	 * Decide how to reply
5955779Sxy150489 	 */
5965779Sxy150489 	switch (status) {
5975779Sxy150489 	default:
5985779Sxy150489 	case IOC_INVAL:
5995779Sxy150489 		/*
6005779Sxy150489 		 * Error, reply with a NAK and EINVAL or the specified error
6015779Sxy150489 		 */
6025779Sxy150489 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
6035779Sxy150489 		    EINVAL : iocp->ioc_error);
6045779Sxy150489 		break;
6055779Sxy150489 
6065779Sxy150489 	case IOC_DONE:
6075779Sxy150489 		/*
6085779Sxy150489 		 * OK, reply already sent
6095779Sxy150489 		 */
6105779Sxy150489 		break;
6115779Sxy150489 
6125779Sxy150489 	case IOC_ACK:
6135779Sxy150489 		/*
6145779Sxy150489 		 * OK, reply with an ACK
6155779Sxy150489 		 */
6165779Sxy150489 		miocack(q, mp, 0, 0);
6175779Sxy150489 		break;
6185779Sxy150489 
6195779Sxy150489 	case IOC_REPLY:
6205779Sxy150489 		/*
6215779Sxy150489 		 * OK, send prepared reply as ACK or NAK
6225779Sxy150489 		 */
6235779Sxy150489 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
6245779Sxy150489 		    M_IOCACK : M_IOCNAK;
6255779Sxy150489 		qreply(q, mp);
6265779Sxy150489 		break;
6275779Sxy150489 	}
6285779Sxy150489 }
6295779Sxy150489 
6305779Sxy150489 /*
6318275SEric Cheng  * Add a MAC address to the target RX group.
6325779Sxy150489  */
6338275SEric Cheng static int
igb_addmac(void * arg,const uint8_t * mac_addr)6348275SEric Cheng igb_addmac(void *arg, const uint8_t *mac_addr)
6355779Sxy150489 {
6368275SEric Cheng 	igb_rx_group_t *rx_group = (igb_rx_group_t *)arg;
6378275SEric Cheng 	igb_t *igb = rx_group->igb;
6388275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
6398275SEric Cheng 	int i, slot;
6405779Sxy150489 
6415779Sxy150489 	mutex_enter(&igb->gen_lock);
6425779Sxy150489 
6435779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
6445779Sxy150489 		mutex_exit(&igb->gen_lock);
6455779Sxy150489 		return (ECANCELED);
6465779Sxy150489 	}
6475779Sxy150489 
6485779Sxy150489 	if (igb->unicst_avail == 0) {
6495779Sxy150489 		/* no slots available */
6505779Sxy150489 		mutex_exit(&igb->gen_lock);
6515779Sxy150489 		return (ENOSPC);
6525779Sxy150489 	}
6535779Sxy150489 
6545779Sxy150489 	/*
6558275SEric Cheng 	 * The slots from 0 to igb->num_rx_groups are reserved slots which
6568275SEric Cheng 	 * are 1 to 1 mapped with group index directly. The other slots are
6578275SEric Cheng 	 * shared between the all of groups. While adding a MAC address,
6588275SEric Cheng 	 * it will try to set the reserved slots first, then the shared slots.
6595779Sxy150489 	 */
6608275SEric Cheng 	slot = -1;
6618275SEric Cheng 	if (igb->unicst_addr[rx_group->index].mac.set == 1) {
6628275SEric Cheng 		/*
6638275SEric Cheng 		 * The reserved slot for current group is used, find the free
6648275SEric Cheng 		 * slots in the shared slots.
6658275SEric Cheng 		 */
6668275SEric Cheng 		for (i = igb->num_rx_groups; i < igb->unicst_total; i++) {
6678275SEric Cheng 			if (igb->unicst_addr[i].mac.set == 0) {
6688275SEric Cheng 				slot = i;
6698275SEric Cheng 				break;
6708275SEric Cheng 			}
6718275SEric Cheng 		}
6728275SEric Cheng 	} else
6738275SEric Cheng 		slot = rx_group->index;
6748275SEric Cheng 
6758275SEric Cheng 	if (slot == -1) {
6768275SEric Cheng 		/* no slots available in the shared slots */
6778275SEric Cheng 		mutex_exit(&igb->gen_lock);
6788275SEric Cheng 		return (ENOSPC);
6795779Sxy150489 	}
6805779Sxy150489 
6818275SEric Cheng 	/* Set VMDq according to the mode supported by hardware. */
6828275SEric Cheng 	e1000_rar_set_vmdq(hw, mac_addr, slot, igb->vmdq_mode, rx_group->index);
6835779Sxy150489 
6848275SEric Cheng 	bcopy(mac_addr, igb->unicst_addr[slot].mac.addr, ETHERADDRL);
6858275SEric Cheng 	igb->unicst_addr[slot].mac.group_index = rx_group->index;
6868275SEric Cheng 	igb->unicst_addr[slot].mac.set = 1;
6878275SEric Cheng 	igb->unicst_avail--;
6885779Sxy150489 
6897072Sxy150489 	mutex_exit(&igb->gen_lock);
6907072Sxy150489 
6918275SEric Cheng 	return (0);
6925779Sxy150489 }
6935779Sxy150489 
6945779Sxy150489 /*
6958275SEric Cheng  * Remove a MAC address from the specified RX group.
6965779Sxy150489  */
6978275SEric Cheng static int
igb_remmac(void * arg,const uint8_t * mac_addr)6988275SEric Cheng igb_remmac(void *arg, const uint8_t *mac_addr)
6995779Sxy150489 {
7008275SEric Cheng 	igb_rx_group_t *rx_group = (igb_rx_group_t *)arg;
7018275SEric Cheng 	igb_t *igb = rx_group->igb;
7028275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
7038275SEric Cheng 	int slot;
7045779Sxy150489 
7055779Sxy150489 	mutex_enter(&igb->gen_lock);
7065779Sxy150489 
7075779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
7085779Sxy150489 		mutex_exit(&igb->gen_lock);
7095779Sxy150489 		return (ECANCELED);
7105779Sxy150489 	}
7115779Sxy150489 
7128275SEric Cheng 	slot = igb_unicst_find(igb, mac_addr);
7138275SEric Cheng 	if (slot == -1) {
7145779Sxy150489 		mutex_exit(&igb->gen_lock);
7155779Sxy150489 		return (EINVAL);
7165779Sxy150489 	}
7175779Sxy150489 
7187072Sxy150489 	if (igb->unicst_addr[slot].mac.set == 0) {
7197072Sxy150489 		mutex_exit(&igb->gen_lock);
7207072Sxy150489 		return (EINVAL);
7217072Sxy150489 	}
7227072Sxy150489 
7238275SEric Cheng 	/* Clear the MAC ddress in the slot */
7248275SEric Cheng 	e1000_rar_clear(hw, slot);
7258275SEric Cheng 	igb->unicst_addr[slot].mac.set = 0;
7268275SEric Cheng 	igb->unicst_avail++;
7275779Sxy150489 
7285779Sxy150489 	mutex_exit(&igb->gen_lock);
7295779Sxy150489 
7308275SEric Cheng 	return (0);
7318275SEric Cheng }
7328275SEric Cheng 
7338275SEric Cheng /*
7348275SEric Cheng  * Enable interrupt on the specificed rx ring.
7358275SEric Cheng  */
7368275SEric Cheng int
igb_rx_ring_intr_enable(mac_intr_handle_t intrh)7378275SEric Cheng igb_rx_ring_intr_enable(mac_intr_handle_t intrh)
7388275SEric Cheng {
7398275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)intrh;
7408275SEric Cheng 	igb_t *igb = rx_ring->igb;
7418275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
7428275SEric Cheng 	uint32_t index = rx_ring->index;
7438275SEric Cheng 
7448275SEric Cheng 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
7458275SEric Cheng 		/* Interrupt enabling for MSI-X */
7468275SEric Cheng 		igb->eims_mask |= (E1000_EICR_RX_QUEUE0 << index);
7478275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
7488275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
7498275SEric Cheng 	} else {
7508275SEric Cheng 		ASSERT(index == 0);
7518275SEric Cheng 		/* Interrupt enabling for MSI and legacy */
7528275SEric Cheng 		igb->ims_mask |= E1000_IMS_RXT0;
7538275SEric Cheng 		E1000_WRITE_REG(hw, E1000_IMS, igb->ims_mask);
7548275SEric Cheng 	}
7558275SEric Cheng 
7568275SEric Cheng 	E1000_WRITE_FLUSH(hw);
7578275SEric Cheng 
7588275SEric Cheng 	return (0);
7598275SEric Cheng }
7608275SEric Cheng 
7618275SEric Cheng /*
7628275SEric Cheng  * Disable interrupt on the specificed rx ring.
7638275SEric Cheng  */
7648275SEric Cheng int
igb_rx_ring_intr_disable(mac_intr_handle_t intrh)7658275SEric Cheng igb_rx_ring_intr_disable(mac_intr_handle_t intrh)
7668275SEric Cheng {
7678275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)intrh;
7688275SEric Cheng 	igb_t *igb = rx_ring->igb;
7698275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
7708275SEric Cheng 	uint32_t index = rx_ring->index;
7718275SEric Cheng 
7728275SEric Cheng 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
7738275SEric Cheng 		/* Interrupt disabling for MSI-X */
7748275SEric Cheng 		igb->eims_mask &= ~(E1000_EICR_RX_QUEUE0 << index);
7758275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIMC,
7768275SEric Cheng 		    (E1000_EICR_RX_QUEUE0 << index));
7778275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
7788275SEric Cheng 	} else {
7798275SEric Cheng 		ASSERT(index == 0);
7808275SEric Cheng 		/* Interrupt disabling for MSI and legacy */
7818275SEric Cheng 		igb->ims_mask &= ~E1000_IMS_RXT0;
7828275SEric Cheng 		E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_RXT0);
7838275SEric Cheng 	}
7848275SEric Cheng 
7858275SEric Cheng 	E1000_WRITE_FLUSH(hw);
7868275SEric Cheng 
7878275SEric Cheng 	return (0);
7885779Sxy150489 }
7895779Sxy150489 
7905779Sxy150489 /*
7918275SEric Cheng  * Get the global ring index by a ring index within a group.
7925779Sxy150489  */
7935779Sxy150489 int
igb_get_rx_ring_index(igb_t * igb,int gindex,int rindex)7948275SEric Cheng igb_get_rx_ring_index(igb_t *igb, int gindex, int rindex)
7955779Sxy150489 {
7968275SEric Cheng 	igb_rx_ring_t *rx_ring;
7978275SEric Cheng 	int i;
7985779Sxy150489 
7998275SEric Cheng 	for (i = 0; i < igb->num_rx_rings; i++) {
8008275SEric Cheng 		rx_ring = &igb->rx_rings[i];
8018275SEric Cheng 		if (rx_ring->group_index == gindex)
8028275SEric Cheng 			rindex--;
8038275SEric Cheng 		if (rindex < 0)
8048275SEric Cheng 			return (i);
8055779Sxy150489 	}
8065779Sxy150489 
8078275SEric Cheng 	return (-1);
8088275SEric Cheng }
8095779Sxy150489 
8108275SEric Cheng static int
igb_ring_start(mac_ring_driver_t rh,uint64_t mr_gen_num)8118275SEric Cheng igb_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
8128275SEric Cheng {
8138275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)rh;
8145779Sxy150489 
8158275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
8168275SEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
8178275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
8188275SEric Cheng 	return (0);
8195779Sxy150489 }
8205779Sxy150489 
8215779Sxy150489 /*
8228275SEric Cheng  * Callback funtion for MAC layer to register all rings.
8235779Sxy150489  */
8248275SEric Cheng /* ARGSUSED */
8258275SEric Cheng void
igb_fill_ring(void * arg,mac_ring_type_t rtype,const int rg_index,const int index,mac_ring_info_t * infop,mac_ring_handle_t rh)8268275SEric Cheng igb_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
8278275SEric Cheng     const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
8285779Sxy150489 {
8295779Sxy150489 	igb_t *igb = (igb_t *)arg;
8308275SEric Cheng 	mac_intr_t *mintr = &infop->mri_intr;
8318275SEric Cheng 
8328275SEric Cheng 	switch (rtype) {
8338275SEric Cheng 	case MAC_RING_TYPE_RX: {
8348275SEric Cheng 		igb_rx_ring_t *rx_ring;
8358275SEric Cheng 		int global_index;
8365779Sxy150489 
8378275SEric Cheng 		/*
8388275SEric Cheng 		 * 'index' is the ring index within the group.
8398275SEric Cheng 		 * We need the global ring index by searching in group.
8408275SEric Cheng 		 */
8418275SEric Cheng 		global_index = igb_get_rx_ring_index(igb, rg_index, index);
8428275SEric Cheng 
8438275SEric Cheng 		ASSERT(global_index >= 0);
8445779Sxy150489 
8458275SEric Cheng 		rx_ring = &igb->rx_rings[global_index];
8468275SEric Cheng 		rx_ring->ring_handle = rh;
8478275SEric Cheng 
8488275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
8498275SEric Cheng 		infop->mri_start = igb_ring_start;
8508275SEric Cheng 		infop->mri_stop = NULL;
8518275SEric Cheng 		infop->mri_poll = (mac_ring_poll_t)igb_rx_ring_poll;
85211878SVenu.Iyer@Sun.COM 		infop->mri_stat = igb_rx_ring_stat;
8538275SEric Cheng 
8548275SEric Cheng 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
8558275SEric Cheng 		mintr->mi_enable = igb_rx_ring_intr_enable;
8568275SEric Cheng 		mintr->mi_disable = igb_rx_ring_intr_disable;
85711878SVenu.Iyer@Sun.COM 		if (igb->intr_type & (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
85811878SVenu.Iyer@Sun.COM 			mintr->mi_ddi_handle =
85911878SVenu.Iyer@Sun.COM 			    igb->htable[rx_ring->intr_vector];
86011878SVenu.Iyer@Sun.COM 		}
8618275SEric Cheng 		break;
8625779Sxy150489 	}
8638275SEric Cheng 	case MAC_RING_TYPE_TX: {
8648275SEric Cheng 		ASSERT(index < igb->num_tx_rings);
8655779Sxy150489 
8668275SEric Cheng 		igb_tx_ring_t *tx_ring = &igb->tx_rings[index];
8678275SEric Cheng 		tx_ring->ring_handle = rh;
8685779Sxy150489 
8698275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
8708275SEric Cheng 		infop->mri_start = NULL;
8718275SEric Cheng 		infop->mri_stop = NULL;
8728275SEric Cheng 		infop->mri_tx = igb_tx_ring_send;
87311878SVenu.Iyer@Sun.COM 		infop->mri_stat = igb_tx_ring_stat;
87411878SVenu.Iyer@Sun.COM 		if (igb->intr_type & (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
87511878SVenu.Iyer@Sun.COM 			mintr->mi_ddi_handle =
87611878SVenu.Iyer@Sun.COM 			    igb->htable[tx_ring->intr_vector];
87711878SVenu.Iyer@Sun.COM 		}
8788275SEric Cheng 		break;
8795779Sxy150489 	}
8808275SEric Cheng 	default:
8818275SEric Cheng 		break;
8828275SEric Cheng 	}
8838275SEric Cheng }
8848275SEric Cheng 
8858275SEric Cheng void
igb_fill_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)8868275SEric Cheng igb_fill_group(void *arg, mac_ring_type_t rtype, const int index,
8878275SEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
8888275SEric Cheng {
8898275SEric Cheng 	igb_t *igb = (igb_t *)arg;
8905779Sxy150489 
8918275SEric Cheng 	switch (rtype) {
8928275SEric Cheng 	case MAC_RING_TYPE_RX: {
8938275SEric Cheng 		igb_rx_group_t *rx_group;
8948275SEric Cheng 
8958275SEric Cheng 		ASSERT((index >= 0) && (index < igb->num_rx_groups));
8968275SEric Cheng 
8978275SEric Cheng 		rx_group = &igb->rx_groups[index];
8988275SEric Cheng 		rx_group->group_handle = gh;
8998275SEric Cheng 
9008275SEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_group;
9018275SEric Cheng 		infop->mgi_start = NULL;
9028275SEric Cheng 		infop->mgi_stop = NULL;
9038275SEric Cheng 		infop->mgi_addmac = igb_addmac;
9048275SEric Cheng 		infop->mgi_remmac = igb_remmac;
9058275SEric Cheng 		infop->mgi_count = (igb->num_rx_rings / igb->num_rx_groups);
9068275SEric Cheng 
9078275SEric Cheng 		break;
9085779Sxy150489 	}
9098275SEric Cheng 	case MAC_RING_TYPE_TX:
9108275SEric Cheng 		break;
9118275SEric Cheng 	default:
9128275SEric Cheng 		break;
9138275SEric Cheng 	}
9145779Sxy150489 }
9155779Sxy150489 
9165779Sxy150489 /*
9175779Sxy150489  * Obtain the MAC's capabilities and associated data from
9185779Sxy150489  * the driver.
9195779Sxy150489  */
9205779Sxy150489 boolean_t
igb_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)9215779Sxy150489 igb_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
9225779Sxy150489 {
9235779Sxy150489 	igb_t *igb = (igb_t *)arg;
9245779Sxy150489 
9255779Sxy150489 	switch (cap) {
9265779Sxy150489 	case MAC_CAPAB_HCKSUM: {
9275779Sxy150489 		uint32_t *tx_hcksum_flags = cap_data;
9285779Sxy150489 
9295779Sxy150489 		/*
9305779Sxy150489 		 * We advertise our capabilities only if tx hcksum offload is
9315779Sxy150489 		 * enabled.  On receive, the stack will accept checksummed
9325779Sxy150489 		 * packets anyway, even if we haven't said we can deliver
9335779Sxy150489 		 * them.
9345779Sxy150489 		 */
9355779Sxy150489 		if (!igb->tx_hcksum_enable)
9365779Sxy150489 			return (B_FALSE);
9375779Sxy150489 
9385779Sxy150489 		*tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
9395779Sxy150489 		break;
9405779Sxy150489 	}
9419188SPaul.Guo@Sun.COM 	case MAC_CAPAB_LSO: {
9429188SPaul.Guo@Sun.COM 		mac_capab_lso_t *cap_lso = cap_data;
9439188SPaul.Guo@Sun.COM 
9449188SPaul.Guo@Sun.COM 		if (igb->lso_enable) {
9459188SPaul.Guo@Sun.COM 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
9469188SPaul.Guo@Sun.COM 			cap_lso->lso_basic_tcp_ipv4.lso_max = IGB_LSO_MAXLEN;
9479188SPaul.Guo@Sun.COM 			break;
9489188SPaul.Guo@Sun.COM 		} else {
9499188SPaul.Guo@Sun.COM 			return (B_FALSE);
9509188SPaul.Guo@Sun.COM 		}
9519188SPaul.Guo@Sun.COM 	}
9528275SEric Cheng 	case MAC_CAPAB_RINGS: {
9538275SEric Cheng 		mac_capab_rings_t *cap_rings = cap_data;
9548275SEric Cheng 
9558275SEric Cheng 		switch (cap_rings->mr_type) {
9568275SEric Cheng 		case MAC_RING_TYPE_RX:
9578275SEric Cheng 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
9588275SEric Cheng 			cap_rings->mr_rnum = igb->num_rx_rings;
9598275SEric Cheng 			cap_rings->mr_gnum = igb->num_rx_groups;
9608275SEric Cheng 			cap_rings->mr_rget = igb_fill_ring;
9618275SEric Cheng 			cap_rings->mr_gget = igb_fill_group;
9628275SEric Cheng 			cap_rings->mr_gaddring = NULL;
9638275SEric Cheng 			cap_rings->mr_gremring = NULL;
9645779Sxy150489 
9658275SEric Cheng 			break;
9668275SEric Cheng 		case MAC_RING_TYPE_TX:
9678275SEric Cheng 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
9688275SEric Cheng 			cap_rings->mr_rnum = igb->num_tx_rings;
9698275SEric Cheng 			cap_rings->mr_gnum = 0;
9708275SEric Cheng 			cap_rings->mr_rget = igb_fill_ring;
9718275SEric Cheng 			cap_rings->mr_gget = NULL;
9728275SEric Cheng 
9738275SEric Cheng 			break;
9748275SEric Cheng 		default:
9758275SEric Cheng 			break;
9768275SEric Cheng 		}
9775779Sxy150489 		break;
9785779Sxy150489 	}
9798275SEric Cheng 
9805779Sxy150489 	default:
9815779Sxy150489 		return (B_FALSE);
9825779Sxy150489 	}
9835779Sxy150489 	return (B_TRUE);
9845779Sxy150489 }
98511502SChenlu.Chen@Sun.COM 
98611502SChenlu.Chen@Sun.COM int
igb_m_setprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)98711502SChenlu.Chen@Sun.COM igb_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
98811502SChenlu.Chen@Sun.COM     uint_t pr_valsize, const void *pr_val)
98911502SChenlu.Chen@Sun.COM {
99011502SChenlu.Chen@Sun.COM 	igb_t *igb = (igb_t *)arg;
99111502SChenlu.Chen@Sun.COM 	struct e1000_hw *hw = &igb->hw;
99211502SChenlu.Chen@Sun.COM 	int err = 0;
99311502SChenlu.Chen@Sun.COM 	uint32_t flow_control;
99411502SChenlu.Chen@Sun.COM 	uint32_t cur_mtu, new_mtu;
99511502SChenlu.Chen@Sun.COM 	uint32_t rx_size;
99611502SChenlu.Chen@Sun.COM 	uint32_t tx_size;
99711502SChenlu.Chen@Sun.COM 
99811502SChenlu.Chen@Sun.COM 	mutex_enter(&igb->gen_lock);
99911502SChenlu.Chen@Sun.COM 	if (igb->igb_state & IGB_SUSPENDED) {
100011502SChenlu.Chen@Sun.COM 		mutex_exit(&igb->gen_lock);
100111502SChenlu.Chen@Sun.COM 		return (ECANCELED);
100211502SChenlu.Chen@Sun.COM 	}
100311502SChenlu.Chen@Sun.COM 
100411502SChenlu.Chen@Sun.COM 	if (igb->loopback_mode != IGB_LB_NONE && igb_param_locked(pr_num)) {
100511502SChenlu.Chen@Sun.COM 		/*
100611502SChenlu.Chen@Sun.COM 		 * All en_* parameters are locked (read-only)
100711502SChenlu.Chen@Sun.COM 		 * while the device is in any sort of loopback mode.
100811502SChenlu.Chen@Sun.COM 		 */
100911502SChenlu.Chen@Sun.COM 		mutex_exit(&igb->gen_lock);
101011502SChenlu.Chen@Sun.COM 		return (EBUSY);
101111502SChenlu.Chen@Sun.COM 	}
101211502SChenlu.Chen@Sun.COM 
101311502SChenlu.Chen@Sun.COM 	switch (pr_num) {
101411502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000FDX_CAP:
101511502SChenlu.Chen@Sun.COM 		/* read/write on copper, read-only on serdes */
101611502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
101711502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
101811502SChenlu.Chen@Sun.COM 			break;
101911502SChenlu.Chen@Sun.COM 		}
102011502SChenlu.Chen@Sun.COM 		igb->param_en_1000fdx_cap = *(uint8_t *)pr_val;
102111502SChenlu.Chen@Sun.COM 		igb->param_adv_1000fdx_cap = *(uint8_t *)pr_val;
102211502SChenlu.Chen@Sun.COM 		goto setup_link;
102311502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
102411502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
102511502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
102611502SChenlu.Chen@Sun.COM 			break;
102711502SChenlu.Chen@Sun.COM 		}
102811502SChenlu.Chen@Sun.COM 		igb->param_en_100fdx_cap = *(uint8_t *)pr_val;
102911502SChenlu.Chen@Sun.COM 		igb->param_adv_100fdx_cap = *(uint8_t *)pr_val;
103011502SChenlu.Chen@Sun.COM 		goto setup_link;
103111502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
103211502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
103311502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
103411502SChenlu.Chen@Sun.COM 			break;
103511502SChenlu.Chen@Sun.COM 		}
103611502SChenlu.Chen@Sun.COM 		igb->param_en_100hdx_cap = *(uint8_t *)pr_val;
103711502SChenlu.Chen@Sun.COM 		igb->param_adv_100hdx_cap = *(uint8_t *)pr_val;
103811502SChenlu.Chen@Sun.COM 		goto setup_link;
103911502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
104011502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
104111502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
104211502SChenlu.Chen@Sun.COM 			break;
104311502SChenlu.Chen@Sun.COM 		}
104411502SChenlu.Chen@Sun.COM 		igb->param_en_10fdx_cap = *(uint8_t *)pr_val;
104511502SChenlu.Chen@Sun.COM 		igb->param_adv_10fdx_cap = *(uint8_t *)pr_val;
104611502SChenlu.Chen@Sun.COM 		goto setup_link;
104711502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
104811502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
104911502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
105011502SChenlu.Chen@Sun.COM 			break;
105111502SChenlu.Chen@Sun.COM 		}
105211502SChenlu.Chen@Sun.COM 		igb->param_en_10hdx_cap = *(uint8_t *)pr_val;
105311502SChenlu.Chen@Sun.COM 		igb->param_adv_10hdx_cap = *(uint8_t *)pr_val;
105411502SChenlu.Chen@Sun.COM 		goto setup_link;
105511502SChenlu.Chen@Sun.COM 	case MAC_PROP_AUTONEG:
105611502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
105711502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
105811502SChenlu.Chen@Sun.COM 			break;
105911502SChenlu.Chen@Sun.COM 		}
106011502SChenlu.Chen@Sun.COM 		igb->param_adv_autoneg_cap = *(uint8_t *)pr_val;
106111502SChenlu.Chen@Sun.COM 		goto setup_link;
106211502SChenlu.Chen@Sun.COM 	case MAC_PROP_FLOWCTRL:
106311502SChenlu.Chen@Sun.COM 		bcopy(pr_val, &flow_control, sizeof (flow_control));
106411502SChenlu.Chen@Sun.COM 
106511502SChenlu.Chen@Sun.COM 		switch (flow_control) {
106611502SChenlu.Chen@Sun.COM 		default:
106711502SChenlu.Chen@Sun.COM 			err = EINVAL;
106811502SChenlu.Chen@Sun.COM 			break;
106911502SChenlu.Chen@Sun.COM 		case LINK_FLOWCTRL_NONE:
107011502SChenlu.Chen@Sun.COM 			hw->fc.requested_mode = e1000_fc_none;
107111502SChenlu.Chen@Sun.COM 			break;
107211502SChenlu.Chen@Sun.COM 		case LINK_FLOWCTRL_RX:
107311502SChenlu.Chen@Sun.COM 			hw->fc.requested_mode = e1000_fc_rx_pause;
107411502SChenlu.Chen@Sun.COM 			break;
107511502SChenlu.Chen@Sun.COM 		case LINK_FLOWCTRL_TX:
107611502SChenlu.Chen@Sun.COM 			hw->fc.requested_mode = e1000_fc_tx_pause;
107711502SChenlu.Chen@Sun.COM 			break;
107811502SChenlu.Chen@Sun.COM 		case LINK_FLOWCTRL_BI:
107911502SChenlu.Chen@Sun.COM 			hw->fc.requested_mode = e1000_fc_full;
108011502SChenlu.Chen@Sun.COM 			break;
108111502SChenlu.Chen@Sun.COM 		}
108211502SChenlu.Chen@Sun.COM setup_link:
108311502SChenlu.Chen@Sun.COM 		if (err == 0) {
108411502SChenlu.Chen@Sun.COM 			if (igb_setup_link(igb, B_TRUE) != IGB_SUCCESS)
108511502SChenlu.Chen@Sun.COM 				err = EINVAL;
108611502SChenlu.Chen@Sun.COM 		}
108711502SChenlu.Chen@Sun.COM 		break;
108811502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000FDX_CAP:
108911502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000HDX_CAP:
109011502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
109111502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
109211502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
109311502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
109411502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
109511502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000HDX_CAP:
109611502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
109711502SChenlu.Chen@Sun.COM 	case MAC_PROP_STATUS:
109811502SChenlu.Chen@Sun.COM 	case MAC_PROP_SPEED:
109911502SChenlu.Chen@Sun.COM 	case MAC_PROP_DUPLEX:
110011502SChenlu.Chen@Sun.COM 		err = ENOTSUP; /* read-only prop. Can't set this. */
110111502SChenlu.Chen@Sun.COM 		break;
110211502SChenlu.Chen@Sun.COM 	case MAC_PROP_MTU:
110311502SChenlu.Chen@Sun.COM 		/* adapter must be stopped for an MTU change */
110411502SChenlu.Chen@Sun.COM 		if (igb->igb_state & IGB_STARTED) {
110511502SChenlu.Chen@Sun.COM 			err = EBUSY;
110611502SChenlu.Chen@Sun.COM 			break;
110711502SChenlu.Chen@Sun.COM 		}
110811502SChenlu.Chen@Sun.COM 
110911502SChenlu.Chen@Sun.COM 		cur_mtu = igb->default_mtu;
111011502SChenlu.Chen@Sun.COM 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
111111502SChenlu.Chen@Sun.COM 		if (new_mtu == cur_mtu) {
111211502SChenlu.Chen@Sun.COM 			err = 0;
111311502SChenlu.Chen@Sun.COM 			break;
111411502SChenlu.Chen@Sun.COM 		}
111511502SChenlu.Chen@Sun.COM 
111611502SChenlu.Chen@Sun.COM 		if (new_mtu < MIN_MTU || new_mtu > MAX_MTU) {
111711502SChenlu.Chen@Sun.COM 			err = EINVAL;
111811502SChenlu.Chen@Sun.COM 			break;
111911502SChenlu.Chen@Sun.COM 		}
112011502SChenlu.Chen@Sun.COM 
112111502SChenlu.Chen@Sun.COM 		err = mac_maxsdu_update(igb->mac_hdl, new_mtu);
112211502SChenlu.Chen@Sun.COM 		if (err == 0) {
112311502SChenlu.Chen@Sun.COM 			igb->default_mtu = new_mtu;
112411502SChenlu.Chen@Sun.COM 			igb->max_frame_size = igb->default_mtu +
112511502SChenlu.Chen@Sun.COM 			    sizeof (struct ether_vlan_header) + ETHERFCSL;
112611502SChenlu.Chen@Sun.COM 
112711502SChenlu.Chen@Sun.COM 			/*
112811502SChenlu.Chen@Sun.COM 			 * Set rx buffer size
112911502SChenlu.Chen@Sun.COM 			 */
113011502SChenlu.Chen@Sun.COM 			rx_size = igb->max_frame_size + IPHDR_ALIGN_ROOM;
113111502SChenlu.Chen@Sun.COM 			igb->rx_buf_size = ((rx_size >> 10) + ((rx_size &
113211502SChenlu.Chen@Sun.COM 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
113311502SChenlu.Chen@Sun.COM 
113411502SChenlu.Chen@Sun.COM 			/*
113511502SChenlu.Chen@Sun.COM 			 * Set tx buffer size
113611502SChenlu.Chen@Sun.COM 			 */
113711502SChenlu.Chen@Sun.COM 			tx_size = igb->max_frame_size;
113811502SChenlu.Chen@Sun.COM 			igb->tx_buf_size = ((tx_size >> 10) + ((tx_size &
113911502SChenlu.Chen@Sun.COM 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
114011502SChenlu.Chen@Sun.COM 		}
114111502SChenlu.Chen@Sun.COM 		break;
114211502SChenlu.Chen@Sun.COM 	case MAC_PROP_PRIVATE:
114311502SChenlu.Chen@Sun.COM 		err = igb_set_priv_prop(igb, pr_name, pr_valsize, pr_val);
114411502SChenlu.Chen@Sun.COM 		break;
114511502SChenlu.Chen@Sun.COM 	default:
114611502SChenlu.Chen@Sun.COM 		err = EINVAL;
114711502SChenlu.Chen@Sun.COM 		break;
114811502SChenlu.Chen@Sun.COM 	}
114911502SChenlu.Chen@Sun.COM 
115011502SChenlu.Chen@Sun.COM 	mutex_exit(&igb->gen_lock);
115111502SChenlu.Chen@Sun.COM 
115211502SChenlu.Chen@Sun.COM 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
115311502SChenlu.Chen@Sun.COM 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
115411502SChenlu.Chen@Sun.COM 		return (EIO);
115511502SChenlu.Chen@Sun.COM 	}
115611502SChenlu.Chen@Sun.COM 
115711502SChenlu.Chen@Sun.COM 	return (err);
115811502SChenlu.Chen@Sun.COM }
115911502SChenlu.Chen@Sun.COM 
116011502SChenlu.Chen@Sun.COM int
igb_m_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)116111502SChenlu.Chen@Sun.COM igb_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
116211878SVenu.Iyer@Sun.COM     uint_t pr_valsize, void *pr_val)
116311502SChenlu.Chen@Sun.COM {
116411502SChenlu.Chen@Sun.COM 	igb_t *igb = (igb_t *)arg;
116511502SChenlu.Chen@Sun.COM 	struct e1000_hw *hw = &igb->hw;
116611502SChenlu.Chen@Sun.COM 	int err = 0;
116711502SChenlu.Chen@Sun.COM 	uint32_t flow_control;
116811502SChenlu.Chen@Sun.COM 	uint64_t tmp = 0;
116911502SChenlu.Chen@Sun.COM 
117011502SChenlu.Chen@Sun.COM 	switch (pr_num) {
117111502SChenlu.Chen@Sun.COM 	case MAC_PROP_DUPLEX:
117211878SVenu.Iyer@Sun.COM 		ASSERT(pr_valsize >= sizeof (link_duplex_t));
117311878SVenu.Iyer@Sun.COM 		bcopy(&igb->link_duplex, pr_val, sizeof (link_duplex_t));
117411502SChenlu.Chen@Sun.COM 		break;
117511502SChenlu.Chen@Sun.COM 	case MAC_PROP_SPEED:
117611878SVenu.Iyer@Sun.COM 		ASSERT(pr_valsize >= sizeof (uint64_t));
117711878SVenu.Iyer@Sun.COM 		tmp = igb->link_speed * 1000000ull;
117811878SVenu.Iyer@Sun.COM 		bcopy(&tmp, pr_val, sizeof (tmp));
117911502SChenlu.Chen@Sun.COM 		break;
118011502SChenlu.Chen@Sun.COM 	case MAC_PROP_AUTONEG:
118111878SVenu.Iyer@Sun.COM 		ASSERT(pr_valsize >= sizeof (uint8_t));
118211502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_autoneg_cap;
118311502SChenlu.Chen@Sun.COM 		break;
118411502SChenlu.Chen@Sun.COM 	case MAC_PROP_FLOWCTRL:
118511878SVenu.Iyer@Sun.COM 		ASSERT(pr_valsize >= sizeof (uint32_t));
118611878SVenu.Iyer@Sun.COM 		switch (hw->fc.requested_mode) {
118711878SVenu.Iyer@Sun.COM 			case e1000_fc_none:
118811878SVenu.Iyer@Sun.COM 				flow_control = LINK_FLOWCTRL_NONE;
118911878SVenu.Iyer@Sun.COM 				break;
119011878SVenu.Iyer@Sun.COM 			case e1000_fc_rx_pause:
119111878SVenu.Iyer@Sun.COM 				flow_control = LINK_FLOWCTRL_RX;
119211878SVenu.Iyer@Sun.COM 				break;
119311878SVenu.Iyer@Sun.COM 			case e1000_fc_tx_pause:
119411878SVenu.Iyer@Sun.COM 				flow_control = LINK_FLOWCTRL_TX;
119511878SVenu.Iyer@Sun.COM 				break;
119611878SVenu.Iyer@Sun.COM 			case e1000_fc_full:
119711878SVenu.Iyer@Sun.COM 				flow_control = LINK_FLOWCTRL_BI;
119811878SVenu.Iyer@Sun.COM 				break;
119911878SVenu.Iyer@Sun.COM 		}
120011878SVenu.Iyer@Sun.COM 		bcopy(&flow_control, pr_val, sizeof (flow_control));
120111502SChenlu.Chen@Sun.COM 		break;
120211502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000FDX_CAP:
120311502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_1000fdx_cap;
120411502SChenlu.Chen@Sun.COM 		break;
120511502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000FDX_CAP:
120611502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_1000fdx_cap;
120711502SChenlu.Chen@Sun.COM 		break;
120811502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000HDX_CAP:
120911502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_1000hdx_cap;
121011502SChenlu.Chen@Sun.COM 		break;
121111502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000HDX_CAP:
121211502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_1000hdx_cap;
121311502SChenlu.Chen@Sun.COM 		break;
121411502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
121511502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_100t4_cap;
121611502SChenlu.Chen@Sun.COM 		break;
121711502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
121811502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_100t4_cap;
121911502SChenlu.Chen@Sun.COM 		break;
122011502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
122111502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_100fdx_cap;
122211502SChenlu.Chen@Sun.COM 		break;
122311502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
122411502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_100fdx_cap;
122511502SChenlu.Chen@Sun.COM 		break;
122611502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
122711502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_100hdx_cap;
122811502SChenlu.Chen@Sun.COM 		break;
122911502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
123011502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_100hdx_cap;
123111502SChenlu.Chen@Sun.COM 		break;
123211502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
123311502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_10fdx_cap;
123411502SChenlu.Chen@Sun.COM 		break;
123511502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
123611502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_10fdx_cap;
123711502SChenlu.Chen@Sun.COM 		break;
123811502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
123911502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_10hdx_cap;
124011502SChenlu.Chen@Sun.COM 		break;
124111502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
124211502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_10hdx_cap;
124311502SChenlu.Chen@Sun.COM 		break;
124411502SChenlu.Chen@Sun.COM 	case MAC_PROP_PRIVATE:
124511878SVenu.Iyer@Sun.COM 		err = igb_get_priv_prop(igb, pr_name, pr_valsize, pr_val);
124611502SChenlu.Chen@Sun.COM 		break;
124711502SChenlu.Chen@Sun.COM 	default:
124811502SChenlu.Chen@Sun.COM 		err = EINVAL;
124911502SChenlu.Chen@Sun.COM 		break;
125011502SChenlu.Chen@Sun.COM 	}
125111502SChenlu.Chen@Sun.COM 	return (err);
125211502SChenlu.Chen@Sun.COM }
125311502SChenlu.Chen@Sun.COM 
125411878SVenu.Iyer@Sun.COM void
igb_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)125511878SVenu.Iyer@Sun.COM igb_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
125611878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t prh)
125711502SChenlu.Chen@Sun.COM {
125811878SVenu.Iyer@Sun.COM 	igb_t *igb = (igb_t *)arg;
125911502SChenlu.Chen@Sun.COM 	struct e1000_hw *hw = &igb->hw;
126011878SVenu.Iyer@Sun.COM 	uint16_t phy_status, phy_ext_status;
126111502SChenlu.Chen@Sun.COM 
126211502SChenlu.Chen@Sun.COM 	switch (pr_num) {
126311878SVenu.Iyer@Sun.COM 	case MAC_PROP_DUPLEX:
126411878SVenu.Iyer@Sun.COM 	case MAC_PROP_SPEED:
126511502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000FDX_CAP:
126611502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000HDX_CAP:
126711502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000HDX_CAP:
126811502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
126911502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
127011878SVenu.Iyer@Sun.COM 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
127111502SChenlu.Chen@Sun.COM 		break;
127211878SVenu.Iyer@Sun.COM 
127311878SVenu.Iyer@Sun.COM 	case MAC_PROP_EN_1000FDX_CAP:
127411878SVenu.Iyer@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
127511878SVenu.Iyer@Sun.COM 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
127611878SVenu.Iyer@Sun.COM 		} else {
127711878SVenu.Iyer@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_EXT_STATUS,
127811878SVenu.Iyer@Sun.COM 			    &phy_ext_status);
127911878SVenu.Iyer@Sun.COM 			mac_prop_info_set_default_uint8(prh,
128011878SVenu.Iyer@Sun.COM 			    ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
128111878SVenu.Iyer@Sun.COM 			    (phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0);
128211878SVenu.Iyer@Sun.COM 		}
128311878SVenu.Iyer@Sun.COM 		break;
128411878SVenu.Iyer@Sun.COM 
128511502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
128611502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
128711502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
128811878SVenu.Iyer@Sun.COM 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
128911502SChenlu.Chen@Sun.COM 		} else {
129011502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
129111878SVenu.Iyer@Sun.COM 			mac_prop_info_set_default_uint8(prh,
129211502SChenlu.Chen@Sun.COM 			    ((phy_status & MII_SR_100X_FD_CAPS) ||
129311878SVenu.Iyer@Sun.COM 			    (phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0);
129411502SChenlu.Chen@Sun.COM 		}
129511502SChenlu.Chen@Sun.COM 		break;
129611878SVenu.Iyer@Sun.COM 
129711502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
129811502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
129911502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
130011878SVenu.Iyer@Sun.COM 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
130111502SChenlu.Chen@Sun.COM 		} else {
130211502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
130311878SVenu.Iyer@Sun.COM 			mac_prop_info_set_default_uint8(prh,
130411502SChenlu.Chen@Sun.COM 			    ((phy_status & MII_SR_100X_HD_CAPS) ||
130511878SVenu.Iyer@Sun.COM 			    (phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0);
130611502SChenlu.Chen@Sun.COM 		}
130711502SChenlu.Chen@Sun.COM 		break;
130811878SVenu.Iyer@Sun.COM 
130911502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
131011502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
131111502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
131211878SVenu.Iyer@Sun.COM 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
131311502SChenlu.Chen@Sun.COM 		} else {
131411502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
131511878SVenu.Iyer@Sun.COM 			mac_prop_info_set_default_uint8(prh,
131611878SVenu.Iyer@Sun.COM 			    (phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0);
131711502SChenlu.Chen@Sun.COM 		}
131811502SChenlu.Chen@Sun.COM 		break;
131911878SVenu.Iyer@Sun.COM 
132011502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
132111502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
132211502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
132311878SVenu.Iyer@Sun.COM 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
132411878SVenu.Iyer@Sun.COM 		} else {
132511878SVenu.Iyer@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
132611878SVenu.Iyer@Sun.COM 			mac_prop_info_set_default_uint8(prh,
132711878SVenu.Iyer@Sun.COM 			    (phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0);
132811878SVenu.Iyer@Sun.COM 		}
132911878SVenu.Iyer@Sun.COM 		break;
133011878SVenu.Iyer@Sun.COM 
133111878SVenu.Iyer@Sun.COM 	case MAC_PROP_AUTONEG:
133211878SVenu.Iyer@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
133311878SVenu.Iyer@Sun.COM 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
133411502SChenlu.Chen@Sun.COM 		} else {
133511502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
133611878SVenu.Iyer@Sun.COM 			mac_prop_info_set_default_uint8(prh,
133711878SVenu.Iyer@Sun.COM 			    (phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0);
133811502SChenlu.Chen@Sun.COM 		}
133911502SChenlu.Chen@Sun.COM 		break;
134011878SVenu.Iyer@Sun.COM 
134111878SVenu.Iyer@Sun.COM 	case MAC_PROP_FLOWCTRL:
134211878SVenu.Iyer@Sun.COM 		mac_prop_info_set_default_link_flowctrl(prh, LINK_FLOWCTRL_BI);
134311878SVenu.Iyer@Sun.COM 		break;
134411878SVenu.Iyer@Sun.COM 
134511878SVenu.Iyer@Sun.COM 	case MAC_PROP_MTU:
134611878SVenu.Iyer@Sun.COM 		mac_prop_info_set_range_uint32(prh, MIN_MTU, MAX_MTU);
134711878SVenu.Iyer@Sun.COM 		break;
134811878SVenu.Iyer@Sun.COM 
134911878SVenu.Iyer@Sun.COM 	case MAC_PROP_PRIVATE:
135011878SVenu.Iyer@Sun.COM 		igb_priv_prop_info(igb, pr_name, prh);
135111502SChenlu.Chen@Sun.COM 		break;
135211502SChenlu.Chen@Sun.COM 	}
135311878SVenu.Iyer@Sun.COM 
135411502SChenlu.Chen@Sun.COM }
135511502SChenlu.Chen@Sun.COM 
135611502SChenlu.Chen@Sun.COM boolean_t
igb_param_locked(mac_prop_id_t pr_num)135711502SChenlu.Chen@Sun.COM igb_param_locked(mac_prop_id_t pr_num)
135811502SChenlu.Chen@Sun.COM {
135911502SChenlu.Chen@Sun.COM 	/*
136011502SChenlu.Chen@Sun.COM 	 * All en_* parameters are locked (read-only) while
136111502SChenlu.Chen@Sun.COM 	 * the device is in any sort of loopback mode ...
136211502SChenlu.Chen@Sun.COM 	 */
136311502SChenlu.Chen@Sun.COM 	switch (pr_num) {
136411502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_1000FDX_CAP:
136511502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_1000HDX_CAP:
136611502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_100T4_CAP:
136711502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_100FDX_CAP:
136811502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_100HDX_CAP:
136911502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_10FDX_CAP:
137011502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_10HDX_CAP:
137111502SChenlu.Chen@Sun.COM 		case MAC_PROP_AUTONEG:
137211502SChenlu.Chen@Sun.COM 		case MAC_PROP_FLOWCTRL:
137311502SChenlu.Chen@Sun.COM 			return (B_TRUE);
137411502SChenlu.Chen@Sun.COM 	}
137511502SChenlu.Chen@Sun.COM 	return (B_FALSE);
137611502SChenlu.Chen@Sun.COM }
137711502SChenlu.Chen@Sun.COM 
137811502SChenlu.Chen@Sun.COM /* ARGSUSED */
137911502SChenlu.Chen@Sun.COM int
igb_set_priv_prop(igb_t * igb,const char * pr_name,uint_t pr_valsize,const void * pr_val)138011502SChenlu.Chen@Sun.COM igb_set_priv_prop(igb_t *igb, const char *pr_name,
138111502SChenlu.Chen@Sun.COM     uint_t pr_valsize, const void *pr_val)
138211502SChenlu.Chen@Sun.COM {
138311502SChenlu.Chen@Sun.COM 	int err = 0;
138411502SChenlu.Chen@Sun.COM 	long result;
138511502SChenlu.Chen@Sun.COM 	struct e1000_hw *hw = &igb->hw;
138611502SChenlu.Chen@Sun.COM 	int i;
138711502SChenlu.Chen@Sun.COM 
138811502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
138911502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
139011502SChenlu.Chen@Sun.COM 			err = EINVAL;
139111502SChenlu.Chen@Sun.COM 			return (err);
139211502SChenlu.Chen@Sun.COM 		}
139311502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
139411502SChenlu.Chen@Sun.COM 		if (result < MIN_TX_COPY_THRESHOLD ||
139511502SChenlu.Chen@Sun.COM 		    result > MAX_TX_COPY_THRESHOLD)
139611502SChenlu.Chen@Sun.COM 			err = EINVAL;
139711502SChenlu.Chen@Sun.COM 		else {
139811502SChenlu.Chen@Sun.COM 			igb->tx_copy_thresh = (uint32_t)result;
139911502SChenlu.Chen@Sun.COM 		}
140011502SChenlu.Chen@Sun.COM 		return (err);
140111502SChenlu.Chen@Sun.COM 	}
140211502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
140311502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
140411502SChenlu.Chen@Sun.COM 			err = EINVAL;
140511502SChenlu.Chen@Sun.COM 			return (err);
140611502SChenlu.Chen@Sun.COM 		}
140711502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
140811502SChenlu.Chen@Sun.COM 		if (result < MIN_TX_RECYCLE_THRESHOLD ||
140911502SChenlu.Chen@Sun.COM 		    result > MAX_TX_RECYCLE_THRESHOLD)
141011502SChenlu.Chen@Sun.COM 			err = EINVAL;
141111502SChenlu.Chen@Sun.COM 		else {
141211502SChenlu.Chen@Sun.COM 			igb->tx_recycle_thresh = (uint32_t)result;
141311502SChenlu.Chen@Sun.COM 		}
141411502SChenlu.Chen@Sun.COM 		return (err);
141511502SChenlu.Chen@Sun.COM 	}
141611502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
141711502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
141811502SChenlu.Chen@Sun.COM 			err = EINVAL;
141911502SChenlu.Chen@Sun.COM 			return (err);
142011502SChenlu.Chen@Sun.COM 		}
142111502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
142211502SChenlu.Chen@Sun.COM 		if (result < MIN_TX_OVERLOAD_THRESHOLD ||
142311502SChenlu.Chen@Sun.COM 		    result > MAX_TX_OVERLOAD_THRESHOLD)
142411502SChenlu.Chen@Sun.COM 			err = EINVAL;
142511502SChenlu.Chen@Sun.COM 		else {
142611502SChenlu.Chen@Sun.COM 			igb->tx_overload_thresh = (uint32_t)result;
142711502SChenlu.Chen@Sun.COM 		}
142811502SChenlu.Chen@Sun.COM 		return (err);
142911502SChenlu.Chen@Sun.COM 	}
143011502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
143111502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
143211502SChenlu.Chen@Sun.COM 			err = EINVAL;
143311502SChenlu.Chen@Sun.COM 			return (err);
143411502SChenlu.Chen@Sun.COM 		}
143511502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
143611502SChenlu.Chen@Sun.COM 		if (result < MIN_TX_RESCHED_THRESHOLD ||
1437*12980SGuoqing.Zhu@Sun.COM 		    result > MAX_TX_RESCHED_THRESHOLD ||
1438*12980SGuoqing.Zhu@Sun.COM 		    result > igb->tx_ring_size)
143911502SChenlu.Chen@Sun.COM 			err = EINVAL;
144011502SChenlu.Chen@Sun.COM 		else {
144111502SChenlu.Chen@Sun.COM 			igb->tx_resched_thresh = (uint32_t)result;
144211502SChenlu.Chen@Sun.COM 		}
144311502SChenlu.Chen@Sun.COM 		return (err);
144411502SChenlu.Chen@Sun.COM 	}
144511502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
144611502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
144711502SChenlu.Chen@Sun.COM 			err = EINVAL;
144811502SChenlu.Chen@Sun.COM 			return (err);
144911502SChenlu.Chen@Sun.COM 		}
145011502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
145111502SChenlu.Chen@Sun.COM 		if (result < MIN_RX_COPY_THRESHOLD ||
145211502SChenlu.Chen@Sun.COM 		    result > MAX_RX_COPY_THRESHOLD)
145311502SChenlu.Chen@Sun.COM 			err = EINVAL;
145411502SChenlu.Chen@Sun.COM 		else {
145511502SChenlu.Chen@Sun.COM 			igb->rx_copy_thresh = (uint32_t)result;
145611502SChenlu.Chen@Sun.COM 		}
145711502SChenlu.Chen@Sun.COM 		return (err);
145811502SChenlu.Chen@Sun.COM 	}
145911502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
146011502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
146111502SChenlu.Chen@Sun.COM 			err = EINVAL;
146211502SChenlu.Chen@Sun.COM 			return (err);
146311502SChenlu.Chen@Sun.COM 		}
146411502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
146511502SChenlu.Chen@Sun.COM 		if (result < MIN_RX_LIMIT_PER_INTR ||
146611502SChenlu.Chen@Sun.COM 		    result > MAX_RX_LIMIT_PER_INTR)
146711502SChenlu.Chen@Sun.COM 			err = EINVAL;
146811502SChenlu.Chen@Sun.COM 		else {
146911502SChenlu.Chen@Sun.COM 			igb->rx_limit_per_intr = (uint32_t)result;
147011502SChenlu.Chen@Sun.COM 		}
147111502SChenlu.Chen@Sun.COM 		return (err);
147211502SChenlu.Chen@Sun.COM 	}
147311502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_intr_throttling") == 0) {
147411502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
147511502SChenlu.Chen@Sun.COM 			err = EINVAL;
147611502SChenlu.Chen@Sun.COM 			return (err);
147711502SChenlu.Chen@Sun.COM 		}
147811502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
147911502SChenlu.Chen@Sun.COM 
148011502SChenlu.Chen@Sun.COM 		if (result < igb->capab->min_intr_throttle ||
148111502SChenlu.Chen@Sun.COM 		    result > igb->capab->max_intr_throttle)
148211502SChenlu.Chen@Sun.COM 			err = EINVAL;
148311502SChenlu.Chen@Sun.COM 		else {
148411502SChenlu.Chen@Sun.COM 			igb->intr_throttling[0] = (uint32_t)result;
148511502SChenlu.Chen@Sun.COM 
148611502SChenlu.Chen@Sun.COM 			for (i = 0; i < MAX_NUM_EITR; i++)
148711502SChenlu.Chen@Sun.COM 				igb->intr_throttling[i] =
148811502SChenlu.Chen@Sun.COM 				    igb->intr_throttling[0];
148911502SChenlu.Chen@Sun.COM 
149011502SChenlu.Chen@Sun.COM 			/* Set interrupt throttling rate */
149111502SChenlu.Chen@Sun.COM 			for (i = 0; i < igb->intr_cnt; i++)
149211502SChenlu.Chen@Sun.COM 				E1000_WRITE_REG(hw, E1000_EITR(i),
149311502SChenlu.Chen@Sun.COM 				    igb->intr_throttling[i]);
149411502SChenlu.Chen@Sun.COM 		}
149511502SChenlu.Chen@Sun.COM 		return (err);
149611502SChenlu.Chen@Sun.COM 	}
149711502SChenlu.Chen@Sun.COM 	return (ENOTSUP);
149811502SChenlu.Chen@Sun.COM }
149911502SChenlu.Chen@Sun.COM 
150011502SChenlu.Chen@Sun.COM int
igb_get_priv_prop(igb_t * igb,const char * pr_name,uint_t pr_valsize,void * pr_val)150111878SVenu.Iyer@Sun.COM igb_get_priv_prop(igb_t *igb, const char *pr_name, uint_t pr_valsize,
150211878SVenu.Iyer@Sun.COM     void *pr_val)
150311502SChenlu.Chen@Sun.COM {
150411502SChenlu.Chen@Sun.COM 	int value;
150511502SChenlu.Chen@Sun.COM 
150611502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_adv_pause_cap") == 0) {
150711878SVenu.Iyer@Sun.COM 		value = igb->param_adv_pause_cap;
150811878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
150911878SVenu.Iyer@Sun.COM 		value = igb->param_adv_asym_pause_cap;
151011878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
151111878SVenu.Iyer@Sun.COM 		value = igb->tx_copy_thresh;
151211878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
151311878SVenu.Iyer@Sun.COM 		value = igb->tx_recycle_thresh;
151411878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
151511878SVenu.Iyer@Sun.COM 		value = igb->tx_overload_thresh;
151611878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
151711878SVenu.Iyer@Sun.COM 		value = igb->tx_resched_thresh;
151811878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
151911878SVenu.Iyer@Sun.COM 		value = igb->rx_copy_thresh;
152011878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
152111878SVenu.Iyer@Sun.COM 		value = igb->rx_limit_per_intr;
152211878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_intr_throttling") == 0) {
152311878SVenu.Iyer@Sun.COM 		value = igb->intr_throttling[0];
152411878SVenu.Iyer@Sun.COM 	} else {
152511878SVenu.Iyer@Sun.COM 		return (ENOTSUP);
152611502SChenlu.Chen@Sun.COM 	}
152711878SVenu.Iyer@Sun.COM 
152811878SVenu.Iyer@Sun.COM 	(void) snprintf(pr_val, pr_valsize, "%d", value);
152911878SVenu.Iyer@Sun.COM 	return (0);
153011878SVenu.Iyer@Sun.COM }
153111878SVenu.Iyer@Sun.COM 
153211878SVenu.Iyer@Sun.COM void
igb_priv_prop_info(igb_t * igb,const char * pr_name,mac_prop_info_handle_t prh)153311878SVenu.Iyer@Sun.COM igb_priv_prop_info(igb_t *igb, const char *pr_name, mac_prop_info_handle_t prh)
153411878SVenu.Iyer@Sun.COM {
153511878SVenu.Iyer@Sun.COM 	char valstr[64];
153611878SVenu.Iyer@Sun.COM 	int value;
153711878SVenu.Iyer@Sun.COM 
153811878SVenu.Iyer@Sun.COM 	if (strcmp(pr_name, "_adv_pause_cap") == 0 ||
153911878SVenu.Iyer@Sun.COM 	    strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
154011878SVenu.Iyer@Sun.COM 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
154111878SVenu.Iyer@Sun.COM 		return;
154211878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
154311878SVenu.Iyer@Sun.COM 		value = DEFAULT_TX_COPY_THRESHOLD;
154411878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
154511878SVenu.Iyer@Sun.COM 		value = DEFAULT_TX_RECYCLE_THRESHOLD;
154611878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
154711878SVenu.Iyer@Sun.COM 		value = DEFAULT_TX_OVERLOAD_THRESHOLD;
154811878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
154911878SVenu.Iyer@Sun.COM 		value = DEFAULT_TX_RESCHED_THRESHOLD;
155011878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
155111878SVenu.Iyer@Sun.COM 		value = DEFAULT_RX_COPY_THRESHOLD;
155211878SVenu.Iyer@Sun.COM 	} else if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
155311878SVenu.Iyer@Sun.COM 		value = DEFAULT_RX_LIMIT_PER_INTR;
155411878SVenu.Iyer@Sun.COM 	} else 	if (strcmp(pr_name, "_intr_throttling") == 0) {
155511878SVenu.Iyer@Sun.COM 		value = igb->capab->def_intr_throttle;
155611878SVenu.Iyer@Sun.COM 	} else {
155711878SVenu.Iyer@Sun.COM 		return;
155811502SChenlu.Chen@Sun.COM 	}
155911878SVenu.Iyer@Sun.COM 
156011878SVenu.Iyer@Sun.COM 	(void) snprintf(valstr, sizeof (valstr), "%d", value);
156111878SVenu.Iyer@Sun.COM 	mac_prop_info_set_default_str(prh, valstr);
156211502SChenlu.Chen@Sun.COM }
1563