xref: /onnv-gate/usr/src/uts/common/io/igb/igb_gld.c (revision 11502:d9233a6f9baa)
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 /*
238275SEric Cheng  * Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
245779Sxy150489  */
255779Sxy150489 
268275SEric Cheng /*
27*11502SChenlu.Chen@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
288275SEric Cheng  * Use is subject to license terms.
298275SEric Cheng  */
305779Sxy150489 
315779Sxy150489 #include "igb_sw.h"
325779Sxy150489 
335779Sxy150489 int
345779Sxy150489 igb_m_stat(void *arg, uint_t stat, uint64_t *val)
355779Sxy150489 {
365779Sxy150489 	igb_t *igb = (igb_t *)arg;
375779Sxy150489 	struct e1000_hw *hw = &igb->hw;
385779Sxy150489 	igb_stat_t *igb_ks;
395779Sxy150489 	uint32_t low_val, high_val;
405779Sxy150489 
415779Sxy150489 	igb_ks = (igb_stat_t *)igb->igb_ks->ks_data;
425779Sxy150489 
435779Sxy150489 	mutex_enter(&igb->gen_lock);
445779Sxy150489 
455779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
465779Sxy150489 		mutex_exit(&igb->gen_lock);
475779Sxy150489 		return (ECANCELED);
485779Sxy150489 	}
495779Sxy150489 
505779Sxy150489 	switch (stat) {
515779Sxy150489 	case MAC_STAT_IFSPEED:
525779Sxy150489 		*val = igb->link_speed * 1000000ull;
535779Sxy150489 		break;
545779Sxy150489 
555779Sxy150489 	case MAC_STAT_MULTIRCV:
565779Sxy150489 		igb_ks->mprc.value.ui64 +=
575779Sxy150489 		    E1000_READ_REG(hw, E1000_MPRC);
585779Sxy150489 		*val = igb_ks->mprc.value.ui64;
595779Sxy150489 		break;
605779Sxy150489 
615779Sxy150489 	case MAC_STAT_BRDCSTRCV:
625779Sxy150489 		igb_ks->bprc.value.ui64 +=
635779Sxy150489 		    E1000_READ_REG(hw, E1000_BPRC);
645779Sxy150489 		*val = igb_ks->bprc.value.ui64;
655779Sxy150489 		break;
665779Sxy150489 
675779Sxy150489 	case MAC_STAT_MULTIXMT:
685779Sxy150489 		igb_ks->mptc.value.ui64 +=
695779Sxy150489 		    E1000_READ_REG(hw, E1000_MPTC);
705779Sxy150489 		*val = igb_ks->mptc.value.ui64;
715779Sxy150489 		break;
725779Sxy150489 
735779Sxy150489 	case MAC_STAT_BRDCSTXMT:
745779Sxy150489 		igb_ks->bptc.value.ui64 +=
755779Sxy150489 		    E1000_READ_REG(hw, E1000_BPTC);
765779Sxy150489 		*val = igb_ks->bptc.value.ui64;
775779Sxy150489 		break;
785779Sxy150489 
795779Sxy150489 	case MAC_STAT_NORCVBUF:
805779Sxy150489 		igb_ks->rnbc.value.ui64 +=
815779Sxy150489 		    E1000_READ_REG(hw, E1000_RNBC);
825779Sxy150489 		*val = igb_ks->rnbc.value.ui64;
835779Sxy150489 		break;
845779Sxy150489 
855779Sxy150489 	case MAC_STAT_IERRORS:
865779Sxy150489 		igb_ks->rxerrc.value.ui64 +=
875779Sxy150489 		    E1000_READ_REG(hw, E1000_RXERRC);
885779Sxy150489 		igb_ks->algnerrc.value.ui64 +=
895779Sxy150489 		    E1000_READ_REG(hw, E1000_ALGNERRC);
905779Sxy150489 		igb_ks->rlec.value.ui64 +=
915779Sxy150489 		    E1000_READ_REG(hw, E1000_RLEC);
925779Sxy150489 		igb_ks->crcerrs.value.ui64 +=
935779Sxy150489 		    E1000_READ_REG(hw, E1000_CRCERRS);
945779Sxy150489 		igb_ks->cexterr.value.ui64 +=
955779Sxy150489 		    E1000_READ_REG(hw, E1000_CEXTERR);
965779Sxy150489 		*val = igb_ks->rxerrc.value.ui64 +
975779Sxy150489 		    igb_ks->algnerrc.value.ui64 +
985779Sxy150489 		    igb_ks->rlec.value.ui64 +
995779Sxy150489 		    igb_ks->crcerrs.value.ui64 +
1005779Sxy150489 		    igb_ks->cexterr.value.ui64;
1015779Sxy150489 		break;
1025779Sxy150489 
1035779Sxy150489 	case MAC_STAT_NOXMTBUF:
1045779Sxy150489 		*val = 0;
1055779Sxy150489 		break;
1065779Sxy150489 
1075779Sxy150489 	case MAC_STAT_OERRORS:
1085779Sxy150489 		igb_ks->ecol.value.ui64 +=
1095779Sxy150489 		    E1000_READ_REG(hw, E1000_ECOL);
1105779Sxy150489 		*val = igb_ks->ecol.value.ui64;
1115779Sxy150489 		break;
1125779Sxy150489 
1135779Sxy150489 	case MAC_STAT_COLLISIONS:
1145779Sxy150489 		igb_ks->colc.value.ui64 +=
1155779Sxy150489 		    E1000_READ_REG(hw, E1000_COLC);
1165779Sxy150489 		*val = igb_ks->colc.value.ui64;
1175779Sxy150489 		break;
1185779Sxy150489 
1195779Sxy150489 	case MAC_STAT_RBYTES:
1205779Sxy150489 		/*
1215779Sxy150489 		 * The 64-bit register will reset whenever the upper
1225779Sxy150489 		 * 32 bits are read. So we need to read the lower
1235779Sxy150489 		 * 32 bits first, then read the upper 32 bits.
1245779Sxy150489 		 */
1255779Sxy150489 		low_val = E1000_READ_REG(hw, E1000_TORL);
1265779Sxy150489 		high_val = E1000_READ_REG(hw, E1000_TORH);
1275779Sxy150489 		igb_ks->tor.value.ui64 +=
1285779Sxy150489 		    (uint64_t)high_val << 32 | (uint64_t)low_val;
1295779Sxy150489 		*val = igb_ks->tor.value.ui64;
1305779Sxy150489 		break;
1315779Sxy150489 
1325779Sxy150489 	case MAC_STAT_IPACKETS:
1335779Sxy150489 		igb_ks->tpr.value.ui64 +=
1345779Sxy150489 		    E1000_READ_REG(hw, E1000_TPR);
1355779Sxy150489 		*val = igb_ks->tpr.value.ui64;
1365779Sxy150489 		break;
1375779Sxy150489 
1385779Sxy150489 	case MAC_STAT_OBYTES:
1395779Sxy150489 		/*
1405779Sxy150489 		 * The 64-bit register will reset whenever the upper
1415779Sxy150489 		 * 32 bits are read. So we need to read the lower
1425779Sxy150489 		 * 32 bits first, then read the upper 32 bits.
1435779Sxy150489 		 */
1445779Sxy150489 		low_val = E1000_READ_REG(hw, E1000_TOTL);
1455779Sxy150489 		high_val = E1000_READ_REG(hw, E1000_TOTH);
1465779Sxy150489 		igb_ks->tot.value.ui64 +=
1475779Sxy150489 		    (uint64_t)high_val << 32 | (uint64_t)low_val;
1485779Sxy150489 		*val = igb_ks->tot.value.ui64;
1495779Sxy150489 		break;
1505779Sxy150489 
1515779Sxy150489 	case MAC_STAT_OPACKETS:
1525779Sxy150489 		igb_ks->tpt.value.ui64 +=
1535779Sxy150489 		    E1000_READ_REG(hw, E1000_TPT);
1545779Sxy150489 		*val = igb_ks->tpt.value.ui64;
1555779Sxy150489 		break;
1565779Sxy150489 
1575779Sxy150489 	/* RFC 1643 stats */
1585779Sxy150489 	case ETHER_STAT_ALIGN_ERRORS:
1595779Sxy150489 		igb_ks->algnerrc.value.ui64 +=
1605779Sxy150489 		    E1000_READ_REG(hw, E1000_ALGNERRC);
1615779Sxy150489 		*val = igb_ks->algnerrc.value.ui64;
1625779Sxy150489 		break;
1635779Sxy150489 
1645779Sxy150489 	case ETHER_STAT_FCS_ERRORS:
1655779Sxy150489 		igb_ks->crcerrs.value.ui64 +=
1665779Sxy150489 		    E1000_READ_REG(hw, E1000_CRCERRS);
1675779Sxy150489 		*val = igb_ks->crcerrs.value.ui64;
1685779Sxy150489 		break;
1695779Sxy150489 
1705779Sxy150489 	case ETHER_STAT_FIRST_COLLISIONS:
1715779Sxy150489 		igb_ks->scc.value.ui64 +=
1725779Sxy150489 		    E1000_READ_REG(hw, E1000_SCC);
1735779Sxy150489 		*val = igb_ks->scc.value.ui64;
1745779Sxy150489 		break;
1755779Sxy150489 
1765779Sxy150489 	case ETHER_STAT_MULTI_COLLISIONS:
1775779Sxy150489 		igb_ks->mcc.value.ui64 +=
1785779Sxy150489 		    E1000_READ_REG(hw, E1000_MCC);
1795779Sxy150489 		*val = igb_ks->mcc.value.ui64;
1805779Sxy150489 		break;
1815779Sxy150489 
1825779Sxy150489 	case ETHER_STAT_SQE_ERRORS:
1835779Sxy150489 		igb_ks->sec.value.ui64 +=
1845779Sxy150489 		    E1000_READ_REG(hw, E1000_SEC);
1855779Sxy150489 		*val = igb_ks->sec.value.ui64;
1865779Sxy150489 		break;
1875779Sxy150489 
1885779Sxy150489 	case ETHER_STAT_DEFER_XMTS:
1895779Sxy150489 		igb_ks->dc.value.ui64 +=
1905779Sxy150489 		    E1000_READ_REG(hw, E1000_DC);
1915779Sxy150489 		*val = igb_ks->dc.value.ui64;
1925779Sxy150489 		break;
1935779Sxy150489 
1945779Sxy150489 	case ETHER_STAT_TX_LATE_COLLISIONS:
1955779Sxy150489 		igb_ks->latecol.value.ui64 +=
1965779Sxy150489 		    E1000_READ_REG(hw, E1000_LATECOL);
1975779Sxy150489 		*val = igb_ks->latecol.value.ui64;
1985779Sxy150489 		break;
1995779Sxy150489 
2005779Sxy150489 	case ETHER_STAT_EX_COLLISIONS:
2015779Sxy150489 		igb_ks->ecol.value.ui64 +=
2025779Sxy150489 		    E1000_READ_REG(hw, E1000_ECOL);
2035779Sxy150489 		*val = igb_ks->ecol.value.ui64;
2045779Sxy150489 		break;
2055779Sxy150489 
2065779Sxy150489 	case ETHER_STAT_MACXMT_ERRORS:
2075779Sxy150489 		igb_ks->ecol.value.ui64 +=
2085779Sxy150489 		    E1000_READ_REG(hw, E1000_ECOL);
2095779Sxy150489 		*val = igb_ks->ecol.value.ui64;
2105779Sxy150489 		break;
2115779Sxy150489 
2125779Sxy150489 	case ETHER_STAT_CARRIER_ERRORS:
2135779Sxy150489 		igb_ks->cexterr.value.ui64 +=
2145779Sxy150489 		    E1000_READ_REG(hw, E1000_CEXTERR);
2155779Sxy150489 		*val = igb_ks->cexterr.value.ui64;
2165779Sxy150489 		break;
2175779Sxy150489 
2185779Sxy150489 	case ETHER_STAT_TOOLONG_ERRORS:
2195779Sxy150489 		igb_ks->roc.value.ui64 +=
2205779Sxy150489 		    E1000_READ_REG(hw, E1000_ROC);
2215779Sxy150489 		*val = igb_ks->roc.value.ui64;
2225779Sxy150489 		break;
2235779Sxy150489 
2245779Sxy150489 	case ETHER_STAT_MACRCV_ERRORS:
2255779Sxy150489 		igb_ks->rxerrc.value.ui64 +=
2265779Sxy150489 		    E1000_READ_REG(hw, E1000_RXERRC);
2275779Sxy150489 		*val = igb_ks->rxerrc.value.ui64;
2285779Sxy150489 		break;
2295779Sxy150489 
2305779Sxy150489 	/* MII/GMII stats */
2315779Sxy150489 	case ETHER_STAT_XCVR_ADDR:
2325779Sxy150489 		/* The Internal PHY's MDI address for each MAC is 1 */
2335779Sxy150489 		*val = 1;
2345779Sxy150489 		break;
2355779Sxy150489 
2365779Sxy150489 	case ETHER_STAT_XCVR_ID:
2375779Sxy150489 		*val = hw->phy.id | hw->phy.revision;
2385779Sxy150489 		break;
2395779Sxy150489 
2405779Sxy150489 	case ETHER_STAT_XCVR_INUSE:
2415779Sxy150489 		switch (igb->link_speed) {
2425779Sxy150489 		case SPEED_1000:
2435779Sxy150489 			*val =
2445779Sxy150489 			    (hw->phy.media_type == e1000_media_type_copper) ?
2455779Sxy150489 			    XCVR_1000T : XCVR_1000X;
2465779Sxy150489 			break;
2475779Sxy150489 		case SPEED_100:
2485779Sxy150489 			*val =
2495779Sxy150489 			    (hw->phy.media_type == e1000_media_type_copper) ?
2505779Sxy150489 			    (igb->param_100t4_cap == 1) ?
2515779Sxy150489 			    XCVR_100T4 : XCVR_100T2 : XCVR_100X;
2525779Sxy150489 			break;
2535779Sxy150489 		case SPEED_10:
2545779Sxy150489 			*val = XCVR_10;
2555779Sxy150489 			break;
2565779Sxy150489 		default:
2575779Sxy150489 			*val = XCVR_NONE;
2585779Sxy150489 			break;
2595779Sxy150489 		}
2605779Sxy150489 		break;
2615779Sxy150489 
2625779Sxy150489 	case ETHER_STAT_CAP_1000FDX:
2635779Sxy150489 		*val = igb->param_1000fdx_cap;
2645779Sxy150489 		break;
2655779Sxy150489 
2665779Sxy150489 	case ETHER_STAT_CAP_1000HDX:
2675779Sxy150489 		*val = igb->param_1000hdx_cap;
2685779Sxy150489 		break;
2695779Sxy150489 
2705779Sxy150489 	case ETHER_STAT_CAP_100FDX:
2715779Sxy150489 		*val = igb->param_100fdx_cap;
2725779Sxy150489 		break;
2735779Sxy150489 
2745779Sxy150489 	case ETHER_STAT_CAP_100HDX:
2755779Sxy150489 		*val = igb->param_100hdx_cap;
2765779Sxy150489 		break;
2775779Sxy150489 
2785779Sxy150489 	case ETHER_STAT_CAP_10FDX:
2795779Sxy150489 		*val = igb->param_10fdx_cap;
2805779Sxy150489 		break;
2815779Sxy150489 
2825779Sxy150489 	case ETHER_STAT_CAP_10HDX:
2835779Sxy150489 		*val = igb->param_10hdx_cap;
2845779Sxy150489 		break;
2855779Sxy150489 
2865779Sxy150489 	case ETHER_STAT_CAP_ASMPAUSE:
2875779Sxy150489 		*val = igb->param_asym_pause_cap;
2885779Sxy150489 		break;
2895779Sxy150489 
2905779Sxy150489 	case ETHER_STAT_CAP_PAUSE:
2915779Sxy150489 		*val = igb->param_pause_cap;
2925779Sxy150489 		break;
2935779Sxy150489 
2945779Sxy150489 	case ETHER_STAT_CAP_AUTONEG:
2955779Sxy150489 		*val = igb->param_autoneg_cap;
2965779Sxy150489 		break;
2975779Sxy150489 
2985779Sxy150489 	case ETHER_STAT_ADV_CAP_1000FDX:
2995779Sxy150489 		*val = igb->param_adv_1000fdx_cap;
3005779Sxy150489 		break;
3015779Sxy150489 
3025779Sxy150489 	case ETHER_STAT_ADV_CAP_1000HDX:
3035779Sxy150489 		*val = igb->param_adv_1000hdx_cap;
3045779Sxy150489 		break;
3055779Sxy150489 
3065779Sxy150489 	case ETHER_STAT_ADV_CAP_100FDX:
3075779Sxy150489 		*val = igb->param_adv_100fdx_cap;
3085779Sxy150489 		break;
3095779Sxy150489 
3105779Sxy150489 	case ETHER_STAT_ADV_CAP_100HDX:
3115779Sxy150489 		*val = igb->param_adv_100hdx_cap;
3125779Sxy150489 		break;
3135779Sxy150489 
3145779Sxy150489 	case ETHER_STAT_ADV_CAP_10FDX:
3155779Sxy150489 		*val = igb->param_adv_10fdx_cap;
3165779Sxy150489 		break;
3175779Sxy150489 
3185779Sxy150489 	case ETHER_STAT_ADV_CAP_10HDX:
3195779Sxy150489 		*val = igb->param_adv_10hdx_cap;
3205779Sxy150489 		break;
3215779Sxy150489 
3225779Sxy150489 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
3235779Sxy150489 		*val = igb->param_adv_asym_pause_cap;
3245779Sxy150489 		break;
3255779Sxy150489 
3265779Sxy150489 	case ETHER_STAT_ADV_CAP_PAUSE:
3275779Sxy150489 		*val = igb->param_adv_pause_cap;
3285779Sxy150489 		break;
3295779Sxy150489 
3305779Sxy150489 	case ETHER_STAT_ADV_CAP_AUTONEG:
3315779Sxy150489 		*val = hw->mac.autoneg;
3325779Sxy150489 		break;
3335779Sxy150489 
3345779Sxy150489 	case ETHER_STAT_LP_CAP_1000FDX:
3355779Sxy150489 		*val = igb->param_lp_1000fdx_cap;
3365779Sxy150489 		break;
3375779Sxy150489 
3385779Sxy150489 	case ETHER_STAT_LP_CAP_1000HDX:
3395779Sxy150489 		*val = igb->param_lp_1000hdx_cap;
3405779Sxy150489 		break;
3415779Sxy150489 
3425779Sxy150489 	case ETHER_STAT_LP_CAP_100FDX:
3435779Sxy150489 		*val = igb->param_lp_100fdx_cap;
3445779Sxy150489 		break;
3455779Sxy150489 
3465779Sxy150489 	case ETHER_STAT_LP_CAP_100HDX:
3475779Sxy150489 		*val = igb->param_lp_100hdx_cap;
3485779Sxy150489 		break;
3495779Sxy150489 
3505779Sxy150489 	case ETHER_STAT_LP_CAP_10FDX:
3515779Sxy150489 		*val = igb->param_lp_10fdx_cap;
3525779Sxy150489 		break;
3535779Sxy150489 
3545779Sxy150489 	case ETHER_STAT_LP_CAP_10HDX:
3555779Sxy150489 		*val = igb->param_lp_10hdx_cap;
3565779Sxy150489 		break;
3575779Sxy150489 
3585779Sxy150489 	case ETHER_STAT_LP_CAP_ASMPAUSE:
3595779Sxy150489 		*val = igb->param_lp_asym_pause_cap;
3605779Sxy150489 		break;
3615779Sxy150489 
3625779Sxy150489 	case ETHER_STAT_LP_CAP_PAUSE:
3635779Sxy150489 		*val = igb->param_lp_pause_cap;
3645779Sxy150489 		break;
3655779Sxy150489 
3665779Sxy150489 	case ETHER_STAT_LP_CAP_AUTONEG:
3675779Sxy150489 		*val = igb->param_lp_autoneg_cap;
3685779Sxy150489 		break;
3695779Sxy150489 
3705779Sxy150489 	case ETHER_STAT_LINK_ASMPAUSE:
3715779Sxy150489 		*val = igb->param_asym_pause_cap;
3725779Sxy150489 		break;
3735779Sxy150489 
3745779Sxy150489 	case ETHER_STAT_LINK_PAUSE:
3755779Sxy150489 		*val = igb->param_pause_cap;
3765779Sxy150489 		break;
3775779Sxy150489 
3785779Sxy150489 	case ETHER_STAT_LINK_AUTONEG:
3795779Sxy150489 		*val = hw->mac.autoneg;
3805779Sxy150489 		break;
3815779Sxy150489 
3825779Sxy150489 	case ETHER_STAT_LINK_DUPLEX:
3835779Sxy150489 		*val = (igb->link_duplex == FULL_DUPLEX) ?
3845779Sxy150489 		    LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
3855779Sxy150489 		break;
3865779Sxy150489 
3875779Sxy150489 	case ETHER_STAT_TOOSHORT_ERRORS:
3885779Sxy150489 		igb_ks->ruc.value.ui64 +=
3895779Sxy150489 		    E1000_READ_REG(hw, E1000_RUC);
3905779Sxy150489 		*val = igb_ks->ruc.value.ui64;
3915779Sxy150489 		break;
3925779Sxy150489 
3935779Sxy150489 	case ETHER_STAT_CAP_REMFAULT:
3945779Sxy150489 		*val = igb->param_rem_fault;
3955779Sxy150489 		break;
3965779Sxy150489 
3975779Sxy150489 	case ETHER_STAT_ADV_REMFAULT:
3985779Sxy150489 		*val = igb->param_adv_rem_fault;
3995779Sxy150489 		break;
4005779Sxy150489 
4015779Sxy150489 	case ETHER_STAT_LP_REMFAULT:
4025779Sxy150489 		*val = igb->param_lp_rem_fault;
4035779Sxy150489 		break;
4045779Sxy150489 
4055779Sxy150489 	case ETHER_STAT_JABBER_ERRORS:
4065779Sxy150489 		igb_ks->rjc.value.ui64 +=
4075779Sxy150489 		    E1000_READ_REG(hw, E1000_RJC);
4085779Sxy150489 		*val = igb_ks->rjc.value.ui64;
4095779Sxy150489 		break;
4105779Sxy150489 
4115779Sxy150489 	case ETHER_STAT_CAP_100T4:
4125779Sxy150489 		*val = igb->param_100t4_cap;
4135779Sxy150489 		break;
4145779Sxy150489 
4155779Sxy150489 	case ETHER_STAT_ADV_CAP_100T4:
4165779Sxy150489 		*val = igb->param_adv_100t4_cap;
4175779Sxy150489 		break;
4185779Sxy150489 
4195779Sxy150489 	case ETHER_STAT_LP_CAP_100T4:
4205779Sxy150489 		*val = igb->param_lp_100t4_cap;
4215779Sxy150489 		break;
4225779Sxy150489 
4235779Sxy150489 	default:
4245779Sxy150489 		mutex_exit(&igb->gen_lock);
4255779Sxy150489 		return (ENOTSUP);
4265779Sxy150489 	}
4275779Sxy150489 
4285779Sxy150489 	mutex_exit(&igb->gen_lock);
4295779Sxy150489 
43011367SJason.Xu@Sun.COM 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
43111367SJason.Xu@Sun.COM 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
43211367SJason.Xu@Sun.COM 		return (EIO);
43311367SJason.Xu@Sun.COM 	}
4346624Sgl147354 
4355779Sxy150489 	return (0);
4365779Sxy150489 }
4375779Sxy150489 
4385779Sxy150489 /*
4395779Sxy150489  * Bring the device out of the reset/quiesced state that it
4405779Sxy150489  * was in when the interface was registered.
4415779Sxy150489  */
4425779Sxy150489 int
4435779Sxy150489 igb_m_start(void *arg)
4445779Sxy150489 {
4455779Sxy150489 	igb_t *igb = (igb_t *)arg;
4465779Sxy150489 
4475779Sxy150489 	mutex_enter(&igb->gen_lock);
4485779Sxy150489 
4495779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
4505779Sxy150489 		mutex_exit(&igb->gen_lock);
4515779Sxy150489 		return (ECANCELED);
4525779Sxy150489 	}
4535779Sxy150489 
454*11502SChenlu.Chen@Sun.COM 	if (igb_start(igb, B_TRUE) != IGB_SUCCESS) {
4555779Sxy150489 		mutex_exit(&igb->gen_lock);
4565779Sxy150489 		return (EIO);
4575779Sxy150489 	}
4585779Sxy150489 
45911367SJason.Xu@Sun.COM 	atomic_or_32(&igb->igb_state, IGB_STARTED);
4605779Sxy150489 
4615779Sxy150489 	mutex_exit(&igb->gen_lock);
4625779Sxy150489 
4635779Sxy150489 	/*
4645779Sxy150489 	 * Enable and start the watchdog timer
4655779Sxy150489 	 */
4665779Sxy150489 	igb_enable_watchdog_timer(igb);
4675779Sxy150489 
4685779Sxy150489 	return (0);
4695779Sxy150489 }
4705779Sxy150489 
4715779Sxy150489 /*
4725779Sxy150489  * Stop the device and put it in a reset/quiesced state such
4735779Sxy150489  * that the interface can be unregistered.
4745779Sxy150489  */
4755779Sxy150489 void
4765779Sxy150489 igb_m_stop(void *arg)
4775779Sxy150489 {
4785779Sxy150489 	igb_t *igb = (igb_t *)arg;
4795779Sxy150489 
4805779Sxy150489 	mutex_enter(&igb->gen_lock);
4815779Sxy150489 
4825779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
4835779Sxy150489 		mutex_exit(&igb->gen_lock);
4845779Sxy150489 		return;
4855779Sxy150489 	}
4865779Sxy150489 
48711367SJason.Xu@Sun.COM 	atomic_and_32(&igb->igb_state, ~IGB_STARTED);
4885779Sxy150489 
489*11502SChenlu.Chen@Sun.COM 	igb_stop(igb, B_TRUE);
4905779Sxy150489 
4915779Sxy150489 	mutex_exit(&igb->gen_lock);
4925779Sxy150489 
4935779Sxy150489 	/*
4945779Sxy150489 	 * Disable and stop the watchdog timer
4955779Sxy150489 	 */
4965779Sxy150489 	igb_disable_watchdog_timer(igb);
4975779Sxy150489 }
4985779Sxy150489 
4995779Sxy150489 /*
5005779Sxy150489  * Set the promiscuity of the device.
5015779Sxy150489  */
5025779Sxy150489 int
5035779Sxy150489 igb_m_promisc(void *arg, boolean_t on)
5045779Sxy150489 {
5055779Sxy150489 	igb_t *igb = (igb_t *)arg;
5065779Sxy150489 	uint32_t reg_val;
5075779Sxy150489 
5085779Sxy150489 	mutex_enter(&igb->gen_lock);
5095779Sxy150489 
5105779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
5115779Sxy150489 		mutex_exit(&igb->gen_lock);
5125779Sxy150489 		return (ECANCELED);
5135779Sxy150489 	}
5145779Sxy150489 
5155779Sxy150489 	reg_val = E1000_READ_REG(&igb->hw, E1000_RCTL);
5165779Sxy150489 
5175779Sxy150489 	if (on)
5185779Sxy150489 		reg_val |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
5195779Sxy150489 	else
5205779Sxy150489 		reg_val &= (~(E1000_RCTL_UPE | E1000_RCTL_MPE));
5215779Sxy150489 
5225779Sxy150489 	E1000_WRITE_REG(&igb->hw, E1000_RCTL, reg_val);
5235779Sxy150489 
5245779Sxy150489 	mutex_exit(&igb->gen_lock);
5255779Sxy150489 
5266624Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
5276624Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
5286624Sgl147354 		return (EIO);
5296624Sgl147354 	}
5306624Sgl147354 
5315779Sxy150489 	return (0);
5325779Sxy150489 }
5335779Sxy150489 
5345779Sxy150489 /*
5355779Sxy150489  * Add/remove the addresses to/from the set of multicast
5365779Sxy150489  * addresses for which the device will receive packets.
5375779Sxy150489  */
5385779Sxy150489 int
5395779Sxy150489 igb_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
5405779Sxy150489 {
5415779Sxy150489 	igb_t *igb = (igb_t *)arg;
5425779Sxy150489 	int result;
5435779Sxy150489 
5445779Sxy150489 	mutex_enter(&igb->gen_lock);
5455779Sxy150489 
5465779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
5475779Sxy150489 		mutex_exit(&igb->gen_lock);
5485779Sxy150489 		return (ECANCELED);
5495779Sxy150489 	}
5505779Sxy150489 
5515779Sxy150489 	result = (add) ? igb_multicst_add(igb, mcst_addr)
5525779Sxy150489 	    : igb_multicst_remove(igb, mcst_addr);
5535779Sxy150489 
5545779Sxy150489 	mutex_exit(&igb->gen_lock);
5555779Sxy150489 
5565779Sxy150489 	return (result);
5575779Sxy150489 }
5585779Sxy150489 
5595779Sxy150489 /*
5605779Sxy150489  * Pass on M_IOCTL messages passed to the DLD, and support
5615779Sxy150489  * private IOCTLs for debugging and ndd.
5625779Sxy150489  */
5635779Sxy150489 void
5645779Sxy150489 igb_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
5655779Sxy150489 {
5665779Sxy150489 	igb_t *igb = (igb_t *)arg;
5675779Sxy150489 	struct iocblk *iocp;
5685779Sxy150489 	enum ioc_reply status;
5695779Sxy150489 
5705779Sxy150489 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
5715779Sxy150489 	iocp->ioc_error = 0;
5725779Sxy150489 
573*11502SChenlu.Chen@Sun.COM 	mutex_enter(&igb->gen_lock);
574*11502SChenlu.Chen@Sun.COM 	if (igb->igb_state & IGB_SUSPENDED) {
575*11502SChenlu.Chen@Sun.COM 		mutex_exit(&igb->gen_lock);
576*11502SChenlu.Chen@Sun.COM 		miocnak(q, mp, 0, EINVAL);
577*11502SChenlu.Chen@Sun.COM 		return;
578*11502SChenlu.Chen@Sun.COM 	}
579*11502SChenlu.Chen@Sun.COM 	mutex_exit(&igb->gen_lock);
580*11502SChenlu.Chen@Sun.COM 
5815779Sxy150489 	switch (iocp->ioc_cmd) {
5825779Sxy150489 	case LB_GET_INFO_SIZE:
5835779Sxy150489 	case LB_GET_INFO:
5845779Sxy150489 	case LB_GET_MODE:
5855779Sxy150489 	case LB_SET_MODE:
5865779Sxy150489 		status = igb_loopback_ioctl(igb, iocp, mp);
5875779Sxy150489 		break;
5885779Sxy150489 
5895779Sxy150489 	default:
5905779Sxy150489 		status = IOC_INVAL;
5915779Sxy150489 		break;
5925779Sxy150489 	}
5935779Sxy150489 
5945779Sxy150489 	/*
5955779Sxy150489 	 * Decide how to reply
5965779Sxy150489 	 */
5975779Sxy150489 	switch (status) {
5985779Sxy150489 	default:
5995779Sxy150489 	case IOC_INVAL:
6005779Sxy150489 		/*
6015779Sxy150489 		 * Error, reply with a NAK and EINVAL or the specified error
6025779Sxy150489 		 */
6035779Sxy150489 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
6045779Sxy150489 		    EINVAL : iocp->ioc_error);
6055779Sxy150489 		break;
6065779Sxy150489 
6075779Sxy150489 	case IOC_DONE:
6085779Sxy150489 		/*
6095779Sxy150489 		 * OK, reply already sent
6105779Sxy150489 		 */
6115779Sxy150489 		break;
6125779Sxy150489 
6135779Sxy150489 	case IOC_ACK:
6145779Sxy150489 		/*
6155779Sxy150489 		 * OK, reply with an ACK
6165779Sxy150489 		 */
6175779Sxy150489 		miocack(q, mp, 0, 0);
6185779Sxy150489 		break;
6195779Sxy150489 
6205779Sxy150489 	case IOC_REPLY:
6215779Sxy150489 		/*
6225779Sxy150489 		 * OK, send prepared reply as ACK or NAK
6235779Sxy150489 		 */
6245779Sxy150489 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
6255779Sxy150489 		    M_IOCACK : M_IOCNAK;
6265779Sxy150489 		qreply(q, mp);
6275779Sxy150489 		break;
6285779Sxy150489 	}
6295779Sxy150489 }
6305779Sxy150489 
6315779Sxy150489 /*
6328275SEric Cheng  * Add a MAC address to the target RX group.
6335779Sxy150489  */
6348275SEric Cheng static int
6358275SEric Cheng igb_addmac(void *arg, const uint8_t *mac_addr)
6365779Sxy150489 {
6378275SEric Cheng 	igb_rx_group_t *rx_group = (igb_rx_group_t *)arg;
6388275SEric Cheng 	igb_t *igb = rx_group->igb;
6398275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
6408275SEric Cheng 	int i, slot;
6415779Sxy150489 
6425779Sxy150489 	mutex_enter(&igb->gen_lock);
6435779Sxy150489 
6445779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
6455779Sxy150489 		mutex_exit(&igb->gen_lock);
6465779Sxy150489 		return (ECANCELED);
6475779Sxy150489 	}
6485779Sxy150489 
6495779Sxy150489 	if (igb->unicst_avail == 0) {
6505779Sxy150489 		/* no slots available */
6515779Sxy150489 		mutex_exit(&igb->gen_lock);
6525779Sxy150489 		return (ENOSPC);
6535779Sxy150489 	}
6545779Sxy150489 
6555779Sxy150489 	/*
6568275SEric Cheng 	 * The slots from 0 to igb->num_rx_groups are reserved slots which
6578275SEric Cheng 	 * are 1 to 1 mapped with group index directly. The other slots are
6588275SEric Cheng 	 * shared between the all of groups. While adding a MAC address,
6598275SEric Cheng 	 * it will try to set the reserved slots first, then the shared slots.
6605779Sxy150489 	 */
6618275SEric Cheng 	slot = -1;
6628275SEric Cheng 	if (igb->unicst_addr[rx_group->index].mac.set == 1) {
6638275SEric Cheng 		/*
6648275SEric Cheng 		 * The reserved slot for current group is used, find the free
6658275SEric Cheng 		 * slots in the shared slots.
6668275SEric Cheng 		 */
6678275SEric Cheng 		for (i = igb->num_rx_groups; i < igb->unicst_total; i++) {
6688275SEric Cheng 			if (igb->unicst_addr[i].mac.set == 0) {
6698275SEric Cheng 				slot = i;
6708275SEric Cheng 				break;
6718275SEric Cheng 			}
6728275SEric Cheng 		}
6738275SEric Cheng 	} else
6748275SEric Cheng 		slot = rx_group->index;
6758275SEric Cheng 
6768275SEric Cheng 	if (slot == -1) {
6778275SEric Cheng 		/* no slots available in the shared slots */
6788275SEric Cheng 		mutex_exit(&igb->gen_lock);
6798275SEric Cheng 		return (ENOSPC);
6805779Sxy150489 	}
6815779Sxy150489 
6828275SEric Cheng 	/* Set VMDq according to the mode supported by hardware. */
6838275SEric Cheng 	e1000_rar_set_vmdq(hw, mac_addr, slot, igb->vmdq_mode, rx_group->index);
6845779Sxy150489 
6858275SEric Cheng 	bcopy(mac_addr, igb->unicst_addr[slot].mac.addr, ETHERADDRL);
6868275SEric Cheng 	igb->unicst_addr[slot].mac.group_index = rx_group->index;
6878275SEric Cheng 	igb->unicst_addr[slot].mac.set = 1;
6888275SEric Cheng 	igb->unicst_avail--;
6895779Sxy150489 
6907072Sxy150489 	mutex_exit(&igb->gen_lock);
6917072Sxy150489 
6928275SEric Cheng 	return (0);
6935779Sxy150489 }
6945779Sxy150489 
6955779Sxy150489 /*
6968275SEric Cheng  * Remove a MAC address from the specified RX group.
6975779Sxy150489  */
6988275SEric Cheng static int
6998275SEric Cheng igb_remmac(void *arg, const uint8_t *mac_addr)
7005779Sxy150489 {
7018275SEric Cheng 	igb_rx_group_t *rx_group = (igb_rx_group_t *)arg;
7028275SEric Cheng 	igb_t *igb = rx_group->igb;
7038275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
7048275SEric Cheng 	int slot;
7055779Sxy150489 
7065779Sxy150489 	mutex_enter(&igb->gen_lock);
7075779Sxy150489 
7085779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
7095779Sxy150489 		mutex_exit(&igb->gen_lock);
7105779Sxy150489 		return (ECANCELED);
7115779Sxy150489 	}
7125779Sxy150489 
7138275SEric Cheng 	slot = igb_unicst_find(igb, mac_addr);
7148275SEric Cheng 	if (slot == -1) {
7155779Sxy150489 		mutex_exit(&igb->gen_lock);
7165779Sxy150489 		return (EINVAL);
7175779Sxy150489 	}
7185779Sxy150489 
7197072Sxy150489 	if (igb->unicst_addr[slot].mac.set == 0) {
7207072Sxy150489 		mutex_exit(&igb->gen_lock);
7217072Sxy150489 		return (EINVAL);
7227072Sxy150489 	}
7237072Sxy150489 
7248275SEric Cheng 	/* Clear the MAC ddress in the slot */
7258275SEric Cheng 	e1000_rar_clear(hw, slot);
7268275SEric Cheng 	igb->unicst_addr[slot].mac.set = 0;
7278275SEric Cheng 	igb->unicst_avail++;
7285779Sxy150489 
7295779Sxy150489 	mutex_exit(&igb->gen_lock);
7305779Sxy150489 
7318275SEric Cheng 	return (0);
7328275SEric Cheng }
7338275SEric Cheng 
7348275SEric Cheng /*
7358275SEric Cheng  * Enable interrupt on the specificed rx ring.
7368275SEric Cheng  */
7378275SEric Cheng int
7388275SEric Cheng igb_rx_ring_intr_enable(mac_intr_handle_t intrh)
7398275SEric Cheng {
7408275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)intrh;
7418275SEric Cheng 	igb_t *igb = rx_ring->igb;
7428275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
7438275SEric Cheng 	uint32_t index = rx_ring->index;
7448275SEric Cheng 
7458275SEric Cheng 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
7468275SEric Cheng 		/* Interrupt enabling for MSI-X */
7478275SEric Cheng 		igb->eims_mask |= (E1000_EICR_RX_QUEUE0 << index);
7488275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
7498275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
7508275SEric Cheng 	} else {
7518275SEric Cheng 		ASSERT(index == 0);
7528275SEric Cheng 		/* Interrupt enabling for MSI and legacy */
7538275SEric Cheng 		igb->ims_mask |= E1000_IMS_RXT0;
7548275SEric Cheng 		E1000_WRITE_REG(hw, E1000_IMS, igb->ims_mask);
7558275SEric Cheng 	}
7568275SEric Cheng 
7578275SEric Cheng 	E1000_WRITE_FLUSH(hw);
7588275SEric Cheng 
7598275SEric Cheng 	return (0);
7608275SEric Cheng }
7618275SEric Cheng 
7628275SEric Cheng /*
7638275SEric Cheng  * Disable interrupt on the specificed rx ring.
7648275SEric Cheng  */
7658275SEric Cheng int
7668275SEric Cheng igb_rx_ring_intr_disable(mac_intr_handle_t intrh)
7678275SEric Cheng {
7688275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)intrh;
7698275SEric Cheng 	igb_t *igb = rx_ring->igb;
7708275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
7718275SEric Cheng 	uint32_t index = rx_ring->index;
7728275SEric Cheng 
7738275SEric Cheng 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
7748275SEric Cheng 		/* Interrupt disabling for MSI-X */
7758275SEric Cheng 		igb->eims_mask &= ~(E1000_EICR_RX_QUEUE0 << index);
7768275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIMC,
7778275SEric Cheng 		    (E1000_EICR_RX_QUEUE0 << index));
7788275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
7798275SEric Cheng 	} else {
7808275SEric Cheng 		ASSERT(index == 0);
7818275SEric Cheng 		/* Interrupt disabling for MSI and legacy */
7828275SEric Cheng 		igb->ims_mask &= ~E1000_IMS_RXT0;
7838275SEric Cheng 		E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_RXT0);
7848275SEric Cheng 	}
7858275SEric Cheng 
7868275SEric Cheng 	E1000_WRITE_FLUSH(hw);
7878275SEric Cheng 
7888275SEric Cheng 	return (0);
7895779Sxy150489 }
7905779Sxy150489 
7915779Sxy150489 /*
7928275SEric Cheng  * Get the global ring index by a ring index within a group.
7935779Sxy150489  */
7945779Sxy150489 int
7958275SEric Cheng igb_get_rx_ring_index(igb_t *igb, int gindex, int rindex)
7965779Sxy150489 {
7978275SEric Cheng 	igb_rx_ring_t *rx_ring;
7988275SEric Cheng 	int i;
7995779Sxy150489 
8008275SEric Cheng 	for (i = 0; i < igb->num_rx_rings; i++) {
8018275SEric Cheng 		rx_ring = &igb->rx_rings[i];
8028275SEric Cheng 		if (rx_ring->group_index == gindex)
8038275SEric Cheng 			rindex--;
8048275SEric Cheng 		if (rindex < 0)
8058275SEric Cheng 			return (i);
8065779Sxy150489 	}
8075779Sxy150489 
8088275SEric Cheng 	return (-1);
8098275SEric Cheng }
8105779Sxy150489 
8118275SEric Cheng static int
8128275SEric Cheng igb_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
8138275SEric Cheng {
8148275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)rh;
8155779Sxy150489 
8168275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
8178275SEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
8188275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
8198275SEric Cheng 	return (0);
8205779Sxy150489 }
8215779Sxy150489 
8225779Sxy150489 /*
8238275SEric Cheng  * Callback funtion for MAC layer to register all rings.
8245779Sxy150489  */
8258275SEric Cheng /* ARGSUSED */
8268275SEric Cheng void
8278275SEric Cheng igb_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
8288275SEric Cheng     const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
8295779Sxy150489 {
8305779Sxy150489 	igb_t *igb = (igb_t *)arg;
8318275SEric Cheng 	mac_intr_t *mintr = &infop->mri_intr;
8328275SEric Cheng 
8338275SEric Cheng 	switch (rtype) {
8348275SEric Cheng 	case MAC_RING_TYPE_RX: {
8358275SEric Cheng 		igb_rx_ring_t *rx_ring;
8368275SEric Cheng 		int global_index;
8375779Sxy150489 
8388275SEric Cheng 		/*
8398275SEric Cheng 		 * 'index' is the ring index within the group.
8408275SEric Cheng 		 * We need the global ring index by searching in group.
8418275SEric Cheng 		 */
8428275SEric Cheng 		global_index = igb_get_rx_ring_index(igb, rg_index, index);
8438275SEric Cheng 
8448275SEric Cheng 		ASSERT(global_index >= 0);
8455779Sxy150489 
8468275SEric Cheng 		rx_ring = &igb->rx_rings[global_index];
8478275SEric Cheng 		rx_ring->ring_handle = rh;
8488275SEric Cheng 
8498275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
8508275SEric Cheng 		infop->mri_start = igb_ring_start;
8518275SEric Cheng 		infop->mri_stop = NULL;
8528275SEric Cheng 		infop->mri_poll = (mac_ring_poll_t)igb_rx_ring_poll;
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;
8578275SEric Cheng 
8588275SEric Cheng 		break;
8595779Sxy150489 	}
8608275SEric Cheng 	case MAC_RING_TYPE_TX: {
8618275SEric Cheng 		ASSERT(index < igb->num_tx_rings);
8625779Sxy150489 
8638275SEric Cheng 		igb_tx_ring_t *tx_ring = &igb->tx_rings[index];
8648275SEric Cheng 		tx_ring->ring_handle = rh;
8655779Sxy150489 
8668275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
8678275SEric Cheng 		infop->mri_start = NULL;
8688275SEric Cheng 		infop->mri_stop = NULL;
8698275SEric Cheng 		infop->mri_tx = igb_tx_ring_send;
8708275SEric Cheng 
8718275SEric Cheng 		break;
8725779Sxy150489 	}
8738275SEric Cheng 	default:
8748275SEric Cheng 		break;
8758275SEric Cheng 	}
8768275SEric Cheng }
8778275SEric Cheng 
8788275SEric Cheng void
8798275SEric Cheng igb_fill_group(void *arg, mac_ring_type_t rtype, const int index,
8808275SEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
8818275SEric Cheng {
8828275SEric Cheng 	igb_t *igb = (igb_t *)arg;
8835779Sxy150489 
8848275SEric Cheng 	switch (rtype) {
8858275SEric Cheng 	case MAC_RING_TYPE_RX: {
8868275SEric Cheng 		igb_rx_group_t *rx_group;
8878275SEric Cheng 
8888275SEric Cheng 		ASSERT((index >= 0) && (index < igb->num_rx_groups));
8898275SEric Cheng 
8908275SEric Cheng 		rx_group = &igb->rx_groups[index];
8918275SEric Cheng 		rx_group->group_handle = gh;
8928275SEric Cheng 
8938275SEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_group;
8948275SEric Cheng 		infop->mgi_start = NULL;
8958275SEric Cheng 		infop->mgi_stop = NULL;
8968275SEric Cheng 		infop->mgi_addmac = igb_addmac;
8978275SEric Cheng 		infop->mgi_remmac = igb_remmac;
8988275SEric Cheng 		infop->mgi_count = (igb->num_rx_rings / igb->num_rx_groups);
8998275SEric Cheng 
9008275SEric Cheng 		break;
9015779Sxy150489 	}
9028275SEric Cheng 	case MAC_RING_TYPE_TX:
9038275SEric Cheng 		break;
9048275SEric Cheng 	default:
9058275SEric Cheng 		break;
9068275SEric Cheng 	}
9075779Sxy150489 }
9085779Sxy150489 
9095779Sxy150489 /*
9105779Sxy150489  * Obtain the MAC's capabilities and associated data from
9115779Sxy150489  * the driver.
9125779Sxy150489  */
9135779Sxy150489 boolean_t
9145779Sxy150489 igb_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
9155779Sxy150489 {
9165779Sxy150489 	igb_t *igb = (igb_t *)arg;
9175779Sxy150489 
9185779Sxy150489 	switch (cap) {
9195779Sxy150489 	case MAC_CAPAB_HCKSUM: {
9205779Sxy150489 		uint32_t *tx_hcksum_flags = cap_data;
9215779Sxy150489 
9225779Sxy150489 		/*
9235779Sxy150489 		 * We advertise our capabilities only if tx hcksum offload is
9245779Sxy150489 		 * enabled.  On receive, the stack will accept checksummed
9255779Sxy150489 		 * packets anyway, even if we haven't said we can deliver
9265779Sxy150489 		 * them.
9275779Sxy150489 		 */
9285779Sxy150489 		if (!igb->tx_hcksum_enable)
9295779Sxy150489 			return (B_FALSE);
9305779Sxy150489 
9315779Sxy150489 		*tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
9325779Sxy150489 		break;
9335779Sxy150489 	}
9349188SPaul.Guo@Sun.COM 	case MAC_CAPAB_LSO: {
9359188SPaul.Guo@Sun.COM 		mac_capab_lso_t *cap_lso = cap_data;
9369188SPaul.Guo@Sun.COM 
9379188SPaul.Guo@Sun.COM 		if (igb->lso_enable) {
9389188SPaul.Guo@Sun.COM 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
9399188SPaul.Guo@Sun.COM 			cap_lso->lso_basic_tcp_ipv4.lso_max = IGB_LSO_MAXLEN;
9409188SPaul.Guo@Sun.COM 			break;
9419188SPaul.Guo@Sun.COM 		} else {
9429188SPaul.Guo@Sun.COM 			return (B_FALSE);
9439188SPaul.Guo@Sun.COM 		}
9449188SPaul.Guo@Sun.COM 	}
9458275SEric Cheng 	case MAC_CAPAB_RINGS: {
9468275SEric Cheng 		mac_capab_rings_t *cap_rings = cap_data;
9478275SEric Cheng 
9488275SEric Cheng 		switch (cap_rings->mr_type) {
9498275SEric Cheng 		case MAC_RING_TYPE_RX:
9508275SEric Cheng 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
9518275SEric Cheng 			cap_rings->mr_rnum = igb->num_rx_rings;
9528275SEric Cheng 			cap_rings->mr_gnum = igb->num_rx_groups;
9538275SEric Cheng 			cap_rings->mr_rget = igb_fill_ring;
9548275SEric Cheng 			cap_rings->mr_gget = igb_fill_group;
9558275SEric Cheng 			cap_rings->mr_gaddring = NULL;
9568275SEric Cheng 			cap_rings->mr_gremring = NULL;
9575779Sxy150489 
9588275SEric Cheng 			break;
9598275SEric Cheng 		case MAC_RING_TYPE_TX:
9608275SEric Cheng 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
9618275SEric Cheng 			cap_rings->mr_rnum = igb->num_tx_rings;
9628275SEric Cheng 			cap_rings->mr_gnum = 0;
9638275SEric Cheng 			cap_rings->mr_rget = igb_fill_ring;
9648275SEric Cheng 			cap_rings->mr_gget = NULL;
9658275SEric Cheng 
9668275SEric Cheng 			break;
9678275SEric Cheng 		default:
9688275SEric Cheng 			break;
9698275SEric Cheng 		}
9705779Sxy150489 		break;
9715779Sxy150489 	}
9728275SEric Cheng 
9735779Sxy150489 	default:
9745779Sxy150489 		return (B_FALSE);
9755779Sxy150489 	}
9765779Sxy150489 	return (B_TRUE);
9775779Sxy150489 }
978*11502SChenlu.Chen@Sun.COM 
979*11502SChenlu.Chen@Sun.COM int
980*11502SChenlu.Chen@Sun.COM igb_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
981*11502SChenlu.Chen@Sun.COM     uint_t pr_valsize, const void *pr_val)
982*11502SChenlu.Chen@Sun.COM {
983*11502SChenlu.Chen@Sun.COM 	igb_t *igb = (igb_t *)arg;
984*11502SChenlu.Chen@Sun.COM 	struct e1000_hw *hw = &igb->hw;
985*11502SChenlu.Chen@Sun.COM 	int err = 0;
986*11502SChenlu.Chen@Sun.COM 	uint32_t flow_control;
987*11502SChenlu.Chen@Sun.COM 	uint32_t cur_mtu, new_mtu;
988*11502SChenlu.Chen@Sun.COM 	uint32_t rx_size;
989*11502SChenlu.Chen@Sun.COM 	uint32_t tx_size;
990*11502SChenlu.Chen@Sun.COM 
991*11502SChenlu.Chen@Sun.COM 	mutex_enter(&igb->gen_lock);
992*11502SChenlu.Chen@Sun.COM 	if (igb->igb_state & IGB_SUSPENDED) {
993*11502SChenlu.Chen@Sun.COM 		mutex_exit(&igb->gen_lock);
994*11502SChenlu.Chen@Sun.COM 		return (ECANCELED);
995*11502SChenlu.Chen@Sun.COM 	}
996*11502SChenlu.Chen@Sun.COM 
997*11502SChenlu.Chen@Sun.COM 	if (igb->loopback_mode != IGB_LB_NONE && igb_param_locked(pr_num)) {
998*11502SChenlu.Chen@Sun.COM 		/*
999*11502SChenlu.Chen@Sun.COM 		 * All en_* parameters are locked (read-only)
1000*11502SChenlu.Chen@Sun.COM 		 * while the device is in any sort of loopback mode.
1001*11502SChenlu.Chen@Sun.COM 		 */
1002*11502SChenlu.Chen@Sun.COM 		mutex_exit(&igb->gen_lock);
1003*11502SChenlu.Chen@Sun.COM 		return (EBUSY);
1004*11502SChenlu.Chen@Sun.COM 	}
1005*11502SChenlu.Chen@Sun.COM 
1006*11502SChenlu.Chen@Sun.COM 	switch (pr_num) {
1007*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000FDX_CAP:
1008*11502SChenlu.Chen@Sun.COM 		/* read/write on copper, read-only on serdes */
1009*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1010*11502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
1011*11502SChenlu.Chen@Sun.COM 			break;
1012*11502SChenlu.Chen@Sun.COM 		}
1013*11502SChenlu.Chen@Sun.COM 		igb->param_en_1000fdx_cap = *(uint8_t *)pr_val;
1014*11502SChenlu.Chen@Sun.COM 		igb->param_adv_1000fdx_cap = *(uint8_t *)pr_val;
1015*11502SChenlu.Chen@Sun.COM 		goto setup_link;
1016*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
1017*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1018*11502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
1019*11502SChenlu.Chen@Sun.COM 			break;
1020*11502SChenlu.Chen@Sun.COM 		}
1021*11502SChenlu.Chen@Sun.COM 		igb->param_en_100fdx_cap = *(uint8_t *)pr_val;
1022*11502SChenlu.Chen@Sun.COM 		igb->param_adv_100fdx_cap = *(uint8_t *)pr_val;
1023*11502SChenlu.Chen@Sun.COM 		goto setup_link;
1024*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
1025*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1026*11502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
1027*11502SChenlu.Chen@Sun.COM 			break;
1028*11502SChenlu.Chen@Sun.COM 		}
1029*11502SChenlu.Chen@Sun.COM 		igb->param_en_100hdx_cap = *(uint8_t *)pr_val;
1030*11502SChenlu.Chen@Sun.COM 		igb->param_adv_100hdx_cap = *(uint8_t *)pr_val;
1031*11502SChenlu.Chen@Sun.COM 		goto setup_link;
1032*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
1033*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1034*11502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
1035*11502SChenlu.Chen@Sun.COM 			break;
1036*11502SChenlu.Chen@Sun.COM 		}
1037*11502SChenlu.Chen@Sun.COM 		igb->param_en_10fdx_cap = *(uint8_t *)pr_val;
1038*11502SChenlu.Chen@Sun.COM 		igb->param_adv_10fdx_cap = *(uint8_t *)pr_val;
1039*11502SChenlu.Chen@Sun.COM 		goto setup_link;
1040*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
1041*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1042*11502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
1043*11502SChenlu.Chen@Sun.COM 			break;
1044*11502SChenlu.Chen@Sun.COM 		}
1045*11502SChenlu.Chen@Sun.COM 		igb->param_en_10hdx_cap = *(uint8_t *)pr_val;
1046*11502SChenlu.Chen@Sun.COM 		igb->param_adv_10hdx_cap = *(uint8_t *)pr_val;
1047*11502SChenlu.Chen@Sun.COM 		goto setup_link;
1048*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_AUTONEG:
1049*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1050*11502SChenlu.Chen@Sun.COM 			err = ENOTSUP;
1051*11502SChenlu.Chen@Sun.COM 			break;
1052*11502SChenlu.Chen@Sun.COM 		}
1053*11502SChenlu.Chen@Sun.COM 		igb->param_adv_autoneg_cap = *(uint8_t *)pr_val;
1054*11502SChenlu.Chen@Sun.COM 		goto setup_link;
1055*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_FLOWCTRL:
1056*11502SChenlu.Chen@Sun.COM 		bcopy(pr_val, &flow_control, sizeof (flow_control));
1057*11502SChenlu.Chen@Sun.COM 
1058*11502SChenlu.Chen@Sun.COM 		switch (flow_control) {
1059*11502SChenlu.Chen@Sun.COM 		default:
1060*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1061*11502SChenlu.Chen@Sun.COM 			break;
1062*11502SChenlu.Chen@Sun.COM 		case LINK_FLOWCTRL_NONE:
1063*11502SChenlu.Chen@Sun.COM 			hw->fc.requested_mode = e1000_fc_none;
1064*11502SChenlu.Chen@Sun.COM 			break;
1065*11502SChenlu.Chen@Sun.COM 		case LINK_FLOWCTRL_RX:
1066*11502SChenlu.Chen@Sun.COM 			hw->fc.requested_mode = e1000_fc_rx_pause;
1067*11502SChenlu.Chen@Sun.COM 			break;
1068*11502SChenlu.Chen@Sun.COM 		case LINK_FLOWCTRL_TX:
1069*11502SChenlu.Chen@Sun.COM 			hw->fc.requested_mode = e1000_fc_tx_pause;
1070*11502SChenlu.Chen@Sun.COM 			break;
1071*11502SChenlu.Chen@Sun.COM 		case LINK_FLOWCTRL_BI:
1072*11502SChenlu.Chen@Sun.COM 			hw->fc.requested_mode = e1000_fc_full;
1073*11502SChenlu.Chen@Sun.COM 			break;
1074*11502SChenlu.Chen@Sun.COM 		}
1075*11502SChenlu.Chen@Sun.COM setup_link:
1076*11502SChenlu.Chen@Sun.COM 		if (err == 0) {
1077*11502SChenlu.Chen@Sun.COM 			if (igb_setup_link(igb, B_TRUE) != IGB_SUCCESS)
1078*11502SChenlu.Chen@Sun.COM 				err = EINVAL;
1079*11502SChenlu.Chen@Sun.COM 		}
1080*11502SChenlu.Chen@Sun.COM 		break;
1081*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000FDX_CAP:
1082*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000HDX_CAP:
1083*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
1084*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
1085*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
1086*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
1087*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
1088*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000HDX_CAP:
1089*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
1090*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_STATUS:
1091*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_SPEED:
1092*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_DUPLEX:
1093*11502SChenlu.Chen@Sun.COM 		err = ENOTSUP; /* read-only prop. Can't set this. */
1094*11502SChenlu.Chen@Sun.COM 		break;
1095*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_MTU:
1096*11502SChenlu.Chen@Sun.COM 		/* adapter must be stopped for an MTU change */
1097*11502SChenlu.Chen@Sun.COM 		if (igb->igb_state & IGB_STARTED) {
1098*11502SChenlu.Chen@Sun.COM 			err = EBUSY;
1099*11502SChenlu.Chen@Sun.COM 			break;
1100*11502SChenlu.Chen@Sun.COM 		}
1101*11502SChenlu.Chen@Sun.COM 
1102*11502SChenlu.Chen@Sun.COM 		cur_mtu = igb->default_mtu;
1103*11502SChenlu.Chen@Sun.COM 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
1104*11502SChenlu.Chen@Sun.COM 		if (new_mtu == cur_mtu) {
1105*11502SChenlu.Chen@Sun.COM 			err = 0;
1106*11502SChenlu.Chen@Sun.COM 			break;
1107*11502SChenlu.Chen@Sun.COM 		}
1108*11502SChenlu.Chen@Sun.COM 
1109*11502SChenlu.Chen@Sun.COM 		if (new_mtu < MIN_MTU || new_mtu > MAX_MTU) {
1110*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1111*11502SChenlu.Chen@Sun.COM 			break;
1112*11502SChenlu.Chen@Sun.COM 		}
1113*11502SChenlu.Chen@Sun.COM 
1114*11502SChenlu.Chen@Sun.COM 		err = mac_maxsdu_update(igb->mac_hdl, new_mtu);
1115*11502SChenlu.Chen@Sun.COM 		if (err == 0) {
1116*11502SChenlu.Chen@Sun.COM 			igb->default_mtu = new_mtu;
1117*11502SChenlu.Chen@Sun.COM 			igb->max_frame_size = igb->default_mtu +
1118*11502SChenlu.Chen@Sun.COM 			    sizeof (struct ether_vlan_header) + ETHERFCSL;
1119*11502SChenlu.Chen@Sun.COM 
1120*11502SChenlu.Chen@Sun.COM 			/*
1121*11502SChenlu.Chen@Sun.COM 			 * Set rx buffer size
1122*11502SChenlu.Chen@Sun.COM 			 */
1123*11502SChenlu.Chen@Sun.COM 			rx_size = igb->max_frame_size + IPHDR_ALIGN_ROOM;
1124*11502SChenlu.Chen@Sun.COM 			igb->rx_buf_size = ((rx_size >> 10) + ((rx_size &
1125*11502SChenlu.Chen@Sun.COM 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
1126*11502SChenlu.Chen@Sun.COM 
1127*11502SChenlu.Chen@Sun.COM 			/*
1128*11502SChenlu.Chen@Sun.COM 			 * Set tx buffer size
1129*11502SChenlu.Chen@Sun.COM 			 */
1130*11502SChenlu.Chen@Sun.COM 			tx_size = igb->max_frame_size;
1131*11502SChenlu.Chen@Sun.COM 			igb->tx_buf_size = ((tx_size >> 10) + ((tx_size &
1132*11502SChenlu.Chen@Sun.COM 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
1133*11502SChenlu.Chen@Sun.COM 		}
1134*11502SChenlu.Chen@Sun.COM 		break;
1135*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_PRIVATE:
1136*11502SChenlu.Chen@Sun.COM 		err = igb_set_priv_prop(igb, pr_name, pr_valsize, pr_val);
1137*11502SChenlu.Chen@Sun.COM 		break;
1138*11502SChenlu.Chen@Sun.COM 	default:
1139*11502SChenlu.Chen@Sun.COM 		err = EINVAL;
1140*11502SChenlu.Chen@Sun.COM 		break;
1141*11502SChenlu.Chen@Sun.COM 	}
1142*11502SChenlu.Chen@Sun.COM 
1143*11502SChenlu.Chen@Sun.COM 	mutex_exit(&igb->gen_lock);
1144*11502SChenlu.Chen@Sun.COM 
1145*11502SChenlu.Chen@Sun.COM 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
1146*11502SChenlu.Chen@Sun.COM 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
1147*11502SChenlu.Chen@Sun.COM 		return (EIO);
1148*11502SChenlu.Chen@Sun.COM 	}
1149*11502SChenlu.Chen@Sun.COM 
1150*11502SChenlu.Chen@Sun.COM 	return (err);
1151*11502SChenlu.Chen@Sun.COM }
1152*11502SChenlu.Chen@Sun.COM 
1153*11502SChenlu.Chen@Sun.COM int
1154*11502SChenlu.Chen@Sun.COM igb_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1155*11502SChenlu.Chen@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
1156*11502SChenlu.Chen@Sun.COM {
1157*11502SChenlu.Chen@Sun.COM 	igb_t *igb = (igb_t *)arg;
1158*11502SChenlu.Chen@Sun.COM 	struct e1000_hw *hw = &igb->hw;
1159*11502SChenlu.Chen@Sun.COM 	int err = 0;
1160*11502SChenlu.Chen@Sun.COM 	uint32_t flow_control;
1161*11502SChenlu.Chen@Sun.COM 	uint64_t tmp = 0;
1162*11502SChenlu.Chen@Sun.COM 	mac_propval_range_t range;
1163*11502SChenlu.Chen@Sun.COM 
1164*11502SChenlu.Chen@Sun.COM 	if (pr_valsize == 0)
1165*11502SChenlu.Chen@Sun.COM 		return (EINVAL);
1166*11502SChenlu.Chen@Sun.COM 
1167*11502SChenlu.Chen@Sun.COM 	*perm = MAC_PROP_PERM_RW;
1168*11502SChenlu.Chen@Sun.COM 
1169*11502SChenlu.Chen@Sun.COM 	bzero(pr_val, pr_valsize);
1170*11502SChenlu.Chen@Sun.COM 	if ((pr_flags & MAC_PROP_DEFAULT) && (pr_num != MAC_PROP_PRIVATE))
1171*11502SChenlu.Chen@Sun.COM 		return (igb_get_def_val(igb, pr_num, pr_valsize, pr_val));
1172*11502SChenlu.Chen@Sun.COM 
1173*11502SChenlu.Chen@Sun.COM 	switch (pr_num) {
1174*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_DUPLEX:
1175*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1176*11502SChenlu.Chen@Sun.COM 		if (pr_valsize >= sizeof (link_duplex_t)) {
1177*11502SChenlu.Chen@Sun.COM 			bcopy(&igb->link_duplex, pr_val,
1178*11502SChenlu.Chen@Sun.COM 			    sizeof (link_duplex_t));
1179*11502SChenlu.Chen@Sun.COM 		} else
1180*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1181*11502SChenlu.Chen@Sun.COM 		break;
1182*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_SPEED:
1183*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1184*11502SChenlu.Chen@Sun.COM 		if (pr_valsize >= sizeof (uint64_t)) {
1185*11502SChenlu.Chen@Sun.COM 			tmp = igb->link_speed * 1000000ull;
1186*11502SChenlu.Chen@Sun.COM 			bcopy(&tmp, pr_val, sizeof (tmp));
1187*11502SChenlu.Chen@Sun.COM 		} else
1188*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1189*11502SChenlu.Chen@Sun.COM 		break;
1190*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_AUTONEG:
1191*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper)
1192*11502SChenlu.Chen@Sun.COM 			*perm = MAC_PROP_PERM_READ;
1193*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_autoneg_cap;
1194*11502SChenlu.Chen@Sun.COM 		break;
1195*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_FLOWCTRL:
1196*11502SChenlu.Chen@Sun.COM 		if (pr_valsize >= sizeof (uint32_t)) {
1197*11502SChenlu.Chen@Sun.COM 			switch (hw->fc.requested_mode) {
1198*11502SChenlu.Chen@Sun.COM 				case e1000_fc_none:
1199*11502SChenlu.Chen@Sun.COM 					flow_control = LINK_FLOWCTRL_NONE;
1200*11502SChenlu.Chen@Sun.COM 					break;
1201*11502SChenlu.Chen@Sun.COM 				case e1000_fc_rx_pause:
1202*11502SChenlu.Chen@Sun.COM 					flow_control = LINK_FLOWCTRL_RX;
1203*11502SChenlu.Chen@Sun.COM 					break;
1204*11502SChenlu.Chen@Sun.COM 				case e1000_fc_tx_pause:
1205*11502SChenlu.Chen@Sun.COM 					flow_control = LINK_FLOWCTRL_TX;
1206*11502SChenlu.Chen@Sun.COM 					break;
1207*11502SChenlu.Chen@Sun.COM 				case e1000_fc_full:
1208*11502SChenlu.Chen@Sun.COM 					flow_control = LINK_FLOWCTRL_BI;
1209*11502SChenlu.Chen@Sun.COM 					break;
1210*11502SChenlu.Chen@Sun.COM 			}
1211*11502SChenlu.Chen@Sun.COM 			bcopy(&flow_control, pr_val, sizeof (flow_control));
1212*11502SChenlu.Chen@Sun.COM 		} else
1213*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1214*11502SChenlu.Chen@Sun.COM 		break;
1215*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000FDX_CAP:
1216*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1217*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_1000fdx_cap;
1218*11502SChenlu.Chen@Sun.COM 		break;
1219*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000FDX_CAP:
1220*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper)
1221*11502SChenlu.Chen@Sun.COM 			*perm = MAC_PROP_PERM_READ;
1222*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_1000fdx_cap;
1223*11502SChenlu.Chen@Sun.COM 		break;
1224*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000HDX_CAP:
1225*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1226*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_1000hdx_cap;
1227*11502SChenlu.Chen@Sun.COM 		break;
1228*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000HDX_CAP:
1229*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1230*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_1000hdx_cap;
1231*11502SChenlu.Chen@Sun.COM 		break;
1232*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
1233*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1234*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_100t4_cap;
1235*11502SChenlu.Chen@Sun.COM 		break;
1236*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
1237*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1238*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_100t4_cap;
1239*11502SChenlu.Chen@Sun.COM 		break;
1240*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
1241*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1242*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_100fdx_cap;
1243*11502SChenlu.Chen@Sun.COM 		break;
1244*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
1245*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper)
1246*11502SChenlu.Chen@Sun.COM 			*perm = MAC_PROP_PERM_READ;
1247*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_100fdx_cap;
1248*11502SChenlu.Chen@Sun.COM 		break;
1249*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
1250*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1251*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_100hdx_cap;
1252*11502SChenlu.Chen@Sun.COM 		break;
1253*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
1254*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper)
1255*11502SChenlu.Chen@Sun.COM 			*perm = MAC_PROP_PERM_READ;
1256*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_100hdx_cap;
1257*11502SChenlu.Chen@Sun.COM 		break;
1258*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
1259*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1260*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_10fdx_cap;
1261*11502SChenlu.Chen@Sun.COM 		break;
1262*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
1263*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper)
1264*11502SChenlu.Chen@Sun.COM 			*perm = MAC_PROP_PERM_READ;
1265*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_10fdx_cap;
1266*11502SChenlu.Chen@Sun.COM 		break;
1267*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
1268*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1269*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_adv_10hdx_cap;
1270*11502SChenlu.Chen@Sun.COM 		break;
1271*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
1272*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper)
1273*11502SChenlu.Chen@Sun.COM 			*perm = MAC_PROP_PERM_READ;
1274*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = igb->param_en_10hdx_cap;
1275*11502SChenlu.Chen@Sun.COM 		break;
1276*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_PRIVATE:
1277*11502SChenlu.Chen@Sun.COM 		err = igb_get_priv_prop(igb, pr_name,
1278*11502SChenlu.Chen@Sun.COM 		    pr_flags, pr_valsize, pr_val, perm);
1279*11502SChenlu.Chen@Sun.COM 		break;
1280*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_MTU:
1281*11502SChenlu.Chen@Sun.COM 		if (!(pr_flags & MAC_PROP_POSSIBLE))
1282*11502SChenlu.Chen@Sun.COM 			return (ENOTSUP);
1283*11502SChenlu.Chen@Sun.COM 		if (pr_valsize < sizeof (mac_propval_range_t))
1284*11502SChenlu.Chen@Sun.COM 			return (EINVAL);
1285*11502SChenlu.Chen@Sun.COM 		range.mpr_count = 1;
1286*11502SChenlu.Chen@Sun.COM 		range.mpr_type = MAC_PROPVAL_UINT32;
1287*11502SChenlu.Chen@Sun.COM 		range.range_uint32[0].mpur_min = MIN_MTU;
1288*11502SChenlu.Chen@Sun.COM 		range.range_uint32[0].mpur_max = MAX_MTU;
1289*11502SChenlu.Chen@Sun.COM 		bcopy(&range, pr_val, sizeof (range));
1290*11502SChenlu.Chen@Sun.COM 		break;
1291*11502SChenlu.Chen@Sun.COM 	default:
1292*11502SChenlu.Chen@Sun.COM 		err = EINVAL;
1293*11502SChenlu.Chen@Sun.COM 		break;
1294*11502SChenlu.Chen@Sun.COM 	}
1295*11502SChenlu.Chen@Sun.COM 	return (err);
1296*11502SChenlu.Chen@Sun.COM }
1297*11502SChenlu.Chen@Sun.COM 
1298*11502SChenlu.Chen@Sun.COM int
1299*11502SChenlu.Chen@Sun.COM igb_get_def_val(igb_t *igb, mac_prop_id_t pr_num,
1300*11502SChenlu.Chen@Sun.COM     uint_t pr_valsize, void *pr_val)
1301*11502SChenlu.Chen@Sun.COM {
1302*11502SChenlu.Chen@Sun.COM 	uint32_t flow_control;
1303*11502SChenlu.Chen@Sun.COM 	struct e1000_hw *hw = &igb->hw;
1304*11502SChenlu.Chen@Sun.COM 	uint16_t phy_status;
1305*11502SChenlu.Chen@Sun.COM 	uint16_t phy_ext_status;
1306*11502SChenlu.Chen@Sun.COM 	int err = 0;
1307*11502SChenlu.Chen@Sun.COM 
1308*11502SChenlu.Chen@Sun.COM 	ASSERT(pr_valsize > 0);
1309*11502SChenlu.Chen@Sun.COM 	switch (pr_num) {
1310*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_AUTONEG:
1311*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1312*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val = 0;
1313*11502SChenlu.Chen@Sun.COM 		} else {
1314*11502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1315*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val =
1316*11502SChenlu.Chen@Sun.COM 			    (phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0;
1317*11502SChenlu.Chen@Sun.COM 		}
1318*11502SChenlu.Chen@Sun.COM 		break;
1319*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_FLOWCTRL:
1320*11502SChenlu.Chen@Sun.COM 		if (pr_valsize < sizeof (uint32_t))
1321*11502SChenlu.Chen@Sun.COM 			return (EINVAL);
1322*11502SChenlu.Chen@Sun.COM 		flow_control = LINK_FLOWCTRL_BI;
1323*11502SChenlu.Chen@Sun.COM 		bcopy(&flow_control, pr_val, sizeof (flow_control));
1324*11502SChenlu.Chen@Sun.COM 		break;
1325*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000FDX_CAP:
1326*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000FDX_CAP:
1327*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1328*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val = 1;
1329*11502SChenlu.Chen@Sun.COM 		} else {
1330*11502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw,
1331*11502SChenlu.Chen@Sun.COM 			    PHY_EXT_STATUS, &phy_ext_status);
1332*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val =
1333*11502SChenlu.Chen@Sun.COM 			    ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
1334*11502SChenlu.Chen@Sun.COM 			    (phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0;
1335*11502SChenlu.Chen@Sun.COM 		}
1336*11502SChenlu.Chen@Sun.COM 		break;
1337*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_1000HDX_CAP:
1338*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_1000HDX_CAP:
1339*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100T4_CAP:
1340*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100T4_CAP:
1341*11502SChenlu.Chen@Sun.COM 		*(uint8_t *)pr_val = 0;
1342*11502SChenlu.Chen@Sun.COM 		break;
1343*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100FDX_CAP:
1344*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100FDX_CAP:
1345*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1346*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val = 0;
1347*11502SChenlu.Chen@Sun.COM 		} else {
1348*11502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1349*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val =
1350*11502SChenlu.Chen@Sun.COM 			    ((phy_status & MII_SR_100X_FD_CAPS) ||
1351*11502SChenlu.Chen@Sun.COM 			    (phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0;
1352*11502SChenlu.Chen@Sun.COM 		}
1353*11502SChenlu.Chen@Sun.COM 		break;
1354*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_100HDX_CAP:
1355*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_100HDX_CAP:
1356*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1357*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val = 0;
1358*11502SChenlu.Chen@Sun.COM 		} else {
1359*11502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1360*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val =
1361*11502SChenlu.Chen@Sun.COM 			    ((phy_status & MII_SR_100X_HD_CAPS) ||
1362*11502SChenlu.Chen@Sun.COM 			    (phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0;
1363*11502SChenlu.Chen@Sun.COM 		}
1364*11502SChenlu.Chen@Sun.COM 		break;
1365*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10FDX_CAP:
1366*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10FDX_CAP:
1367*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1368*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val = 0;
1369*11502SChenlu.Chen@Sun.COM 		} else {
1370*11502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1371*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val =
1372*11502SChenlu.Chen@Sun.COM 			    (phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0;
1373*11502SChenlu.Chen@Sun.COM 		}
1374*11502SChenlu.Chen@Sun.COM 		break;
1375*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_ADV_10HDX_CAP:
1376*11502SChenlu.Chen@Sun.COM 	case MAC_PROP_EN_10HDX_CAP:
1377*11502SChenlu.Chen@Sun.COM 		if (hw->phy.media_type != e1000_media_type_copper) {
1378*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val = 0;
1379*11502SChenlu.Chen@Sun.COM 		} else {
1380*11502SChenlu.Chen@Sun.COM 			(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
1381*11502SChenlu.Chen@Sun.COM 			*(uint8_t *)pr_val =
1382*11502SChenlu.Chen@Sun.COM 			    (phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0;
1383*11502SChenlu.Chen@Sun.COM 		}
1384*11502SChenlu.Chen@Sun.COM 		break;
1385*11502SChenlu.Chen@Sun.COM 	default:
1386*11502SChenlu.Chen@Sun.COM 		err = ENOTSUP;
1387*11502SChenlu.Chen@Sun.COM 		break;
1388*11502SChenlu.Chen@Sun.COM 	}
1389*11502SChenlu.Chen@Sun.COM 	return (err);
1390*11502SChenlu.Chen@Sun.COM }
1391*11502SChenlu.Chen@Sun.COM 
1392*11502SChenlu.Chen@Sun.COM boolean_t
1393*11502SChenlu.Chen@Sun.COM igb_param_locked(mac_prop_id_t pr_num)
1394*11502SChenlu.Chen@Sun.COM {
1395*11502SChenlu.Chen@Sun.COM 	/*
1396*11502SChenlu.Chen@Sun.COM 	 * All en_* parameters are locked (read-only) while
1397*11502SChenlu.Chen@Sun.COM 	 * the device is in any sort of loopback mode ...
1398*11502SChenlu.Chen@Sun.COM 	 */
1399*11502SChenlu.Chen@Sun.COM 	switch (pr_num) {
1400*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_1000FDX_CAP:
1401*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_1000HDX_CAP:
1402*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_100T4_CAP:
1403*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_100FDX_CAP:
1404*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_100HDX_CAP:
1405*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_10FDX_CAP:
1406*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_EN_10HDX_CAP:
1407*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_AUTONEG:
1408*11502SChenlu.Chen@Sun.COM 		case MAC_PROP_FLOWCTRL:
1409*11502SChenlu.Chen@Sun.COM 			return (B_TRUE);
1410*11502SChenlu.Chen@Sun.COM 	}
1411*11502SChenlu.Chen@Sun.COM 	return (B_FALSE);
1412*11502SChenlu.Chen@Sun.COM }
1413*11502SChenlu.Chen@Sun.COM 
1414*11502SChenlu.Chen@Sun.COM /* ARGSUSED */
1415*11502SChenlu.Chen@Sun.COM int
1416*11502SChenlu.Chen@Sun.COM igb_set_priv_prop(igb_t *igb, const char *pr_name,
1417*11502SChenlu.Chen@Sun.COM     uint_t pr_valsize, const void *pr_val)
1418*11502SChenlu.Chen@Sun.COM {
1419*11502SChenlu.Chen@Sun.COM 	int err = 0;
1420*11502SChenlu.Chen@Sun.COM 	long result;
1421*11502SChenlu.Chen@Sun.COM 	struct e1000_hw *hw = &igb->hw;
1422*11502SChenlu.Chen@Sun.COM 	int i;
1423*11502SChenlu.Chen@Sun.COM 
1424*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
1425*11502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
1426*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1427*11502SChenlu.Chen@Sun.COM 			return (err);
1428*11502SChenlu.Chen@Sun.COM 		}
1429*11502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1430*11502SChenlu.Chen@Sun.COM 		if (result < MIN_TX_COPY_THRESHOLD ||
1431*11502SChenlu.Chen@Sun.COM 		    result > MAX_TX_COPY_THRESHOLD)
1432*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1433*11502SChenlu.Chen@Sun.COM 		else {
1434*11502SChenlu.Chen@Sun.COM 			igb->tx_copy_thresh = (uint32_t)result;
1435*11502SChenlu.Chen@Sun.COM 		}
1436*11502SChenlu.Chen@Sun.COM 		return (err);
1437*11502SChenlu.Chen@Sun.COM 	}
1438*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
1439*11502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
1440*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1441*11502SChenlu.Chen@Sun.COM 			return (err);
1442*11502SChenlu.Chen@Sun.COM 		}
1443*11502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1444*11502SChenlu.Chen@Sun.COM 		if (result < MIN_TX_RECYCLE_THRESHOLD ||
1445*11502SChenlu.Chen@Sun.COM 		    result > MAX_TX_RECYCLE_THRESHOLD)
1446*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1447*11502SChenlu.Chen@Sun.COM 		else {
1448*11502SChenlu.Chen@Sun.COM 			igb->tx_recycle_thresh = (uint32_t)result;
1449*11502SChenlu.Chen@Sun.COM 		}
1450*11502SChenlu.Chen@Sun.COM 		return (err);
1451*11502SChenlu.Chen@Sun.COM 	}
1452*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
1453*11502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
1454*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1455*11502SChenlu.Chen@Sun.COM 			return (err);
1456*11502SChenlu.Chen@Sun.COM 		}
1457*11502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1458*11502SChenlu.Chen@Sun.COM 		if (result < MIN_TX_OVERLOAD_THRESHOLD ||
1459*11502SChenlu.Chen@Sun.COM 		    result > MAX_TX_OVERLOAD_THRESHOLD)
1460*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1461*11502SChenlu.Chen@Sun.COM 		else {
1462*11502SChenlu.Chen@Sun.COM 			igb->tx_overload_thresh = (uint32_t)result;
1463*11502SChenlu.Chen@Sun.COM 		}
1464*11502SChenlu.Chen@Sun.COM 		return (err);
1465*11502SChenlu.Chen@Sun.COM 	}
1466*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
1467*11502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
1468*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1469*11502SChenlu.Chen@Sun.COM 			return (err);
1470*11502SChenlu.Chen@Sun.COM 		}
1471*11502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1472*11502SChenlu.Chen@Sun.COM 		if (result < MIN_TX_RESCHED_THRESHOLD ||
1473*11502SChenlu.Chen@Sun.COM 		    result > MAX_TX_RESCHED_THRESHOLD)
1474*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1475*11502SChenlu.Chen@Sun.COM 		else {
1476*11502SChenlu.Chen@Sun.COM 			igb->tx_resched_thresh = (uint32_t)result;
1477*11502SChenlu.Chen@Sun.COM 		}
1478*11502SChenlu.Chen@Sun.COM 		return (err);
1479*11502SChenlu.Chen@Sun.COM 	}
1480*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
1481*11502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
1482*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1483*11502SChenlu.Chen@Sun.COM 			return (err);
1484*11502SChenlu.Chen@Sun.COM 		}
1485*11502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1486*11502SChenlu.Chen@Sun.COM 		if (result < MIN_RX_COPY_THRESHOLD ||
1487*11502SChenlu.Chen@Sun.COM 		    result > MAX_RX_COPY_THRESHOLD)
1488*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1489*11502SChenlu.Chen@Sun.COM 		else {
1490*11502SChenlu.Chen@Sun.COM 			igb->rx_copy_thresh = (uint32_t)result;
1491*11502SChenlu.Chen@Sun.COM 		}
1492*11502SChenlu.Chen@Sun.COM 		return (err);
1493*11502SChenlu.Chen@Sun.COM 	}
1494*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
1495*11502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
1496*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1497*11502SChenlu.Chen@Sun.COM 			return (err);
1498*11502SChenlu.Chen@Sun.COM 		}
1499*11502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1500*11502SChenlu.Chen@Sun.COM 		if (result < MIN_RX_LIMIT_PER_INTR ||
1501*11502SChenlu.Chen@Sun.COM 		    result > MAX_RX_LIMIT_PER_INTR)
1502*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1503*11502SChenlu.Chen@Sun.COM 		else {
1504*11502SChenlu.Chen@Sun.COM 			igb->rx_limit_per_intr = (uint32_t)result;
1505*11502SChenlu.Chen@Sun.COM 		}
1506*11502SChenlu.Chen@Sun.COM 		return (err);
1507*11502SChenlu.Chen@Sun.COM 	}
1508*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_intr_throttling") == 0) {
1509*11502SChenlu.Chen@Sun.COM 		if (pr_val == NULL) {
1510*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1511*11502SChenlu.Chen@Sun.COM 			return (err);
1512*11502SChenlu.Chen@Sun.COM 		}
1513*11502SChenlu.Chen@Sun.COM 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1514*11502SChenlu.Chen@Sun.COM 
1515*11502SChenlu.Chen@Sun.COM 		if (result < igb->capab->min_intr_throttle ||
1516*11502SChenlu.Chen@Sun.COM 		    result > igb->capab->max_intr_throttle)
1517*11502SChenlu.Chen@Sun.COM 			err = EINVAL;
1518*11502SChenlu.Chen@Sun.COM 		else {
1519*11502SChenlu.Chen@Sun.COM 			igb->intr_throttling[0] = (uint32_t)result;
1520*11502SChenlu.Chen@Sun.COM 
1521*11502SChenlu.Chen@Sun.COM 			for (i = 0; i < MAX_NUM_EITR; i++)
1522*11502SChenlu.Chen@Sun.COM 				igb->intr_throttling[i] =
1523*11502SChenlu.Chen@Sun.COM 				    igb->intr_throttling[0];
1524*11502SChenlu.Chen@Sun.COM 
1525*11502SChenlu.Chen@Sun.COM 			/* Set interrupt throttling rate */
1526*11502SChenlu.Chen@Sun.COM 			for (i = 0; i < igb->intr_cnt; i++)
1527*11502SChenlu.Chen@Sun.COM 				E1000_WRITE_REG(hw, E1000_EITR(i),
1528*11502SChenlu.Chen@Sun.COM 				    igb->intr_throttling[i]);
1529*11502SChenlu.Chen@Sun.COM 		}
1530*11502SChenlu.Chen@Sun.COM 		return (err);
1531*11502SChenlu.Chen@Sun.COM 	}
1532*11502SChenlu.Chen@Sun.COM 	return (ENOTSUP);
1533*11502SChenlu.Chen@Sun.COM }
1534*11502SChenlu.Chen@Sun.COM 
1535*11502SChenlu.Chen@Sun.COM int
1536*11502SChenlu.Chen@Sun.COM igb_get_priv_prop(igb_t *igb, const char *pr_name,
1537*11502SChenlu.Chen@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
1538*11502SChenlu.Chen@Sun.COM {
1539*11502SChenlu.Chen@Sun.COM 	int err = ENOTSUP;
1540*11502SChenlu.Chen@Sun.COM 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
1541*11502SChenlu.Chen@Sun.COM 	int value;
1542*11502SChenlu.Chen@Sun.COM 
1543*11502SChenlu.Chen@Sun.COM 	*perm = MAC_PROP_PERM_RW;
1544*11502SChenlu.Chen@Sun.COM 
1545*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_adv_pause_cap") == 0) {
1546*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1547*11502SChenlu.Chen@Sun.COM 		value = (is_default ? 1 : igb->param_adv_pause_cap);
1548*11502SChenlu.Chen@Sun.COM 		err = 0;
1549*11502SChenlu.Chen@Sun.COM 		goto done;
1550*11502SChenlu.Chen@Sun.COM 	}
1551*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
1552*11502SChenlu.Chen@Sun.COM 		*perm = MAC_PROP_PERM_READ;
1553*11502SChenlu.Chen@Sun.COM 		value = (is_default ? 1 : igb->param_adv_asym_pause_cap);
1554*11502SChenlu.Chen@Sun.COM 		err = 0;
1555*11502SChenlu.Chen@Sun.COM 		goto done;
1556*11502SChenlu.Chen@Sun.COM 	}
1557*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
1558*11502SChenlu.Chen@Sun.COM 		value = (is_default ? DEFAULT_TX_COPY_THRESHOLD :
1559*11502SChenlu.Chen@Sun.COM 		    igb->tx_copy_thresh);
1560*11502SChenlu.Chen@Sun.COM 		err = 0;
1561*11502SChenlu.Chen@Sun.COM 		goto done;
1562*11502SChenlu.Chen@Sun.COM 	}
1563*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
1564*11502SChenlu.Chen@Sun.COM 		value = (is_default ? DEFAULT_TX_RECYCLE_THRESHOLD :
1565*11502SChenlu.Chen@Sun.COM 		    igb->tx_recycle_thresh);
1566*11502SChenlu.Chen@Sun.COM 		err = 0;
1567*11502SChenlu.Chen@Sun.COM 		goto done;
1568*11502SChenlu.Chen@Sun.COM 	}
1569*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
1570*11502SChenlu.Chen@Sun.COM 		value = (is_default ? DEFAULT_TX_OVERLOAD_THRESHOLD :
1571*11502SChenlu.Chen@Sun.COM 		    igb->tx_overload_thresh);
1572*11502SChenlu.Chen@Sun.COM 		err = 0;
1573*11502SChenlu.Chen@Sun.COM 		goto done;
1574*11502SChenlu.Chen@Sun.COM 	}
1575*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
1576*11502SChenlu.Chen@Sun.COM 		value = (is_default ? DEFAULT_TX_RESCHED_THRESHOLD :
1577*11502SChenlu.Chen@Sun.COM 		    igb->tx_resched_thresh);
1578*11502SChenlu.Chen@Sun.COM 		err = 0;
1579*11502SChenlu.Chen@Sun.COM 		goto done;
1580*11502SChenlu.Chen@Sun.COM 	}
1581*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
1582*11502SChenlu.Chen@Sun.COM 		value = (is_default ? DEFAULT_RX_COPY_THRESHOLD :
1583*11502SChenlu.Chen@Sun.COM 		    igb->rx_copy_thresh);
1584*11502SChenlu.Chen@Sun.COM 		err = 0;
1585*11502SChenlu.Chen@Sun.COM 		goto done;
1586*11502SChenlu.Chen@Sun.COM 	}
1587*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
1588*11502SChenlu.Chen@Sun.COM 		value = (is_default ? DEFAULT_RX_LIMIT_PER_INTR :
1589*11502SChenlu.Chen@Sun.COM 		    igb->rx_limit_per_intr);
1590*11502SChenlu.Chen@Sun.COM 		err = 0;
1591*11502SChenlu.Chen@Sun.COM 		goto done;
1592*11502SChenlu.Chen@Sun.COM 	}
1593*11502SChenlu.Chen@Sun.COM 	if (strcmp(pr_name, "_intr_throttling") == 0) {
1594*11502SChenlu.Chen@Sun.COM 		value = (is_default ? igb->capab->def_intr_throttle :
1595*11502SChenlu.Chen@Sun.COM 		    igb->intr_throttling[0]);
1596*11502SChenlu.Chen@Sun.COM 		err = 0;
1597*11502SChenlu.Chen@Sun.COM 		goto done;
1598*11502SChenlu.Chen@Sun.COM 	}
1599*11502SChenlu.Chen@Sun.COM done:
1600*11502SChenlu.Chen@Sun.COM 	if (err == 0) {
1601*11502SChenlu.Chen@Sun.COM 		(void) snprintf(pr_val, pr_valsize, "%d", value);
1602*11502SChenlu.Chen@Sun.COM 	}
1603*11502SChenlu.Chen@Sun.COM 	return (err);
1604*11502SChenlu.Chen@Sun.COM }
1605