xref: /onnv-gate/usr/src/uts/common/io/igb/igb_gld.c (revision 9188:ab6acbc59f0c)
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*9188SPaul.Guo@Sun.COM  * Copyright 2009 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 
4306624Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
4316624Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
4326624Sgl147354 
4335779Sxy150489 	return (0);
4345779Sxy150489 }
4355779Sxy150489 
4365779Sxy150489 /*
4375779Sxy150489  * Bring the device out of the reset/quiesced state that it
4385779Sxy150489  * was in when the interface was registered.
4395779Sxy150489  */
4405779Sxy150489 int
4415779Sxy150489 igb_m_start(void *arg)
4425779Sxy150489 {
4435779Sxy150489 	igb_t *igb = (igb_t *)arg;
4445779Sxy150489 
4455779Sxy150489 	mutex_enter(&igb->gen_lock);
4465779Sxy150489 
4475779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
4485779Sxy150489 		mutex_exit(&igb->gen_lock);
4495779Sxy150489 		return (ECANCELED);
4505779Sxy150489 	}
4515779Sxy150489 
4525779Sxy150489 	if (igb_start(igb) != IGB_SUCCESS) {
4535779Sxy150489 		mutex_exit(&igb->gen_lock);
4545779Sxy150489 		return (EIO);
4555779Sxy150489 	}
4565779Sxy150489 
4575779Sxy150489 	igb->igb_state |= IGB_STARTED;
4585779Sxy150489 
4595779Sxy150489 	mutex_exit(&igb->gen_lock);
4605779Sxy150489 
4615779Sxy150489 	/*
4625779Sxy150489 	 * Enable and start the watchdog timer
4635779Sxy150489 	 */
4645779Sxy150489 	igb_enable_watchdog_timer(igb);
4655779Sxy150489 
4665779Sxy150489 	return (0);
4675779Sxy150489 }
4685779Sxy150489 
4695779Sxy150489 /*
4705779Sxy150489  * Stop the device and put it in a reset/quiesced state such
4715779Sxy150489  * that the interface can be unregistered.
4725779Sxy150489  */
4735779Sxy150489 void
4745779Sxy150489 igb_m_stop(void *arg)
4755779Sxy150489 {
4765779Sxy150489 	igb_t *igb = (igb_t *)arg;
4775779Sxy150489 
4785779Sxy150489 	mutex_enter(&igb->gen_lock);
4795779Sxy150489 
4805779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
4815779Sxy150489 		mutex_exit(&igb->gen_lock);
4825779Sxy150489 		return;
4835779Sxy150489 	}
4845779Sxy150489 
4855779Sxy150489 	igb->igb_state &= ~IGB_STARTED;
4865779Sxy150489 
4875779Sxy150489 	igb_stop(igb);
4885779Sxy150489 
4895779Sxy150489 	mutex_exit(&igb->gen_lock);
4905779Sxy150489 
4915779Sxy150489 	/*
4925779Sxy150489 	 * Disable and stop the watchdog timer
4935779Sxy150489 	 */
4945779Sxy150489 	igb_disable_watchdog_timer(igb);
4955779Sxy150489 }
4965779Sxy150489 
4975779Sxy150489 /*
4985779Sxy150489  * Set the promiscuity of the device.
4995779Sxy150489  */
5005779Sxy150489 int
5015779Sxy150489 igb_m_promisc(void *arg, boolean_t on)
5025779Sxy150489 {
5035779Sxy150489 	igb_t *igb = (igb_t *)arg;
5045779Sxy150489 	uint32_t reg_val;
5055779Sxy150489 
5065779Sxy150489 	mutex_enter(&igb->gen_lock);
5075779Sxy150489 
5085779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
5095779Sxy150489 		mutex_exit(&igb->gen_lock);
5105779Sxy150489 		return (ECANCELED);
5115779Sxy150489 	}
5125779Sxy150489 
5135779Sxy150489 	reg_val = E1000_READ_REG(&igb->hw, E1000_RCTL);
5145779Sxy150489 
5155779Sxy150489 	if (on)
5165779Sxy150489 		reg_val |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
5175779Sxy150489 	else
5185779Sxy150489 		reg_val &= (~(E1000_RCTL_UPE | E1000_RCTL_MPE));
5195779Sxy150489 
5205779Sxy150489 	E1000_WRITE_REG(&igb->hw, E1000_RCTL, reg_val);
5215779Sxy150489 
5225779Sxy150489 	mutex_exit(&igb->gen_lock);
5235779Sxy150489 
5246624Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
5256624Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
5266624Sgl147354 		return (EIO);
5276624Sgl147354 	}
5286624Sgl147354 
5295779Sxy150489 	return (0);
5305779Sxy150489 }
5315779Sxy150489 
5325779Sxy150489 /*
5335779Sxy150489  * Add/remove the addresses to/from the set of multicast
5345779Sxy150489  * addresses for which the device will receive packets.
5355779Sxy150489  */
5365779Sxy150489 int
5375779Sxy150489 igb_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
5385779Sxy150489 {
5395779Sxy150489 	igb_t *igb = (igb_t *)arg;
5405779Sxy150489 	int result;
5415779Sxy150489 
5425779Sxy150489 	mutex_enter(&igb->gen_lock);
5435779Sxy150489 
5445779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
5455779Sxy150489 		mutex_exit(&igb->gen_lock);
5465779Sxy150489 		return (ECANCELED);
5475779Sxy150489 	}
5485779Sxy150489 
5495779Sxy150489 	result = (add) ? igb_multicst_add(igb, mcst_addr)
5505779Sxy150489 	    : igb_multicst_remove(igb, mcst_addr);
5515779Sxy150489 
5525779Sxy150489 	mutex_exit(&igb->gen_lock);
5535779Sxy150489 
5545779Sxy150489 	return (result);
5555779Sxy150489 }
5565779Sxy150489 
5575779Sxy150489 /*
5585779Sxy150489  * Pass on M_IOCTL messages passed to the DLD, and support
5595779Sxy150489  * private IOCTLs for debugging and ndd.
5605779Sxy150489  */
5615779Sxy150489 void
5625779Sxy150489 igb_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
5635779Sxy150489 {
5645779Sxy150489 	igb_t *igb = (igb_t *)arg;
5655779Sxy150489 	struct iocblk *iocp;
5665779Sxy150489 	enum ioc_reply status;
5675779Sxy150489 
5685779Sxy150489 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
5695779Sxy150489 	iocp->ioc_error = 0;
5705779Sxy150489 
5715779Sxy150489 	switch (iocp->ioc_cmd) {
5725779Sxy150489 	case LB_GET_INFO_SIZE:
5735779Sxy150489 	case LB_GET_INFO:
5745779Sxy150489 	case LB_GET_MODE:
5755779Sxy150489 	case LB_SET_MODE:
5765779Sxy150489 		status = igb_loopback_ioctl(igb, iocp, mp);
5775779Sxy150489 		break;
5785779Sxy150489 
5795779Sxy150489 	case ND_GET:
5805779Sxy150489 	case ND_SET:
5815779Sxy150489 		status = igb_nd_ioctl(igb, q, mp, iocp);
5825779Sxy150489 		break;
5835779Sxy150489 
5845779Sxy150489 	default:
5855779Sxy150489 		status = IOC_INVAL;
5865779Sxy150489 		break;
5875779Sxy150489 	}
5885779Sxy150489 
5895779Sxy150489 	/*
5905779Sxy150489 	 * Decide how to reply
5915779Sxy150489 	 */
5925779Sxy150489 	switch (status) {
5935779Sxy150489 	default:
5945779Sxy150489 	case IOC_INVAL:
5955779Sxy150489 		/*
5965779Sxy150489 		 * Error, reply with a NAK and EINVAL or the specified error
5975779Sxy150489 		 */
5985779Sxy150489 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
5995779Sxy150489 		    EINVAL : iocp->ioc_error);
6005779Sxy150489 		break;
6015779Sxy150489 
6025779Sxy150489 	case IOC_DONE:
6035779Sxy150489 		/*
6045779Sxy150489 		 * OK, reply already sent
6055779Sxy150489 		 */
6065779Sxy150489 		break;
6075779Sxy150489 
6085779Sxy150489 	case IOC_ACK:
6095779Sxy150489 		/*
6105779Sxy150489 		 * OK, reply with an ACK
6115779Sxy150489 		 */
6125779Sxy150489 		miocack(q, mp, 0, 0);
6135779Sxy150489 		break;
6145779Sxy150489 
6155779Sxy150489 	case IOC_REPLY:
6165779Sxy150489 		/*
6175779Sxy150489 		 * OK, send prepared reply as ACK or NAK
6185779Sxy150489 		 */
6195779Sxy150489 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
6205779Sxy150489 		    M_IOCACK : M_IOCNAK;
6215779Sxy150489 		qreply(q, mp);
6225779Sxy150489 		break;
6235779Sxy150489 	}
6245779Sxy150489 }
6255779Sxy150489 
6265779Sxy150489 /*
6278275SEric Cheng  * Add a MAC address to the target RX group.
6285779Sxy150489  */
6298275SEric Cheng static int
6308275SEric Cheng igb_addmac(void *arg, const uint8_t *mac_addr)
6315779Sxy150489 {
6328275SEric Cheng 	igb_rx_group_t *rx_group = (igb_rx_group_t *)arg;
6338275SEric Cheng 	igb_t *igb = rx_group->igb;
6348275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
6358275SEric Cheng 	int i, slot;
6365779Sxy150489 
6375779Sxy150489 	mutex_enter(&igb->gen_lock);
6385779Sxy150489 
6395779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
6405779Sxy150489 		mutex_exit(&igb->gen_lock);
6415779Sxy150489 		return (ECANCELED);
6425779Sxy150489 	}
6435779Sxy150489 
6445779Sxy150489 	if (igb->unicst_avail == 0) {
6455779Sxy150489 		/* no slots available */
6465779Sxy150489 		mutex_exit(&igb->gen_lock);
6475779Sxy150489 		return (ENOSPC);
6485779Sxy150489 	}
6495779Sxy150489 
6505779Sxy150489 	/*
6518275SEric Cheng 	 * The slots from 0 to igb->num_rx_groups are reserved slots which
6528275SEric Cheng 	 * are 1 to 1 mapped with group index directly. The other slots are
6538275SEric Cheng 	 * shared between the all of groups. While adding a MAC address,
6548275SEric Cheng 	 * it will try to set the reserved slots first, then the shared slots.
6555779Sxy150489 	 */
6568275SEric Cheng 	slot = -1;
6578275SEric Cheng 	if (igb->unicst_addr[rx_group->index].mac.set == 1) {
6588275SEric Cheng 		/*
6598275SEric Cheng 		 * The reserved slot for current group is used, find the free
6608275SEric Cheng 		 * slots in the shared slots.
6618275SEric Cheng 		 */
6628275SEric Cheng 		for (i = igb->num_rx_groups; i < igb->unicst_total; i++) {
6638275SEric Cheng 			if (igb->unicst_addr[i].mac.set == 0) {
6648275SEric Cheng 				slot = i;
6658275SEric Cheng 				break;
6668275SEric Cheng 			}
6678275SEric Cheng 		}
6688275SEric Cheng 	} else
6698275SEric Cheng 		slot = rx_group->index;
6708275SEric Cheng 
6718275SEric Cheng 	if (slot == -1) {
6728275SEric Cheng 		/* no slots available in the shared slots */
6738275SEric Cheng 		mutex_exit(&igb->gen_lock);
6748275SEric Cheng 		return (ENOSPC);
6755779Sxy150489 	}
6765779Sxy150489 
6778275SEric Cheng 	/* Set VMDq according to the mode supported by hardware. */
6788275SEric Cheng 	e1000_rar_set_vmdq(hw, mac_addr, slot, igb->vmdq_mode, rx_group->index);
6795779Sxy150489 
6808275SEric Cheng 	bcopy(mac_addr, igb->unicst_addr[slot].mac.addr, ETHERADDRL);
6818275SEric Cheng 	igb->unicst_addr[slot].mac.group_index = rx_group->index;
6828275SEric Cheng 	igb->unicst_addr[slot].mac.set = 1;
6838275SEric Cheng 	igb->unicst_avail--;
6845779Sxy150489 
6857072Sxy150489 	mutex_exit(&igb->gen_lock);
6867072Sxy150489 
6878275SEric Cheng 	return (0);
6885779Sxy150489 }
6895779Sxy150489 
6905779Sxy150489 /*
6918275SEric Cheng  * Remove a MAC address from the specified RX group.
6925779Sxy150489  */
6938275SEric Cheng static int
6948275SEric Cheng igb_remmac(void *arg, const uint8_t *mac_addr)
6955779Sxy150489 {
6968275SEric Cheng 	igb_rx_group_t *rx_group = (igb_rx_group_t *)arg;
6978275SEric Cheng 	igb_t *igb = rx_group->igb;
6988275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
6998275SEric Cheng 	int slot;
7005779Sxy150489 
7015779Sxy150489 	mutex_enter(&igb->gen_lock);
7025779Sxy150489 
7035779Sxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
7045779Sxy150489 		mutex_exit(&igb->gen_lock);
7055779Sxy150489 		return (ECANCELED);
7065779Sxy150489 	}
7075779Sxy150489 
7088275SEric Cheng 	slot = igb_unicst_find(igb, mac_addr);
7098275SEric Cheng 	if (slot == -1) {
7105779Sxy150489 		mutex_exit(&igb->gen_lock);
7115779Sxy150489 		return (EINVAL);
7125779Sxy150489 	}
7135779Sxy150489 
7147072Sxy150489 	if (igb->unicst_addr[slot].mac.set == 0) {
7157072Sxy150489 		mutex_exit(&igb->gen_lock);
7167072Sxy150489 		return (EINVAL);
7177072Sxy150489 	}
7187072Sxy150489 
7198275SEric Cheng 	/* Clear the MAC ddress in the slot */
7208275SEric Cheng 	e1000_rar_clear(hw, slot);
7218275SEric Cheng 	igb->unicst_addr[slot].mac.set = 0;
7228275SEric Cheng 	igb->unicst_avail++;
7235779Sxy150489 
7245779Sxy150489 	mutex_exit(&igb->gen_lock);
7255779Sxy150489 
7268275SEric Cheng 	return (0);
7278275SEric Cheng }
7288275SEric Cheng 
7298275SEric Cheng /*
7308275SEric Cheng  * Enable interrupt on the specificed rx ring.
7318275SEric Cheng  */
7328275SEric Cheng int
7338275SEric Cheng igb_rx_ring_intr_enable(mac_intr_handle_t intrh)
7348275SEric Cheng {
7358275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)intrh;
7368275SEric Cheng 	igb_t *igb = rx_ring->igb;
7378275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
7388275SEric Cheng 	uint32_t index = rx_ring->index;
7398275SEric Cheng 
7408275SEric Cheng 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
7418275SEric Cheng 		/* Interrupt enabling for MSI-X */
7428275SEric Cheng 		igb->eims_mask |= (E1000_EICR_RX_QUEUE0 << index);
7438275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
7448275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
7458275SEric Cheng 	} else {
7468275SEric Cheng 		ASSERT(index == 0);
7478275SEric Cheng 		/* Interrupt enabling for MSI and legacy */
7488275SEric Cheng 		igb->ims_mask |= E1000_IMS_RXT0;
7498275SEric Cheng 		E1000_WRITE_REG(hw, E1000_IMS, igb->ims_mask);
7508275SEric Cheng 	}
7518275SEric Cheng 
7528275SEric Cheng 	E1000_WRITE_FLUSH(hw);
7538275SEric Cheng 
7548275SEric Cheng 	return (0);
7558275SEric Cheng }
7568275SEric Cheng 
7578275SEric Cheng /*
7588275SEric Cheng  * Disable interrupt on the specificed rx ring.
7598275SEric Cheng  */
7608275SEric Cheng int
7618275SEric Cheng igb_rx_ring_intr_disable(mac_intr_handle_t intrh)
7628275SEric Cheng {
7638275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)intrh;
7648275SEric Cheng 	igb_t *igb = rx_ring->igb;
7658275SEric Cheng 	struct e1000_hw *hw = &igb->hw;
7668275SEric Cheng 	uint32_t index = rx_ring->index;
7678275SEric Cheng 
7688275SEric Cheng 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
7698275SEric Cheng 		/* Interrupt disabling for MSI-X */
7708275SEric Cheng 		igb->eims_mask &= ~(E1000_EICR_RX_QUEUE0 << index);
7718275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIMC,
7728275SEric Cheng 		    (E1000_EICR_RX_QUEUE0 << index));
7738275SEric Cheng 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
7748275SEric Cheng 	} else {
7758275SEric Cheng 		ASSERT(index == 0);
7768275SEric Cheng 		/* Interrupt disabling for MSI and legacy */
7778275SEric Cheng 		igb->ims_mask &= ~E1000_IMS_RXT0;
7788275SEric Cheng 		E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_RXT0);
7798275SEric Cheng 	}
7808275SEric Cheng 
7818275SEric Cheng 	E1000_WRITE_FLUSH(hw);
7828275SEric Cheng 
7838275SEric Cheng 	return (0);
7845779Sxy150489 }
7855779Sxy150489 
7865779Sxy150489 /*
7878275SEric Cheng  * Get the global ring index by a ring index within a group.
7885779Sxy150489  */
7895779Sxy150489 int
7908275SEric Cheng igb_get_rx_ring_index(igb_t *igb, int gindex, int rindex)
7915779Sxy150489 {
7928275SEric Cheng 	igb_rx_ring_t *rx_ring;
7938275SEric Cheng 	int i;
7945779Sxy150489 
7958275SEric Cheng 	for (i = 0; i < igb->num_rx_rings; i++) {
7968275SEric Cheng 		rx_ring = &igb->rx_rings[i];
7978275SEric Cheng 		if (rx_ring->group_index == gindex)
7988275SEric Cheng 			rindex--;
7998275SEric Cheng 		if (rindex < 0)
8008275SEric Cheng 			return (i);
8015779Sxy150489 	}
8025779Sxy150489 
8038275SEric Cheng 	return (-1);
8048275SEric Cheng }
8055779Sxy150489 
8068275SEric Cheng static int
8078275SEric Cheng igb_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
8088275SEric Cheng {
8098275SEric Cheng 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)rh;
8105779Sxy150489 
8118275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
8128275SEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
8138275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
8148275SEric Cheng 	return (0);
8155779Sxy150489 }
8165779Sxy150489 
8175779Sxy150489 /*
8188275SEric Cheng  * Callback funtion for MAC layer to register all rings.
8195779Sxy150489  */
8208275SEric Cheng /* ARGSUSED */
8218275SEric Cheng void
8228275SEric Cheng igb_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
8238275SEric Cheng     const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
8245779Sxy150489 {
8255779Sxy150489 	igb_t *igb = (igb_t *)arg;
8268275SEric Cheng 	mac_intr_t *mintr = &infop->mri_intr;
8278275SEric Cheng 
8288275SEric Cheng 	switch (rtype) {
8298275SEric Cheng 	case MAC_RING_TYPE_RX: {
8308275SEric Cheng 		igb_rx_ring_t *rx_ring;
8318275SEric Cheng 		int global_index;
8325779Sxy150489 
8338275SEric Cheng 		/*
8348275SEric Cheng 		 * 'index' is the ring index within the group.
8358275SEric Cheng 		 * We need the global ring index by searching in group.
8368275SEric Cheng 		 */
8378275SEric Cheng 		global_index = igb_get_rx_ring_index(igb, rg_index, index);
8388275SEric Cheng 
8398275SEric Cheng 		ASSERT(global_index >= 0);
8405779Sxy150489 
8418275SEric Cheng 		rx_ring = &igb->rx_rings[global_index];
8428275SEric Cheng 		rx_ring->ring_handle = rh;
8438275SEric Cheng 
8448275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
8458275SEric Cheng 		infop->mri_start = igb_ring_start;
8468275SEric Cheng 		infop->mri_stop = NULL;
8478275SEric Cheng 		infop->mri_poll = (mac_ring_poll_t)igb_rx_ring_poll;
8488275SEric Cheng 
8498275SEric Cheng 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
8508275SEric Cheng 		mintr->mi_enable = igb_rx_ring_intr_enable;
8518275SEric Cheng 		mintr->mi_disable = igb_rx_ring_intr_disable;
8528275SEric Cheng 
8538275SEric Cheng 		break;
8545779Sxy150489 	}
8558275SEric Cheng 	case MAC_RING_TYPE_TX: {
8568275SEric Cheng 		ASSERT(index < igb->num_tx_rings);
8575779Sxy150489 
8588275SEric Cheng 		igb_tx_ring_t *tx_ring = &igb->tx_rings[index];
8598275SEric Cheng 		tx_ring->ring_handle = rh;
8605779Sxy150489 
8618275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
8628275SEric Cheng 		infop->mri_start = NULL;
8638275SEric Cheng 		infop->mri_stop = NULL;
8648275SEric Cheng 		infop->mri_tx = igb_tx_ring_send;
8658275SEric Cheng 
8668275SEric Cheng 		break;
8675779Sxy150489 	}
8688275SEric Cheng 	default:
8698275SEric Cheng 		break;
8708275SEric Cheng 	}
8718275SEric Cheng }
8728275SEric Cheng 
8738275SEric Cheng void
8748275SEric Cheng igb_fill_group(void *arg, mac_ring_type_t rtype, const int index,
8758275SEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
8768275SEric Cheng {
8778275SEric Cheng 	igb_t *igb = (igb_t *)arg;
8785779Sxy150489 
8798275SEric Cheng 	switch (rtype) {
8808275SEric Cheng 	case MAC_RING_TYPE_RX: {
8818275SEric Cheng 		igb_rx_group_t *rx_group;
8828275SEric Cheng 
8838275SEric Cheng 		ASSERT((index >= 0) && (index < igb->num_rx_groups));
8848275SEric Cheng 
8858275SEric Cheng 		rx_group = &igb->rx_groups[index];
8868275SEric Cheng 		rx_group->group_handle = gh;
8878275SEric Cheng 
8888275SEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_group;
8898275SEric Cheng 		infop->mgi_start = NULL;
8908275SEric Cheng 		infop->mgi_stop = NULL;
8918275SEric Cheng 		infop->mgi_addmac = igb_addmac;
8928275SEric Cheng 		infop->mgi_remmac = igb_remmac;
8938275SEric Cheng 		infop->mgi_count = (igb->num_rx_rings / igb->num_rx_groups);
8948275SEric Cheng 
8958275SEric Cheng 		break;
8965779Sxy150489 	}
8978275SEric Cheng 	case MAC_RING_TYPE_TX:
8988275SEric Cheng 		break;
8998275SEric Cheng 	default:
9008275SEric Cheng 		break;
9018275SEric Cheng 	}
9025779Sxy150489 }
9035779Sxy150489 
9045779Sxy150489 /*
9055779Sxy150489  * Obtain the MAC's capabilities and associated data from
9065779Sxy150489  * the driver.
9075779Sxy150489  */
9085779Sxy150489 boolean_t
9095779Sxy150489 igb_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
9105779Sxy150489 {
9115779Sxy150489 	igb_t *igb = (igb_t *)arg;
9125779Sxy150489 
9135779Sxy150489 	switch (cap) {
9145779Sxy150489 	case MAC_CAPAB_HCKSUM: {
9155779Sxy150489 		uint32_t *tx_hcksum_flags = cap_data;
9165779Sxy150489 
9175779Sxy150489 		/*
9185779Sxy150489 		 * We advertise our capabilities only if tx hcksum offload is
9195779Sxy150489 		 * enabled.  On receive, the stack will accept checksummed
9205779Sxy150489 		 * packets anyway, even if we haven't said we can deliver
9215779Sxy150489 		 * them.
9225779Sxy150489 		 */
9235779Sxy150489 		if (!igb->tx_hcksum_enable)
9245779Sxy150489 			return (B_FALSE);
9255779Sxy150489 
9265779Sxy150489 		*tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
9275779Sxy150489 		break;
9285779Sxy150489 	}
929*9188SPaul.Guo@Sun.COM 	case MAC_CAPAB_LSO: {
930*9188SPaul.Guo@Sun.COM 		mac_capab_lso_t *cap_lso = cap_data;
931*9188SPaul.Guo@Sun.COM 
932*9188SPaul.Guo@Sun.COM 		if (igb->lso_enable) {
933*9188SPaul.Guo@Sun.COM 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
934*9188SPaul.Guo@Sun.COM 			cap_lso->lso_basic_tcp_ipv4.lso_max = IGB_LSO_MAXLEN;
935*9188SPaul.Guo@Sun.COM 			break;
936*9188SPaul.Guo@Sun.COM 		} else {
937*9188SPaul.Guo@Sun.COM 			return (B_FALSE);
938*9188SPaul.Guo@Sun.COM 		}
939*9188SPaul.Guo@Sun.COM 	}
9408275SEric Cheng 	case MAC_CAPAB_RINGS: {
9418275SEric Cheng 		mac_capab_rings_t *cap_rings = cap_data;
9428275SEric Cheng 
9438275SEric Cheng 		switch (cap_rings->mr_type) {
9448275SEric Cheng 		case MAC_RING_TYPE_RX:
9458275SEric Cheng 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
9468275SEric Cheng 			cap_rings->mr_rnum = igb->num_rx_rings;
9478275SEric Cheng 			cap_rings->mr_gnum = igb->num_rx_groups;
9488275SEric Cheng 			cap_rings->mr_rget = igb_fill_ring;
9498275SEric Cheng 			cap_rings->mr_gget = igb_fill_group;
9508275SEric Cheng 			cap_rings->mr_gaddring = NULL;
9518275SEric Cheng 			cap_rings->mr_gremring = NULL;
9525779Sxy150489 
9538275SEric Cheng 			break;
9548275SEric Cheng 		case MAC_RING_TYPE_TX:
9558275SEric Cheng 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
9568275SEric Cheng 			cap_rings->mr_rnum = igb->num_tx_rings;
9578275SEric Cheng 			cap_rings->mr_gnum = 0;
9588275SEric Cheng 			cap_rings->mr_rget = igb_fill_ring;
9598275SEric Cheng 			cap_rings->mr_gget = NULL;
9608275SEric Cheng 
9618275SEric Cheng 			break;
9628275SEric Cheng 		default:
9638275SEric Cheng 			break;
9648275SEric Cheng 		}
9655779Sxy150489 		break;
9665779Sxy150489 	}
9678275SEric Cheng 
9685779Sxy150489 	default:
9695779Sxy150489 		return (B_FALSE);
9705779Sxy150489 	}
9715779Sxy150489 	return (B_TRUE);
9725779Sxy150489 }
973