xref: /onnv-gate/usr/src/uts/common/io/ixgbe/ixgbe_main.c (revision 13006:22e6d3edaab5)
16621Sbt150084 /*
26621Sbt150084  * CDDL HEADER START
36621Sbt150084  *
46621Sbt150084  * The contents of this file are subject to the terms of the
56621Sbt150084  * Common Development and Distribution License (the "License").
66621Sbt150084  * You may not use this file except in compliance with the License.
76621Sbt150084  *
87656SSherry.Moore@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97656SSherry.Moore@Sun.COM  * or http://www.opensolaris.org/os/licensing.
106621Sbt150084  * See the License for the specific language governing permissions
116621Sbt150084  * and limitations under the License.
126621Sbt150084  *
137656SSherry.Moore@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147656SSherry.Moore@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156621Sbt150084  * If applicable, add the following below this CDDL HEADER, with the
166621Sbt150084  * fields enclosed by brackets "[]" replaced with your own identifying
176621Sbt150084  * information: Portions Copyright [yyyy] [name of copyright owner]
186621Sbt150084  *
196621Sbt150084  * CDDL HEADER END
206621Sbt150084  */
216621Sbt150084 
226621Sbt150084 /*
2312280SChenlu.Chen@Sun.COM  * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
2412280SChenlu.Chen@Sun.COM  */
2512280SChenlu.Chen@Sun.COM 
2612280SChenlu.Chen@Sun.COM /*
2712280SChenlu.Chen@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
287656SSherry.Moore@Sun.COM  */
297656SSherry.Moore@Sun.COM 
306621Sbt150084 #include "ixgbe_sw.h"
316621Sbt150084 
3211486SZhen.W@Sun.COM static char ixgbe_ident[] = "Intel 10Gb Ethernet";
33*13006SChenlu.Chen@Sun.COM static char ixgbe_version[] = "ixgbe 1.1.7";
346621Sbt150084 
356621Sbt150084 /*
366621Sbt150084  * Local function protoypes
376621Sbt150084  */
386621Sbt150084 static int ixgbe_register_mac(ixgbe_t *);
396621Sbt150084 static int ixgbe_identify_hardware(ixgbe_t *);
406621Sbt150084 static int ixgbe_regs_map(ixgbe_t *);
416621Sbt150084 static void ixgbe_init_properties(ixgbe_t *);
426621Sbt150084 static int ixgbe_init_driver_settings(ixgbe_t *);
436621Sbt150084 static void ixgbe_init_locks(ixgbe_t *);
446621Sbt150084 static void ixgbe_destroy_locks(ixgbe_t *);
456621Sbt150084 static int ixgbe_init(ixgbe_t *);
466621Sbt150084 static int ixgbe_chip_start(ixgbe_t *);
476621Sbt150084 static void ixgbe_chip_stop(ixgbe_t *);
486621Sbt150084 static int ixgbe_reset(ixgbe_t *);
496621Sbt150084 static void ixgbe_tx_clean(ixgbe_t *);
506621Sbt150084 static boolean_t ixgbe_tx_drain(ixgbe_t *);
516621Sbt150084 static boolean_t ixgbe_rx_drain(ixgbe_t *);
526621Sbt150084 static int ixgbe_alloc_rings(ixgbe_t *);
536621Sbt150084 static void ixgbe_free_rings(ixgbe_t *);
5410376SChenlu.Chen@Sun.COM static int ixgbe_alloc_rx_data(ixgbe_t *);
5510376SChenlu.Chen@Sun.COM static void ixgbe_free_rx_data(ixgbe_t *);
566621Sbt150084 static void ixgbe_setup_rings(ixgbe_t *);
576621Sbt150084 static void ixgbe_setup_rx(ixgbe_t *);
586621Sbt150084 static void ixgbe_setup_tx(ixgbe_t *);
596621Sbt150084 static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *);
606621Sbt150084 static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *);
616621Sbt150084 static void ixgbe_setup_rss(ixgbe_t *);
6211878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq(ixgbe_t *);
6311878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq_rss(ixgbe_t *);
646621Sbt150084 static void ixgbe_init_unicst(ixgbe_t *);
658275SEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *);
666621Sbt150084 static void ixgbe_setup_multicst(ixgbe_t *);
676621Sbt150084 static void ixgbe_get_hw_state(ixgbe_t *);
6811878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe);
696621Sbt150084 static void ixgbe_get_conf(ixgbe_t *);
7010376SChenlu.Chen@Sun.COM static void ixgbe_init_params(ixgbe_t *);
716621Sbt150084 static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int);
7211233SPaul.Guo@Sun.COM static void ixgbe_driver_link_check(ixgbe_t *);
739353SSamuel.Tu@Sun.COM static void ixgbe_sfp_check(void *);
74*13006SChenlu.Chen@Sun.COM static void ixgbe_overtemp_check(void *);
7511233SPaul.Guo@Sun.COM static void ixgbe_link_timer(void *);
766621Sbt150084 static void ixgbe_local_timer(void *);
776621Sbt150084 static void ixgbe_arm_watchdog_timer(ixgbe_t *);
786621Sbt150084 static void ixgbe_restart_watchdog_timer(ixgbe_t *);
796621Sbt150084 static void ixgbe_disable_adapter_interrupts(ixgbe_t *);
806621Sbt150084 static void ixgbe_enable_adapter_interrupts(ixgbe_t *);
816621Sbt150084 static boolean_t is_valid_mac_addr(uint8_t *);
826621Sbt150084 static boolean_t ixgbe_stall_check(ixgbe_t *);
836621Sbt150084 static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t);
846621Sbt150084 static void ixgbe_set_internal_mac_loopback(ixgbe_t *);
856621Sbt150084 static boolean_t ixgbe_find_mac_address(ixgbe_t *);
866621Sbt150084 static int ixgbe_alloc_intrs(ixgbe_t *);
876621Sbt150084 static int ixgbe_alloc_intr_handles(ixgbe_t *, int);
886621Sbt150084 static int ixgbe_add_intr_handlers(ixgbe_t *);
896621Sbt150084 static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int);
906621Sbt150084 static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int);
919353SSamuel.Tu@Sun.COM static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t);
929353SSamuel.Tu@Sun.COM static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t);
939353SSamuel.Tu@Sun.COM static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t);
9411878SVenu.Iyer@Sun.COM static uint32_t ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index);
959353SSamuel.Tu@Sun.COM static int ixgbe_map_intrs_to_vectors(ixgbe_t *);
966621Sbt150084 static void ixgbe_setup_adapter_vector(ixgbe_t *);
976621Sbt150084 static void ixgbe_rem_intr_handlers(ixgbe_t *);
986621Sbt150084 static void ixgbe_rem_intrs(ixgbe_t *);
996621Sbt150084 static int ixgbe_enable_intrs(ixgbe_t *);
1006621Sbt150084 static int ixgbe_disable_intrs(ixgbe_t *);
1016621Sbt150084 static uint_t ixgbe_intr_legacy(void *, void *);
1026621Sbt150084 static uint_t ixgbe_intr_msi(void *, void *);
1039353SSamuel.Tu@Sun.COM static uint_t ixgbe_intr_msix(void *, void *);
1046621Sbt150084 static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *);
1056621Sbt150084 static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *);
1068490SPaul.Guo@Sun.COM static void ixgbe_intr_other_work(ixgbe_t *, uint32_t);
1076621Sbt150084 static void ixgbe_get_driver_control(struct ixgbe_hw *);
1088275SEric Cheng static int ixgbe_addmac(void *, const uint8_t *);
1098275SEric Cheng static int ixgbe_remmac(void *, const uint8_t *);
1106621Sbt150084 static void ixgbe_release_driver_control(struct ixgbe_hw *);
1116621Sbt150084 
1126621Sbt150084 static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t);
1136621Sbt150084 static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t);
1146621Sbt150084 static int ixgbe_resume(dev_info_t *);
1156621Sbt150084 static int ixgbe_suspend(dev_info_t *);
1166621Sbt150084 static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *);
1176621Sbt150084 static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *);
11811878SVenu.Iyer@Sun.COM static int ixgbe_cbfunc(dev_info_t *, ddi_cb_action_t, void *, void *, void *);
11911878SVenu.Iyer@Sun.COM static int ixgbe_intr_cb_register(ixgbe_t *);
12011878SVenu.Iyer@Sun.COM static int ixgbe_intr_adjust(ixgbe_t *, ddi_cb_action_t, int);
1216621Sbt150084 
1226621Sbt150084 static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
1236621Sbt150084     const void *impl_data);
1246621Sbt150084 static void ixgbe_fm_init(ixgbe_t *);
1256621Sbt150084 static void ixgbe_fm_fini(ixgbe_t *);
1266621Sbt150084 
12711878SVenu.Iyer@Sun.COM char *ixgbe_priv_props[] = {
12811878SVenu.Iyer@Sun.COM 	"_tx_copy_thresh",
12911878SVenu.Iyer@Sun.COM 	"_tx_recycle_thresh",
13011878SVenu.Iyer@Sun.COM 	"_tx_overload_thresh",
13111878SVenu.Iyer@Sun.COM 	"_tx_resched_thresh",
13211878SVenu.Iyer@Sun.COM 	"_rx_copy_thresh",
13311878SVenu.Iyer@Sun.COM 	"_rx_limit_per_intr",
13411878SVenu.Iyer@Sun.COM 	"_intr_throttling",
13511878SVenu.Iyer@Sun.COM 	"_adv_pause_cap",
13611878SVenu.Iyer@Sun.COM 	"_adv_asym_pause_cap",
13711878SVenu.Iyer@Sun.COM 	NULL
13810376SChenlu.Chen@Sun.COM };
13910376SChenlu.Chen@Sun.COM 
14010376SChenlu.Chen@Sun.COM #define	IXGBE_MAX_PRIV_PROPS \
14110376SChenlu.Chen@Sun.COM 	(sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t))
14210376SChenlu.Chen@Sun.COM 
1436621Sbt150084 static struct cb_ops ixgbe_cb_ops = {
1446621Sbt150084 	nulldev,		/* cb_open */
1456621Sbt150084 	nulldev,		/* cb_close */
1466621Sbt150084 	nodev,			/* cb_strategy */
1476621Sbt150084 	nodev,			/* cb_print */
1486621Sbt150084 	nodev,			/* cb_dump */
1496621Sbt150084 	nodev,			/* cb_read */
1506621Sbt150084 	nodev,			/* cb_write */
1516621Sbt150084 	nodev,			/* cb_ioctl */
1526621Sbt150084 	nodev,			/* cb_devmap */
1536621Sbt150084 	nodev,			/* cb_mmap */
1546621Sbt150084 	nodev,			/* cb_segmap */
1556621Sbt150084 	nochpoll,		/* cb_chpoll */
1566621Sbt150084 	ddi_prop_op,		/* cb_prop_op */
1576621Sbt150084 	NULL,			/* cb_stream */
1586621Sbt150084 	D_MP | D_HOTPLUG,	/* cb_flag */
1596621Sbt150084 	CB_REV,			/* cb_rev */
1606621Sbt150084 	nodev,			/* cb_aread */
1616621Sbt150084 	nodev			/* cb_awrite */
1626621Sbt150084 };
1636621Sbt150084 
1646621Sbt150084 static struct dev_ops ixgbe_dev_ops = {
1656621Sbt150084 	DEVO_REV,		/* devo_rev */
1666621Sbt150084 	0,			/* devo_refcnt */
1676621Sbt150084 	NULL,			/* devo_getinfo */
1686621Sbt150084 	nulldev,		/* devo_identify */
1696621Sbt150084 	nulldev,		/* devo_probe */
1706621Sbt150084 	ixgbe_attach,		/* devo_attach */
1716621Sbt150084 	ixgbe_detach,		/* devo_detach */
1726621Sbt150084 	nodev,			/* devo_reset */
1736621Sbt150084 	&ixgbe_cb_ops,		/* devo_cb_ops */
1746621Sbt150084 	NULL,			/* devo_bus_ops */
1757656SSherry.Moore@Sun.COM 	ddi_power,		/* devo_power */
1767656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
1776621Sbt150084 };
1786621Sbt150084 
1796621Sbt150084 static struct modldrv ixgbe_modldrv = {
1806621Sbt150084 	&mod_driverops,		/* Type of module.  This one is a driver */
18111486SZhen.W@Sun.COM 	ixgbe_ident,		/* Discription string */
1826621Sbt150084 	&ixgbe_dev_ops		/* driver ops */
1836621Sbt150084 };
1846621Sbt150084 
1856621Sbt150084 static struct modlinkage ixgbe_modlinkage = {
1866621Sbt150084 	MODREV_1, &ixgbe_modldrv, NULL
1876621Sbt150084 };
1886621Sbt150084 
1896621Sbt150084 /*
1906621Sbt150084  * Access attributes for register mapping
1916621Sbt150084  */
1926621Sbt150084 ddi_device_acc_attr_t ixgbe_regs_acc_attr = {
19311236SStephen.Hanson@Sun.COM 	DDI_DEVICE_ATTR_V1,
1946621Sbt150084 	DDI_STRUCTURE_LE_ACC,
1956621Sbt150084 	DDI_STRICTORDER_ACC,
1966621Sbt150084 	DDI_FLAGERR_ACC
1976621Sbt150084 };
1986621Sbt150084 
1996621Sbt150084 /*
2006621Sbt150084  * Loopback property
2016621Sbt150084  */
2026621Sbt150084 static lb_property_t lb_normal = {
2036621Sbt150084 	normal,	"normal", IXGBE_LB_NONE
2046621Sbt150084 };
2056621Sbt150084 
2066621Sbt150084 static lb_property_t lb_mac = {
2076621Sbt150084 	internal, "MAC", IXGBE_LB_INTERNAL_MAC
2086621Sbt150084 };
2096621Sbt150084 
21011150SZhen.W@Sun.COM static lb_property_t lb_external = {
21111150SZhen.W@Sun.COM 	external, "External", IXGBE_LB_EXTERNAL
21211150SZhen.W@Sun.COM };
21311150SZhen.W@Sun.COM 
21410376SChenlu.Chen@Sun.COM #define	IXGBE_M_CALLBACK_FLAGS \
21511878SVenu.Iyer@Sun.COM 	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
2166621Sbt150084 
2176621Sbt150084 static mac_callbacks_t ixgbe_m_callbacks = {
2186621Sbt150084 	IXGBE_M_CALLBACK_FLAGS,
2196621Sbt150084 	ixgbe_m_stat,
2206621Sbt150084 	ixgbe_m_start,
2216621Sbt150084 	ixgbe_m_stop,
2226621Sbt150084 	ixgbe_m_promisc,
2236621Sbt150084 	ixgbe_m_multicst,
2248275SEric Cheng 	NULL,
2256621Sbt150084 	NULL,
22611878SVenu.Iyer@Sun.COM 	NULL,
2276621Sbt150084 	ixgbe_m_ioctl,
22810376SChenlu.Chen@Sun.COM 	ixgbe_m_getcapab,
22910376SChenlu.Chen@Sun.COM 	NULL,
23010376SChenlu.Chen@Sun.COM 	NULL,
23110376SChenlu.Chen@Sun.COM 	ixgbe_m_setprop,
23211878SVenu.Iyer@Sun.COM 	ixgbe_m_getprop,
23311878SVenu.Iyer@Sun.COM 	ixgbe_m_propinfo
2346621Sbt150084 };
2356621Sbt150084 
2366621Sbt150084 /*
2378490SPaul.Guo@Sun.COM  * Initialize capabilities of each supported adapter type
2388490SPaul.Guo@Sun.COM  */
2398490SPaul.Guo@Sun.COM static adapter_info_t ixgbe_82598eb_cap = {
2408490SPaul.Guo@Sun.COM 	64,		/* maximum number of rx queues */
2418490SPaul.Guo@Sun.COM 	1,		/* minimum number of rx queues */
24211878SVenu.Iyer@Sun.COM 	64,		/* default number of rx queues */
24311878SVenu.Iyer@Sun.COM 	16,		/* maximum number of rx groups */
24411878SVenu.Iyer@Sun.COM 	1,		/* minimum number of rx groups */
24511878SVenu.Iyer@Sun.COM 	1,		/* default number of rx groups */
2468490SPaul.Guo@Sun.COM 	32,		/* maximum number of tx queues */
2478490SPaul.Guo@Sun.COM 	1,		/* minimum number of tx queues */
2488490SPaul.Guo@Sun.COM 	8,		/* default number of tx queues */
24911150SZhen.W@Sun.COM 	16366,		/* maximum MTU size */
25010376SChenlu.Chen@Sun.COM 	0xFFFF,		/* maximum interrupt throttle rate */
25110376SChenlu.Chen@Sun.COM 	0,		/* minimum interrupt throttle rate */
25210376SChenlu.Chen@Sun.COM 	200,		/* default interrupt throttle rate */
2538490SPaul.Guo@Sun.COM 	18,		/* maximum total msix vectors */
2548490SPaul.Guo@Sun.COM 	16,		/* maximum number of ring vectors */
2558490SPaul.Guo@Sun.COM 	2,		/* maximum number of other vectors */
2568490SPaul.Guo@Sun.COM 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
257*13006SChenlu.Chen@Sun.COM 	0,		/* "other" interrupt types enable mask */
2588490SPaul.Guo@Sun.COM 	(IXGBE_FLAG_DCA_CAPABLE	/* capability flags */
2598490SPaul.Guo@Sun.COM 	| IXGBE_FLAG_RSS_CAPABLE
2608490SPaul.Guo@Sun.COM 	| IXGBE_FLAG_VMDQ_CAPABLE)
2618490SPaul.Guo@Sun.COM };
2628490SPaul.Guo@Sun.COM 
2639353SSamuel.Tu@Sun.COM static adapter_info_t ixgbe_82599eb_cap = {
2649353SSamuel.Tu@Sun.COM 	128,		/* maximum number of rx queues */
2659353SSamuel.Tu@Sun.COM 	1,		/* minimum number of rx queues */
26611878SVenu.Iyer@Sun.COM 	128,		/* default number of rx queues */
26711878SVenu.Iyer@Sun.COM 	64,		/* maximum number of rx groups */
26811878SVenu.Iyer@Sun.COM 	1,		/* minimum number of rx groups */
26911878SVenu.Iyer@Sun.COM 	1,		/* default number of rx groups */
2709353SSamuel.Tu@Sun.COM 	128,		/* maximum number of tx queues */
2719353SSamuel.Tu@Sun.COM 	1,		/* minimum number of tx queues */
2729353SSamuel.Tu@Sun.COM 	8,		/* default number of tx queues */
27311150SZhen.W@Sun.COM 	15500,		/* maximum MTU size */
27410376SChenlu.Chen@Sun.COM 	0xFF8,		/* maximum interrupt throttle rate */
27510376SChenlu.Chen@Sun.COM 	0,		/* minimum interrupt throttle rate */
27610376SChenlu.Chen@Sun.COM 	200,		/* default interrupt throttle rate */
2779353SSamuel.Tu@Sun.COM 	64,		/* maximum total msix vectors */
2789353SSamuel.Tu@Sun.COM 	16,		/* maximum number of ring vectors */
2799353SSamuel.Tu@Sun.COM 	2,		/* maximum number of other vectors */
280*13006SChenlu.Chen@Sun.COM 	(IXGBE_EICR_LSC
281*13006SChenlu.Chen@Sun.COM 	| IXGBE_EICR_GPI_SDP1
282*13006SChenlu.Chen@Sun.COM 	| IXGBE_EICR_GPI_SDP2), /* "other" interrupt types handled */
283*13006SChenlu.Chen@Sun.COM 
284*13006SChenlu.Chen@Sun.COM 	(IXGBE_SDP1_GPIEN
285*13006SChenlu.Chen@Sun.COM 	| IXGBE_SDP2_GPIEN), /* "other" interrupt types enable mask */
286*13006SChenlu.Chen@Sun.COM 
287*13006SChenlu.Chen@Sun.COM 	(IXGBE_FLAG_DCA_CAPABLE
2889353SSamuel.Tu@Sun.COM 	| IXGBE_FLAG_RSS_CAPABLE
28911486SZhen.W@Sun.COM 	| IXGBE_FLAG_VMDQ_CAPABLE
290*13006SChenlu.Chen@Sun.COM 	| IXGBE_FLAG_RSC_CAPABLE
291*13006SChenlu.Chen@Sun.COM 	| IXGBE_FLAG_SFP_PLUG_CAPABLE) /* capability flags */
2929353SSamuel.Tu@Sun.COM };
2939353SSamuel.Tu@Sun.COM 
2948490SPaul.Guo@Sun.COM /*
2956621Sbt150084  * Module Initialization Functions.
2966621Sbt150084  */
2976621Sbt150084 
2986621Sbt150084 int
_init(void)2996621Sbt150084 _init(void)
3006621Sbt150084 {
3016621Sbt150084 	int status;
3026621Sbt150084 
3036621Sbt150084 	mac_init_ops(&ixgbe_dev_ops, MODULE_NAME);
3046621Sbt150084 
3056621Sbt150084 	status = mod_install(&ixgbe_modlinkage);
3066621Sbt150084 
3076621Sbt150084 	if (status != DDI_SUCCESS) {
3086621Sbt150084 		mac_fini_ops(&ixgbe_dev_ops);
3096621Sbt150084 	}
3106621Sbt150084 
3116621Sbt150084 	return (status);
3126621Sbt150084 }
3136621Sbt150084 
3146621Sbt150084 int
_fini(void)3156621Sbt150084 _fini(void)
3166621Sbt150084 {
3176621Sbt150084 	int status;
3186621Sbt150084 
3196621Sbt150084 	status = mod_remove(&ixgbe_modlinkage);
3206621Sbt150084 
3216621Sbt150084 	if (status == DDI_SUCCESS) {
3226621Sbt150084 		mac_fini_ops(&ixgbe_dev_ops);
3236621Sbt150084 	}
3246621Sbt150084 
3256621Sbt150084 	return (status);
3266621Sbt150084 }
3276621Sbt150084 
3286621Sbt150084 int
_info(struct modinfo * modinfop)3296621Sbt150084 _info(struct modinfo *modinfop)
3306621Sbt150084 {
3316621Sbt150084 	int status;
3326621Sbt150084 
3336621Sbt150084 	status = mod_info(&ixgbe_modlinkage, modinfop);
3346621Sbt150084 
3356621Sbt150084 	return (status);
3366621Sbt150084 }
3376621Sbt150084 
3386621Sbt150084 /*
3396621Sbt150084  * ixgbe_attach - Driver attach.
3406621Sbt150084  *
3416621Sbt150084  * This function is the device specific initialization entry
3426621Sbt150084  * point. This entry point is required and must be written.
3436621Sbt150084  * The DDI_ATTACH command must be provided in the attach entry
3446621Sbt150084  * point. When attach() is called with cmd set to DDI_ATTACH,
3456621Sbt150084  * all normal kernel services (such as kmem_alloc(9F)) are
3466621Sbt150084  * available for use by the driver.
3476621Sbt150084  *
3486621Sbt150084  * The attach() function will be called once for each instance
3496621Sbt150084  * of  the  device  on  the  system with cmd set to DDI_ATTACH.
3506621Sbt150084  * Until attach() succeeds, the only driver entry points which
3516621Sbt150084  * may be called are open(9E) and getinfo(9E).
3526621Sbt150084  */
3536621Sbt150084 static int
ixgbe_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)3546621Sbt150084 ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3556621Sbt150084 {
3566621Sbt150084 	ixgbe_t *ixgbe;
3576621Sbt150084 	struct ixgbe_osdep *osdep;
3586621Sbt150084 	struct ixgbe_hw *hw;
3596621Sbt150084 	int instance;
3608490SPaul.Guo@Sun.COM 	char taskqname[32];
3616621Sbt150084 
3626621Sbt150084 	/*
3636621Sbt150084 	 * Check the command and perform corresponding operations
3646621Sbt150084 	 */
3656621Sbt150084 	switch (cmd) {
3666621Sbt150084 	default:
3676621Sbt150084 		return (DDI_FAILURE);
3686621Sbt150084 
3696621Sbt150084 	case DDI_RESUME:
3706621Sbt150084 		return (ixgbe_resume(devinfo));
3716621Sbt150084 
3726621Sbt150084 	case DDI_ATTACH:
3736621Sbt150084 		break;
3746621Sbt150084 	}
3756621Sbt150084 
3766621Sbt150084 	/* Get the device instance */
3776621Sbt150084 	instance = ddi_get_instance(devinfo);
3786621Sbt150084 
3796621Sbt150084 	/* Allocate memory for the instance data structure */
3806621Sbt150084 	ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP);
3816621Sbt150084 
3826621Sbt150084 	ixgbe->dip = devinfo;
3836621Sbt150084 	ixgbe->instance = instance;
3846621Sbt150084 
3856621Sbt150084 	hw = &ixgbe->hw;
3866621Sbt150084 	osdep = &ixgbe->osdep;
3876621Sbt150084 	hw->back = osdep;
3886621Sbt150084 	osdep->ixgbe = ixgbe;
3896621Sbt150084 
3906621Sbt150084 	/* Attach the instance pointer to the dev_info data structure */
3916621Sbt150084 	ddi_set_driver_private(devinfo, ixgbe);
3926621Sbt150084 
3936621Sbt150084 	/*
3946621Sbt150084 	 * Initialize for fma support
3956621Sbt150084 	 */
3967167Sgg161487 	ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE,
3976621Sbt150084 	    0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
3986621Sbt150084 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
3996621Sbt150084 	ixgbe_fm_init(ixgbe);
4006621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT;
4016621Sbt150084 
4026621Sbt150084 	/*
4036621Sbt150084 	 * Map PCI config space registers
4046621Sbt150084 	 */
4056621Sbt150084 	if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
4066621Sbt150084 		ixgbe_error(ixgbe, "Failed to map PCI configurations");
4076621Sbt150084 		goto attach_fail;
4086621Sbt150084 	}
4096621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
4106621Sbt150084 
4116621Sbt150084 	/*
4126621Sbt150084 	 * Identify the chipset family
4136621Sbt150084 	 */
4146621Sbt150084 	if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) {
4156621Sbt150084 		ixgbe_error(ixgbe, "Failed to identify hardware");
4166621Sbt150084 		goto attach_fail;
4176621Sbt150084 	}
4186621Sbt150084 
4196621Sbt150084 	/*
4206621Sbt150084 	 * Map device registers
4216621Sbt150084 	 */
4226621Sbt150084 	if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) {
4236621Sbt150084 		ixgbe_error(ixgbe, "Failed to map device registers");
4246621Sbt150084 		goto attach_fail;
4256621Sbt150084 	}
4266621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP;
4276621Sbt150084 
4286621Sbt150084 	/*
4296621Sbt150084 	 * Initialize driver parameters
4306621Sbt150084 	 */
4316621Sbt150084 	ixgbe_init_properties(ixgbe);
4326621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS;
4336621Sbt150084 
4346621Sbt150084 	/*
43511878SVenu.Iyer@Sun.COM 	 * Register interrupt callback
43611878SVenu.Iyer@Sun.COM 	 */
43711878SVenu.Iyer@Sun.COM 	if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) {
43811878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe, "Failed to register interrupt callback");
43911878SVenu.Iyer@Sun.COM 		goto attach_fail;
44011878SVenu.Iyer@Sun.COM 	}
44111878SVenu.Iyer@Sun.COM 
44211878SVenu.Iyer@Sun.COM 	/*
4436621Sbt150084 	 * Allocate interrupts
4446621Sbt150084 	 */
4456621Sbt150084 	if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) {
4466621Sbt150084 		ixgbe_error(ixgbe, "Failed to allocate interrupts");
4476621Sbt150084 		goto attach_fail;
4486621Sbt150084 	}
4496621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
4506621Sbt150084 
4516621Sbt150084 	/*
4526621Sbt150084 	 * Allocate rx/tx rings based on the ring numbers.
4536621Sbt150084 	 * The actual numbers of rx/tx rings are decided by the number of
4546621Sbt150084 	 * allocated interrupt vectors, so we should allocate the rings after
4556621Sbt150084 	 * interrupts are allocated.
4566621Sbt150084 	 */
4576621Sbt150084 	if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) {
4586621Sbt150084 		ixgbe_error(ixgbe, "Failed to allocate rx and tx rings");
4596621Sbt150084 		goto attach_fail;
4606621Sbt150084 	}
4616621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS;
4626621Sbt150084 
4636621Sbt150084 	/*
4646621Sbt150084 	 * Map rings to interrupt vectors
4656621Sbt150084 	 */
4669353SSamuel.Tu@Sun.COM 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
4679353SSamuel.Tu@Sun.COM 		ixgbe_error(ixgbe, "Failed to map interrupts to vectors");
4686621Sbt150084 		goto attach_fail;
4696621Sbt150084 	}
4706621Sbt150084 
4716621Sbt150084 	/*
4726621Sbt150084 	 * Add interrupt handlers
4736621Sbt150084 	 */
4746621Sbt150084 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
4756621Sbt150084 		ixgbe_error(ixgbe, "Failed to add interrupt handlers");
4766621Sbt150084 		goto attach_fail;
4776621Sbt150084 	}
4786621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
4796621Sbt150084 
4806621Sbt150084 	/*
48111233SPaul.Guo@Sun.COM 	 * Create a taskq for sfp-change
4828490SPaul.Guo@Sun.COM 	 */
483*13006SChenlu.Chen@Sun.COM 	(void) sprintf(taskqname, "ixgbe%d_sfp_taskq", instance);
48411233SPaul.Guo@Sun.COM 	if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname,
4858490SPaul.Guo@Sun.COM 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
486*13006SChenlu.Chen@Sun.COM 		ixgbe_error(ixgbe, "sfp_taskq create failed");
4878490SPaul.Guo@Sun.COM 		goto attach_fail;
4888490SPaul.Guo@Sun.COM 	}
48911233SPaul.Guo@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ;
4908490SPaul.Guo@Sun.COM 
4918490SPaul.Guo@Sun.COM 	/*
492*13006SChenlu.Chen@Sun.COM 	 * Create a taskq for over-temp
493*13006SChenlu.Chen@Sun.COM 	 */
494*13006SChenlu.Chen@Sun.COM 	(void) sprintf(taskqname, "ixgbe%d_overtemp_taskq", instance);
495*13006SChenlu.Chen@Sun.COM 	if ((ixgbe->overtemp_taskq = ddi_taskq_create(devinfo, taskqname,
496*13006SChenlu.Chen@Sun.COM 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
497*13006SChenlu.Chen@Sun.COM 		ixgbe_error(ixgbe, "overtemp_taskq create failed");
498*13006SChenlu.Chen@Sun.COM 		goto attach_fail;
499*13006SChenlu.Chen@Sun.COM 	}
500*13006SChenlu.Chen@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_OVERTEMP_TASKQ;
501*13006SChenlu.Chen@Sun.COM 
502*13006SChenlu.Chen@Sun.COM 	/*
5036621Sbt150084 	 * Initialize driver parameters
5046621Sbt150084 	 */
5056621Sbt150084 	if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) {
5066621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize driver settings");
5076621Sbt150084 		goto attach_fail;
5086621Sbt150084 	}
5096621Sbt150084 
5106621Sbt150084 	/*
5116621Sbt150084 	 * Initialize mutexes for this device.
5126621Sbt150084 	 * Do this before enabling the interrupt handler and
5136621Sbt150084 	 * register the softint to avoid the condition where
5146621Sbt150084 	 * interrupt handler can try using uninitialized mutex.
5156621Sbt150084 	 */
5166621Sbt150084 	ixgbe_init_locks(ixgbe);
5176621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS;
5186621Sbt150084 
5196621Sbt150084 	/*
5206621Sbt150084 	 * Initialize chipset hardware
5216621Sbt150084 	 */
5226621Sbt150084 	if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) {
5236621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize adapter");
5246621Sbt150084 		goto attach_fail;
5256621Sbt150084 	}
52611233SPaul.Guo@Sun.COM 	ixgbe->link_check_complete = B_FALSE;
52711233SPaul.Guo@Sun.COM 	ixgbe->link_check_hrtime = gethrtime() +
52811233SPaul.Guo@Sun.COM 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
5296621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_INIT;
5306621Sbt150084 
5316621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) {
5326621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
5336621Sbt150084 		goto attach_fail;
5346621Sbt150084 	}
5356621Sbt150084 
5366621Sbt150084 	/*
5376621Sbt150084 	 * Initialize statistics
5386621Sbt150084 	 */
5396621Sbt150084 	if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) {
5406621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize statistics");
5416621Sbt150084 		goto attach_fail;
5426621Sbt150084 	}
5436621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_STATS;
5446621Sbt150084 
5456621Sbt150084 	/*
5466621Sbt150084 	 * Register the driver to the MAC
5476621Sbt150084 	 */
5486621Sbt150084 	if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) {
5496621Sbt150084 		ixgbe_error(ixgbe, "Failed to register MAC");
5506621Sbt150084 		goto attach_fail;
5516621Sbt150084 	}
5528490SPaul.Guo@Sun.COM 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
5536621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_MAC;
5546621Sbt150084 
55511233SPaul.Guo@Sun.COM 	ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe,
55611233SPaul.Guo@Sun.COM 	    IXGBE_CYCLIC_PERIOD, DDI_IPL_0);
55711233SPaul.Guo@Sun.COM 	if (ixgbe->periodic_id == 0) {
55811233SPaul.Guo@Sun.COM 		ixgbe_error(ixgbe, "Failed to add the link check timer");
55911233SPaul.Guo@Sun.COM 		goto attach_fail;
56011233SPaul.Guo@Sun.COM 	}
56111233SPaul.Guo@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER;
56211233SPaul.Guo@Sun.COM 
5636621Sbt150084 	/*
5646621Sbt150084 	 * Now that mutex locks are initialized, and the chip is also
5656621Sbt150084 	 * initialized, enable interrupts.
5666621Sbt150084 	 */
5676621Sbt150084 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
5686621Sbt150084 		ixgbe_error(ixgbe, "Failed to enable DDI interrupts");
5696621Sbt150084 		goto attach_fail;
5706621Sbt150084 	}
5716621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
5726621Sbt150084 
57311486SZhen.W@Sun.COM 	ixgbe_log(ixgbe, "%s, %s", ixgbe_ident, ixgbe_version);
57411233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED);
5756621Sbt150084 
5766621Sbt150084 	return (DDI_SUCCESS);
5776621Sbt150084 
5786621Sbt150084 attach_fail:
5796621Sbt150084 	ixgbe_unconfigure(devinfo, ixgbe);
5806621Sbt150084 	return (DDI_FAILURE);
5816621Sbt150084 }
5826621Sbt150084 
5836621Sbt150084 /*
5846621Sbt150084  * ixgbe_detach - Driver detach.
5856621Sbt150084  *
5866621Sbt150084  * The detach() function is the complement of the attach routine.
5876621Sbt150084  * If cmd is set to DDI_DETACH, detach() is used to remove  the
5886621Sbt150084  * state  associated  with  a  given  instance of a device node
5896621Sbt150084  * prior to the removal of that instance from the system.
5906621Sbt150084  *
5916621Sbt150084  * The detach() function will be called once for each  instance
5926621Sbt150084  * of the device for which there has been a successful attach()
5936621Sbt150084  * once there are no longer  any  opens  on  the  device.
5946621Sbt150084  *
5956621Sbt150084  * Interrupts routine are disabled, All memory allocated by this
5966621Sbt150084  * driver are freed.
5976621Sbt150084  */
5986621Sbt150084 static int
ixgbe_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)5996621Sbt150084 ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
6006621Sbt150084 {
6016621Sbt150084 	ixgbe_t *ixgbe;
6026621Sbt150084 
6036621Sbt150084 	/*
6046621Sbt150084 	 * Check detach command
6056621Sbt150084 	 */
6066621Sbt150084 	switch (cmd) {
6076621Sbt150084 	default:
6086621Sbt150084 		return (DDI_FAILURE);
6096621Sbt150084 
6106621Sbt150084 	case DDI_SUSPEND:
6116621Sbt150084 		return (ixgbe_suspend(devinfo));
6126621Sbt150084 
6136621Sbt150084 	case DDI_DETACH:
6146621Sbt150084 		break;
6156621Sbt150084 	}
6166621Sbt150084 
6176621Sbt150084 	/*
6186621Sbt150084 	 * Get the pointer to the driver private data structure
6196621Sbt150084 	 */
6206621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
6216621Sbt150084 	if (ixgbe == NULL)
6226621Sbt150084 		return (DDI_FAILURE);
6236621Sbt150084 
6246621Sbt150084 	/*
6256621Sbt150084 	 * If the device is still running, it needs to be stopped first.
6266621Sbt150084 	 * This check is necessary because under some specific circumstances,
6276621Sbt150084 	 * the detach routine can be called without stopping the interface
6286621Sbt150084 	 * first.
6296621Sbt150084 	 */
6306621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
63111233SPaul.Guo@Sun.COM 		atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
63211233SPaul.Guo@Sun.COM 		mutex_enter(&ixgbe->gen_lock);
63310376SChenlu.Chen@Sun.COM 		ixgbe_stop(ixgbe, B_TRUE);
6346621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
6356621Sbt150084 		/* Disable and stop the watchdog timer */
6366621Sbt150084 		ixgbe_disable_watchdog_timer(ixgbe);
63711233SPaul.Guo@Sun.COM 	}
6386621Sbt150084 
6396621Sbt150084 	/*
6406621Sbt150084 	 * Check if there are still rx buffers held by the upper layer.
6416621Sbt150084 	 * If so, fail the detach.
6426621Sbt150084 	 */
6436621Sbt150084 	if (!ixgbe_rx_drain(ixgbe))
6446621Sbt150084 		return (DDI_FAILURE);
6456621Sbt150084 
6466621Sbt150084 	/*
6476621Sbt150084 	 * Do the remaining unconfigure routines
6486621Sbt150084 	 */
6496621Sbt150084 	ixgbe_unconfigure(devinfo, ixgbe);
6506621Sbt150084 
6516621Sbt150084 	return (DDI_SUCCESS);
6526621Sbt150084 }
6536621Sbt150084 
6546621Sbt150084 static void
ixgbe_unconfigure(dev_info_t * devinfo,ixgbe_t * ixgbe)6556621Sbt150084 ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe)
6566621Sbt150084 {
6576621Sbt150084 	/*
6586621Sbt150084 	 * Disable interrupt
6596621Sbt150084 	 */
6606621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
6616621Sbt150084 		(void) ixgbe_disable_intrs(ixgbe);
6626621Sbt150084 	}
6636621Sbt150084 
6646621Sbt150084 	/*
66511233SPaul.Guo@Sun.COM 	 * remove the link check timer
66611233SPaul.Guo@Sun.COM 	 */
66711233SPaul.Guo@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) {
66811233SPaul.Guo@Sun.COM 		if (ixgbe->periodic_id != NULL) {
66911233SPaul.Guo@Sun.COM 			ddi_periodic_delete(ixgbe->periodic_id);
67011233SPaul.Guo@Sun.COM 			ixgbe->periodic_id = NULL;
67111233SPaul.Guo@Sun.COM 		}
67211233SPaul.Guo@Sun.COM 	}
67311233SPaul.Guo@Sun.COM 
67411233SPaul.Guo@Sun.COM 	/*
6756621Sbt150084 	 * Unregister MAC
6766621Sbt150084 	 */
6776621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) {
6786621Sbt150084 		(void) mac_unregister(ixgbe->mac_hdl);
6796621Sbt150084 	}
6806621Sbt150084 
6816621Sbt150084 	/*
6826621Sbt150084 	 * Free statistics
6836621Sbt150084 	 */
6846621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) {
6856621Sbt150084 		kstat_delete((kstat_t *)ixgbe->ixgbe_ks);
6866621Sbt150084 	}
6876621Sbt150084 
6886621Sbt150084 	/*
6896621Sbt150084 	 * Remove interrupt handlers
6906621Sbt150084 	 */
6916621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
6926621Sbt150084 		ixgbe_rem_intr_handlers(ixgbe);
6936621Sbt150084 	}
6946621Sbt150084 
6956621Sbt150084 	/*
69611233SPaul.Guo@Sun.COM 	 * Remove taskq for sfp-status-change
6978490SPaul.Guo@Sun.COM 	 */
69811233SPaul.Guo@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) {
69911233SPaul.Guo@Sun.COM 		ddi_taskq_destroy(ixgbe->sfp_taskq);
7008490SPaul.Guo@Sun.COM 	}
7018490SPaul.Guo@Sun.COM 
7028490SPaul.Guo@Sun.COM 	/*
703*13006SChenlu.Chen@Sun.COM 	 * Remove taskq for over-temp
704*13006SChenlu.Chen@Sun.COM 	 */
705*13006SChenlu.Chen@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_OVERTEMP_TASKQ) {
706*13006SChenlu.Chen@Sun.COM 		ddi_taskq_destroy(ixgbe->overtemp_taskq);
707*13006SChenlu.Chen@Sun.COM 	}
708*13006SChenlu.Chen@Sun.COM 
709*13006SChenlu.Chen@Sun.COM 	/*
7106621Sbt150084 	 * Remove interrupts
7116621Sbt150084 	 */
7126621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) {
7136621Sbt150084 		ixgbe_rem_intrs(ixgbe);
7146621Sbt150084 	}
7156621Sbt150084 
7166621Sbt150084 	/*
71711878SVenu.Iyer@Sun.COM 	 * Unregister interrupt callback handler
71811878SVenu.Iyer@Sun.COM 	 */
71911878SVenu.Iyer@Sun.COM 	(void) ddi_cb_unregister(ixgbe->cb_hdl);
72011878SVenu.Iyer@Sun.COM 
72111878SVenu.Iyer@Sun.COM 	/*
7226621Sbt150084 	 * Remove driver properties
7236621Sbt150084 	 */
7246621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) {
7256621Sbt150084 		(void) ddi_prop_remove_all(devinfo);
7266621Sbt150084 	}
7276621Sbt150084 
7286621Sbt150084 	/*
7296621Sbt150084 	 * Stop the chipset
7306621Sbt150084 	 */
7316621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) {
7326621Sbt150084 		mutex_enter(&ixgbe->gen_lock);
7336621Sbt150084 		ixgbe_chip_stop(ixgbe);
7346621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
7356621Sbt150084 	}
7366621Sbt150084 
7376621Sbt150084 	/*
7386621Sbt150084 	 * Free register handle
7396621Sbt150084 	 */
7406621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
7416621Sbt150084 		if (ixgbe->osdep.reg_handle != NULL)
7426621Sbt150084 			ddi_regs_map_free(&ixgbe->osdep.reg_handle);
7436621Sbt150084 	}
7446621Sbt150084 
7456621Sbt150084 	/*
7466621Sbt150084 	 * Free PCI config handle
7476621Sbt150084 	 */
7486621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) {
7496621Sbt150084 		if (ixgbe->osdep.cfg_handle != NULL)
7506621Sbt150084 			pci_config_teardown(&ixgbe->osdep.cfg_handle);
7516621Sbt150084 	}
7526621Sbt150084 
7536621Sbt150084 	/*
7546621Sbt150084 	 * Free locks
7556621Sbt150084 	 */
7566621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) {
7576621Sbt150084 		ixgbe_destroy_locks(ixgbe);
7586621Sbt150084 	}
7596621Sbt150084 
7606621Sbt150084 	/*
7616621Sbt150084 	 * Free the rx/tx rings
7626621Sbt150084 	 */
7636621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) {
7646621Sbt150084 		ixgbe_free_rings(ixgbe);
7656621Sbt150084 	}
7666621Sbt150084 
7676621Sbt150084 	/*
7686621Sbt150084 	 * Unregister FMA capabilities
7696621Sbt150084 	 */
7706621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) {
7716621Sbt150084 		ixgbe_fm_fini(ixgbe);
7726621Sbt150084 	}
7736621Sbt150084 
7746621Sbt150084 	/*
7756621Sbt150084 	 * Free the driver data structure
7766621Sbt150084 	 */
7776621Sbt150084 	kmem_free(ixgbe, sizeof (ixgbe_t));
7786621Sbt150084 
7796621Sbt150084 	ddi_set_driver_private(devinfo, NULL);
7806621Sbt150084 }
7816621Sbt150084 
7826621Sbt150084 /*
7836621Sbt150084  * ixgbe_register_mac - Register the driver and its function pointers with
7846621Sbt150084  * the GLD interface.
7856621Sbt150084  */
7866621Sbt150084 static int
ixgbe_register_mac(ixgbe_t * ixgbe)7876621Sbt150084 ixgbe_register_mac(ixgbe_t *ixgbe)
7886621Sbt150084 {
7896621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
7906621Sbt150084 	mac_register_t *mac;
7916621Sbt150084 	int status;
7926621Sbt150084 
7936621Sbt150084 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
7946621Sbt150084 		return (IXGBE_FAILURE);
7956621Sbt150084 
7966621Sbt150084 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
7976621Sbt150084 	mac->m_driver = ixgbe;
7986621Sbt150084 	mac->m_dip = ixgbe->dip;
7996621Sbt150084 	mac->m_src_addr = hw->mac.addr;
8006621Sbt150084 	mac->m_callbacks = &ixgbe_m_callbacks;
8016621Sbt150084 	mac->m_min_sdu = 0;
8026621Sbt150084 	mac->m_max_sdu = ixgbe->default_mtu;
8036621Sbt150084 	mac->m_margin = VLAN_TAGSZ;
80410376SChenlu.Chen@Sun.COM 	mac->m_priv_props = ixgbe_priv_props;
8058275SEric Cheng 	mac->m_v12n = MAC_VIRT_LEVEL1;
8066621Sbt150084 
8076621Sbt150084 	status = mac_register(mac, &ixgbe->mac_hdl);
8086621Sbt150084 
8096621Sbt150084 	mac_free(mac);
8106621Sbt150084 
8116621Sbt150084 	return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE);
8126621Sbt150084 }
8136621Sbt150084 
8146621Sbt150084 /*
8156621Sbt150084  * ixgbe_identify_hardware - Identify the type of the chipset.
8166621Sbt150084  */
8176621Sbt150084 static int
ixgbe_identify_hardware(ixgbe_t * ixgbe)8186621Sbt150084 ixgbe_identify_hardware(ixgbe_t *ixgbe)
8196621Sbt150084 {
8206621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
8216621Sbt150084 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
8226621Sbt150084 
8236621Sbt150084 	/*
8246621Sbt150084 	 * Get the device id
8256621Sbt150084 	 */
8266621Sbt150084 	hw->vendor_id =
8276621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
8286621Sbt150084 	hw->device_id =
8296621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
8306621Sbt150084 	hw->revision_id =
8316621Sbt150084 	    pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
8326621Sbt150084 	hw->subsystem_device_id =
8336621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
8346621Sbt150084 	hw->subsystem_vendor_id =
8356621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
8366621Sbt150084 
8378490SPaul.Guo@Sun.COM 	/*
8388490SPaul.Guo@Sun.COM 	 * Set the mac type of the adapter based on the device id
8398490SPaul.Guo@Sun.COM 	 */
8408490SPaul.Guo@Sun.COM 	if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) {
8418490SPaul.Guo@Sun.COM 		return (IXGBE_FAILURE);
8428490SPaul.Guo@Sun.COM 	}
8438490SPaul.Guo@Sun.COM 
8448490SPaul.Guo@Sun.COM 	/*
8458490SPaul.Guo@Sun.COM 	 * Install adapter capabilities
8468490SPaul.Guo@Sun.COM 	 */
8478490SPaul.Guo@Sun.COM 	switch (hw->mac.type) {
8488490SPaul.Guo@Sun.COM 	case ixgbe_mac_82598EB:
84912003SPaul.Guo@Sun.COM 		IXGBE_DEBUGLOG_0(ixgbe, "identify 82598 adapter\n");
8508490SPaul.Guo@Sun.COM 		ixgbe->capab = &ixgbe_82598eb_cap;
8518490SPaul.Guo@Sun.COM 
8528490SPaul.Guo@Sun.COM 		if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) {
8538490SPaul.Guo@Sun.COM 			ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
8548490SPaul.Guo@Sun.COM 			ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1;
855*13006SChenlu.Chen@Sun.COM 			ixgbe->capab->other_gpie |= IXGBE_SDP1_GPIEN;
8568490SPaul.Guo@Sun.COM 		}
8579353SSamuel.Tu@Sun.COM 		break;
858*13006SChenlu.Chen@Sun.COM 
8599353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
86012003SPaul.Guo@Sun.COM 		IXGBE_DEBUGLOG_0(ixgbe, "identify 82599 adapter\n");
8619353SSamuel.Tu@Sun.COM 		ixgbe->capab = &ixgbe_82599eb_cap;
8629353SSamuel.Tu@Sun.COM 
863*13006SChenlu.Chen@Sun.COM 		if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM) {
864*13006SChenlu.Chen@Sun.COM 			ixgbe->capab->flags |= IXGBE_FLAG_TEMP_SENSOR_CAPABLE;
865*13006SChenlu.Chen@Sun.COM 			ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP0;
866*13006SChenlu.Chen@Sun.COM 			ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN;
867*13006SChenlu.Chen@Sun.COM 		}
8688490SPaul.Guo@Sun.COM 		break;
869*13006SChenlu.Chen@Sun.COM 
8708490SPaul.Guo@Sun.COM 	default:
87112003SPaul.Guo@Sun.COM 		IXGBE_DEBUGLOG_1(ixgbe,
8728490SPaul.Guo@Sun.COM 		    "adapter not supported in ixgbe_identify_hardware(): %d\n",
8738490SPaul.Guo@Sun.COM 		    hw->mac.type);
8748490SPaul.Guo@Sun.COM 		return (IXGBE_FAILURE);
8758490SPaul.Guo@Sun.COM 	}
8768490SPaul.Guo@Sun.COM 
8776621Sbt150084 	return (IXGBE_SUCCESS);
8786621Sbt150084 }
8796621Sbt150084 
8806621Sbt150084 /*
8816621Sbt150084  * ixgbe_regs_map - Map the device registers.
8826621Sbt150084  *
8836621Sbt150084  */
8846621Sbt150084 static int
ixgbe_regs_map(ixgbe_t * ixgbe)8856621Sbt150084 ixgbe_regs_map(ixgbe_t *ixgbe)
8866621Sbt150084 {
8876621Sbt150084 	dev_info_t *devinfo = ixgbe->dip;
8886621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
8896621Sbt150084 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
8906621Sbt150084 	off_t mem_size;
8916621Sbt150084 
8926621Sbt150084 	/*
8936621Sbt150084 	 * First get the size of device registers to be mapped.
8946621Sbt150084 	 */
8959353SSamuel.Tu@Sun.COM 	if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size)
8969353SSamuel.Tu@Sun.COM 	    != DDI_SUCCESS) {
8976621Sbt150084 		return (IXGBE_FAILURE);
8986621Sbt150084 	}
8996621Sbt150084 
9006621Sbt150084 	/*
9016621Sbt150084 	 * Call ddi_regs_map_setup() to map registers
9026621Sbt150084 	 */
9039353SSamuel.Tu@Sun.COM 	if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET,
9046621Sbt150084 	    (caddr_t *)&hw->hw_addr, 0,
9056621Sbt150084 	    mem_size, &ixgbe_regs_acc_attr,
9066621Sbt150084 	    &osdep->reg_handle)) != DDI_SUCCESS) {
9076621Sbt150084 		return (IXGBE_FAILURE);
9086621Sbt150084 	}
9096621Sbt150084 
9106621Sbt150084 	return (IXGBE_SUCCESS);
9116621Sbt150084 }
9126621Sbt150084 
9136621Sbt150084 /*
9146621Sbt150084  * ixgbe_init_properties - Initialize driver properties.
9156621Sbt150084  */
9166621Sbt150084 static void
ixgbe_init_properties(ixgbe_t * ixgbe)9176621Sbt150084 ixgbe_init_properties(ixgbe_t *ixgbe)
9186621Sbt150084 {
9196621Sbt150084 	/*
9206621Sbt150084 	 * Get conf file properties, including link settings
9216621Sbt150084 	 * jumbo frames, ring number, descriptor number, etc.
9226621Sbt150084 	 */
9236621Sbt150084 	ixgbe_get_conf(ixgbe);
92410376SChenlu.Chen@Sun.COM 
92510376SChenlu.Chen@Sun.COM 	ixgbe_init_params(ixgbe);
9266621Sbt150084 }
9276621Sbt150084 
9286621Sbt150084 /*
9296621Sbt150084  * ixgbe_init_driver_settings - Initialize driver settings.
9306621Sbt150084  *
9316621Sbt150084  * The settings include hardware function pointers, bus information,
9326621Sbt150084  * rx/tx rings settings, link state, and any other parameters that
9336621Sbt150084  * need to be setup during driver initialization.
9346621Sbt150084  */
9356621Sbt150084 static int
ixgbe_init_driver_settings(ixgbe_t * ixgbe)9366621Sbt150084 ixgbe_init_driver_settings(ixgbe_t *ixgbe)
9376621Sbt150084 {
9386621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
9398275SEric Cheng 	dev_info_t *devinfo = ixgbe->dip;
9406621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
94111878SVenu.Iyer@Sun.COM 	ixgbe_rx_group_t *rx_group;
9426621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
9436621Sbt150084 	uint32_t rx_size;
9446621Sbt150084 	uint32_t tx_size;
94511878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
9466621Sbt150084 	int i;
9476621Sbt150084 
9486621Sbt150084 	/*
9496621Sbt150084 	 * Initialize chipset specific hardware function pointers
9506621Sbt150084 	 */
9516621Sbt150084 	if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) {
9526621Sbt150084 		return (IXGBE_FAILURE);
9536621Sbt150084 	}
9546621Sbt150084 
9556621Sbt150084 	/*
9568275SEric Cheng 	 * Get the system page size
9578275SEric Cheng 	 */
9588275SEric Cheng 	ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1);
9598275SEric Cheng 
9608275SEric Cheng 	/*
9616621Sbt150084 	 * Set rx buffer size
9626621Sbt150084 	 *
9636621Sbt150084 	 * The IP header alignment room is counted in the calculation.
9646621Sbt150084 	 * The rx buffer size is in unit of 1K that is required by the
9656621Sbt150084 	 * chipset hardware.
9666621Sbt150084 	 */
9676621Sbt150084 	rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
9686621Sbt150084 	ixgbe->rx_buf_size = ((rx_size >> 10) +
9696621Sbt150084 	    ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
9706621Sbt150084 
9716621Sbt150084 	/*
9726621Sbt150084 	 * Set tx buffer size
9736621Sbt150084 	 */
9746621Sbt150084 	tx_size = ixgbe->max_frame_size;
9756621Sbt150084 	ixgbe->tx_buf_size = ((tx_size >> 10) +
9766621Sbt150084 	    ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
9776621Sbt150084 
9786621Sbt150084 	/*
97911878SVenu.Iyer@Sun.COM 	 * Initialize rx/tx rings/groups parameters
98011878SVenu.Iyer@Sun.COM 	 */
98111878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
9826621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
9836621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
9846621Sbt150084 		rx_ring->index = i;
9856621Sbt150084 		rx_ring->ixgbe = ixgbe;
98611878SVenu.Iyer@Sun.COM 		rx_ring->group_index = i / ring_per_group;
98711878SVenu.Iyer@Sun.COM 		rx_ring->hw_index = ixgbe_get_hw_rx_index(ixgbe, i);
98811878SVenu.Iyer@Sun.COM 	}
98911878SVenu.Iyer@Sun.COM 
99011878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_rx_groups; i++) {
99111878SVenu.Iyer@Sun.COM 		rx_group = &ixgbe->rx_groups[i];
99211878SVenu.Iyer@Sun.COM 		rx_group->index = i;
99311878SVenu.Iyer@Sun.COM 		rx_group->ixgbe = ixgbe;
9946621Sbt150084 	}
9956621Sbt150084 
9966621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
9976621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
9986621Sbt150084 		tx_ring->index = i;
9996621Sbt150084 		tx_ring->ixgbe = ixgbe;
10006621Sbt150084 		if (ixgbe->tx_head_wb_enable)
10016621Sbt150084 			tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb;
10026621Sbt150084 		else
10036621Sbt150084 			tx_ring->tx_recycle = ixgbe_tx_recycle_legacy;
10046621Sbt150084 
10056621Sbt150084 		tx_ring->ring_size = ixgbe->tx_ring_size;
10066621Sbt150084 		tx_ring->free_list_size = ixgbe->tx_ring_size +
10076621Sbt150084 		    (ixgbe->tx_ring_size >> 1);
10086621Sbt150084 	}
10096621Sbt150084 
10106621Sbt150084 	/*
10116621Sbt150084 	 * Initialize values of interrupt throttling rate
10126621Sbt150084 	 */
10139353SSamuel.Tu@Sun.COM 	for (i = 1; i < MAX_INTR_VECTOR; i++)
10146621Sbt150084 		ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0];
10156621Sbt150084 
10166621Sbt150084 	/*
10176621Sbt150084 	 * The initial link state should be "unknown"
10186621Sbt150084 	 */
10196621Sbt150084 	ixgbe->link_state = LINK_STATE_UNKNOWN;
10209353SSamuel.Tu@Sun.COM 
10216621Sbt150084 	return (IXGBE_SUCCESS);
10226621Sbt150084 }
10236621Sbt150084 
10246621Sbt150084 /*
10256621Sbt150084  * ixgbe_init_locks - Initialize locks.
10266621Sbt150084  */
10276621Sbt150084 static void
ixgbe_init_locks(ixgbe_t * ixgbe)10286621Sbt150084 ixgbe_init_locks(ixgbe_t *ixgbe)
10296621Sbt150084 {
10306621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
10316621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
10326621Sbt150084 	int i;
10336621Sbt150084 
10346621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
10356621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
10366621Sbt150084 		mutex_init(&rx_ring->rx_lock, NULL,
10376621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10386621Sbt150084 	}
10396621Sbt150084 
10406621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
10416621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
10426621Sbt150084 		mutex_init(&tx_ring->tx_lock, NULL,
10436621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10446621Sbt150084 		mutex_init(&tx_ring->recycle_lock, NULL,
10456621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10466621Sbt150084 		mutex_init(&tx_ring->tcb_head_lock, NULL,
10476621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10486621Sbt150084 		mutex_init(&tx_ring->tcb_tail_lock, NULL,
10496621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10506621Sbt150084 	}
10516621Sbt150084 
10526621Sbt150084 	mutex_init(&ixgbe->gen_lock, NULL,
10536621Sbt150084 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10546621Sbt150084 
10556621Sbt150084 	mutex_init(&ixgbe->watchdog_lock, NULL,
10566621Sbt150084 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10576621Sbt150084 }
10586621Sbt150084 
10596621Sbt150084 /*
10606621Sbt150084  * ixgbe_destroy_locks - Destroy locks.
10616621Sbt150084  */
10626621Sbt150084 static void
ixgbe_destroy_locks(ixgbe_t * ixgbe)10636621Sbt150084 ixgbe_destroy_locks(ixgbe_t *ixgbe)
10646621Sbt150084 {
10656621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
10666621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
10676621Sbt150084 	int i;
10686621Sbt150084 
10696621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
10706621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
10716621Sbt150084 		mutex_destroy(&rx_ring->rx_lock);
10726621Sbt150084 	}
10736621Sbt150084 
10746621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
10756621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
10766621Sbt150084 		mutex_destroy(&tx_ring->tx_lock);
10776621Sbt150084 		mutex_destroy(&tx_ring->recycle_lock);
10786621Sbt150084 		mutex_destroy(&tx_ring->tcb_head_lock);
10796621Sbt150084 		mutex_destroy(&tx_ring->tcb_tail_lock);
10806621Sbt150084 	}
10816621Sbt150084 
10826621Sbt150084 	mutex_destroy(&ixgbe->gen_lock);
10836621Sbt150084 	mutex_destroy(&ixgbe->watchdog_lock);
10846621Sbt150084 }
10856621Sbt150084 
10866621Sbt150084 static int
ixgbe_resume(dev_info_t * devinfo)10876621Sbt150084 ixgbe_resume(dev_info_t *devinfo)
10886621Sbt150084 {
10896621Sbt150084 	ixgbe_t *ixgbe;
109011233SPaul.Guo@Sun.COM 	int i;
10916621Sbt150084 
10926621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
10936621Sbt150084 	if (ixgbe == NULL)
10946621Sbt150084 		return (DDI_FAILURE);
10956621Sbt150084 
10966621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
10976621Sbt150084 
10986621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
109910376SChenlu.Chen@Sun.COM 		if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
11006621Sbt150084 			mutex_exit(&ixgbe->gen_lock);
11016621Sbt150084 			return (DDI_FAILURE);
11026621Sbt150084 		}
11036621Sbt150084 
11046621Sbt150084 		/*
11056621Sbt150084 		 * Enable and start the watchdog timer
11066621Sbt150084 		 */
11076621Sbt150084 		ixgbe_enable_watchdog_timer(ixgbe);
11086621Sbt150084 	}
11096621Sbt150084 
111011233SPaul.Guo@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED);
111111233SPaul.Guo@Sun.COM 
111211233SPaul.Guo@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
111311233SPaul.Guo@Sun.COM 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
111411233SPaul.Guo@Sun.COM 			mac_tx_ring_update(ixgbe->mac_hdl,
111511233SPaul.Guo@Sun.COM 			    ixgbe->tx_rings[i].ring_handle);
111611233SPaul.Guo@Sun.COM 		}
111711233SPaul.Guo@Sun.COM 	}
11186621Sbt150084 
11196621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
11206621Sbt150084 
11216621Sbt150084 	return (DDI_SUCCESS);
11226621Sbt150084 }
11236621Sbt150084 
11246621Sbt150084 static int
ixgbe_suspend(dev_info_t * devinfo)11256621Sbt150084 ixgbe_suspend(dev_info_t *devinfo)
11266621Sbt150084 {
11276621Sbt150084 	ixgbe_t *ixgbe;
11286621Sbt150084 
11296621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
11306621Sbt150084 	if (ixgbe == NULL)
11316621Sbt150084 		return (DDI_FAILURE);
11326621Sbt150084 
11336621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
11346621Sbt150084 
113511233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED);
113610376SChenlu.Chen@Sun.COM 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
113710376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
113810376SChenlu.Chen@Sun.COM 		return (DDI_SUCCESS);
113910376SChenlu.Chen@Sun.COM 	}
114010376SChenlu.Chen@Sun.COM 	ixgbe_stop(ixgbe, B_FALSE);
11416621Sbt150084 
11426621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
11436621Sbt150084 
11446621Sbt150084 	/*
11456621Sbt150084 	 * Disable and stop the watchdog timer
11466621Sbt150084 	 */
11476621Sbt150084 	ixgbe_disable_watchdog_timer(ixgbe);
11486621Sbt150084 
11496621Sbt150084 	return (DDI_SUCCESS);
11506621Sbt150084 }
11516621Sbt150084 
11526621Sbt150084 /*
11536621Sbt150084  * ixgbe_init - Initialize the device.
11546621Sbt150084  */
11556621Sbt150084 static int
ixgbe_init(ixgbe_t * ixgbe)11566621Sbt150084 ixgbe_init(ixgbe_t *ixgbe)
11576621Sbt150084 {
11586621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
11596621Sbt150084 
11606621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
11616621Sbt150084 
11626621Sbt150084 	/*
11636621Sbt150084 	 * Reset chipset to put the hardware in a known state
11646621Sbt150084 	 * before we try to do anything with the eeprom.
11656621Sbt150084 	 */
11666621Sbt150084 	if (ixgbe_reset_hw(hw) != IXGBE_SUCCESS) {
11676621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11686621Sbt150084 		goto init_fail;
11696621Sbt150084 	}
11706621Sbt150084 
11716621Sbt150084 	/*
11726621Sbt150084 	 * Need to init eeprom before validating the checksum.
11736621Sbt150084 	 */
11746621Sbt150084 	if (ixgbe_init_eeprom_params(hw) < 0) {
11756621Sbt150084 		ixgbe_error(ixgbe,
11766621Sbt150084 		    "Unable to intitialize the eeprom interface.");
11776621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11786621Sbt150084 		goto init_fail;
11796621Sbt150084 	}
11806621Sbt150084 
11816621Sbt150084 	/*
11826621Sbt150084 	 * NVM validation
11836621Sbt150084 	 */
11846621Sbt150084 	if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
11856621Sbt150084 		/*
11866621Sbt150084 		 * Some PCI-E parts fail the first check due to
11876621Sbt150084 		 * the link being in sleep state.  Call it again,
11886621Sbt150084 		 * if it fails a second time it's a real issue.
11896621Sbt150084 		 */
11906621Sbt150084 		if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
11916621Sbt150084 			ixgbe_error(ixgbe,
11926621Sbt150084 			    "Invalid NVM checksum. Please contact "
11936621Sbt150084 			    "the vendor to update the NVM.");
11946621Sbt150084 			ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11956621Sbt150084 			goto init_fail;
11966621Sbt150084 		}
11976621Sbt150084 	}
11986621Sbt150084 
11996621Sbt150084 	/*
12006621Sbt150084 	 * Setup default flow control thresholds - enable/disable
12016621Sbt150084 	 * & flow control type is controlled by ixgbe.conf
12026621Sbt150084 	 */
12036621Sbt150084 	hw->fc.high_water = DEFAULT_FCRTH;
12046621Sbt150084 	hw->fc.low_water = DEFAULT_FCRTL;
12056621Sbt150084 	hw->fc.pause_time = DEFAULT_FCPAUSE;
12066621Sbt150084 	hw->fc.send_xon = B_TRUE;
12076621Sbt150084 
12086621Sbt150084 	/*
12096621Sbt150084 	 * Initialize link settings
12106621Sbt150084 	 */
12116621Sbt150084 	(void) ixgbe_driver_setup_link(ixgbe, B_FALSE);
12126621Sbt150084 
12136621Sbt150084 	/*
12146621Sbt150084 	 * Initialize the chipset hardware
12156621Sbt150084 	 */
12166621Sbt150084 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
12176621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
12186621Sbt150084 		goto init_fail;
12196621Sbt150084 	}
12206621Sbt150084 
12216621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
12226621Sbt150084 		goto init_fail;
12236621Sbt150084 	}
12246621Sbt150084 
12256621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
12266621Sbt150084 	return (IXGBE_SUCCESS);
12276621Sbt150084 
12286621Sbt150084 init_fail:
12296621Sbt150084 	/*
12306621Sbt150084 	 * Reset PHY
12316621Sbt150084 	 */
12326621Sbt150084 	(void) ixgbe_reset_phy(hw);
12336621Sbt150084 
12346621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
12356621Sbt150084 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
12366621Sbt150084 	return (IXGBE_FAILURE);
12376621Sbt150084 }
12386621Sbt150084 
12396621Sbt150084 /*
12406621Sbt150084  * ixgbe_chip_start - Initialize and start the chipset hardware.
12416621Sbt150084  */
12426621Sbt150084 static int
ixgbe_chip_start(ixgbe_t * ixgbe)12436621Sbt150084 ixgbe_chip_start(ixgbe_t *ixgbe)
12446621Sbt150084 {
12456621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
124610305SPaul.Guo@Sun.COM 	int ret_val, i;
12476621Sbt150084 
12486621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
12496621Sbt150084 
12506621Sbt150084 	/*
12516621Sbt150084 	 * Get the mac address
12526621Sbt150084 	 * This function should handle SPARC case correctly.
12536621Sbt150084 	 */
12546621Sbt150084 	if (!ixgbe_find_mac_address(ixgbe)) {
12556621Sbt150084 		ixgbe_error(ixgbe, "Failed to get the mac address");
12566621Sbt150084 		return (IXGBE_FAILURE);
12576621Sbt150084 	}
12586621Sbt150084 
12596621Sbt150084 	/*
12606621Sbt150084 	 * Validate the mac address
12616621Sbt150084 	 */
12626621Sbt150084 	(void) ixgbe_init_rx_addrs(hw);
12636621Sbt150084 	if (!is_valid_mac_addr(hw->mac.addr)) {
12646621Sbt150084 		ixgbe_error(ixgbe, "Invalid mac address");
12656621Sbt150084 		return (IXGBE_FAILURE);
12666621Sbt150084 	}
12676621Sbt150084 
12686621Sbt150084 	/*
12696621Sbt150084 	 * Configure/Initialize hardware
12706621Sbt150084 	 */
127110305SPaul.Guo@Sun.COM 	ret_val = ixgbe_init_hw(hw);
127210305SPaul.Guo@Sun.COM 	if (ret_val != IXGBE_SUCCESS) {
127310305SPaul.Guo@Sun.COM 		if (ret_val == IXGBE_ERR_EEPROM_VERSION) {
127410305SPaul.Guo@Sun.COM 			ixgbe_error(ixgbe,
127510305SPaul.Guo@Sun.COM 			    "This 82599 device is pre-release and contains"
127610305SPaul.Guo@Sun.COM 			    " outdated firmware, please contact your hardware"
127710305SPaul.Guo@Sun.COM 			    " vendor for a replacement.");
127810305SPaul.Guo@Sun.COM 		} else {
127910305SPaul.Guo@Sun.COM 			ixgbe_error(ixgbe, "Failed to initialize hardware");
128010305SPaul.Guo@Sun.COM 			return (IXGBE_FAILURE);
128110305SPaul.Guo@Sun.COM 		}
12826621Sbt150084 	}
12836621Sbt150084 
12846621Sbt150084 	/*
128512003SPaul.Guo@Sun.COM 	 * Re-enable relaxed ordering for performance.  It is disabled
128612003SPaul.Guo@Sun.COM 	 * by default in the hardware init.
128712003SPaul.Guo@Sun.COM 	 */
1288*13006SChenlu.Chen@Sun.COM 	if (ixgbe->relax_order_enable == B_TRUE)
1289*13006SChenlu.Chen@Sun.COM 		ixgbe_enable_relaxed_ordering(hw);
129012003SPaul.Guo@Sun.COM 
129112003SPaul.Guo@Sun.COM 	/*
12926621Sbt150084 	 * Setup adapter interrupt vectors
12936621Sbt150084 	 */
12946621Sbt150084 	ixgbe_setup_adapter_vector(ixgbe);
12956621Sbt150084 
12966621Sbt150084 	/*
12976621Sbt150084 	 * Initialize unicast addresses.
12986621Sbt150084 	 */
12996621Sbt150084 	ixgbe_init_unicst(ixgbe);
13006621Sbt150084 
13016621Sbt150084 	/*
13026621Sbt150084 	 * Setup and initialize the mctable structures.
13036621Sbt150084 	 */
13046621Sbt150084 	ixgbe_setup_multicst(ixgbe);
13056621Sbt150084 
13066621Sbt150084 	/*
13076621Sbt150084 	 * Set interrupt throttling rate
13086621Sbt150084 	 */
13099353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->intr_cnt; i++) {
13106621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]);
13119353SSamuel.Tu@Sun.COM 	}
13126621Sbt150084 
13136621Sbt150084 	/*
13146621Sbt150084 	 * Save the state of the phy
13156621Sbt150084 	 */
13166621Sbt150084 	ixgbe_get_hw_state(ixgbe);
13176621Sbt150084 
13186621Sbt150084 	/*
13196621Sbt150084 	 * Make sure driver has control
13206621Sbt150084 	 */
13216621Sbt150084 	ixgbe_get_driver_control(hw);
13226621Sbt150084 
13236621Sbt150084 	return (IXGBE_SUCCESS);
13246621Sbt150084 }
13256621Sbt150084 
13266621Sbt150084 /*
13276621Sbt150084  * ixgbe_chip_stop - Stop the chipset hardware
13286621Sbt150084  */
13296621Sbt150084 static void
ixgbe_chip_stop(ixgbe_t * ixgbe)13306621Sbt150084 ixgbe_chip_stop(ixgbe_t *ixgbe)
13316621Sbt150084 {
13326621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
13336621Sbt150084 
13346621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
13356621Sbt150084 
13366621Sbt150084 	/*
13376621Sbt150084 	 * Tell firmware driver is no longer in control
13386621Sbt150084 	 */
13396621Sbt150084 	ixgbe_release_driver_control(hw);
13406621Sbt150084 
13416621Sbt150084 	/*
13426621Sbt150084 	 * Reset the chipset
13436621Sbt150084 	 */
13446621Sbt150084 	(void) ixgbe_reset_hw(hw);
13456621Sbt150084 
13466621Sbt150084 	/*
13476621Sbt150084 	 * Reset PHY
13486621Sbt150084 	 */
13496621Sbt150084 	(void) ixgbe_reset_phy(hw);
13506621Sbt150084 }
13516621Sbt150084 
13526621Sbt150084 /*
13536621Sbt150084  * ixgbe_reset - Reset the chipset and re-start the driver.
13546621Sbt150084  *
13556621Sbt150084  * It involves stopping and re-starting the chipset,
13566621Sbt150084  * and re-configuring the rx/tx rings.
13576621Sbt150084  */
13586621Sbt150084 static int
ixgbe_reset(ixgbe_t * ixgbe)13596621Sbt150084 ixgbe_reset(ixgbe_t *ixgbe)
13606621Sbt150084 {
136111233SPaul.Guo@Sun.COM 	int i;
136211233SPaul.Guo@Sun.COM 
136310376SChenlu.Chen@Sun.COM 	/*
136410376SChenlu.Chen@Sun.COM 	 * Disable and stop the watchdog timer
136510376SChenlu.Chen@Sun.COM 	 */
136610376SChenlu.Chen@Sun.COM 	ixgbe_disable_watchdog_timer(ixgbe);
13676621Sbt150084 
13686621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
13696621Sbt150084 
13706621Sbt150084 	ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED);
137111233SPaul.Guo@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
13726621Sbt150084 
137310376SChenlu.Chen@Sun.COM 	ixgbe_stop(ixgbe, B_FALSE);
137410376SChenlu.Chen@Sun.COM 
137510376SChenlu.Chen@Sun.COM 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
137610376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
137710376SChenlu.Chen@Sun.COM 		return (IXGBE_FAILURE);
13786621Sbt150084 	}
13796621Sbt150084 
138011233SPaul.Guo@Sun.COM 	/*
138111233SPaul.Guo@Sun.COM 	 * After resetting, need to recheck the link status.
138211233SPaul.Guo@Sun.COM 	 */
138311233SPaul.Guo@Sun.COM 	ixgbe->link_check_complete = B_FALSE;
138411233SPaul.Guo@Sun.COM 	ixgbe->link_check_hrtime = gethrtime() +
138511233SPaul.Guo@Sun.COM 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
138611233SPaul.Guo@Sun.COM 
138711233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED);
138811233SPaul.Guo@Sun.COM 
138911233SPaul.Guo@Sun.COM 	if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) {
139011233SPaul.Guo@Sun.COM 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
139111233SPaul.Guo@Sun.COM 			mac_tx_ring_update(ixgbe->mac_hdl,
139211233SPaul.Guo@Sun.COM 			    ixgbe->tx_rings[i].ring_handle);
139311233SPaul.Guo@Sun.COM 		}
139411233SPaul.Guo@Sun.COM 	}
139511233SPaul.Guo@Sun.COM 
13966621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
13976621Sbt150084 
139810376SChenlu.Chen@Sun.COM 	/*
139910376SChenlu.Chen@Sun.COM 	 * Enable and start the watchdog timer
140010376SChenlu.Chen@Sun.COM 	 */
140110376SChenlu.Chen@Sun.COM 	ixgbe_enable_watchdog_timer(ixgbe);
140210376SChenlu.Chen@Sun.COM 
14036621Sbt150084 	return (IXGBE_SUCCESS);
14046621Sbt150084 }
14056621Sbt150084 
14066621Sbt150084 /*
14076621Sbt150084  * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources.
14086621Sbt150084  */
14096621Sbt150084 static void
ixgbe_tx_clean(ixgbe_t * ixgbe)14106621Sbt150084 ixgbe_tx_clean(ixgbe_t *ixgbe)
14116621Sbt150084 {
14126621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
14136621Sbt150084 	tx_control_block_t *tcb;
14146621Sbt150084 	link_list_t pending_list;
14156621Sbt150084 	uint32_t desc_num;
14166621Sbt150084 	int i, j;
14176621Sbt150084 
14186621Sbt150084 	LINK_LIST_INIT(&pending_list);
14196621Sbt150084 
14206621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
14216621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
14226621Sbt150084 
14236621Sbt150084 		mutex_enter(&tx_ring->recycle_lock);
14246621Sbt150084 
14256621Sbt150084 		/*
14266621Sbt150084 		 * Clean the pending tx data - the pending packets in the
14276621Sbt150084 		 * work_list that have no chances to be transmitted again.
14286621Sbt150084 		 *
14296621Sbt150084 		 * We must ensure the chipset is stopped or the link is down
14306621Sbt150084 		 * before cleaning the transmit packets.
14316621Sbt150084 		 */
14326621Sbt150084 		desc_num = 0;
14336621Sbt150084 		for (j = 0; j < tx_ring->ring_size; j++) {
14346621Sbt150084 			tcb = tx_ring->work_list[j];
14356621Sbt150084 			if (tcb != NULL) {
14366621Sbt150084 				desc_num += tcb->desc_num;
14376621Sbt150084 
14386621Sbt150084 				tx_ring->work_list[j] = NULL;
14396621Sbt150084 
14406621Sbt150084 				ixgbe_free_tcb(tcb);
14416621Sbt150084 
14426621Sbt150084 				LIST_PUSH_TAIL(&pending_list, &tcb->link);
14436621Sbt150084 			}
14446621Sbt150084 		}
14456621Sbt150084 
14466621Sbt150084 		if (desc_num > 0) {
14476621Sbt150084 			atomic_add_32(&tx_ring->tbd_free, desc_num);
14486621Sbt150084 			ASSERT(tx_ring->tbd_free == tx_ring->ring_size);
14496621Sbt150084 
14506621Sbt150084 			/*
14516621Sbt150084 			 * Reset the head and tail pointers of the tbd ring;
14526621Sbt150084 			 * Reset the writeback head if it's enable.
14536621Sbt150084 			 */
14546621Sbt150084 			tx_ring->tbd_head = 0;
14556621Sbt150084 			tx_ring->tbd_tail = 0;
14566621Sbt150084 			if (ixgbe->tx_head_wb_enable)
14576621Sbt150084 				*tx_ring->tbd_head_wb = 0;
14586621Sbt150084 
14596621Sbt150084 			IXGBE_WRITE_REG(&ixgbe->hw,
14606621Sbt150084 			    IXGBE_TDH(tx_ring->index), 0);
14616621Sbt150084 			IXGBE_WRITE_REG(&ixgbe->hw,
14626621Sbt150084 			    IXGBE_TDT(tx_ring->index), 0);
14636621Sbt150084 		}
14646621Sbt150084 
14656621Sbt150084 		mutex_exit(&tx_ring->recycle_lock);
14666621Sbt150084 
14676621Sbt150084 		/*
14686621Sbt150084 		 * Add the tx control blocks in the pending list to
14696621Sbt150084 		 * the free list.
14706621Sbt150084 		 */
14716621Sbt150084 		ixgbe_put_free_list(tx_ring, &pending_list);
14726621Sbt150084 	}
14736621Sbt150084 }
14746621Sbt150084 
14756621Sbt150084 /*
14766621Sbt150084  * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be
14776621Sbt150084  * transmitted.
14786621Sbt150084  */
14796621Sbt150084 static boolean_t
ixgbe_tx_drain(ixgbe_t * ixgbe)14806621Sbt150084 ixgbe_tx_drain(ixgbe_t *ixgbe)
14816621Sbt150084 {
14826621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
14836621Sbt150084 	boolean_t done;
14846621Sbt150084 	int i, j;
14856621Sbt150084 
14866621Sbt150084 	/*
14876621Sbt150084 	 * Wait for a specific time to allow pending tx packets
14886621Sbt150084 	 * to be transmitted.
14896621Sbt150084 	 *
14906621Sbt150084 	 * Check the counter tbd_free to see if transmission is done.
14916621Sbt150084 	 * No lock protection is needed here.
14926621Sbt150084 	 *
14936621Sbt150084 	 * Return B_TRUE if all pending packets have been transmitted;
14946621Sbt150084 	 * Otherwise return B_FALSE;
14956621Sbt150084 	 */
14966621Sbt150084 	for (i = 0; i < TX_DRAIN_TIME; i++) {
14976621Sbt150084 
14986621Sbt150084 		done = B_TRUE;
14996621Sbt150084 		for (j = 0; j < ixgbe->num_tx_rings; j++) {
15006621Sbt150084 			tx_ring = &ixgbe->tx_rings[j];
15016621Sbt150084 			done = done &&
15026621Sbt150084 			    (tx_ring->tbd_free == tx_ring->ring_size);
15036621Sbt150084 		}
15046621Sbt150084 
15056621Sbt150084 		if (done)
15066621Sbt150084 			break;
15076621Sbt150084 
15086621Sbt150084 		msec_delay(1);
15096621Sbt150084 	}
15106621Sbt150084 
15116621Sbt150084 	return (done);
15126621Sbt150084 }
15136621Sbt150084 
15146621Sbt150084 /*
15156621Sbt150084  * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer.
15166621Sbt150084  */
15176621Sbt150084 static boolean_t
ixgbe_rx_drain(ixgbe_t * ixgbe)15186621Sbt150084 ixgbe_rx_drain(ixgbe_t *ixgbe)
15196621Sbt150084 {
152010376SChenlu.Chen@Sun.COM 	boolean_t done = B_TRUE;
152110376SChenlu.Chen@Sun.COM 	int i;
15226621Sbt150084 
15236621Sbt150084 	/*
15246621Sbt150084 	 * Polling the rx free list to check if those rx buffers held by
15256621Sbt150084 	 * the upper layer are released.
15266621Sbt150084 	 *
15276621Sbt150084 	 * Check the counter rcb_free to see if all pending buffers are
15286621Sbt150084 	 * released. No lock protection is needed here.
15296621Sbt150084 	 *
15306621Sbt150084 	 * Return B_TRUE if all pending buffers have been released;
15316621Sbt150084 	 * Otherwise return B_FALSE;
15326621Sbt150084 	 */
15336621Sbt150084 	for (i = 0; i < RX_DRAIN_TIME; i++) {
153410376SChenlu.Chen@Sun.COM 		done = (ixgbe->rcb_pending == 0);
15356621Sbt150084 
15366621Sbt150084 		if (done)
15376621Sbt150084 			break;
15386621Sbt150084 
15396621Sbt150084 		msec_delay(1);
15406621Sbt150084 	}
15416621Sbt150084 
15426621Sbt150084 	return (done);
15436621Sbt150084 }
15446621Sbt150084 
15456621Sbt150084 /*
15466621Sbt150084  * ixgbe_start - Start the driver/chipset.
15476621Sbt150084  */
15486621Sbt150084 int
ixgbe_start(ixgbe_t * ixgbe,boolean_t alloc_buffer)154910376SChenlu.Chen@Sun.COM ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer)
15506621Sbt150084 {
15516621Sbt150084 	int i;
15526621Sbt150084 
15536621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
15546621Sbt150084 
155510376SChenlu.Chen@Sun.COM 	if (alloc_buffer) {
155610376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) {
155710376SChenlu.Chen@Sun.COM 			ixgbe_error(ixgbe,
155810376SChenlu.Chen@Sun.COM 			    "Failed to allocate software receive rings");
155910376SChenlu.Chen@Sun.COM 			return (IXGBE_FAILURE);
156010376SChenlu.Chen@Sun.COM 		}
156110376SChenlu.Chen@Sun.COM 
156210376SChenlu.Chen@Sun.COM 		/* Allocate buffers for all the rx/tx rings */
156310376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) {
156410376SChenlu.Chen@Sun.COM 			ixgbe_error(ixgbe, "Failed to allocate DMA resource");
156510376SChenlu.Chen@Sun.COM 			return (IXGBE_FAILURE);
156610376SChenlu.Chen@Sun.COM 		}
156710376SChenlu.Chen@Sun.COM 
156810376SChenlu.Chen@Sun.COM 		ixgbe->tx_ring_init = B_TRUE;
156910376SChenlu.Chen@Sun.COM 	} else {
157010376SChenlu.Chen@Sun.COM 		ixgbe->tx_ring_init = B_FALSE;
157110376SChenlu.Chen@Sun.COM 	}
157210376SChenlu.Chen@Sun.COM 
15736621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++)
15746621Sbt150084 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
15756621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++)
15766621Sbt150084 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
15776621Sbt150084 
15786621Sbt150084 	/*
15796621Sbt150084 	 * Start the chipset hardware
15806621Sbt150084 	 */
15816621Sbt150084 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
15826621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
15836621Sbt150084 		goto start_failure;
15846621Sbt150084 	}
15856621Sbt150084 
15866621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
15876621Sbt150084 		goto start_failure;
15886621Sbt150084 	}
15896621Sbt150084 
15906621Sbt150084 	/*
15916621Sbt150084 	 * Setup the rx/tx rings
15926621Sbt150084 	 */
15936621Sbt150084 	ixgbe_setup_rings(ixgbe);
15946621Sbt150084 
15956621Sbt150084 	/*
159611233SPaul.Guo@Sun.COM 	 * ixgbe_start() will be called when resetting, however if reset
1597*13006SChenlu.Chen@Sun.COM 	 * happens, we need to clear the ERROR, STALL and OVERTEMP flags
1598*13006SChenlu.Chen@Sun.COM 	 * before enabling the interrupts.
1599*13006SChenlu.Chen@Sun.COM 	 */
1600*13006SChenlu.Chen@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR
1601*13006SChenlu.Chen@Sun.COM 	    | IXGBE_STALL| IXGBE_OVERTEMP));
160211233SPaul.Guo@Sun.COM 
160311233SPaul.Guo@Sun.COM 	/*
16046621Sbt150084 	 * Enable adapter interrupts
16056621Sbt150084 	 * The interrupts must be enabled after the driver state is START
16066621Sbt150084 	 */
16076621Sbt150084 	ixgbe_enable_adapter_interrupts(ixgbe);
16086621Sbt150084 
16096621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
16106621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
16116621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
16126621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
16136621Sbt150084 
16146621Sbt150084 	return (IXGBE_SUCCESS);
16156621Sbt150084 
16166621Sbt150084 start_failure:
16176621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
16186621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
16196621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
16206621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
16216621Sbt150084 
16226621Sbt150084 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
16236621Sbt150084 
16246621Sbt150084 	return (IXGBE_FAILURE);
16256621Sbt150084 }
16266621Sbt150084 
16276621Sbt150084 /*
16286621Sbt150084  * ixgbe_stop - Stop the driver/chipset.
16296621Sbt150084  */
16306621Sbt150084 void
ixgbe_stop(ixgbe_t * ixgbe,boolean_t free_buffer)163110376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer)
16326621Sbt150084 {
16336621Sbt150084 	int i;
16346621Sbt150084 
16356621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
16366621Sbt150084 
16376621Sbt150084 	/*
16386621Sbt150084 	 * Disable the adapter interrupts
16396621Sbt150084 	 */
16406621Sbt150084 	ixgbe_disable_adapter_interrupts(ixgbe);
16416621Sbt150084 
16426621Sbt150084 	/*
16436621Sbt150084 	 * Drain the pending tx packets
16446621Sbt150084 	 */
16456621Sbt150084 	(void) ixgbe_tx_drain(ixgbe);
16466621Sbt150084 
16476621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++)
16486621Sbt150084 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
16496621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++)
16506621Sbt150084 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
16516621Sbt150084 
16526621Sbt150084 	/*
16536621Sbt150084 	 * Stop the chipset hardware
16546621Sbt150084 	 */
16556621Sbt150084 	ixgbe_chip_stop(ixgbe);
16566621Sbt150084 
16576621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
16586621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
16596621Sbt150084 	}
16606621Sbt150084 
16616621Sbt150084 	/*
16626621Sbt150084 	 * Clean the pending tx data/resources
16636621Sbt150084 	 */
16646621Sbt150084 	ixgbe_tx_clean(ixgbe);
16656621Sbt150084 
16666621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
16676621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
16686621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
16696621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
167010376SChenlu.Chen@Sun.COM 
167110376SChenlu.Chen@Sun.COM 	if (ixgbe->link_state == LINK_STATE_UP) {
167210376SChenlu.Chen@Sun.COM 		ixgbe->link_state = LINK_STATE_UNKNOWN;
167310376SChenlu.Chen@Sun.COM 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
167410376SChenlu.Chen@Sun.COM 	}
167510376SChenlu.Chen@Sun.COM 
167610376SChenlu.Chen@Sun.COM 	if (free_buffer) {
167710376SChenlu.Chen@Sun.COM 		/*
167810376SChenlu.Chen@Sun.COM 		 * Release the DMA/memory resources of rx/tx rings
167910376SChenlu.Chen@Sun.COM 		 */
168010376SChenlu.Chen@Sun.COM 		ixgbe_free_dma(ixgbe);
168110376SChenlu.Chen@Sun.COM 		ixgbe_free_rx_data(ixgbe);
168210376SChenlu.Chen@Sun.COM 	}
16836621Sbt150084 }
16846621Sbt150084 
16856621Sbt150084 /*
168611878SVenu.Iyer@Sun.COM  * ixgbe_cbfunc - Driver interface for generic DDI callbacks
168711878SVenu.Iyer@Sun.COM  */
168811878SVenu.Iyer@Sun.COM /* ARGSUSED */
168911878SVenu.Iyer@Sun.COM static int
ixgbe_cbfunc(dev_info_t * dip,ddi_cb_action_t cbaction,void * cbarg,void * arg1,void * arg2)169011878SVenu.Iyer@Sun.COM ixgbe_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
169111878SVenu.Iyer@Sun.COM     void *arg1, void *arg2)
169211878SVenu.Iyer@Sun.COM {
169311878SVenu.Iyer@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
169411878SVenu.Iyer@Sun.COM 
169511878SVenu.Iyer@Sun.COM 	switch (cbaction) {
169611878SVenu.Iyer@Sun.COM 	/* IRM callback */
169711878SVenu.Iyer@Sun.COM 	int count;
169811878SVenu.Iyer@Sun.COM 	case DDI_CB_INTR_ADD:
169911878SVenu.Iyer@Sun.COM 	case DDI_CB_INTR_REMOVE:
170011878SVenu.Iyer@Sun.COM 		count = (int)(uintptr_t)cbarg;
170111878SVenu.Iyer@Sun.COM 		ASSERT(ixgbe->intr_type == DDI_INTR_TYPE_MSIX);
170211878SVenu.Iyer@Sun.COM 		DTRACE_PROBE2(ixgbe__irm__callback, int, count,
170311878SVenu.Iyer@Sun.COM 		    int, ixgbe->intr_cnt);
170411878SVenu.Iyer@Sun.COM 		if (ixgbe_intr_adjust(ixgbe, cbaction, count) !=
170511878SVenu.Iyer@Sun.COM 		    DDI_SUCCESS) {
170611878SVenu.Iyer@Sun.COM 			ixgbe_error(ixgbe,
170711878SVenu.Iyer@Sun.COM 			    "IRM CB: Failed to adjust interrupts");
170811878SVenu.Iyer@Sun.COM 			goto cb_fail;
170911878SVenu.Iyer@Sun.COM 		}
171011878SVenu.Iyer@Sun.COM 		break;
171111878SVenu.Iyer@Sun.COM 	default:
171211878SVenu.Iyer@Sun.COM 		IXGBE_DEBUGLOG_1(ixgbe, "DDI CB: action 0x%x NOT supported",
171311878SVenu.Iyer@Sun.COM 		    cbaction);
171411878SVenu.Iyer@Sun.COM 		return (DDI_ENOTSUP);
171511878SVenu.Iyer@Sun.COM 	}
171611878SVenu.Iyer@Sun.COM 	return (DDI_SUCCESS);
171711878SVenu.Iyer@Sun.COM cb_fail:
171811878SVenu.Iyer@Sun.COM 	return (DDI_FAILURE);
171911878SVenu.Iyer@Sun.COM }
172011878SVenu.Iyer@Sun.COM 
172111878SVenu.Iyer@Sun.COM /*
172211878SVenu.Iyer@Sun.COM  * ixgbe_intr_adjust - Adjust interrupt to respond to IRM request.
172311878SVenu.Iyer@Sun.COM  */
172411878SVenu.Iyer@Sun.COM static int
ixgbe_intr_adjust(ixgbe_t * ixgbe,ddi_cb_action_t cbaction,int count)172511878SVenu.Iyer@Sun.COM ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count)
172611878SVenu.Iyer@Sun.COM {
172711878SVenu.Iyer@Sun.COM 	int i, rc, actual;
172811878SVenu.Iyer@Sun.COM 
172911878SVenu.Iyer@Sun.COM 	if (count == 0)
173011878SVenu.Iyer@Sun.COM 		return (DDI_SUCCESS);
173111878SVenu.Iyer@Sun.COM 
173211878SVenu.Iyer@Sun.COM 	if ((cbaction == DDI_CB_INTR_ADD &&
173311878SVenu.Iyer@Sun.COM 	    ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) ||
173411878SVenu.Iyer@Sun.COM 	    (cbaction == DDI_CB_INTR_REMOVE &&
173511878SVenu.Iyer@Sun.COM 	    ixgbe->intr_cnt - count < ixgbe->intr_cnt_min))
173611878SVenu.Iyer@Sun.COM 		return (DDI_FAILURE);
173711878SVenu.Iyer@Sun.COM 
173811878SVenu.Iyer@Sun.COM 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
173911878SVenu.Iyer@Sun.COM 		return (DDI_FAILURE);
174011878SVenu.Iyer@Sun.COM 	}
174111878SVenu.Iyer@Sun.COM 
174211878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++)
174311878SVenu.Iyer@Sun.COM 		mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL);
174411878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++)
174511878SVenu.Iyer@Sun.COM 		mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL);
174611878SVenu.Iyer@Sun.COM 
174711878SVenu.Iyer@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
174811878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state &= ~IXGBE_STARTED;
174911878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST;
175011878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state |= IXGBE_SUSPENDED;
175111878SVenu.Iyer@Sun.COM 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
175211878SVenu.Iyer@Sun.COM 
175311878SVenu.Iyer@Sun.COM 	ixgbe_stop(ixgbe, B_FALSE);
175411878SVenu.Iyer@Sun.COM 	/*
175511878SVenu.Iyer@Sun.COM 	 * Disable interrupts
175611878SVenu.Iyer@Sun.COM 	 */
175711878SVenu.Iyer@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
175811878SVenu.Iyer@Sun.COM 		rc = ixgbe_disable_intrs(ixgbe);
175911878SVenu.Iyer@Sun.COM 		ASSERT(rc == IXGBE_SUCCESS);
176011878SVenu.Iyer@Sun.COM 	}
176111878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress &= ~ATTACH_PROGRESS_ENABLE_INTR;
176211878SVenu.Iyer@Sun.COM 
176311878SVenu.Iyer@Sun.COM 	/*
176411878SVenu.Iyer@Sun.COM 	 * Remove interrupt handlers
176511878SVenu.Iyer@Sun.COM 	 */
176611878SVenu.Iyer@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
176711878SVenu.Iyer@Sun.COM 		ixgbe_rem_intr_handlers(ixgbe);
176811878SVenu.Iyer@Sun.COM 	}
176911878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress &= ~ATTACH_PROGRESS_ADD_INTR;
177011878SVenu.Iyer@Sun.COM 
177111878SVenu.Iyer@Sun.COM 	/*
177211878SVenu.Iyer@Sun.COM 	 * Clear vect_map
177311878SVenu.Iyer@Sun.COM 	 */
177411878SVenu.Iyer@Sun.COM 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
177511878SVenu.Iyer@Sun.COM 	switch (cbaction) {
177611878SVenu.Iyer@Sun.COM 	case DDI_CB_INTR_ADD:
177711878SVenu.Iyer@Sun.COM 		rc = ddi_intr_alloc(ixgbe->dip, ixgbe->htable,
177811878SVenu.Iyer@Sun.COM 		    DDI_INTR_TYPE_MSIX, ixgbe->intr_cnt, count, &actual,
177911878SVenu.Iyer@Sun.COM 		    DDI_INTR_ALLOC_NORMAL);
178011878SVenu.Iyer@Sun.COM 		if (rc != DDI_SUCCESS || actual != count) {
178111878SVenu.Iyer@Sun.COM 			ixgbe_log(ixgbe, "Adjust interrupts failed."
178211878SVenu.Iyer@Sun.COM 			    "return: %d, irm cb size: %d, actual: %d",
178311878SVenu.Iyer@Sun.COM 			    rc, count, actual);
178411878SVenu.Iyer@Sun.COM 			goto intr_adjust_fail;
178511878SVenu.Iyer@Sun.COM 		}
178611878SVenu.Iyer@Sun.COM 		ixgbe->intr_cnt += count;
178711878SVenu.Iyer@Sun.COM 		break;
178811878SVenu.Iyer@Sun.COM 
178911878SVenu.Iyer@Sun.COM 	case DDI_CB_INTR_REMOVE:
179011878SVenu.Iyer@Sun.COM 		for (i = ixgbe->intr_cnt - count;
179111878SVenu.Iyer@Sun.COM 		    i < ixgbe->intr_cnt; i ++) {
179211878SVenu.Iyer@Sun.COM 			rc = ddi_intr_free(ixgbe->htable[i]);
179311878SVenu.Iyer@Sun.COM 			ixgbe->htable[i] = NULL;
179411878SVenu.Iyer@Sun.COM 			if (rc != DDI_SUCCESS) {
179511878SVenu.Iyer@Sun.COM 				ixgbe_log(ixgbe, "Adjust interrupts failed."
179611878SVenu.Iyer@Sun.COM 				    "return: %d, irm cb size: %d, actual: %d",
179711878SVenu.Iyer@Sun.COM 				    rc, count, actual);
179811878SVenu.Iyer@Sun.COM 				goto intr_adjust_fail;
179911878SVenu.Iyer@Sun.COM 			}
180011878SVenu.Iyer@Sun.COM 		}
180111878SVenu.Iyer@Sun.COM 		ixgbe->intr_cnt -= count;
180211878SVenu.Iyer@Sun.COM 		break;
180311878SVenu.Iyer@Sun.COM 	}
180411878SVenu.Iyer@Sun.COM 
180511878SVenu.Iyer@Sun.COM 	/*
180611878SVenu.Iyer@Sun.COM 	 * Get priority for first vector, assume remaining are all the same
180711878SVenu.Iyer@Sun.COM 	 */
180811878SVenu.Iyer@Sun.COM 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
180911878SVenu.Iyer@Sun.COM 	if (rc != DDI_SUCCESS) {
181011878SVenu.Iyer@Sun.COM 		ixgbe_log(ixgbe,
181111878SVenu.Iyer@Sun.COM 		    "Get interrupt priority failed: %d", rc);
181211878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
181311878SVenu.Iyer@Sun.COM 	}
181411878SVenu.Iyer@Sun.COM 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
181511878SVenu.Iyer@Sun.COM 	if (rc != DDI_SUCCESS) {
181611878SVenu.Iyer@Sun.COM 		ixgbe_log(ixgbe, "Get interrupt cap failed: %d", rc);
181711878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
181811878SVenu.Iyer@Sun.COM 	}
181911878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
182011878SVenu.Iyer@Sun.COM 
182111878SVenu.Iyer@Sun.COM 	/*
182211878SVenu.Iyer@Sun.COM 	 * Map rings to interrupt vectors
182311878SVenu.Iyer@Sun.COM 	 */
182411878SVenu.Iyer@Sun.COM 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
182511878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe,
182611878SVenu.Iyer@Sun.COM 		    "IRM CB: Failed to map interrupts to vectors");
182711878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
182811878SVenu.Iyer@Sun.COM 	}
182911878SVenu.Iyer@Sun.COM 
183011878SVenu.Iyer@Sun.COM 	/*
183111878SVenu.Iyer@Sun.COM 	 * Add interrupt handlers
183211878SVenu.Iyer@Sun.COM 	 */
183311878SVenu.Iyer@Sun.COM 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
183411878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe, "IRM CB: Failed to add interrupt handlers");
183511878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
183611878SVenu.Iyer@Sun.COM 	}
183711878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
183811878SVenu.Iyer@Sun.COM 
183911878SVenu.Iyer@Sun.COM 	/*
184011878SVenu.Iyer@Sun.COM 	 * Now that mutex locks are initialized, and the chip is also
184111878SVenu.Iyer@Sun.COM 	 * initialized, enable interrupts.
184211878SVenu.Iyer@Sun.COM 	 */
184311878SVenu.Iyer@Sun.COM 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
184411878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts");
184511878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
184611878SVenu.Iyer@Sun.COM 	}
184711878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
184811878SVenu.Iyer@Sun.COM 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
184911878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe, "IRM CB: Failed to start");
185011878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
185111878SVenu.Iyer@Sun.COM 	}
185211878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST;
185311878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED;
185411878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state |= IXGBE_STARTED;
185511878SVenu.Iyer@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
185611878SVenu.Iyer@Sun.COM 
185711878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
185811878SVenu.Iyer@Sun.COM 		mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle,
185911878SVenu.Iyer@Sun.COM 		    ixgbe->htable[ixgbe->rx_rings[i].intr_vector]);
186011878SVenu.Iyer@Sun.COM 	}
186111878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
186211878SVenu.Iyer@Sun.COM 		mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle,
186311878SVenu.Iyer@Sun.COM 		    ixgbe->htable[ixgbe->tx_rings[i].intr_vector]);
186411878SVenu.Iyer@Sun.COM 	}
186511878SVenu.Iyer@Sun.COM 
186611878SVenu.Iyer@Sun.COM 	/* Wakeup all Tx rings */
186711878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
186811878SVenu.Iyer@Sun.COM 		mac_tx_ring_update(ixgbe->mac_hdl,
186911878SVenu.Iyer@Sun.COM 		    ixgbe->tx_rings[i].ring_handle);
187011878SVenu.Iyer@Sun.COM 	}
187111878SVenu.Iyer@Sun.COM 
187211878SVenu.Iyer@Sun.COM 	IXGBE_DEBUGLOG_3(ixgbe,
187311878SVenu.Iyer@Sun.COM 	    "IRM CB: interrupts new value: 0x%x(0x%x:0x%x).",
187411878SVenu.Iyer@Sun.COM 	    ixgbe->intr_cnt, ixgbe->intr_cnt_min, ixgbe->intr_cnt_max);
187511878SVenu.Iyer@Sun.COM 	return (DDI_SUCCESS);
187611878SVenu.Iyer@Sun.COM 
187711878SVenu.Iyer@Sun.COM intr_adjust_fail:
187811878SVenu.Iyer@Sun.COM 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
187911878SVenu.Iyer@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
188011878SVenu.Iyer@Sun.COM 	return (DDI_FAILURE);
188111878SVenu.Iyer@Sun.COM }
188211878SVenu.Iyer@Sun.COM 
188311878SVenu.Iyer@Sun.COM /*
188411878SVenu.Iyer@Sun.COM  * ixgbe_intr_cb_register - Register interrupt callback function.
188511878SVenu.Iyer@Sun.COM  */
188611878SVenu.Iyer@Sun.COM static int
ixgbe_intr_cb_register(ixgbe_t * ixgbe)188711878SVenu.Iyer@Sun.COM ixgbe_intr_cb_register(ixgbe_t *ixgbe)
188811878SVenu.Iyer@Sun.COM {
188911878SVenu.Iyer@Sun.COM 	if (ddi_cb_register(ixgbe->dip, DDI_CB_FLAG_INTR, ixgbe_cbfunc,
189011878SVenu.Iyer@Sun.COM 	    ixgbe, NULL, &ixgbe->cb_hdl) != DDI_SUCCESS) {
189111878SVenu.Iyer@Sun.COM 		return (IXGBE_FAILURE);
189211878SVenu.Iyer@Sun.COM 	}
189311878SVenu.Iyer@Sun.COM 	IXGBE_DEBUGLOG_0(ixgbe, "Interrupt callback function registered.");
189411878SVenu.Iyer@Sun.COM 	return (IXGBE_SUCCESS);
189511878SVenu.Iyer@Sun.COM }
189611878SVenu.Iyer@Sun.COM 
189711878SVenu.Iyer@Sun.COM /*
18986621Sbt150084  * ixgbe_alloc_rings - Allocate memory space for rx/tx rings.
18996621Sbt150084  */
19006621Sbt150084 static int
ixgbe_alloc_rings(ixgbe_t * ixgbe)19016621Sbt150084 ixgbe_alloc_rings(ixgbe_t *ixgbe)
19026621Sbt150084 {
19036621Sbt150084 	/*
19046621Sbt150084 	 * Allocate memory space for rx rings
19056621Sbt150084 	 */
19066621Sbt150084 	ixgbe->rx_rings = kmem_zalloc(
19076621Sbt150084 	    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings,
19086621Sbt150084 	    KM_NOSLEEP);
19096621Sbt150084 
19106621Sbt150084 	if (ixgbe->rx_rings == NULL) {
19116621Sbt150084 		return (IXGBE_FAILURE);
19126621Sbt150084 	}
19136621Sbt150084 
19146621Sbt150084 	/*
19156621Sbt150084 	 * Allocate memory space for tx rings
19166621Sbt150084 	 */
19176621Sbt150084 	ixgbe->tx_rings = kmem_zalloc(
19186621Sbt150084 	    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings,
19196621Sbt150084 	    KM_NOSLEEP);
19206621Sbt150084 
19216621Sbt150084 	if (ixgbe->tx_rings == NULL) {
19226621Sbt150084 		kmem_free(ixgbe->rx_rings,
19236621Sbt150084 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
19246621Sbt150084 		ixgbe->rx_rings = NULL;
19256621Sbt150084 		return (IXGBE_FAILURE);
19266621Sbt150084 	}
19276621Sbt150084 
19288275SEric Cheng 	/*
19298275SEric Cheng 	 * Allocate memory space for rx ring groups
19308275SEric Cheng 	 */
19318275SEric Cheng 	ixgbe->rx_groups = kmem_zalloc(
19328275SEric Cheng 	    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups,
19338275SEric Cheng 	    KM_NOSLEEP);
19348275SEric Cheng 
19358275SEric Cheng 	if (ixgbe->rx_groups == NULL) {
19368275SEric Cheng 		kmem_free(ixgbe->rx_rings,
19378275SEric Cheng 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
19388275SEric Cheng 		kmem_free(ixgbe->tx_rings,
19398275SEric Cheng 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
19408275SEric Cheng 		ixgbe->rx_rings = NULL;
19418275SEric Cheng 		ixgbe->tx_rings = NULL;
19428275SEric Cheng 		return (IXGBE_FAILURE);
19438275SEric Cheng 	}
19448275SEric Cheng 
19456621Sbt150084 	return (IXGBE_SUCCESS);
19466621Sbt150084 }
19476621Sbt150084 
19486621Sbt150084 /*
19496621Sbt150084  * ixgbe_free_rings - Free the memory space of rx/tx rings.
19506621Sbt150084  */
19516621Sbt150084 static void
ixgbe_free_rings(ixgbe_t * ixgbe)19526621Sbt150084 ixgbe_free_rings(ixgbe_t *ixgbe)
19536621Sbt150084 {
19546621Sbt150084 	if (ixgbe->rx_rings != NULL) {
19556621Sbt150084 		kmem_free(ixgbe->rx_rings,
19566621Sbt150084 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
19576621Sbt150084 		ixgbe->rx_rings = NULL;
19586621Sbt150084 	}
19596621Sbt150084 
19606621Sbt150084 	if (ixgbe->tx_rings != NULL) {
19616621Sbt150084 		kmem_free(ixgbe->tx_rings,
19626621Sbt150084 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
19636621Sbt150084 		ixgbe->tx_rings = NULL;
19646621Sbt150084 	}
19658275SEric Cheng 
19668275SEric Cheng 	if (ixgbe->rx_groups != NULL) {
19678275SEric Cheng 		kmem_free(ixgbe->rx_groups,
19688275SEric Cheng 		    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups);
19698275SEric Cheng 		ixgbe->rx_groups = NULL;
19708275SEric Cheng 	}
19716621Sbt150084 }
19726621Sbt150084 
197310376SChenlu.Chen@Sun.COM static int
ixgbe_alloc_rx_data(ixgbe_t * ixgbe)197410376SChenlu.Chen@Sun.COM ixgbe_alloc_rx_data(ixgbe_t *ixgbe)
197510376SChenlu.Chen@Sun.COM {
197610376SChenlu.Chen@Sun.COM 	ixgbe_rx_ring_t *rx_ring;
197710376SChenlu.Chen@Sun.COM 	int i;
197810376SChenlu.Chen@Sun.COM 
197910376SChenlu.Chen@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
198010376SChenlu.Chen@Sun.COM 		rx_ring = &ixgbe->rx_rings[i];
198110376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS)
198210376SChenlu.Chen@Sun.COM 			goto alloc_rx_rings_failure;
198310376SChenlu.Chen@Sun.COM 	}
198410376SChenlu.Chen@Sun.COM 	return (IXGBE_SUCCESS);
198510376SChenlu.Chen@Sun.COM 
198610376SChenlu.Chen@Sun.COM alloc_rx_rings_failure:
198710376SChenlu.Chen@Sun.COM 	ixgbe_free_rx_data(ixgbe);
198810376SChenlu.Chen@Sun.COM 	return (IXGBE_FAILURE);
198910376SChenlu.Chen@Sun.COM }
199010376SChenlu.Chen@Sun.COM 
199110376SChenlu.Chen@Sun.COM static void
ixgbe_free_rx_data(ixgbe_t * ixgbe)199210376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe_t *ixgbe)
199310376SChenlu.Chen@Sun.COM {
199410376SChenlu.Chen@Sun.COM 	ixgbe_rx_ring_t *rx_ring;
199510376SChenlu.Chen@Sun.COM 	ixgbe_rx_data_t *rx_data;
199610376SChenlu.Chen@Sun.COM 	int i;
199710376SChenlu.Chen@Sun.COM 
199810376SChenlu.Chen@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
199910376SChenlu.Chen@Sun.COM 		rx_ring = &ixgbe->rx_rings[i];
200010376SChenlu.Chen@Sun.COM 
200110376SChenlu.Chen@Sun.COM 		mutex_enter(&ixgbe->rx_pending_lock);
200210376SChenlu.Chen@Sun.COM 		rx_data = rx_ring->rx_data;
200310376SChenlu.Chen@Sun.COM 
200410376SChenlu.Chen@Sun.COM 		if (rx_data != NULL) {
200510376SChenlu.Chen@Sun.COM 			rx_data->flag |= IXGBE_RX_STOPPED;
200610376SChenlu.Chen@Sun.COM 
200710376SChenlu.Chen@Sun.COM 			if (rx_data->rcb_pending == 0) {
200810376SChenlu.Chen@Sun.COM 				ixgbe_free_rx_ring_data(rx_data);
200910376SChenlu.Chen@Sun.COM 				rx_ring->rx_data = NULL;
201010376SChenlu.Chen@Sun.COM 			}
201110376SChenlu.Chen@Sun.COM 		}
201210376SChenlu.Chen@Sun.COM 
201310376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->rx_pending_lock);
201410376SChenlu.Chen@Sun.COM 	}
201510376SChenlu.Chen@Sun.COM }
201610376SChenlu.Chen@Sun.COM 
20176621Sbt150084 /*
20186621Sbt150084  * ixgbe_setup_rings - Setup rx/tx rings.
20196621Sbt150084  */
20206621Sbt150084 static void
ixgbe_setup_rings(ixgbe_t * ixgbe)20216621Sbt150084 ixgbe_setup_rings(ixgbe_t *ixgbe)
20226621Sbt150084 {
20236621Sbt150084 	/*
20246621Sbt150084 	 * Setup the rx/tx rings, including the following:
20256621Sbt150084 	 *
20266621Sbt150084 	 * 1. Setup the descriptor ring and the control block buffers;
20276621Sbt150084 	 * 2. Initialize necessary registers for receive/transmit;
20286621Sbt150084 	 * 3. Initialize software pointers/parameters for receive/transmit;
20296621Sbt150084 	 */
20306621Sbt150084 	ixgbe_setup_rx(ixgbe);
20316621Sbt150084 
20326621Sbt150084 	ixgbe_setup_tx(ixgbe);
20336621Sbt150084 }
20346621Sbt150084 
20356621Sbt150084 static void
ixgbe_setup_rx_ring(ixgbe_rx_ring_t * rx_ring)20366621Sbt150084 ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring)
20376621Sbt150084 {
20386621Sbt150084 	ixgbe_t *ixgbe = rx_ring->ixgbe;
203910376SChenlu.Chen@Sun.COM 	ixgbe_rx_data_t *rx_data = rx_ring->rx_data;
20406621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
20416621Sbt150084 	rx_control_block_t *rcb;
20426621Sbt150084 	union ixgbe_adv_rx_desc	*rbd;
20436621Sbt150084 	uint32_t size;
20446621Sbt150084 	uint32_t buf_low;
20456621Sbt150084 	uint32_t buf_high;
20466621Sbt150084 	uint32_t reg_val;
20476621Sbt150084 	int i;
20486621Sbt150084 
20496621Sbt150084 	ASSERT(mutex_owned(&rx_ring->rx_lock));
20506621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
20516621Sbt150084 
20526621Sbt150084 	for (i = 0; i < ixgbe->rx_ring_size; i++) {
205310376SChenlu.Chen@Sun.COM 		rcb = rx_data->work_list[i];
205410376SChenlu.Chen@Sun.COM 		rbd = &rx_data->rbd_ring[i];
20556621Sbt150084 
20566621Sbt150084 		rbd->read.pkt_addr = rcb->rx_buf.dma_address;
20576621Sbt150084 		rbd->read.hdr_addr = NULL;
20586621Sbt150084 	}
20596621Sbt150084 
20606621Sbt150084 	/*
20616621Sbt150084 	 * Initialize the length register
20626621Sbt150084 	 */
206310376SChenlu.Chen@Sun.COM 	size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc);
206411878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->hw_index), size);
20656621Sbt150084 
20666621Sbt150084 	/*
20676621Sbt150084 	 * Initialize the base address registers
20686621Sbt150084 	 */
206910376SChenlu.Chen@Sun.COM 	buf_low = (uint32_t)rx_data->rbd_area.dma_address;
207010376SChenlu.Chen@Sun.COM 	buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32);
207111878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->hw_index), buf_high);
207211878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->hw_index), buf_low);
20736621Sbt150084 
20746621Sbt150084 	/*
20756621Sbt150084 	 * Setup head & tail pointers
20766621Sbt150084 	 */
207711878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->hw_index),
207811878SVenu.Iyer@Sun.COM 	    rx_data->ring_size - 1);
207911878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->hw_index), 0);
20806621Sbt150084 
208110376SChenlu.Chen@Sun.COM 	rx_data->rbd_next = 0;
208211486SZhen.W@Sun.COM 	rx_data->lro_first = 0;
20836621Sbt150084 
20846621Sbt150084 	/*
20856621Sbt150084 	 * Setup the Receive Descriptor Control Register (RXDCTL)
20866621Sbt150084 	 * PTHRESH=32 descriptors (half the internal cache)
20876621Sbt150084 	 * HTHRESH=0 descriptors (to minimize latency on fetch)
20886621Sbt150084 	 * WTHRESH defaults to 1 (writeback each descriptor)
20896621Sbt150084 	 */
209011878SVenu.Iyer@Sun.COM 	reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index));
20916621Sbt150084 	reg_val |= IXGBE_RXDCTL_ENABLE;	/* enable queue */
20929353SSamuel.Tu@Sun.COM 
20939353SSamuel.Tu@Sun.COM 	/* Not a valid value for 82599 */
20949353SSamuel.Tu@Sun.COM 	if (hw->mac.type < ixgbe_mac_82599EB) {
20959353SSamuel.Tu@Sun.COM 		reg_val |= 0x0020;	/* pthresh */
20969353SSamuel.Tu@Sun.COM 	}
209711878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val);
20986621Sbt150084 
20999353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
21009353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
21019353SSamuel.Tu@Sun.COM 		reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS);
21029353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
21039353SSamuel.Tu@Sun.COM 	}
21049353SSamuel.Tu@Sun.COM 
21056621Sbt150084 	/*
21066621Sbt150084 	 * Setup the Split and Replication Receive Control Register.
21076621Sbt150084 	 * Set the rx buffer size and the advanced descriptor type.
21086621Sbt150084 	 */
21096621Sbt150084 	reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) |
21106621Sbt150084 	    IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
21119353SSamuel.Tu@Sun.COM 	reg_val |= IXGBE_SRRCTL_DROP_EN;
211211878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->hw_index), reg_val);
21136621Sbt150084 }
21146621Sbt150084 
21156621Sbt150084 static void
ixgbe_setup_rx(ixgbe_t * ixgbe)21166621Sbt150084 ixgbe_setup_rx(ixgbe_t *ixgbe)
21176621Sbt150084 {
21186621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
21196621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
21206621Sbt150084 	uint32_t reg_val;
21218275SEric Cheng 	uint32_t ring_mapping;
212211878SVenu.Iyer@Sun.COM 	uint32_t i, index;
212311878SVenu.Iyer@Sun.COM 	uint32_t psrtype_rss_bit;
21246621Sbt150084 
21259353SSamuel.Tu@Sun.COM 	/* PSRTYPE must be configured for 82599 */
212611878SVenu.Iyer@Sun.COM 	if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ &&
212711878SVenu.Iyer@Sun.COM 	    ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) {
212811878SVenu.Iyer@Sun.COM 		reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
212911878SVenu.Iyer@Sun.COM 		    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
213011878SVenu.Iyer@Sun.COM 		reg_val |= IXGBE_PSRTYPE_L2HDR;
213111878SVenu.Iyer@Sun.COM 		reg_val |= 0x80000000;
213211878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val);
213311878SVenu.Iyer@Sun.COM 	} else {
213411878SVenu.Iyer@Sun.COM 		if (ixgbe->num_rx_groups > 32) {
213511878SVenu.Iyer@Sun.COM 			psrtype_rss_bit = 0x20000000;
213611878SVenu.Iyer@Sun.COM 		} else {
213711878SVenu.Iyer@Sun.COM 			psrtype_rss_bit = 0x40000000;
213811878SVenu.Iyer@Sun.COM 		}
213911878SVenu.Iyer@Sun.COM 		for (i = 0; i < ixgbe->capab->max_rx_grp_num; i++) {
214011878SVenu.Iyer@Sun.COM 			reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
214111878SVenu.Iyer@Sun.COM 			    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
214211878SVenu.Iyer@Sun.COM 			reg_val |= IXGBE_PSRTYPE_L2HDR;
214311878SVenu.Iyer@Sun.COM 			reg_val |= psrtype_rss_bit;
214411878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val);
214511878SVenu.Iyer@Sun.COM 		}
214611878SVenu.Iyer@Sun.COM 	}
21479353SSamuel.Tu@Sun.COM 
21486621Sbt150084 	/*
21496621Sbt150084 	 * Set filter control in FCTRL to accept broadcast packets and do
21506621Sbt150084 	 * not pass pause frames to host.  Flow control settings are already
21516621Sbt150084 	 * in this register, so preserve them.
21526621Sbt150084 	 */
21536621Sbt150084 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
21546621Sbt150084 	reg_val |= IXGBE_FCTRL_BAM;	/* broadcast accept mode */
21556621Sbt150084 	reg_val |= IXGBE_FCTRL_DPF;	/* discard pause frames */
21566621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val);
21576621Sbt150084 
21586621Sbt150084 	/*
215911878SVenu.Iyer@Sun.COM 	 * Hardware checksum settings
216011878SVenu.Iyer@Sun.COM 	 */
216111878SVenu.Iyer@Sun.COM 	if (ixgbe->rx_hcksum_enable) {
216211878SVenu.Iyer@Sun.COM 		reg_val = IXGBE_RXCSUM_IPPCSE;	/* IP checksum */
216311878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val);
216411878SVenu.Iyer@Sun.COM 	}
216511878SVenu.Iyer@Sun.COM 
216611878SVenu.Iyer@Sun.COM 	/*
216711878SVenu.Iyer@Sun.COM 	 * Setup VMDq and RSS for multiple receive queues
216811878SVenu.Iyer@Sun.COM 	 */
216911878SVenu.Iyer@Sun.COM 	switch (ixgbe->classify_mode) {
217011878SVenu.Iyer@Sun.COM 	case IXGBE_CLASSIFY_RSS:
217111878SVenu.Iyer@Sun.COM 		/*
217211878SVenu.Iyer@Sun.COM 		 * One group, only RSS is needed when more than
217311878SVenu.Iyer@Sun.COM 		 * one ring enabled.
217411878SVenu.Iyer@Sun.COM 		 */
217511878SVenu.Iyer@Sun.COM 		ixgbe_setup_rss(ixgbe);
217611878SVenu.Iyer@Sun.COM 		break;
217711878SVenu.Iyer@Sun.COM 
217811878SVenu.Iyer@Sun.COM 	case IXGBE_CLASSIFY_VMDQ:
217911878SVenu.Iyer@Sun.COM 		/*
218011878SVenu.Iyer@Sun.COM 		 * Multiple groups, each group has one ring,
218111878SVenu.Iyer@Sun.COM 		 * only VMDq is needed.
218211878SVenu.Iyer@Sun.COM 		 */
218311878SVenu.Iyer@Sun.COM 		ixgbe_setup_vmdq(ixgbe);
218411878SVenu.Iyer@Sun.COM 		break;
218511878SVenu.Iyer@Sun.COM 
218611878SVenu.Iyer@Sun.COM 	case IXGBE_CLASSIFY_VMDQ_RSS:
218711878SVenu.Iyer@Sun.COM 		/*
218811878SVenu.Iyer@Sun.COM 		 * Multiple groups and multiple rings, both
218911878SVenu.Iyer@Sun.COM 		 * VMDq and RSS are needed.
219011878SVenu.Iyer@Sun.COM 		 */
219111878SVenu.Iyer@Sun.COM 		ixgbe_setup_vmdq_rss(ixgbe);
219211878SVenu.Iyer@Sun.COM 		break;
219311878SVenu.Iyer@Sun.COM 
219411878SVenu.Iyer@Sun.COM 	default:
219511878SVenu.Iyer@Sun.COM 		break;
219611878SVenu.Iyer@Sun.COM 	}
219711878SVenu.Iyer@Sun.COM 
219811878SVenu.Iyer@Sun.COM 	/*
21996621Sbt150084 	 * Enable the receive unit.  This must be done after filter
22006621Sbt150084 	 * control is set in FCTRL.
22016621Sbt150084 	 */
22026621Sbt150084 	reg_val = (IXGBE_RXCTRL_RXEN	/* Enable Receive Unit */
22036621Sbt150084 	    | IXGBE_RXCTRL_DMBYPS);	/* descriptor monitor bypass */
22046621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
22056621Sbt150084 
22066621Sbt150084 	/*
22076621Sbt150084 	 * ixgbe_setup_rx_ring must be called after configuring RXCTRL
22086621Sbt150084 	 */
22096621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
22106621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
22116621Sbt150084 		ixgbe_setup_rx_ring(rx_ring);
22126621Sbt150084 	}
22136621Sbt150084 
22146621Sbt150084 	/*
22158275SEric Cheng 	 * Setup the per-ring statistics mapping.
22168275SEric Cheng 	 */
22178275SEric Cheng 	ring_mapping = 0;
22188275SEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
221911878SVenu.Iyer@Sun.COM 		index = ixgbe->rx_rings[i].hw_index;
222011878SVenu.Iyer@Sun.COM 		ring_mapping = IXGBE_READ_REG(hw, IXGBE_RQSMR(index >> 2));
222111878SVenu.Iyer@Sun.COM 		ring_mapping |= (i & 0xF) << (8 * (index & 0x3));
222211878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(index >> 2), ring_mapping);
222311878SVenu.Iyer@Sun.COM 	}
22248275SEric Cheng 
22258275SEric Cheng 	/*
22269353SSamuel.Tu@Sun.COM 	 * The Max Frame Size in MHADD/MAXFRS will be internally increased
22279353SSamuel.Tu@Sun.COM 	 * by four bytes if the packet has a VLAN field, so includes MTU,
22289353SSamuel.Tu@Sun.COM 	 * ethernet header and frame check sequence.
22299353SSamuel.Tu@Sun.COM 	 * Register is MAXFRS in 82599.
22306621Sbt150084 	 */
22316621Sbt150084 	reg_val = (ixgbe->default_mtu + sizeof (struct ether_header)
22326621Sbt150084 	    + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT;
22336621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val);
22346621Sbt150084 
22356621Sbt150084 	/*
22366621Sbt150084 	 * Setup Jumbo Frame enable bit
22376621Sbt150084 	 */
22386621Sbt150084 	if (ixgbe->default_mtu > ETHERMTU) {
22396621Sbt150084 		reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
22406621Sbt150084 		reg_val |= IXGBE_HLREG0_JUMBOEN;
22416621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
22426621Sbt150084 	}
224311891SVenu.Iyer@Sun.COM 
224411891SVenu.Iyer@Sun.COM 	/*
224511891SVenu.Iyer@Sun.COM 	 * Setup RSC for multiple receive queues.
224611891SVenu.Iyer@Sun.COM 	 */
224711891SVenu.Iyer@Sun.COM 	if (ixgbe->lro_enable) {
224811891SVenu.Iyer@Sun.COM 		for (i = 0; i < ixgbe->num_rx_rings; i++) {
224911891SVenu.Iyer@Sun.COM 			/*
225011891SVenu.Iyer@Sun.COM 			 * Make sure rx_buf_size * MAXDESC not greater
225111891SVenu.Iyer@Sun.COM 			 * than 65535.
225211891SVenu.Iyer@Sun.COM 			 * Intel recommends 4 for MAXDESC field value.
225311891SVenu.Iyer@Sun.COM 			 */
225411891SVenu.Iyer@Sun.COM 			reg_val = IXGBE_READ_REG(hw, IXGBE_RSCCTL(i));
225511891SVenu.Iyer@Sun.COM 			reg_val |= IXGBE_RSCCTL_RSCEN;
225611891SVenu.Iyer@Sun.COM 			if (ixgbe->rx_buf_size == IXGBE_PKG_BUF_16k)
225711891SVenu.Iyer@Sun.COM 				reg_val |= IXGBE_RSCCTL_MAXDESC_1;
225811891SVenu.Iyer@Sun.COM 			else
225911891SVenu.Iyer@Sun.COM 				reg_val |= IXGBE_RSCCTL_MAXDESC_4;
226011891SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw,  IXGBE_RSCCTL(i), reg_val);
226111891SVenu.Iyer@Sun.COM 		}
226211891SVenu.Iyer@Sun.COM 
226311891SVenu.Iyer@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_RSCDBU);
226411891SVenu.Iyer@Sun.COM 		reg_val |= IXGBE_RSCDBU_RSCACKDIS;
226511891SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, reg_val);
226611891SVenu.Iyer@Sun.COM 
226711891SVenu.Iyer@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
226811891SVenu.Iyer@Sun.COM 		reg_val |= IXGBE_RDRXCTL_RSCACKC;
226912003SPaul.Guo@Sun.COM 		reg_val |= IXGBE_RDRXCTL_FCOE_WRFIX;
227011891SVenu.Iyer@Sun.COM 		reg_val &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
227111891SVenu.Iyer@Sun.COM 
227211891SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
227311891SVenu.Iyer@Sun.COM 	}
22746621Sbt150084 }
22756621Sbt150084 
22766621Sbt150084 static void
ixgbe_setup_tx_ring(ixgbe_tx_ring_t * tx_ring)22776621Sbt150084 ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring)
22786621Sbt150084 {
22796621Sbt150084 	ixgbe_t *ixgbe = tx_ring->ixgbe;
22806621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
22816621Sbt150084 	uint32_t size;
22826621Sbt150084 	uint32_t buf_low;
22836621Sbt150084 	uint32_t buf_high;
22846621Sbt150084 	uint32_t reg_val;
22856621Sbt150084 
22866621Sbt150084 	ASSERT(mutex_owned(&tx_ring->tx_lock));
22876621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
22886621Sbt150084 
22896621Sbt150084 	/*
22906621Sbt150084 	 * Initialize the length register
22916621Sbt150084 	 */
22926621Sbt150084 	size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc);
22936621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size);
22946621Sbt150084 
22956621Sbt150084 	/*
22966621Sbt150084 	 * Initialize the base address registers
22976621Sbt150084 	 */
22986621Sbt150084 	buf_low = (uint32_t)tx_ring->tbd_area.dma_address;
22996621Sbt150084 	buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32);
23006621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low);
23016621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high);
23026621Sbt150084 
23036621Sbt150084 	/*
23046621Sbt150084 	 * Setup head & tail pointers
23056621Sbt150084 	 */
23066621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0);
23076621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0);
23086621Sbt150084 
23096621Sbt150084 	/*
23106621Sbt150084 	 * Setup head write-back
23116621Sbt150084 	 */
23126621Sbt150084 	if (ixgbe->tx_head_wb_enable) {
23136621Sbt150084 		/*
23146621Sbt150084 		 * The memory of the head write-back is allocated using
23156621Sbt150084 		 * the extra tbd beyond the tail of the tbd ring.
23166621Sbt150084 		 */
23176621Sbt150084 		tx_ring->tbd_head_wb = (uint32_t *)
23186621Sbt150084 		    ((uintptr_t)tx_ring->tbd_area.address + size);
23196621Sbt150084 		*tx_ring->tbd_head_wb = 0;
23206621Sbt150084 
23216621Sbt150084 		buf_low = (uint32_t)
23226621Sbt150084 		    (tx_ring->tbd_area.dma_address + size);
23236621Sbt150084 		buf_high = (uint32_t)
23246621Sbt150084 		    ((tx_ring->tbd_area.dma_address + size) >> 32);
23256621Sbt150084 
23266621Sbt150084 		/* Set the head write-back enable bit */
23276621Sbt150084 		buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE;
23286621Sbt150084 
23296621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low);
23306621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high);
23316621Sbt150084 
23326621Sbt150084 		/*
23336621Sbt150084 		 * Turn off relaxed ordering for head write back or it will
23346621Sbt150084 		 * cause problems with the tx recycling
23356621Sbt150084 		 */
23366621Sbt150084 		reg_val = IXGBE_READ_REG(hw,
23376621Sbt150084 		    IXGBE_DCA_TXCTRL(tx_ring->index));
23386621Sbt150084 		reg_val &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
23396621Sbt150084 		IXGBE_WRITE_REG(hw,
23406621Sbt150084 		    IXGBE_DCA_TXCTRL(tx_ring->index), reg_val);
23416621Sbt150084 	} else {
23426621Sbt150084 		tx_ring->tbd_head_wb = NULL;
23436621Sbt150084 	}
23446621Sbt150084 
23456621Sbt150084 	tx_ring->tbd_head = 0;
23466621Sbt150084 	tx_ring->tbd_tail = 0;
23476621Sbt150084 	tx_ring->tbd_free = tx_ring->ring_size;
23486621Sbt150084 
234910376SChenlu.Chen@Sun.COM 	if (ixgbe->tx_ring_init == B_TRUE) {
23506621Sbt150084 		tx_ring->tcb_head = 0;
23516621Sbt150084 		tx_ring->tcb_tail = 0;
23526621Sbt150084 		tx_ring->tcb_free = tx_ring->free_list_size;
23536621Sbt150084 	}
23546621Sbt150084 
23556621Sbt150084 	/*
23567245Sgg161487 	 * Initialize the s/w context structure
23576621Sbt150084 	 */
23587245Sgg161487 	bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t));
23596621Sbt150084 }
23606621Sbt150084 
23616621Sbt150084 static void
ixgbe_setup_tx(ixgbe_t * ixgbe)23626621Sbt150084 ixgbe_setup_tx(ixgbe_t *ixgbe)
23636621Sbt150084 {
23647167Sgg161487 	struct ixgbe_hw *hw = &ixgbe->hw;
23656621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
23667167Sgg161487 	uint32_t reg_val;
23678275SEric Cheng 	uint32_t ring_mapping;
23686621Sbt150084 	int i;
23696621Sbt150084 
23706621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
23716621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
23726621Sbt150084 		ixgbe_setup_tx_ring(tx_ring);
23736621Sbt150084 	}
23747167Sgg161487 
23757167Sgg161487 	/*
23768275SEric Cheng 	 * Setup the per-ring statistics mapping.
23778275SEric Cheng 	 */
23788275SEric Cheng 	ring_mapping = 0;
23798275SEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
23808275SEric Cheng 		ring_mapping |= (i & 0xF) << (8 * (i & 0x3));
23818275SEric Cheng 		if ((i & 0x3) == 0x3) {
2382*13006SChenlu.Chen@Sun.COM 			switch (hw->mac.type) {
2383*13006SChenlu.Chen@Sun.COM 			case ixgbe_mac_82598EB:
23849353SSamuel.Tu@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2),
23859353SSamuel.Tu@Sun.COM 				    ring_mapping);
2386*13006SChenlu.Chen@Sun.COM 				break;
2387*13006SChenlu.Chen@Sun.COM 
2388*13006SChenlu.Chen@Sun.COM 			case ixgbe_mac_82599EB:
2389*13006SChenlu.Chen@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2),
2390*13006SChenlu.Chen@Sun.COM 				    ring_mapping);
2391*13006SChenlu.Chen@Sun.COM 				break;
2392*13006SChenlu.Chen@Sun.COM 
2393*13006SChenlu.Chen@Sun.COM 			default:
2394*13006SChenlu.Chen@Sun.COM 				break;
23959353SSamuel.Tu@Sun.COM 			}
2396*13006SChenlu.Chen@Sun.COM 
23978275SEric Cheng 			ring_mapping = 0;
23988275SEric Cheng 		}
23998275SEric Cheng 	}
2400*13006SChenlu.Chen@Sun.COM 	if (i & 0x3) {
2401*13006SChenlu.Chen@Sun.COM 		switch (hw->mac.type) {
2402*13006SChenlu.Chen@Sun.COM 		case ixgbe_mac_82598EB:
2403*13006SChenlu.Chen@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping);
2404*13006SChenlu.Chen@Sun.COM 			break;
2405*13006SChenlu.Chen@Sun.COM 
2406*13006SChenlu.Chen@Sun.COM 		case ixgbe_mac_82599EB:
24079353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping);
2408*13006SChenlu.Chen@Sun.COM 			break;
2409*13006SChenlu.Chen@Sun.COM 
2410*13006SChenlu.Chen@Sun.COM 		default:
2411*13006SChenlu.Chen@Sun.COM 			break;
24129353SSamuel.Tu@Sun.COM 		}
2413*13006SChenlu.Chen@Sun.COM 	}
24148275SEric Cheng 
24158275SEric Cheng 	/*
24167167Sgg161487 	 * Enable CRC appending and TX padding (for short tx frames)
24177167Sgg161487 	 */
24187167Sgg161487 	reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
24197167Sgg161487 	reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN;
24207167Sgg161487 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
24219353SSamuel.Tu@Sun.COM 
24229353SSamuel.Tu@Sun.COM 	/*
24239353SSamuel.Tu@Sun.COM 	 * enable DMA for 82599 parts
24249353SSamuel.Tu@Sun.COM 	 */
24259353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
24269353SSamuel.Tu@Sun.COM 	/* DMATXCTL.TE must be set after all Tx config is complete */
24279353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
24289353SSamuel.Tu@Sun.COM 		reg_val |= IXGBE_DMATXCTL_TE;
24299353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val);
24309353SSamuel.Tu@Sun.COM 	}
24319353SSamuel.Tu@Sun.COM 
24329353SSamuel.Tu@Sun.COM 	/*
24339353SSamuel.Tu@Sun.COM 	 * Enabling tx queues ..
24349353SSamuel.Tu@Sun.COM 	 * For 82599 must be done after DMATXCTL.TE is set
24359353SSamuel.Tu@Sun.COM 	 */
24369353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
24379353SSamuel.Tu@Sun.COM 		tx_ring = &ixgbe->tx_rings[i];
24389353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index));
24399353SSamuel.Tu@Sun.COM 		reg_val |= IXGBE_TXDCTL_ENABLE;
24409353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val);
24419353SSamuel.Tu@Sun.COM 	}
24426621Sbt150084 }
24436621Sbt150084 
24446621Sbt150084 /*
24456621Sbt150084  * ixgbe_setup_rss - Setup receive-side scaling feature.
24466621Sbt150084  */
24476621Sbt150084 static void
ixgbe_setup_rss(ixgbe_t * ixgbe)24486621Sbt150084 ixgbe_setup_rss(ixgbe_t *ixgbe)
24496621Sbt150084 {
24506621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
24517167Sgg161487 	uint32_t i, mrqc, rxcsum;
24526621Sbt150084 	uint32_t random;
24536621Sbt150084 	uint32_t reta;
245411878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
24556621Sbt150084 
24566621Sbt150084 	/*
24576621Sbt150084 	 * Fill out redirection table
24586621Sbt150084 	 */
24596621Sbt150084 	reta = 0;
246011878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
246111878SVenu.Iyer@Sun.COM 
24626621Sbt150084 	for (i = 0; i < 128; i++) {
246311878SVenu.Iyer@Sun.COM 		reta = (reta << 8) | (i % ring_per_group) |
246411878SVenu.Iyer@Sun.COM 		    ((i % ring_per_group) << 4);
24657167Sgg161487 		if ((i & 3) == 3)
24666621Sbt150084 			IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
24676621Sbt150084 	}
24686621Sbt150084 
24696621Sbt150084 	/*
24706621Sbt150084 	 * Fill out hash function seeds with a random constant
24716621Sbt150084 	 */
24726621Sbt150084 	for (i = 0; i < 10; i++) {
24736621Sbt150084 		(void) random_get_pseudo_bytes((uint8_t *)&random,
24746621Sbt150084 		    sizeof (uint32_t));
24756621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random);
24766621Sbt150084 	}
24776621Sbt150084 
24786621Sbt150084 	/*
24797167Sgg161487 	 * Enable RSS & perform hash on these packet types
24806621Sbt150084 	 */
24816621Sbt150084 	mrqc = IXGBE_MRQC_RSSEN |
24826621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4 |
24836621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
24846621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
24856621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
24866621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
24876621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6 |
24886621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
24896621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
24906621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
24916621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
24926621Sbt150084 
24936621Sbt150084 	/*
24946621Sbt150084 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
24956621Sbt150084 	 * It is an adapter hardware limitation that Packet Checksum is
24966621Sbt150084 	 * mutually exclusive with RSS.
24976621Sbt150084 	 */
24986621Sbt150084 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
24996621Sbt150084 	rxcsum |= IXGBE_RXCSUM_PCSD;
25006621Sbt150084 	rxcsum &= ~IXGBE_RXCSUM_IPPCSE;
25016621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
25026621Sbt150084 }
25036621Sbt150084 
25046621Sbt150084 /*
250511878SVenu.Iyer@Sun.COM  * ixgbe_setup_vmdq - Setup MAC classification feature
250611878SVenu.Iyer@Sun.COM  */
250711878SVenu.Iyer@Sun.COM static void
ixgbe_setup_vmdq(ixgbe_t * ixgbe)250811878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq(ixgbe_t *ixgbe)
250911878SVenu.Iyer@Sun.COM {
251011878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
251111878SVenu.Iyer@Sun.COM 	uint32_t vmdctl, i, vtctl;
251211878SVenu.Iyer@Sun.COM 
251311878SVenu.Iyer@Sun.COM 	/*
251411878SVenu.Iyer@Sun.COM 	 * Setup the VMDq Control register, enable VMDq based on
251511878SVenu.Iyer@Sun.COM 	 * packet destination MAC address:
251611878SVenu.Iyer@Sun.COM 	 */
251711878SVenu.Iyer@Sun.COM 	switch (hw->mac.type) {
251811878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82598EB:
251911878SVenu.Iyer@Sun.COM 		/*
252011878SVenu.Iyer@Sun.COM 		 * VMDq Enable = 1;
252111878SVenu.Iyer@Sun.COM 		 * VMDq Filter = 0; MAC filtering
252211878SVenu.Iyer@Sun.COM 		 * Default VMDq output index = 0;
252311878SVenu.Iyer@Sun.COM 		 */
252411878SVenu.Iyer@Sun.COM 		vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
252511878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
252611878SVenu.Iyer@Sun.COM 		break;
252711878SVenu.Iyer@Sun.COM 
252811878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82599EB:
252911878SVenu.Iyer@Sun.COM 		/*
253011878SVenu.Iyer@Sun.COM 		 * Enable VMDq-only.
253111878SVenu.Iyer@Sun.COM 		 */
253211878SVenu.Iyer@Sun.COM 		vmdctl = IXGBE_MRQC_VMDQEN;
253311878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl);
253411878SVenu.Iyer@Sun.COM 
253511878SVenu.Iyer@Sun.COM 		for (i = 0; i < hw->mac.num_rar_entries; i++) {
253611878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0);
253711878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0);
253811878SVenu.Iyer@Sun.COM 		}
253911878SVenu.Iyer@Sun.COM 
254011878SVenu.Iyer@Sun.COM 		/*
254111878SVenu.Iyer@Sun.COM 		 * Enable Virtualization and Replication.
254211878SVenu.Iyer@Sun.COM 		 */
254311878SVenu.Iyer@Sun.COM 		vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
254411878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
254511878SVenu.Iyer@Sun.COM 
254611878SVenu.Iyer@Sun.COM 		/*
254711878SVenu.Iyer@Sun.COM 		 * Enable receiving packets to all VFs
254811878SVenu.Iyer@Sun.COM 		 */
254911878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL);
255011878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL);
255111878SVenu.Iyer@Sun.COM 		break;
255211878SVenu.Iyer@Sun.COM 
255311878SVenu.Iyer@Sun.COM 	default:
255411878SVenu.Iyer@Sun.COM 		break;
255511878SVenu.Iyer@Sun.COM 	}
255611878SVenu.Iyer@Sun.COM }
255711878SVenu.Iyer@Sun.COM 
255811878SVenu.Iyer@Sun.COM /*
255911878SVenu.Iyer@Sun.COM  * ixgbe_setup_vmdq_rss - Setup both vmdq feature and rss feature.
256011878SVenu.Iyer@Sun.COM  */
256111878SVenu.Iyer@Sun.COM static void
ixgbe_setup_vmdq_rss(ixgbe_t * ixgbe)256211878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe)
256311878SVenu.Iyer@Sun.COM {
256411878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
256511878SVenu.Iyer@Sun.COM 	uint32_t i, mrqc, rxcsum;
256611878SVenu.Iyer@Sun.COM 	uint32_t random;
256711878SVenu.Iyer@Sun.COM 	uint32_t reta;
256811878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
256911878SVenu.Iyer@Sun.COM 	uint32_t vmdctl, vtctl;
257011878SVenu.Iyer@Sun.COM 
257111878SVenu.Iyer@Sun.COM 	/*
257211878SVenu.Iyer@Sun.COM 	 * Fill out redirection table
257311878SVenu.Iyer@Sun.COM 	 */
257411878SVenu.Iyer@Sun.COM 	reta = 0;
257511878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
257611878SVenu.Iyer@Sun.COM 	for (i = 0; i < 128; i++) {
257711878SVenu.Iyer@Sun.COM 		reta = (reta << 8) | (i % ring_per_group) |
257811878SVenu.Iyer@Sun.COM 		    ((i % ring_per_group) << 4);
257911878SVenu.Iyer@Sun.COM 		if ((i & 3) == 3)
258011878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
258111878SVenu.Iyer@Sun.COM 	}
258211878SVenu.Iyer@Sun.COM 
258311878SVenu.Iyer@Sun.COM 	/*
258411878SVenu.Iyer@Sun.COM 	 * Fill out hash function seeds with a random constant
258511878SVenu.Iyer@Sun.COM 	 */
258611878SVenu.Iyer@Sun.COM 	for (i = 0; i < 10; i++) {
258711878SVenu.Iyer@Sun.COM 		(void) random_get_pseudo_bytes((uint8_t *)&random,
258811878SVenu.Iyer@Sun.COM 		    sizeof (uint32_t));
258911878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random);
259011878SVenu.Iyer@Sun.COM 	}
259111878SVenu.Iyer@Sun.COM 
259211878SVenu.Iyer@Sun.COM 	/*
259311878SVenu.Iyer@Sun.COM 	 * Enable and setup RSS and VMDq
259411878SVenu.Iyer@Sun.COM 	 */
259511878SVenu.Iyer@Sun.COM 	switch (hw->mac.type) {
259611878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82598EB:
259711878SVenu.Iyer@Sun.COM 		/*
259811878SVenu.Iyer@Sun.COM 		 * Enable RSS & Setup RSS Hash functions
259911878SVenu.Iyer@Sun.COM 		 */
260011878SVenu.Iyer@Sun.COM 		mrqc = IXGBE_MRQC_RSSEN |
260111878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4 |
260211878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
260311878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
260411878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
260511878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
260611878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6 |
260711878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
260811878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
260911878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
261011878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
261111878SVenu.Iyer@Sun.COM 
261211878SVenu.Iyer@Sun.COM 		/*
261311878SVenu.Iyer@Sun.COM 		 * Enable and Setup VMDq
261411878SVenu.Iyer@Sun.COM 		 * VMDq Filter = 0; MAC filtering
261511878SVenu.Iyer@Sun.COM 		 * Default VMDq output index = 0;
261611878SVenu.Iyer@Sun.COM 		 */
261711878SVenu.Iyer@Sun.COM 		vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
261811878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
261911878SVenu.Iyer@Sun.COM 		break;
262011878SVenu.Iyer@Sun.COM 
262111878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82599EB:
262211878SVenu.Iyer@Sun.COM 		/*
262311878SVenu.Iyer@Sun.COM 		 * Enable RSS & Setup RSS Hash functions
262411878SVenu.Iyer@Sun.COM 		 */
262511878SVenu.Iyer@Sun.COM 		mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 |
262611878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
262711878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
262811878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
262911878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
263011878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6 |
263111878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
263211878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
263311878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
263411878SVenu.Iyer@Sun.COM 
263511878SVenu.Iyer@Sun.COM 		/*
263611878SVenu.Iyer@Sun.COM 		 * Enable VMDq+RSS.
263711878SVenu.Iyer@Sun.COM 		 */
263811878SVenu.Iyer@Sun.COM 		if (ixgbe->num_rx_groups > 32)  {
263911878SVenu.Iyer@Sun.COM 			mrqc = mrqc | IXGBE_MRQC_VMDQRSS64EN;
264011878SVenu.Iyer@Sun.COM 		} else {
264111878SVenu.Iyer@Sun.COM 			mrqc = mrqc | IXGBE_MRQC_VMDQRSS32EN;
264211878SVenu.Iyer@Sun.COM 		}
264311878SVenu.Iyer@Sun.COM 
264411878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
264511878SVenu.Iyer@Sun.COM 
264611878SVenu.Iyer@Sun.COM 		for (i = 0; i < hw->mac.num_rar_entries; i++) {
264711878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0);
264811878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0);
264911878SVenu.Iyer@Sun.COM 		}
265011878SVenu.Iyer@Sun.COM 		break;
265111878SVenu.Iyer@Sun.COM 
265211878SVenu.Iyer@Sun.COM 	default:
265311878SVenu.Iyer@Sun.COM 		break;
265411878SVenu.Iyer@Sun.COM 
265511878SVenu.Iyer@Sun.COM 	}
265611878SVenu.Iyer@Sun.COM 
265711878SVenu.Iyer@Sun.COM 	/*
265811878SVenu.Iyer@Sun.COM 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
265911878SVenu.Iyer@Sun.COM 	 * It is an adapter hardware limitation that Packet Checksum is
266011878SVenu.Iyer@Sun.COM 	 * mutually exclusive with RSS.
266111878SVenu.Iyer@Sun.COM 	 */
266211878SVenu.Iyer@Sun.COM 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
266311878SVenu.Iyer@Sun.COM 	rxcsum |= IXGBE_RXCSUM_PCSD;
266411878SVenu.Iyer@Sun.COM 	rxcsum &= ~IXGBE_RXCSUM_IPPCSE;
266511878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
266611878SVenu.Iyer@Sun.COM 
266711878SVenu.Iyer@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
266811878SVenu.Iyer@Sun.COM 		/*
266911878SVenu.Iyer@Sun.COM 		 * Enable Virtualization and Replication.
267011878SVenu.Iyer@Sun.COM 		 */
267111878SVenu.Iyer@Sun.COM 		vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
267211878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
267311878SVenu.Iyer@Sun.COM 
267411878SVenu.Iyer@Sun.COM 		/*
267511878SVenu.Iyer@Sun.COM 		 * Enable receiving packets to all VFs
267611878SVenu.Iyer@Sun.COM 		 */
267711878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL);
267811878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL);
267911878SVenu.Iyer@Sun.COM 	}
268011878SVenu.Iyer@Sun.COM }
268111878SVenu.Iyer@Sun.COM 
268211878SVenu.Iyer@Sun.COM /*
26836621Sbt150084  * ixgbe_init_unicst - Initialize the unicast addresses.
26846621Sbt150084  */
26856621Sbt150084 static void
ixgbe_init_unicst(ixgbe_t * ixgbe)26866621Sbt150084 ixgbe_init_unicst(ixgbe_t *ixgbe)
26876621Sbt150084 {
26886621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
26898275SEric Cheng 	uint8_t *mac_addr;
26906621Sbt150084 	int slot;
26916621Sbt150084 	/*
26926621Sbt150084 	 * Here we should consider two situations:
26936621Sbt150084 	 *
26948275SEric Cheng 	 * 1. Chipset is initialized at the first time,
26958275SEric Cheng 	 *    Clear all the multiple unicast addresses.
26966621Sbt150084 	 *
26976621Sbt150084 	 * 2. Chipset is reset
26986621Sbt150084 	 *    Recover the multiple unicast addresses from the
26996621Sbt150084 	 *    software data structure to the RAR registers.
27006621Sbt150084 	 */
27016621Sbt150084 	if (!ixgbe->unicst_init) {
27026621Sbt150084 		/*
27036621Sbt150084 		 * Initialize the multiple unicast addresses
27046621Sbt150084 		 */
270511878SVenu.Iyer@Sun.COM 		ixgbe->unicst_total = hw->mac.num_rar_entries;
27068275SEric Cheng 		ixgbe->unicst_avail = ixgbe->unicst_total;
27078275SEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
27088275SEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
27098275SEric Cheng 			bzero(mac_addr, ETHERADDRL);
27108275SEric Cheng 			(void) ixgbe_set_rar(hw, slot, mac_addr, NULL, NULL);
27116621Sbt150084 			ixgbe->unicst_addr[slot].mac.set = 0;
27128275SEric Cheng 		}
27136621Sbt150084 		ixgbe->unicst_init = B_TRUE;
27146621Sbt150084 	} else {
27156621Sbt150084 		/* Re-configure the RAR registers */
27168275SEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
27178275SEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
27188275SEric Cheng 			if (ixgbe->unicst_addr[slot].mac.set == 1) {
27198275SEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
272011878SVenu.Iyer@Sun.COM 				    ixgbe->unicst_addr[slot].mac.group_index,
272111878SVenu.Iyer@Sun.COM 				    IXGBE_RAH_AV);
27228275SEric Cheng 			} else {
27238275SEric Cheng 				bzero(mac_addr, ETHERADDRL);
27248275SEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
27258275SEric Cheng 				    NULL, NULL);
27268275SEric Cheng 			}
27278275SEric Cheng 		}
27286621Sbt150084 	}
27296621Sbt150084 }
27308275SEric Cheng 
27316621Sbt150084 /*
27328275SEric Cheng  * ixgbe_unicst_find - Find the slot for the specified unicast address
27338275SEric Cheng  */
27348275SEric Cheng int
ixgbe_unicst_find(ixgbe_t * ixgbe,const uint8_t * mac_addr)27358275SEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr)
27368275SEric Cheng {
27378275SEric Cheng 	int slot;
27388275SEric Cheng 
27398275SEric Cheng 	ASSERT(mutex_owned(&ixgbe->gen_lock));
27408275SEric Cheng 
27418275SEric Cheng 	for (slot = 0; slot < ixgbe->unicst_total; slot++) {
27428275SEric Cheng 		if (bcmp(ixgbe->unicst_addr[slot].mac.addr,
27438275SEric Cheng 		    mac_addr, ETHERADDRL) == 0)
27448275SEric Cheng 			return (slot);
27458275SEric Cheng 	}
27468275SEric Cheng 
27478275SEric Cheng 	return (-1);
27488275SEric Cheng }
27498275SEric Cheng 
27508275SEric Cheng /*
27516621Sbt150084  * ixgbe_multicst_add - Add a multicst address.
27526621Sbt150084  */
27536621Sbt150084 int
ixgbe_multicst_add(ixgbe_t * ixgbe,const uint8_t * multiaddr)27546621Sbt150084 ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr)
27556621Sbt150084 {
27566621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
27576621Sbt150084 
27586621Sbt150084 	if ((multiaddr[0] & 01) == 0) {
27596621Sbt150084 		return (EINVAL);
27606621Sbt150084 	}
27616621Sbt150084 
27626621Sbt150084 	if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) {
27636621Sbt150084 		return (ENOENT);
27646621Sbt150084 	}
27656621Sbt150084 
27666621Sbt150084 	bcopy(multiaddr,
27676621Sbt150084 	    &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL);
27686621Sbt150084 	ixgbe->mcast_count++;
27696621Sbt150084 
27706621Sbt150084 	/*
27716621Sbt150084 	 * Update the multicast table in the hardware
27726621Sbt150084 	 */
27736621Sbt150084 	ixgbe_setup_multicst(ixgbe);
27746621Sbt150084 
27756621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
27766621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
27776621Sbt150084 		return (EIO);
27786621Sbt150084 	}
27796621Sbt150084 
27806621Sbt150084 	return (0);
27816621Sbt150084 }
27826621Sbt150084 
27836621Sbt150084 /*
27846621Sbt150084  * ixgbe_multicst_remove - Remove a multicst address.
27856621Sbt150084  */
27866621Sbt150084 int
ixgbe_multicst_remove(ixgbe_t * ixgbe,const uint8_t * multiaddr)27876621Sbt150084 ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr)
27886621Sbt150084 {
27896621Sbt150084 	int i;
27906621Sbt150084 
27916621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
27926621Sbt150084 
27936621Sbt150084 	for (i = 0; i < ixgbe->mcast_count; i++) {
27946621Sbt150084 		if (bcmp(multiaddr, &ixgbe->mcast_table[i],
27956621Sbt150084 		    ETHERADDRL) == 0) {
27966621Sbt150084 			for (i++; i < ixgbe->mcast_count; i++) {
27976621Sbt150084 				ixgbe->mcast_table[i - 1] =
27986621Sbt150084 				    ixgbe->mcast_table[i];
27996621Sbt150084 			}
28006621Sbt150084 			ixgbe->mcast_count--;
28016621Sbt150084 			break;
28026621Sbt150084 		}
28036621Sbt150084 	}
28046621Sbt150084 
28056621Sbt150084 	/*
28066621Sbt150084 	 * Update the multicast table in the hardware
28076621Sbt150084 	 */
28086621Sbt150084 	ixgbe_setup_multicst(ixgbe);
28096621Sbt150084 
28106621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
28116621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
28126621Sbt150084 		return (EIO);
28136621Sbt150084 	}
28146621Sbt150084 
28156621Sbt150084 	return (0);
28166621Sbt150084 }
28176621Sbt150084 
28186621Sbt150084 /*
28196621Sbt150084  * ixgbe_setup_multicast - Setup multicast data structures.
28206621Sbt150084  *
28216621Sbt150084  * This routine initializes all of the multicast related structures
28226621Sbt150084  * and save them in the hardware registers.
28236621Sbt150084  */
28246621Sbt150084 static void
ixgbe_setup_multicst(ixgbe_t * ixgbe)28256621Sbt150084 ixgbe_setup_multicst(ixgbe_t *ixgbe)
28266621Sbt150084 {
28276621Sbt150084 	uint8_t *mc_addr_list;
28286621Sbt150084 	uint32_t mc_addr_count;
28296621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
28306621Sbt150084 
28316621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
28326621Sbt150084 
28336621Sbt150084 	ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES);
28346621Sbt150084 
28356621Sbt150084 	mc_addr_list = (uint8_t *)ixgbe->mcast_table;
28366621Sbt150084 	mc_addr_count = ixgbe->mcast_count;
28376621Sbt150084 
28386621Sbt150084 	/*
28396621Sbt150084 	 * Update the multicast addresses to the MTA registers
28406621Sbt150084 	 */
28416621Sbt150084 	(void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
28426621Sbt150084 	    ixgbe_mc_table_itr);
28436621Sbt150084 }
28446621Sbt150084 
28456621Sbt150084 /*
284611878SVenu.Iyer@Sun.COM  * ixgbe_setup_vmdq_rss_conf - Configure vmdq and rss (number and mode).
284711878SVenu.Iyer@Sun.COM  *
284811878SVenu.Iyer@Sun.COM  * Configure the rx classification mode (vmdq & rss) and vmdq & rss numbers.
284911878SVenu.Iyer@Sun.COM  * Different chipsets may have different allowed configuration of vmdq and rss.
285011878SVenu.Iyer@Sun.COM  */
285111878SVenu.Iyer@Sun.COM static void
ixgbe_setup_vmdq_rss_conf(ixgbe_t * ixgbe)285211878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe)
285311878SVenu.Iyer@Sun.COM {
285411878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
285511878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
285611878SVenu.Iyer@Sun.COM 
285711878SVenu.Iyer@Sun.COM 	switch (hw->mac.type) {
285811878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82598EB:
285911878SVenu.Iyer@Sun.COM 		/*
286011878SVenu.Iyer@Sun.COM 		 * 82598 supports the following combination:
286111878SVenu.Iyer@Sun.COM 		 * vmdq no. x rss no.
286211878SVenu.Iyer@Sun.COM 		 * [5..16]  x 1
286311878SVenu.Iyer@Sun.COM 		 * [1..4]   x [1..16]
286411878SVenu.Iyer@Sun.COM 		 * However 8 rss queue per pool (vmdq) is sufficient for
286511878SVenu.Iyer@Sun.COM 		 * most cases.
286611878SVenu.Iyer@Sun.COM 		 */
286711878SVenu.Iyer@Sun.COM 		ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
286811878SVenu.Iyer@Sun.COM 		if (ixgbe->num_rx_groups > 4) {
286911878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = ixgbe->num_rx_groups;
287011878SVenu.Iyer@Sun.COM 		} else {
287111878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
287211878SVenu.Iyer@Sun.COM 			    min(8, ring_per_group);
287311878SVenu.Iyer@Sun.COM 		}
287411878SVenu.Iyer@Sun.COM 
287511878SVenu.Iyer@Sun.COM 		break;
287611878SVenu.Iyer@Sun.COM 
287711878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82599EB:
287811878SVenu.Iyer@Sun.COM 		/*
287911878SVenu.Iyer@Sun.COM 		 * 82599 supports the following combination:
288011878SVenu.Iyer@Sun.COM 		 * vmdq no. x rss no.
288111878SVenu.Iyer@Sun.COM 		 * [33..64] x [1..2]
288211878SVenu.Iyer@Sun.COM 		 * [2..32]  x [1..4]
288311878SVenu.Iyer@Sun.COM 		 * 1 x [1..16]
288411878SVenu.Iyer@Sun.COM 		 * However 8 rss queue per pool (vmdq) is sufficient for
288511878SVenu.Iyer@Sun.COM 		 * most cases.
288611878SVenu.Iyer@Sun.COM 		 */
288711878SVenu.Iyer@Sun.COM 		ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
288811878SVenu.Iyer@Sun.COM 		if (ixgbe->num_rx_groups == 1) {
288911878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = min(8, ring_per_group);
289011878SVenu.Iyer@Sun.COM 		} else if (ixgbe->num_rx_groups <= 32) {
289111878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
289211878SVenu.Iyer@Sun.COM 			    min(4, ring_per_group);
289311878SVenu.Iyer@Sun.COM 		} else if (ixgbe->num_rx_groups <= 64) {
289411878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
289511878SVenu.Iyer@Sun.COM 			    min(2, ring_per_group);
289611878SVenu.Iyer@Sun.COM 		}
289711878SVenu.Iyer@Sun.COM 		break;
289811878SVenu.Iyer@Sun.COM 
289911878SVenu.Iyer@Sun.COM 	default:
290011878SVenu.Iyer@Sun.COM 		break;
290111878SVenu.Iyer@Sun.COM 	}
290211878SVenu.Iyer@Sun.COM 
290311878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
290411878SVenu.Iyer@Sun.COM 
290511878SVenu.Iyer@Sun.COM 	if (ixgbe->num_rx_groups == 1 && ring_per_group == 1) {
290611878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
290711878SVenu.Iyer@Sun.COM 	} else if (ixgbe->num_rx_groups != 1 && ring_per_group == 1) {
290811878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ;
290911878SVenu.Iyer@Sun.COM 	} else if (ixgbe->num_rx_groups != 1 && ring_per_group != 1) {
291011878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ_RSS;
291111878SVenu.Iyer@Sun.COM 	} else {
291211878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_RSS;
291311878SVenu.Iyer@Sun.COM 	}
291411878SVenu.Iyer@Sun.COM 
291512003SPaul.Guo@Sun.COM 	IXGBE_DEBUGLOG_2(ixgbe, "rx group number:%d, rx ring number:%d",
291611878SVenu.Iyer@Sun.COM 	    ixgbe->num_rx_groups, ixgbe->num_rx_rings);
291711878SVenu.Iyer@Sun.COM }
291811878SVenu.Iyer@Sun.COM 
291911878SVenu.Iyer@Sun.COM /*
29206621Sbt150084  * ixgbe_get_conf - Get driver configurations set in driver.conf.
29216621Sbt150084  *
29226621Sbt150084  * This routine gets user-configured values out of the configuration
29236621Sbt150084  * file ixgbe.conf.
29246621Sbt150084  *
29256621Sbt150084  * For each configurable value, there is a minimum, a maximum, and a
29266621Sbt150084  * default.
29276621Sbt150084  * If user does not configure a value, use the default.
29286621Sbt150084  * If user configures below the minimum, use the minumum.
29296621Sbt150084  * If user configures above the maximum, use the maxumum.
29306621Sbt150084  */
29316621Sbt150084 static void
ixgbe_get_conf(ixgbe_t * ixgbe)29326621Sbt150084 ixgbe_get_conf(ixgbe_t *ixgbe)
29336621Sbt150084 {
29346621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
29356621Sbt150084 	uint32_t flow_control;
29366621Sbt150084 
29376621Sbt150084 	/*
29386621Sbt150084 	 * ixgbe driver supports the following user configurations:
29396621Sbt150084 	 *
29406621Sbt150084 	 * Jumbo frame configuration:
29416621Sbt150084 	 *    default_mtu
29426621Sbt150084 	 *
29436621Sbt150084 	 * Ethernet flow control configuration:
29446621Sbt150084 	 *    flow_control
29456621Sbt150084 	 *
29466621Sbt150084 	 * Multiple rings configurations:
29476621Sbt150084 	 *    tx_queue_number
29486621Sbt150084 	 *    tx_ring_size
29496621Sbt150084 	 *    rx_queue_number
29506621Sbt150084 	 *    rx_ring_size
29516621Sbt150084 	 *
29526621Sbt150084 	 * Call ixgbe_get_prop() to get the value for a specific
29536621Sbt150084 	 * configuration parameter.
29546621Sbt150084 	 */
29556621Sbt150084 
29566621Sbt150084 	/*
29576621Sbt150084 	 * Jumbo frame configuration - max_frame_size controls host buffer
29586621Sbt150084 	 * allocation, so includes MTU, ethernet header, vlan tag and
29596621Sbt150084 	 * frame check sequence.
29606621Sbt150084 	 */
29616621Sbt150084 	ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU,
296211150SZhen.W@Sun.COM 	    MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU);
29636621Sbt150084 
29646621Sbt150084 	ixgbe->max_frame_size = ixgbe->default_mtu +
29656621Sbt150084 	    sizeof (struct ether_vlan_header) + ETHERFCSL;
29666621Sbt150084 
29676621Sbt150084 	/*
29686621Sbt150084 	 * Ethernet flow control configuration
29696621Sbt150084 	 */
29706621Sbt150084 	flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL,
29718275SEric Cheng 	    ixgbe_fc_none, 3, ixgbe_fc_none);
29726621Sbt150084 	if (flow_control == 3)
29736621Sbt150084 		flow_control = ixgbe_fc_default;
29746621Sbt150084 
29759353SSamuel.Tu@Sun.COM 	/*
29769353SSamuel.Tu@Sun.COM 	 * fc.requested mode is what the user requests.  After autoneg,
29779353SSamuel.Tu@Sun.COM 	 * fc.current_mode will be the flow_control mode that was negotiated.
29789353SSamuel.Tu@Sun.COM 	 */
29799353SSamuel.Tu@Sun.COM 	hw->fc.requested_mode = flow_control;
29806621Sbt150084 
29816621Sbt150084 	/*
29826621Sbt150084 	 * Multiple rings configurations
29836621Sbt150084 	 */
29846621Sbt150084 	ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM,
29858490SPaul.Guo@Sun.COM 	    ixgbe->capab->min_tx_que_num,
29868490SPaul.Guo@Sun.COM 	    ixgbe->capab->max_tx_que_num,
29878490SPaul.Guo@Sun.COM 	    ixgbe->capab->def_tx_que_num);
29886621Sbt150084 	ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE,
29896621Sbt150084 	    MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE);
29906621Sbt150084 
29916621Sbt150084 	ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM,
29928490SPaul.Guo@Sun.COM 	    ixgbe->capab->min_rx_que_num,
29938490SPaul.Guo@Sun.COM 	    ixgbe->capab->max_rx_que_num,
29948490SPaul.Guo@Sun.COM 	    ixgbe->capab->def_rx_que_num);
29956621Sbt150084 	ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE,
29966621Sbt150084 	    MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE);
29976621Sbt150084 
29986621Sbt150084 	/*
29998275SEric Cheng 	 * Multiple groups configuration
30008275SEric Cheng 	 */
30018275SEric Cheng 	ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM,
300211878SVenu.Iyer@Sun.COM 	    ixgbe->capab->min_rx_grp_num, ixgbe->capab->max_rx_grp_num,
300311878SVenu.Iyer@Sun.COM 	    ixgbe->capab->def_rx_grp_num);
30048275SEric Cheng 
30058275SEric Cheng 	ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE,
30068275SEric Cheng 	    0, 1, DEFAULT_MR_ENABLE);
30078275SEric Cheng 
30088275SEric Cheng 	if (ixgbe->mr_enable == B_FALSE) {
30098275SEric Cheng 		ixgbe->num_tx_rings = 1;
30108275SEric Cheng 		ixgbe->num_rx_rings = 1;
30118275SEric Cheng 		ixgbe->num_rx_groups = 1;
301211878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
301311878SVenu.Iyer@Sun.COM 	} else {
301411878SVenu.Iyer@Sun.COM 		ixgbe->num_rx_rings = ixgbe->num_rx_groups *
301511878SVenu.Iyer@Sun.COM 		    max(ixgbe->num_rx_rings / ixgbe->num_rx_groups, 1);
301611878SVenu.Iyer@Sun.COM 		/*
301711878SVenu.Iyer@Sun.COM 		 * The combination of num_rx_rings and num_rx_groups
301811878SVenu.Iyer@Sun.COM 		 * may be not supported by h/w. We need to adjust
301911878SVenu.Iyer@Sun.COM 		 * them to appropriate values.
302011878SVenu.Iyer@Sun.COM 		 */
302111878SVenu.Iyer@Sun.COM 		ixgbe_setup_vmdq_rss_conf(ixgbe);
30228275SEric Cheng 	}
30238275SEric Cheng 
30248275SEric Cheng 	/*
30256621Sbt150084 	 * Tunable used to force an interrupt type. The only use is
30266621Sbt150084 	 * for testing of the lesser interrupt types.
30276621Sbt150084 	 * 0 = don't force interrupt type
30288275SEric Cheng 	 * 1 = force interrupt type MSI-X
30296621Sbt150084 	 * 2 = force interrupt type MSI
30306621Sbt150084 	 * 3 = force interrupt type Legacy
30316621Sbt150084 	 */
30326621Sbt150084 	ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE,
30336621Sbt150084 	    IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE);
30346621Sbt150084 
30356621Sbt150084 	ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE,
30367167Sgg161487 	    0, 1, DEFAULT_TX_HCKSUM_ENABLE);
30376621Sbt150084 	ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE,
30387167Sgg161487 	    0, 1, DEFAULT_RX_HCKSUM_ENABLE);
30396621Sbt150084 	ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE,
30407167Sgg161487 	    0, 1, DEFAULT_LSO_ENABLE);
304111486SZhen.W@Sun.COM 	ixgbe->lro_enable = ixgbe_get_prop(ixgbe, PROP_LRO_ENABLE,
304211486SZhen.W@Sun.COM 	    0, 1, DEFAULT_LRO_ENABLE);
30436621Sbt150084 	ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE,
30447167Sgg161487 	    0, 1, DEFAULT_TX_HEAD_WB_ENABLE);
3045*13006SChenlu.Chen@Sun.COM 	ixgbe->relax_order_enable = ixgbe_get_prop(ixgbe,
3046*13006SChenlu.Chen@Sun.COM 	    PROP_RELAX_ORDER_ENABLE, 0, 1, DEFAULT_RELAX_ORDER_ENABLE);
30477167Sgg161487 
30489353SSamuel.Tu@Sun.COM 	/* Head Write Back not recommended for 82599 */
30499353SSamuel.Tu@Sun.COM 	if (hw->mac.type >= ixgbe_mac_82599EB) {
30509353SSamuel.Tu@Sun.COM 		ixgbe->tx_head_wb_enable = B_FALSE;
30519353SSamuel.Tu@Sun.COM 	}
30529353SSamuel.Tu@Sun.COM 
30537167Sgg161487 	/*
30547167Sgg161487 	 * ixgbe LSO needs the tx h/w checksum support.
30557167Sgg161487 	 * LSO will be disabled if tx h/w checksum is not
30567167Sgg161487 	 * enabled.
30577167Sgg161487 	 */
30587167Sgg161487 	if (ixgbe->tx_hcksum_enable == B_FALSE) {
30597167Sgg161487 		ixgbe->lso_enable = B_FALSE;
30607167Sgg161487 	}
30616621Sbt150084 
306211486SZhen.W@Sun.COM 	/*
306311486SZhen.W@Sun.COM 	 * ixgbe LRO needs the rx h/w checksum support.
306411486SZhen.W@Sun.COM 	 * LRO will be disabled if rx h/w checksum is not
306511486SZhen.W@Sun.COM 	 * enabled.
306611486SZhen.W@Sun.COM 	 */
306711486SZhen.W@Sun.COM 	if (ixgbe->rx_hcksum_enable == B_FALSE) {
306811486SZhen.W@Sun.COM 		ixgbe->lro_enable = B_FALSE;
306911486SZhen.W@Sun.COM 	}
307011486SZhen.W@Sun.COM 
307111486SZhen.W@Sun.COM 	/*
307211486SZhen.W@Sun.COM 	 * ixgbe LRO only been supported by 82599 now
307311486SZhen.W@Sun.COM 	 */
307411486SZhen.W@Sun.COM 	if (hw->mac.type != ixgbe_mac_82599EB) {
307511486SZhen.W@Sun.COM 		ixgbe->lro_enable = B_FALSE;
307611486SZhen.W@Sun.COM 	}
30776621Sbt150084 	ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD,
30786621Sbt150084 	    MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD,
30796621Sbt150084 	    DEFAULT_TX_COPY_THRESHOLD);
30806621Sbt150084 	ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe,
30816621Sbt150084 	    PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD,
30826621Sbt150084 	    MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD);
30836621Sbt150084 	ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe,
30846621Sbt150084 	    PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD,
30856621Sbt150084 	    MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD);
30866621Sbt150084 	ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe,
30876621Sbt150084 	    PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD,
30886621Sbt150084 	    MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD);
30896621Sbt150084 
30906621Sbt150084 	ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD,
30916621Sbt150084 	    MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD,
30926621Sbt150084 	    DEFAULT_RX_COPY_THRESHOLD);
30936621Sbt150084 	ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR,
30946621Sbt150084 	    MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR,
30956621Sbt150084 	    DEFAULT_RX_LIMIT_PER_INTR);
30966621Sbt150084 
309710376SChenlu.Chen@Sun.COM 	ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING,
309810376SChenlu.Chen@Sun.COM 	    ixgbe->capab->min_intr_throttle,
309910376SChenlu.Chen@Sun.COM 	    ixgbe->capab->max_intr_throttle,
310010376SChenlu.Chen@Sun.COM 	    ixgbe->capab->def_intr_throttle);
31019353SSamuel.Tu@Sun.COM 	/*
310210376SChenlu.Chen@Sun.COM 	 * 82599 requires the interupt throttling rate is
310310376SChenlu.Chen@Sun.COM 	 * a multiple of 8. This is enforced by the register
310410376SChenlu.Chen@Sun.COM 	 * definiton.
31059353SSamuel.Tu@Sun.COM 	 */
310610376SChenlu.Chen@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB)
310710376SChenlu.Chen@Sun.COM 		ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8;
310810376SChenlu.Chen@Sun.COM }
310910376SChenlu.Chen@Sun.COM 
311010376SChenlu.Chen@Sun.COM static void
ixgbe_init_params(ixgbe_t * ixgbe)311110376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe_t *ixgbe)
311210376SChenlu.Chen@Sun.COM {
311310376SChenlu.Chen@Sun.COM 	ixgbe->param_en_10000fdx_cap = 1;
311410376SChenlu.Chen@Sun.COM 	ixgbe->param_en_1000fdx_cap = 1;
311510376SChenlu.Chen@Sun.COM 	ixgbe->param_en_100fdx_cap = 1;
311610376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_10000fdx_cap = 1;
311710376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_1000fdx_cap = 1;
311810376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_100fdx_cap = 1;
311910376SChenlu.Chen@Sun.COM 
312010376SChenlu.Chen@Sun.COM 	ixgbe->param_pause_cap = 1;
312110376SChenlu.Chen@Sun.COM 	ixgbe->param_asym_pause_cap = 1;
312210376SChenlu.Chen@Sun.COM 	ixgbe->param_rem_fault = 0;
312310376SChenlu.Chen@Sun.COM 
312410376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_autoneg_cap = 1;
312510376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_pause_cap = 1;
312610376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_asym_pause_cap = 1;
312710376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_rem_fault = 0;
312810376SChenlu.Chen@Sun.COM 
312910376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_10000fdx_cap = 0;
313010376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_1000fdx_cap = 0;
313110376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_100fdx_cap = 0;
313210376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_autoneg_cap = 0;
313310376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_pause_cap = 0;
313410376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_asym_pause_cap = 0;
313510376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_rem_fault = 0;
31366621Sbt150084 }
31376621Sbt150084 
31386621Sbt150084 /*
31396621Sbt150084  * ixgbe_get_prop - Get a property value out of the configuration file
31406621Sbt150084  * ixgbe.conf.
31416621Sbt150084  *
31426621Sbt150084  * Caller provides the name of the property, a default value, a minimum
31436621Sbt150084  * value, and a maximum value.
31446621Sbt150084  *
31456621Sbt150084  * Return configured value of the property, with default, minimum and
31466621Sbt150084  * maximum properly applied.
31476621Sbt150084  */
31486621Sbt150084 static int
ixgbe_get_prop(ixgbe_t * ixgbe,char * propname,int minval,int maxval,int defval)31496621Sbt150084 ixgbe_get_prop(ixgbe_t *ixgbe,
31506621Sbt150084     char *propname,	/* name of the property */
31516621Sbt150084     int minval,		/* minimum acceptable value */
31526621Sbt150084     int maxval,		/* maximim acceptable value */
31536621Sbt150084     int defval)		/* default value */
31546621Sbt150084 {
31556621Sbt150084 	int value;
31566621Sbt150084 
31576621Sbt150084 	/*
31586621Sbt150084 	 * Call ddi_prop_get_int() to read the conf settings
31596621Sbt150084 	 */
31606621Sbt150084 	value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip,
31616621Sbt150084 	    DDI_PROP_DONTPASS, propname, defval);
31626621Sbt150084 	if (value > maxval)
31636621Sbt150084 		value = maxval;
31646621Sbt150084 
31656621Sbt150084 	if (value < minval)
31666621Sbt150084 		value = minval;
31676621Sbt150084 
31686621Sbt150084 	return (value);
31696621Sbt150084 }
31706621Sbt150084 
31716621Sbt150084 /*
31726621Sbt150084  * ixgbe_driver_setup_link - Using the link properties to setup the link.
31736621Sbt150084  */
31746621Sbt150084 int
ixgbe_driver_setup_link(ixgbe_t * ixgbe,boolean_t setup_hw)31756621Sbt150084 ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw)
31766621Sbt150084 {
317710998SChenlu.Chen@Sun.COM 	u32 autoneg_advertised = 0;
317810998SChenlu.Chen@Sun.COM 
317910998SChenlu.Chen@Sun.COM 	/*
318010998SChenlu.Chen@Sun.COM 	 * No half duplex support with 10Gb parts
318110998SChenlu.Chen@Sun.COM 	 */
318210998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_10000fdx_cap == 1)
318310998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
318410998SChenlu.Chen@Sun.COM 
318510998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_1000fdx_cap == 1)
318610998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
318710998SChenlu.Chen@Sun.COM 
318810998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_100fdx_cap == 1)
318910998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
319010998SChenlu.Chen@Sun.COM 
319110998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_autoneg_cap == 1 && autoneg_advertised == 0) {
319210998SChenlu.Chen@Sun.COM 		ixgbe_notice(ixgbe, "Invalid link settings. Setup link "
319310998SChenlu.Chen@Sun.COM 		    "to autonegotiation with full link capabilities.");
319410998SChenlu.Chen@Sun.COM 
319510998SChenlu.Chen@Sun.COM 		autoneg_advertised = IXGBE_LINK_SPEED_10GB_FULL |
319610998SChenlu.Chen@Sun.COM 		    IXGBE_LINK_SPEED_1GB_FULL |
319710998SChenlu.Chen@Sun.COM 		    IXGBE_LINK_SPEED_100_FULL;
31986621Sbt150084 	}
31996621Sbt150084 
32006621Sbt150084 	if (setup_hw) {
320110998SChenlu.Chen@Sun.COM 		if (ixgbe_setup_link(&ixgbe->hw, autoneg_advertised,
320210998SChenlu.Chen@Sun.COM 		    ixgbe->param_adv_autoneg_cap, B_TRUE) != IXGBE_SUCCESS) {
32039353SSamuel.Tu@Sun.COM 			ixgbe_notice(ixgbe, "Setup link failed on this "
32049353SSamuel.Tu@Sun.COM 			    "device.");
32056621Sbt150084 			return (IXGBE_FAILURE);
32069353SSamuel.Tu@Sun.COM 		}
32076621Sbt150084 	}
32086621Sbt150084 
32096621Sbt150084 	return (IXGBE_SUCCESS);
32106621Sbt150084 }
32116621Sbt150084 
32126621Sbt150084 /*
321311233SPaul.Guo@Sun.COM  * ixgbe_driver_link_check - Link status processing.
321411233SPaul.Guo@Sun.COM  *
321511233SPaul.Guo@Sun.COM  * This function can be called in both kernel context and interrupt context
32166621Sbt150084  */
32178490SPaul.Guo@Sun.COM static void
ixgbe_driver_link_check(ixgbe_t * ixgbe)321811233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe_t *ixgbe)
32196621Sbt150084 {
32206621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
32216621Sbt150084 	ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
32226621Sbt150084 	boolean_t link_up = B_FALSE;
32236621Sbt150084 	boolean_t link_changed = B_FALSE;
32246621Sbt150084 
322511233SPaul.Guo@Sun.COM 	ASSERT(mutex_owned(&ixgbe->gen_lock));
322611233SPaul.Guo@Sun.COM 
322711233SPaul.Guo@Sun.COM 	(void) ixgbe_check_link(hw, &speed, &link_up, false);
32286621Sbt150084 	if (link_up) {
322911233SPaul.Guo@Sun.COM 		ixgbe->link_check_complete = B_TRUE;
323011233SPaul.Guo@Sun.COM 
32319353SSamuel.Tu@Sun.COM 		/* Link is up, enable flow control settings */
32329353SSamuel.Tu@Sun.COM 		(void) ixgbe_fc_enable(hw, 0);
32339353SSamuel.Tu@Sun.COM 
32346621Sbt150084 		/*
32356621Sbt150084 		 * The Link is up, check whether it was marked as down earlier
32366621Sbt150084 		 */
32376621Sbt150084 		if (ixgbe->link_state != LINK_STATE_UP) {
32386621Sbt150084 			switch (speed) {
32399353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_10GB_FULL:
32409353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_10GB;
32419353SSamuel.Tu@Sun.COM 				break;
32429353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_1GB_FULL:
32439353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_1GB;
32449353SSamuel.Tu@Sun.COM 				break;
32459353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_100_FULL:
32469353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_100;
32476621Sbt150084 			}
32486621Sbt150084 			ixgbe->link_duplex = LINK_DUPLEX_FULL;
32496621Sbt150084 			ixgbe->link_state = LINK_STATE_UP;
32506621Sbt150084 			link_changed = B_TRUE;
32516621Sbt150084 		}
32526621Sbt150084 	} else {
325311233SPaul.Guo@Sun.COM 		if (ixgbe->link_check_complete == B_TRUE ||
325411233SPaul.Guo@Sun.COM 		    (ixgbe->link_check_complete == B_FALSE &&
325511233SPaul.Guo@Sun.COM 		    gethrtime() >= ixgbe->link_check_hrtime)) {
325611233SPaul.Guo@Sun.COM 			/*
325711233SPaul.Guo@Sun.COM 			 * The link is really down
325811233SPaul.Guo@Sun.COM 			 */
325911233SPaul.Guo@Sun.COM 			ixgbe->link_check_complete = B_TRUE;
326011233SPaul.Guo@Sun.COM 
326111233SPaul.Guo@Sun.COM 			if (ixgbe->link_state != LINK_STATE_DOWN) {
326211233SPaul.Guo@Sun.COM 				ixgbe->link_speed = 0;
326311233SPaul.Guo@Sun.COM 				ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN;
326411233SPaul.Guo@Sun.COM 				ixgbe->link_state = LINK_STATE_DOWN;
326511233SPaul.Guo@Sun.COM 				link_changed = B_TRUE;
326611233SPaul.Guo@Sun.COM 			}
32676621Sbt150084 		}
32686621Sbt150084 	}
32696621Sbt150084 
32708490SPaul.Guo@Sun.COM 	/*
327111233SPaul.Guo@Sun.COM 	 * If we are in an interrupt context, need to re-enable the
327211233SPaul.Guo@Sun.COM 	 * interrupt, which was automasked
327311233SPaul.Guo@Sun.COM 	 */
327411233SPaul.Guo@Sun.COM 	if (servicing_interrupt() != 0) {
327511233SPaul.Guo@Sun.COM 		ixgbe->eims |= IXGBE_EICR_LSC;
327611233SPaul.Guo@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
327711233SPaul.Guo@Sun.COM 	}
327811233SPaul.Guo@Sun.COM 
32798490SPaul.Guo@Sun.COM 	if (link_changed) {
32808490SPaul.Guo@Sun.COM 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
32818490SPaul.Guo@Sun.COM 	}
32826621Sbt150084 }
32836621Sbt150084 
32846621Sbt150084 /*
32859353SSamuel.Tu@Sun.COM  * ixgbe_sfp_check - sfp module processing done in taskq only for 82599.
32869353SSamuel.Tu@Sun.COM  */
32879353SSamuel.Tu@Sun.COM static void
ixgbe_sfp_check(void * arg)32889353SSamuel.Tu@Sun.COM ixgbe_sfp_check(void *arg)
32899353SSamuel.Tu@Sun.COM {
32909353SSamuel.Tu@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
32919353SSamuel.Tu@Sun.COM 	uint32_t eicr = ixgbe->eicr;
32929353SSamuel.Tu@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
32939353SSamuel.Tu@Sun.COM 
329411233SPaul.Guo@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
32959353SSamuel.Tu@Sun.COM 	if (eicr & IXGBE_EICR_GPI_SDP1) {
32969353SSamuel.Tu@Sun.COM 		/* clear the interrupt */
32979353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
32989353SSamuel.Tu@Sun.COM 
32999353SSamuel.Tu@Sun.COM 		/* if link up, do multispeed fiber setup */
330010998SChenlu.Chen@Sun.COM 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
330110998SChenlu.Chen@Sun.COM 		    B_TRUE, B_TRUE);
33029353SSamuel.Tu@Sun.COM 		ixgbe_driver_link_check(ixgbe);
3303*13006SChenlu.Chen@Sun.COM 		ixgbe_get_hw_state(ixgbe);
33049353SSamuel.Tu@Sun.COM 	} else if (eicr & IXGBE_EICR_GPI_SDP2) {
33059353SSamuel.Tu@Sun.COM 		/* clear the interrupt */
33069353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
33079353SSamuel.Tu@Sun.COM 
33089353SSamuel.Tu@Sun.COM 		/* if link up, do sfp module setup */
33099353SSamuel.Tu@Sun.COM 		(void) hw->mac.ops.setup_sfp(hw);
33109353SSamuel.Tu@Sun.COM 
33119353SSamuel.Tu@Sun.COM 		/* do multispeed fiber setup */
331210998SChenlu.Chen@Sun.COM 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
331310998SChenlu.Chen@Sun.COM 		    B_TRUE, B_TRUE);
33149353SSamuel.Tu@Sun.COM 		ixgbe_driver_link_check(ixgbe);
3315*13006SChenlu.Chen@Sun.COM 		ixgbe_get_hw_state(ixgbe);
3316*13006SChenlu.Chen@Sun.COM 	}
3317*13006SChenlu.Chen@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
3318*13006SChenlu.Chen@Sun.COM 
3319*13006SChenlu.Chen@Sun.COM 	/*
3320*13006SChenlu.Chen@Sun.COM 	 * We need to fully re-check the link later.
3321*13006SChenlu.Chen@Sun.COM 	 */
3322*13006SChenlu.Chen@Sun.COM 	ixgbe->link_check_complete = B_FALSE;
3323*13006SChenlu.Chen@Sun.COM 	ixgbe->link_check_hrtime = gethrtime() +
3324*13006SChenlu.Chen@Sun.COM 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
3325*13006SChenlu.Chen@Sun.COM }
3326*13006SChenlu.Chen@Sun.COM 
3327*13006SChenlu.Chen@Sun.COM /*
3328*13006SChenlu.Chen@Sun.COM  * ixgbe_overtemp_check - overtemp module processing done in taskq
3329*13006SChenlu.Chen@Sun.COM  *
3330*13006SChenlu.Chen@Sun.COM  * This routine will only be called on adapters with temperature sensor.
3331*13006SChenlu.Chen@Sun.COM  * The indication of over-temperature can be either SDP0 interrupt or the link
3332*13006SChenlu.Chen@Sun.COM  * status change interrupt.
3333*13006SChenlu.Chen@Sun.COM  */
3334*13006SChenlu.Chen@Sun.COM static void
ixgbe_overtemp_check(void * arg)3335*13006SChenlu.Chen@Sun.COM ixgbe_overtemp_check(void *arg)
3336*13006SChenlu.Chen@Sun.COM {
3337*13006SChenlu.Chen@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
3338*13006SChenlu.Chen@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
3339*13006SChenlu.Chen@Sun.COM 	uint32_t eicr = ixgbe->eicr;
3340*13006SChenlu.Chen@Sun.COM 	ixgbe_link_speed speed;
3341*13006SChenlu.Chen@Sun.COM 	boolean_t link_up;
3342*13006SChenlu.Chen@Sun.COM 
3343*13006SChenlu.Chen@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
3344*13006SChenlu.Chen@Sun.COM 
3345*13006SChenlu.Chen@Sun.COM 	/* make sure we know current state of link */
3346*13006SChenlu.Chen@Sun.COM 	(void) ixgbe_check_link(hw, &speed, &link_up, false);
3347*13006SChenlu.Chen@Sun.COM 
3348*13006SChenlu.Chen@Sun.COM 	/* check over-temp condition */
3349*13006SChenlu.Chen@Sun.COM 	if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
3350*13006SChenlu.Chen@Sun.COM 	    (eicr & IXGBE_EICR_LSC)) {
3351*13006SChenlu.Chen@Sun.COM 		if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) {
3352*13006SChenlu.Chen@Sun.COM 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
3353*13006SChenlu.Chen@Sun.COM 
3354*13006SChenlu.Chen@Sun.COM 			/*
3355*13006SChenlu.Chen@Sun.COM 			 * Disable the adapter interrupts
3356*13006SChenlu.Chen@Sun.COM 			 */
3357*13006SChenlu.Chen@Sun.COM 			ixgbe_disable_adapter_interrupts(ixgbe);
3358*13006SChenlu.Chen@Sun.COM 
3359*13006SChenlu.Chen@Sun.COM 			/*
3360*13006SChenlu.Chen@Sun.COM 			 * Disable Rx/Tx units
3361*13006SChenlu.Chen@Sun.COM 			 */
3362*13006SChenlu.Chen@Sun.COM 			(void) ixgbe_stop_adapter(hw);
3363*13006SChenlu.Chen@Sun.COM 
3364*13006SChenlu.Chen@Sun.COM 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
3365*13006SChenlu.Chen@Sun.COM 			ixgbe_error(ixgbe,
3366*13006SChenlu.Chen@Sun.COM 			    "Problem: Network adapter has been stopped "
3367*13006SChenlu.Chen@Sun.COM 			    "because it has overheated");
3368*13006SChenlu.Chen@Sun.COM 			ixgbe_error(ixgbe,
3369*13006SChenlu.Chen@Sun.COM 			    "Action: Restart the computer. "
3370*13006SChenlu.Chen@Sun.COM 			    "If the problem persists, power off the system "
3371*13006SChenlu.Chen@Sun.COM 			    "and replace the adapter");
3372*13006SChenlu.Chen@Sun.COM 		}
3373*13006SChenlu.Chen@Sun.COM 	}
3374*13006SChenlu.Chen@Sun.COM 
3375*13006SChenlu.Chen@Sun.COM 	/* write to clear the interrupt */
3376*13006SChenlu.Chen@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
3377*13006SChenlu.Chen@Sun.COM 
337811233SPaul.Guo@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
337911233SPaul.Guo@Sun.COM }
338011233SPaul.Guo@Sun.COM 
338111233SPaul.Guo@Sun.COM /*
338211233SPaul.Guo@Sun.COM  * ixgbe_link_timer - timer for link status detection
338311233SPaul.Guo@Sun.COM  */
338411233SPaul.Guo@Sun.COM static void
ixgbe_link_timer(void * arg)338511233SPaul.Guo@Sun.COM ixgbe_link_timer(void *arg)
338611233SPaul.Guo@Sun.COM {
338711233SPaul.Guo@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
338811233SPaul.Guo@Sun.COM 
338911233SPaul.Guo@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
339011233SPaul.Guo@Sun.COM 	ixgbe_driver_link_check(ixgbe);
339111233SPaul.Guo@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
33929353SSamuel.Tu@Sun.COM }
33939353SSamuel.Tu@Sun.COM 
33949353SSamuel.Tu@Sun.COM /*
33956621Sbt150084  * ixgbe_local_timer - Driver watchdog function.
33966621Sbt150084  *
339711233SPaul.Guo@Sun.COM  * This function will handle the transmit stall check and other routines.
33986621Sbt150084  */
33996621Sbt150084 static void
ixgbe_local_timer(void * arg)34006621Sbt150084 ixgbe_local_timer(void *arg)
34016621Sbt150084 {
34026621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
34036621Sbt150084 
3404*13006SChenlu.Chen@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_OVERTEMP)
3405*13006SChenlu.Chen@Sun.COM 		goto out;
3406*13006SChenlu.Chen@Sun.COM 
340711233SPaul.Guo@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_ERROR) {
34086621Sbt150084 		ixgbe->reset_count++;
34096621Sbt150084 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
34106621Sbt150084 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
3411*13006SChenlu.Chen@Sun.COM 		goto out;
34126621Sbt150084 	}
34136621Sbt150084 
341411233SPaul.Guo@Sun.COM 	if (ixgbe_stall_check(ixgbe)) {
341511233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL);
341611233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
341711233SPaul.Guo@Sun.COM 
341811233SPaul.Guo@Sun.COM 		ixgbe->reset_count++;
341911233SPaul.Guo@Sun.COM 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
342011233SPaul.Guo@Sun.COM 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
342111233SPaul.Guo@Sun.COM 	}
342211486SZhen.W@Sun.COM 
3423*13006SChenlu.Chen@Sun.COM out:
342411486SZhen.W@Sun.COM 	ixgbe_restart_watchdog_timer(ixgbe);
34256621Sbt150084 }
34266621Sbt150084 
34276621Sbt150084 /*
34286621Sbt150084  * ixgbe_stall_check - Check for transmit stall.
34296621Sbt150084  *
34306621Sbt150084  * This function checks if the adapter is stalled (in transmit).
34316621Sbt150084  *
34326621Sbt150084  * It is called each time the watchdog timeout is invoked.
34336621Sbt150084  * If the transmit descriptor reclaim continuously fails,
34346621Sbt150084  * the watchdog value will increment by 1. If the watchdog
34356621Sbt150084  * value exceeds the threshold, the ixgbe is assumed to
34366621Sbt150084  * have stalled and need to be reset.
34376621Sbt150084  */
34386621Sbt150084 static boolean_t
ixgbe_stall_check(ixgbe_t * ixgbe)34396621Sbt150084 ixgbe_stall_check(ixgbe_t *ixgbe)
34406621Sbt150084 {
34416621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
34426621Sbt150084 	boolean_t result;
34436621Sbt150084 	int i;
34446621Sbt150084 
34456621Sbt150084 	if (ixgbe->link_state != LINK_STATE_UP)
34466621Sbt150084 		return (B_FALSE);
34476621Sbt150084 
34486621Sbt150084 	/*
34496621Sbt150084 	 * If any tx ring is stalled, we'll reset the chipset
34506621Sbt150084 	 */
34516621Sbt150084 	result = B_FALSE;
34526621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
34536621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
345410376SChenlu.Chen@Sun.COM 		if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) {
345510305SPaul.Guo@Sun.COM 			tx_ring->tx_recycle(tx_ring);
345610305SPaul.Guo@Sun.COM 		}
34576621Sbt150084 
34586621Sbt150084 		if (tx_ring->recycle_fail > 0)
34596621Sbt150084 			tx_ring->stall_watchdog++;
34606621Sbt150084 		else
34616621Sbt150084 			tx_ring->stall_watchdog = 0;
34626621Sbt150084 
34636621Sbt150084 		if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) {
34646621Sbt150084 			result = B_TRUE;
34656621Sbt150084 			break;
34666621Sbt150084 		}
34676621Sbt150084 	}
34686621Sbt150084 
34696621Sbt150084 	if (result) {
34706621Sbt150084 		tx_ring->stall_watchdog = 0;
34716621Sbt150084 		tx_ring->recycle_fail = 0;
34726621Sbt150084 	}
34736621Sbt150084 
34746621Sbt150084 	return (result);
34756621Sbt150084 }
34766621Sbt150084 
34776621Sbt150084 
34786621Sbt150084 /*
34796621Sbt150084  * is_valid_mac_addr - Check if the mac address is valid.
34806621Sbt150084  */
34816621Sbt150084 static boolean_t
is_valid_mac_addr(uint8_t * mac_addr)34826621Sbt150084 is_valid_mac_addr(uint8_t *mac_addr)
34836621Sbt150084 {
34846621Sbt150084 	const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 };
34856621Sbt150084 	const uint8_t addr_test2[6] =
34866621Sbt150084 	    { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
34876621Sbt150084 
34886621Sbt150084 	if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) ||
34896621Sbt150084 	    !(bcmp(addr_test2, mac_addr, ETHERADDRL)))
34906621Sbt150084 		return (B_FALSE);
34916621Sbt150084 
34926621Sbt150084 	return (B_TRUE);
34936621Sbt150084 }
34946621Sbt150084 
34956621Sbt150084 static boolean_t
ixgbe_find_mac_address(ixgbe_t * ixgbe)34966621Sbt150084 ixgbe_find_mac_address(ixgbe_t *ixgbe)
34976621Sbt150084 {
34986621Sbt150084 #ifdef __sparc
34996621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
35006621Sbt150084 	uchar_t *bytes;
35016621Sbt150084 	struct ether_addr sysaddr;
35026621Sbt150084 	uint_t nelts;
35036621Sbt150084 	int err;
35046621Sbt150084 	boolean_t found = B_FALSE;
35056621Sbt150084 
35066621Sbt150084 	/*
35076621Sbt150084 	 * The "vendor's factory-set address" may already have
35086621Sbt150084 	 * been extracted from the chip, but if the property
35096621Sbt150084 	 * "local-mac-address" is set we use that instead.
35106621Sbt150084 	 *
35116621Sbt150084 	 * We check whether it looks like an array of 6
35126621Sbt150084 	 * bytes (which it should, if OBP set it).  If we can't
35136621Sbt150084 	 * make sense of it this way, we'll ignore it.
35146621Sbt150084 	 */
35156621Sbt150084 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
35166621Sbt150084 	    DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts);
35176621Sbt150084 	if (err == DDI_PROP_SUCCESS) {
35186621Sbt150084 		if (nelts == ETHERADDRL) {
35196621Sbt150084 			while (nelts--)
35206621Sbt150084 				hw->mac.addr[nelts] = bytes[nelts];
35216621Sbt150084 			found = B_TRUE;
35226621Sbt150084 		}
35236621Sbt150084 		ddi_prop_free(bytes);
35246621Sbt150084 	}
35256621Sbt150084 
35266621Sbt150084 	/*
35276621Sbt150084 	 * Look up the OBP property "local-mac-address?". If the user has set
35286621Sbt150084 	 * 'local-mac-address? = false', use "the system address" instead.
35296621Sbt150084 	 */
35306621Sbt150084 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0,
35316621Sbt150084 	    "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) {
35326621Sbt150084 		if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) {
35336621Sbt150084 			if (localetheraddr(NULL, &sysaddr) != 0) {
35346621Sbt150084 				bcopy(&sysaddr, hw->mac.addr, ETHERADDRL);
35356621Sbt150084 				found = B_TRUE;
35366621Sbt150084 			}
35376621Sbt150084 		}
35386621Sbt150084 		ddi_prop_free(bytes);
35396621Sbt150084 	}
35406621Sbt150084 
35416621Sbt150084 	/*
35426621Sbt150084 	 * Finally(!), if there's a valid "mac-address" property (created
35436621Sbt150084 	 * if we netbooted from this interface), we must use this instead
35446621Sbt150084 	 * of any of the above to ensure that the NFS/install server doesn't
35456621Sbt150084 	 * get confused by the address changing as Solaris takes over!
35466621Sbt150084 	 */
35476621Sbt150084 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
35486621Sbt150084 	    DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts);
35496621Sbt150084 	if (err == DDI_PROP_SUCCESS) {
35506621Sbt150084 		if (nelts == ETHERADDRL) {
35516621Sbt150084 			while (nelts--)
35526621Sbt150084 				hw->mac.addr[nelts] = bytes[nelts];
35536621Sbt150084 			found = B_TRUE;
35546621Sbt150084 		}
35556621Sbt150084 		ddi_prop_free(bytes);
35566621Sbt150084 	}
35576621Sbt150084 
35586621Sbt150084 	if (found) {
35596621Sbt150084 		bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
35606621Sbt150084 		return (B_TRUE);
35616621Sbt150084 	}
35626621Sbt150084 #else
35636621Sbt150084 	_NOTE(ARGUNUSED(ixgbe));
35646621Sbt150084 #endif
35656621Sbt150084 
35666621Sbt150084 	return (B_TRUE);
35676621Sbt150084 }
35686621Sbt150084 
35696621Sbt150084 #pragma inline(ixgbe_arm_watchdog_timer)
35706621Sbt150084 static void
ixgbe_arm_watchdog_timer(ixgbe_t * ixgbe)35716621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe)
35726621Sbt150084 {
35736621Sbt150084 	/*
35746621Sbt150084 	 * Fire a watchdog timer
35756621Sbt150084 	 */
35766621Sbt150084 	ixgbe->watchdog_tid =
35776621Sbt150084 	    timeout(ixgbe_local_timer,
35786621Sbt150084 	    (void *)ixgbe, 1 * drv_usectohz(1000000));
35796621Sbt150084 
35806621Sbt150084 }
35816621Sbt150084 
35826621Sbt150084 /*
35836621Sbt150084  * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer.
35846621Sbt150084  */
35856621Sbt150084 void
ixgbe_enable_watchdog_timer(ixgbe_t * ixgbe)35866621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe)
35876621Sbt150084 {
35886621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
35896621Sbt150084 
35906621Sbt150084 	if (!ixgbe->watchdog_enable) {
35916621Sbt150084 		ixgbe->watchdog_enable = B_TRUE;
35926621Sbt150084 		ixgbe->watchdog_start = B_TRUE;
35936621Sbt150084 		ixgbe_arm_watchdog_timer(ixgbe);
35946621Sbt150084 	}
35956621Sbt150084 
35966621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
35976621Sbt150084 }
35986621Sbt150084 
35996621Sbt150084 /*
36006621Sbt150084  * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer.
36016621Sbt150084  */
36026621Sbt150084 void
ixgbe_disable_watchdog_timer(ixgbe_t * ixgbe)36036621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe)
36046621Sbt150084 {
36056621Sbt150084 	timeout_id_t tid;
36066621Sbt150084 
36076621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
36086621Sbt150084 
36096621Sbt150084 	ixgbe->watchdog_enable = B_FALSE;
36106621Sbt150084 	ixgbe->watchdog_start = B_FALSE;
36116621Sbt150084 	tid = ixgbe->watchdog_tid;
36126621Sbt150084 	ixgbe->watchdog_tid = 0;
36136621Sbt150084 
36146621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
36156621Sbt150084 
36166621Sbt150084 	if (tid != 0)
36176621Sbt150084 		(void) untimeout(tid);
36186621Sbt150084 }
36196621Sbt150084 
36206621Sbt150084 /*
36216621Sbt150084  * ixgbe_start_watchdog_timer - Start the driver watchdog timer.
36226621Sbt150084  */
36238490SPaul.Guo@Sun.COM void
ixgbe_start_watchdog_timer(ixgbe_t * ixgbe)36246621Sbt150084 ixgbe_start_watchdog_timer(ixgbe_t *ixgbe)
36256621Sbt150084 {
36266621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
36276621Sbt150084 
36286621Sbt150084 	if (ixgbe->watchdog_enable) {
36296621Sbt150084 		if (!ixgbe->watchdog_start) {
36306621Sbt150084 			ixgbe->watchdog_start = B_TRUE;
36316621Sbt150084 			ixgbe_arm_watchdog_timer(ixgbe);
36326621Sbt150084 		}
36336621Sbt150084 	}
36346621Sbt150084 
36356621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
36366621Sbt150084 }
36376621Sbt150084 
36386621Sbt150084 /*
36396621Sbt150084  * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer.
36406621Sbt150084  */
36416621Sbt150084 static void
ixgbe_restart_watchdog_timer(ixgbe_t * ixgbe)36426621Sbt150084 ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe)
36436621Sbt150084 {
36446621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
36456621Sbt150084 
36466621Sbt150084 	if (ixgbe->watchdog_start)
36476621Sbt150084 		ixgbe_arm_watchdog_timer(ixgbe);
36486621Sbt150084 
36496621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
36506621Sbt150084 }
36516621Sbt150084 
36526621Sbt150084 /*
36536621Sbt150084  * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer.
36546621Sbt150084  */
36558490SPaul.Guo@Sun.COM void
ixgbe_stop_watchdog_timer(ixgbe_t * ixgbe)36566621Sbt150084 ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe)
36576621Sbt150084 {
36586621Sbt150084 	timeout_id_t tid;
36596621Sbt150084 
36606621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
36616621Sbt150084 
36626621Sbt150084 	ixgbe->watchdog_start = B_FALSE;
36636621Sbt150084 	tid = ixgbe->watchdog_tid;
36646621Sbt150084 	ixgbe->watchdog_tid = 0;
36656621Sbt150084 
36666621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
36676621Sbt150084 
36686621Sbt150084 	if (tid != 0)
36696621Sbt150084 		(void) untimeout(tid);
36706621Sbt150084 }
36716621Sbt150084 
36726621Sbt150084 /*
36736621Sbt150084  * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts.
36746621Sbt150084  */
36756621Sbt150084 static void
ixgbe_disable_adapter_interrupts(ixgbe_t * ixgbe)36766621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe)
36776621Sbt150084 {
36786621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
36796621Sbt150084 
36806621Sbt150084 	/*
36816621Sbt150084 	 * mask all interrupts off
36826621Sbt150084 	 */
36836621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff);
36846621Sbt150084 
36856621Sbt150084 	/*
36866621Sbt150084 	 * for MSI-X, also disable autoclear
36876621Sbt150084 	 */
36886621Sbt150084 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
36896621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0);
36906621Sbt150084 	}
36916621Sbt150084 
36926621Sbt150084 	IXGBE_WRITE_FLUSH(hw);
36936621Sbt150084 }
36946621Sbt150084 
36956621Sbt150084 /*
36966621Sbt150084  * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts.
36976621Sbt150084  */
36986621Sbt150084 static void
ixgbe_enable_adapter_interrupts(ixgbe_t * ixgbe)36996621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe)
37006621Sbt150084 {
37016621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
37028490SPaul.Guo@Sun.COM 	uint32_t eiac, eiam;
37038490SPaul.Guo@Sun.COM 	uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
37048490SPaul.Guo@Sun.COM 
37058490SPaul.Guo@Sun.COM 	/* interrupt types to enable */
37068490SPaul.Guo@Sun.COM 	ixgbe->eims = IXGBE_EIMS_ENABLE_MASK;	/* shared code default */
37078490SPaul.Guo@Sun.COM 	ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER;	/* minus tcp timer */
37088490SPaul.Guo@Sun.COM 	ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */
37098490SPaul.Guo@Sun.COM 
37108490SPaul.Guo@Sun.COM 	/* enable automask on "other" causes that this adapter can generate */
37118490SPaul.Guo@Sun.COM 	eiam = ixgbe->capab->other_intr;
37126621Sbt150084 
37136621Sbt150084 	/*
37146621Sbt150084 	 * msi-x mode
37156621Sbt150084 	 */
37166621Sbt150084 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
37176621Sbt150084 		/* enable autoclear but not on bits 29:20 */
37188490SPaul.Guo@Sun.COM 		eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR);
37196621Sbt150084 
37206621Sbt150084 		/* general purpose interrupt enable */
37218490SPaul.Guo@Sun.COM 		gpie |= (IXGBE_GPIE_MSIX_MODE
37228490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_PBA_SUPPORT
37238490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_OCD
37248490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_EIAME);
37256621Sbt150084 	/*
37266621Sbt150084 	 * non-msi-x mode
37276621Sbt150084 	 */
37286621Sbt150084 	} else {
37296621Sbt150084 
37306621Sbt150084 		/* disable autoclear, leave gpie at default */
37316621Sbt150084 		eiac = 0;
37328490SPaul.Guo@Sun.COM 
37339353SSamuel.Tu@Sun.COM 		/*
37349353SSamuel.Tu@Sun.COM 		 * General purpose interrupt enable.
37359353SSamuel.Tu@Sun.COM 		 * For 82599, extended interrupt automask enable
37369353SSamuel.Tu@Sun.COM 		 * only in MSI or MSI-X mode
37379353SSamuel.Tu@Sun.COM 		 */
37389353SSamuel.Tu@Sun.COM 		if ((hw->mac.type < ixgbe_mac_82599EB) ||
37399353SSamuel.Tu@Sun.COM 		    (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) {
37409353SSamuel.Tu@Sun.COM 			gpie |= IXGBE_GPIE_EIAME;
37419353SSamuel.Tu@Sun.COM 		}
37429353SSamuel.Tu@Sun.COM 	}
3743*13006SChenlu.Chen@Sun.COM 
3744*13006SChenlu.Chen@Sun.COM 	/* Enable specific "other" interrupt types */
3745*13006SChenlu.Chen@Sun.COM 	switch (hw->mac.type) {
3746*13006SChenlu.Chen@Sun.COM 	case ixgbe_mac_82598EB:
3747*13006SChenlu.Chen@Sun.COM 		gpie |= ixgbe->capab->other_gpie;
3748*13006SChenlu.Chen@Sun.COM 		break;
3749*13006SChenlu.Chen@Sun.COM 
3750*13006SChenlu.Chen@Sun.COM 	case ixgbe_mac_82599EB:
3751*13006SChenlu.Chen@Sun.COM 		gpie |= ixgbe->capab->other_gpie;
3752*13006SChenlu.Chen@Sun.COM 
3753*13006SChenlu.Chen@Sun.COM 		/* Enable RSC Delay 8us when LRO enabled  */
3754*13006SChenlu.Chen@Sun.COM 		if (ixgbe->lro_enable) {
3755*13006SChenlu.Chen@Sun.COM 			gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT);
3756*13006SChenlu.Chen@Sun.COM 		}
3757*13006SChenlu.Chen@Sun.COM 		break;
3758*13006SChenlu.Chen@Sun.COM 
3759*13006SChenlu.Chen@Sun.COM 	default:
3760*13006SChenlu.Chen@Sun.COM 		break;
3761*13006SChenlu.Chen@Sun.COM 	}
3762*13006SChenlu.Chen@Sun.COM 
37638490SPaul.Guo@Sun.COM 	/* write to interrupt control registers */
37648490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
37656621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac);
37668490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam);
37676621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
37686621Sbt150084 	IXGBE_WRITE_FLUSH(hw);
37696621Sbt150084 }
37706621Sbt150084 
37716621Sbt150084 /*
37726621Sbt150084  * ixgbe_loopback_ioctl - Loopback support.
37736621Sbt150084  */
37746621Sbt150084 enum ioc_reply
ixgbe_loopback_ioctl(ixgbe_t * ixgbe,struct iocblk * iocp,mblk_t * mp)37756621Sbt150084 ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp)
37766621Sbt150084 {
37776621Sbt150084 	lb_info_sz_t *lbsp;
37786621Sbt150084 	lb_property_t *lbpp;
37796621Sbt150084 	uint32_t *lbmp;
37806621Sbt150084 	uint32_t size;
37816621Sbt150084 	uint32_t value;
37826621Sbt150084 
37836621Sbt150084 	if (mp->b_cont == NULL)
37846621Sbt150084 		return (IOC_INVAL);
37856621Sbt150084 
37866621Sbt150084 	switch (iocp->ioc_cmd) {
37876621Sbt150084 	default:
37886621Sbt150084 		return (IOC_INVAL);
37896621Sbt150084 
37906621Sbt150084 	case LB_GET_INFO_SIZE:
37916621Sbt150084 		size = sizeof (lb_info_sz_t);
37926621Sbt150084 		if (iocp->ioc_count != size)
37936621Sbt150084 			return (IOC_INVAL);
37946621Sbt150084 
37956621Sbt150084 		value = sizeof (lb_normal);
37966621Sbt150084 		value += sizeof (lb_mac);
379711150SZhen.W@Sun.COM 		value += sizeof (lb_external);
37986621Sbt150084 
37996621Sbt150084 		lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr;
38006621Sbt150084 		*lbsp = value;
38016621Sbt150084 		break;
38026621Sbt150084 
38036621Sbt150084 	case LB_GET_INFO:
38046621Sbt150084 		value = sizeof (lb_normal);
38056621Sbt150084 		value += sizeof (lb_mac);
380611150SZhen.W@Sun.COM 		value += sizeof (lb_external);
38076621Sbt150084 
38086621Sbt150084 		size = value;
38096621Sbt150084 		if (iocp->ioc_count != size)
38106621Sbt150084 			return (IOC_INVAL);
38116621Sbt150084 
38126621Sbt150084 		value = 0;
38136621Sbt150084 		lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr;
38146621Sbt150084 
38156621Sbt150084 		lbpp[value++] = lb_normal;
38166621Sbt150084 		lbpp[value++] = lb_mac;
381711150SZhen.W@Sun.COM 		lbpp[value++] = lb_external;
38186621Sbt150084 		break;
38196621Sbt150084 
38206621Sbt150084 	case LB_GET_MODE:
38216621Sbt150084 		size = sizeof (uint32_t);
38226621Sbt150084 		if (iocp->ioc_count != size)
38236621Sbt150084 			return (IOC_INVAL);
38246621Sbt150084 
38256621Sbt150084 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
38266621Sbt150084 		*lbmp = ixgbe->loopback_mode;
38276621Sbt150084 		break;
38286621Sbt150084 
38296621Sbt150084 	case LB_SET_MODE:
38306621Sbt150084 		size = 0;
38316621Sbt150084 		if (iocp->ioc_count != sizeof (uint32_t))
38326621Sbt150084 			return (IOC_INVAL);
38336621Sbt150084 
38346621Sbt150084 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
38356621Sbt150084 		if (!ixgbe_set_loopback_mode(ixgbe, *lbmp))
38366621Sbt150084 			return (IOC_INVAL);
38376621Sbt150084 		break;
38386621Sbt150084 	}
38396621Sbt150084 
38406621Sbt150084 	iocp->ioc_count = size;
38416621Sbt150084 	iocp->ioc_error = 0;
38426621Sbt150084 
38436621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
38446621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
38456621Sbt150084 		return (IOC_INVAL);
38466621Sbt150084 	}
38476621Sbt150084 
38486621Sbt150084 	return (IOC_REPLY);
38496621Sbt150084 }
38506621Sbt150084 
38516621Sbt150084 /*
38526621Sbt150084  * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode.
38536621Sbt150084  */
38546621Sbt150084 static boolean_t
ixgbe_set_loopback_mode(ixgbe_t * ixgbe,uint32_t mode)38556621Sbt150084 ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode)
38566621Sbt150084 {
38576621Sbt150084 	if (mode == ixgbe->loopback_mode)
38586621Sbt150084 		return (B_TRUE);
38596621Sbt150084 
38606621Sbt150084 	ixgbe->loopback_mode = mode;
38616621Sbt150084 
38626621Sbt150084 	if (mode == IXGBE_LB_NONE) {
38636621Sbt150084 		/*
38646621Sbt150084 		 * Reset the chip
38656621Sbt150084 		 */
38666621Sbt150084 		(void) ixgbe_reset(ixgbe);
38676621Sbt150084 		return (B_TRUE);
38686621Sbt150084 	}
38696621Sbt150084 
38706621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
38716621Sbt150084 
38726621Sbt150084 	switch (mode) {
38736621Sbt150084 	default:
38746621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
38756621Sbt150084 		return (B_FALSE);
38766621Sbt150084 
387711150SZhen.W@Sun.COM 	case IXGBE_LB_EXTERNAL:
387811150SZhen.W@Sun.COM 		break;
387911150SZhen.W@Sun.COM 
38806621Sbt150084 	case IXGBE_LB_INTERNAL_MAC:
38816621Sbt150084 		ixgbe_set_internal_mac_loopback(ixgbe);
38826621Sbt150084 		break;
38836621Sbt150084 	}
38846621Sbt150084 
38856621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
38866621Sbt150084 
38876621Sbt150084 	return (B_TRUE);
38886621Sbt150084 }
38896621Sbt150084 
38906621Sbt150084 /*
38916621Sbt150084  * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode.
38926621Sbt150084  */
38936621Sbt150084 static void
ixgbe_set_internal_mac_loopback(ixgbe_t * ixgbe)38946621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe)
38956621Sbt150084 {
38966621Sbt150084 	struct ixgbe_hw *hw;
38976621Sbt150084 	uint32_t reg;
38986621Sbt150084 	uint8_t atlas;
38996621Sbt150084 
39006621Sbt150084 	hw = &ixgbe->hw;
39016621Sbt150084 
39026621Sbt150084 	/*
39036621Sbt150084 	 * Setup MAC loopback
39046621Sbt150084 	 */
39056621Sbt150084 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0);
39066621Sbt150084 	reg |= IXGBE_HLREG0_LPBK;
39076621Sbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg);
39086621Sbt150084 
39096621Sbt150084 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
39106621Sbt150084 	reg &= ~IXGBE_AUTOC_LMS_MASK;
39116621Sbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
39126621Sbt150084 
39136621Sbt150084 	/*
39146621Sbt150084 	 * Disable Atlas Tx lanes to keep packets in loopback and not on wire
39156621Sbt150084 	 */
3916*13006SChenlu.Chen@Sun.COM 	switch (hw->mac.type) {
3917*13006SChenlu.Chen@Sun.COM 	case ixgbe_mac_82598EB:
39186621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
39196621Sbt150084 		    &atlas);
39206621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_REG_EN;
39216621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
39226621Sbt150084 		    atlas);
39236621Sbt150084 
39246621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
39256621Sbt150084 		    &atlas);
39266621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
39276621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
39286621Sbt150084 		    atlas);
39296621Sbt150084 
39306621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
39316621Sbt150084 		    &atlas);
39326621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
39336621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
39346621Sbt150084 		    atlas);
39356621Sbt150084 
39366621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
39376621Sbt150084 		    &atlas);
39386621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
39396621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
39406621Sbt150084 		    atlas);
3941*13006SChenlu.Chen@Sun.COM 		break;
3942*13006SChenlu.Chen@Sun.COM 
3943*13006SChenlu.Chen@Sun.COM 	case ixgbe_mac_82599EB:
394412280SChenlu.Chen@Sun.COM 		reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
394512280SChenlu.Chen@Sun.COM 		reg |= (IXGBE_AUTOC_FLU |
394612280SChenlu.Chen@Sun.COM 		    IXGBE_AUTOC_10G_KX4);
394712280SChenlu.Chen@Sun.COM 		IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
394812280SChenlu.Chen@Sun.COM 
394912280SChenlu.Chen@Sun.COM 		(void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL,
395012280SChenlu.Chen@Sun.COM 		    B_FALSE, B_TRUE);
3951*13006SChenlu.Chen@Sun.COM 		break;
3952*13006SChenlu.Chen@Sun.COM 
3953*13006SChenlu.Chen@Sun.COM 	default:
3954*13006SChenlu.Chen@Sun.COM 		break;
39556621Sbt150084 	}
39566621Sbt150084 }
39576621Sbt150084 
39586621Sbt150084 #pragma inline(ixgbe_intr_rx_work)
39596621Sbt150084 /*
39606621Sbt150084  * ixgbe_intr_rx_work - RX processing of ISR.
39616621Sbt150084  */
39626621Sbt150084 static void
ixgbe_intr_rx_work(ixgbe_rx_ring_t * rx_ring)39636621Sbt150084 ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring)
39646621Sbt150084 {
39656621Sbt150084 	mblk_t *mp;
39666621Sbt150084 
39676621Sbt150084 	mutex_enter(&rx_ring->rx_lock);
39686621Sbt150084 
39698275SEric Cheng 	mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
39706621Sbt150084 	mutex_exit(&rx_ring->rx_lock);
39716621Sbt150084 
39726621Sbt150084 	if (mp != NULL)
39738275SEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
39748275SEric Cheng 		    rx_ring->ring_gen_num);
39756621Sbt150084 }
39766621Sbt150084 
39776621Sbt150084 #pragma inline(ixgbe_intr_tx_work)
39786621Sbt150084 /*
39796621Sbt150084  * ixgbe_intr_tx_work - TX processing of ISR.
39806621Sbt150084  */
39816621Sbt150084 static void
ixgbe_intr_tx_work(ixgbe_tx_ring_t * tx_ring)39826621Sbt150084 ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring)
39836621Sbt150084 {
398410376SChenlu.Chen@Sun.COM 	ixgbe_t *ixgbe = tx_ring->ixgbe;
398510376SChenlu.Chen@Sun.COM 
39866621Sbt150084 	/*
39876621Sbt150084 	 * Recycle the tx descriptors
39886621Sbt150084 	 */
39896621Sbt150084 	tx_ring->tx_recycle(tx_ring);
39906621Sbt150084 
39916621Sbt150084 	/*
39926621Sbt150084 	 * Schedule the re-transmit
39936621Sbt150084 	 */
39946621Sbt150084 	if (tx_ring->reschedule &&
399510376SChenlu.Chen@Sun.COM 	    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) {
39966621Sbt150084 		tx_ring->reschedule = B_FALSE;
39978275SEric Cheng 		mac_tx_ring_update(tx_ring->ixgbe->mac_hdl,
39988275SEric Cheng 		    tx_ring->ring_handle);
39996621Sbt150084 		IXGBE_DEBUG_STAT(tx_ring->stat_reschedule);
40006621Sbt150084 	}
40016621Sbt150084 }
40026621Sbt150084 
40036621Sbt150084 #pragma inline(ixgbe_intr_other_work)
40046621Sbt150084 /*
40058490SPaul.Guo@Sun.COM  * ixgbe_intr_other_work - Process interrupt types other than tx/rx
40066621Sbt150084  */
40076621Sbt150084 static void
ixgbe_intr_other_work(ixgbe_t * ixgbe,uint32_t eicr)40088490SPaul.Guo@Sun.COM ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr)
40096621Sbt150084 {
401011233SPaul.Guo@Sun.COM 	ASSERT(mutex_owned(&ixgbe->gen_lock));
401111233SPaul.Guo@Sun.COM 
40128490SPaul.Guo@Sun.COM 	/*
401311233SPaul.Guo@Sun.COM 	 * handle link status change
40148490SPaul.Guo@Sun.COM 	 */
40158490SPaul.Guo@Sun.COM 	if (eicr & IXGBE_EICR_LSC) {
401611233SPaul.Guo@Sun.COM 		ixgbe_driver_link_check(ixgbe);
4017*13006SChenlu.Chen@Sun.COM 		ixgbe_get_hw_state(ixgbe);
40188490SPaul.Guo@Sun.COM 	}
40196621Sbt150084 
40206621Sbt150084 	/*
40218490SPaul.Guo@Sun.COM 	 * check for fan failure on adapters with fans
40226621Sbt150084 	 */
40238490SPaul.Guo@Sun.COM 	if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
40248490SPaul.Guo@Sun.COM 	    (eicr & IXGBE_EICR_GPI_SDP1)) {
4025*13006SChenlu.Chen@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
4026*13006SChenlu.Chen@Sun.COM 
4027*13006SChenlu.Chen@Sun.COM 		/*
4028*13006SChenlu.Chen@Sun.COM 		 * Disable the adapter interrupts
4029*13006SChenlu.Chen@Sun.COM 		 */
4030*13006SChenlu.Chen@Sun.COM 		ixgbe_disable_adapter_interrupts(ixgbe);
4031*13006SChenlu.Chen@Sun.COM 
4032*13006SChenlu.Chen@Sun.COM 		/*
4033*13006SChenlu.Chen@Sun.COM 		 * Disable Rx/Tx units
4034*13006SChenlu.Chen@Sun.COM 		 */
4035*13006SChenlu.Chen@Sun.COM 		(void) ixgbe_stop_adapter(&ixgbe->hw);
4036*13006SChenlu.Chen@Sun.COM 
4037*13006SChenlu.Chen@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
4038*13006SChenlu.Chen@Sun.COM 		ixgbe_error(ixgbe,
4039*13006SChenlu.Chen@Sun.COM 		    "Problem: Network adapter has been stopped "
4040*13006SChenlu.Chen@Sun.COM 		    "because the fan has stopped.\n");
4041*13006SChenlu.Chen@Sun.COM 		ixgbe_error(ixgbe,
4042*13006SChenlu.Chen@Sun.COM 		    "Action: Replace the adapter.\n");
4043*13006SChenlu.Chen@Sun.COM 
4044*13006SChenlu.Chen@Sun.COM 		/* re-enable the interrupt, which was automasked */
4045*13006SChenlu.Chen@Sun.COM 		ixgbe->eims |= IXGBE_EICR_GPI_SDP1;
4046*13006SChenlu.Chen@Sun.COM 	}
4047*13006SChenlu.Chen@Sun.COM 
4048*13006SChenlu.Chen@Sun.COM 	/*
4049*13006SChenlu.Chen@Sun.COM 	 * Do SFP check for adapters with hot-plug capability
4050*13006SChenlu.Chen@Sun.COM 	 */
4051*13006SChenlu.Chen@Sun.COM 	if ((ixgbe->capab->flags & IXGBE_FLAG_SFP_PLUG_CAPABLE) &&
4052*13006SChenlu.Chen@Sun.COM 	    ((eicr & IXGBE_EICR_GPI_SDP1) || (eicr & IXGBE_EICR_GPI_SDP2))) {
4053*13006SChenlu.Chen@Sun.COM 		ixgbe->eicr = eicr;
405411233SPaul.Guo@Sun.COM 		if ((ddi_taskq_dispatch(ixgbe->sfp_taskq,
40559353SSamuel.Tu@Sun.COM 		    ixgbe_sfp_check, (void *)ixgbe,
40569353SSamuel.Tu@Sun.COM 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
405710305SPaul.Guo@Sun.COM 			ixgbe_log(ixgbe, "No memory available to dispatch "
405810305SPaul.Guo@Sun.COM 			    "taskq for SFP check");
40599353SSamuel.Tu@Sun.COM 		}
4060*13006SChenlu.Chen@Sun.COM 	}
4061*13006SChenlu.Chen@Sun.COM 
4062*13006SChenlu.Chen@Sun.COM 	/*
4063*13006SChenlu.Chen@Sun.COM 	 * Do over-temperature check for adapters with temp sensor
4064*13006SChenlu.Chen@Sun.COM 	 */
4065*13006SChenlu.Chen@Sun.COM 	if ((ixgbe->capab->flags & IXGBE_FLAG_TEMP_SENSOR_CAPABLE) &&
4066*13006SChenlu.Chen@Sun.COM 	    ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
4067*13006SChenlu.Chen@Sun.COM 		ixgbe->eicr = eicr;
4068*13006SChenlu.Chen@Sun.COM 		if ((ddi_taskq_dispatch(ixgbe->overtemp_taskq,
4069*13006SChenlu.Chen@Sun.COM 		    ixgbe_overtemp_check, (void *)ixgbe,
4070*13006SChenlu.Chen@Sun.COM 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
4071*13006SChenlu.Chen@Sun.COM 			ixgbe_log(ixgbe, "No memory available to dispatch "
4072*13006SChenlu.Chen@Sun.COM 			    "taskq for overtemp check");
4073*13006SChenlu.Chen@Sun.COM 		}
40748490SPaul.Guo@Sun.COM 	}
40756621Sbt150084 }
40766621Sbt150084 
40776621Sbt150084 /*
40786621Sbt150084  * ixgbe_intr_legacy - Interrupt handler for legacy interrupts.
40796621Sbt150084  */
40806621Sbt150084 static uint_t
ixgbe_intr_legacy(void * arg1,void * arg2)40816621Sbt150084 ixgbe_intr_legacy(void *arg1, void *arg2)
40826621Sbt150084 {
40836621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
40846621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
40856621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
40868275SEric Cheng 	ixgbe_rx_ring_t *rx_ring;
40876621Sbt150084 	uint32_t eicr;
40886621Sbt150084 	mblk_t *mp;
40896621Sbt150084 	boolean_t tx_reschedule;
40906621Sbt150084 	uint_t result;
40916621Sbt150084 
40928490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
40936621Sbt150084 
40946621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
40956621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
40966621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
40976621Sbt150084 		return (DDI_INTR_UNCLAIMED);
40986621Sbt150084 	}
40996621Sbt150084 
41006621Sbt150084 	mp = NULL;
41016621Sbt150084 	tx_reschedule = B_FALSE;
41026621Sbt150084 
41036621Sbt150084 	/*
41046621Sbt150084 	 * Any bit set in eicr: claim this interrupt
41056621Sbt150084 	 */
41066621Sbt150084 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
410711233SPaul.Guo@Sun.COM 
410811233SPaul.Guo@Sun.COM 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
410912003SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
411011233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
411111233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
411211233SPaul.Guo@Sun.COM 		return (DDI_INTR_CLAIMED);
411311233SPaul.Guo@Sun.COM 	}
411411233SPaul.Guo@Sun.COM 
41156621Sbt150084 	if (eicr) {
41166621Sbt150084 		/*
41176621Sbt150084 		 * For legacy interrupt, we have only one interrupt,
41186621Sbt150084 		 * so we have only one rx ring and one tx ring enabled.
41196621Sbt150084 		 */
41206621Sbt150084 		ASSERT(ixgbe->num_rx_rings == 1);
41216621Sbt150084 		ASSERT(ixgbe->num_tx_rings == 1);
41226621Sbt150084 
41236621Sbt150084 		/*
41248275SEric Cheng 		 * For legacy interrupt, rx rings[0] will use RTxQ[0].
41256621Sbt150084 		 */
41268275SEric Cheng 		if (eicr & 0x1) {
41279353SSamuel.Tu@Sun.COM 			ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE;
41289353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
41299353SSamuel.Tu@Sun.COM 			ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
41306621Sbt150084 			/*
41316621Sbt150084 			 * Clean the rx descriptors
41326621Sbt150084 			 */
41338275SEric Cheng 			rx_ring = &ixgbe->rx_rings[0];
41348275SEric Cheng 			mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
41358275SEric Cheng 		}
41368275SEric Cheng 
41378275SEric Cheng 		/*
41388275SEric Cheng 		 * For legacy interrupt, tx rings[0] will use RTxQ[1].
41398275SEric Cheng 		 */
41408275SEric Cheng 		if (eicr & 0x2) {
41416621Sbt150084 			/*
41426621Sbt150084 			 * Recycle the tx descriptors
41436621Sbt150084 			 */
41446621Sbt150084 			tx_ring = &ixgbe->tx_rings[0];
41456621Sbt150084 			tx_ring->tx_recycle(tx_ring);
41466621Sbt150084 
41476621Sbt150084 			/*
41486621Sbt150084 			 * Schedule the re-transmit
41496621Sbt150084 			 */
41506621Sbt150084 			tx_reschedule = (tx_ring->reschedule &&
415110376SChenlu.Chen@Sun.COM 			    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh));
41526621Sbt150084 		}
41536621Sbt150084 
41548490SPaul.Guo@Sun.COM 		/* any interrupt type other than tx/rx */
41558490SPaul.Guo@Sun.COM 		if (eicr & ixgbe->capab->other_intr) {
4156*13006SChenlu.Chen@Sun.COM 			switch (hw->mac.type) {
4157*13006SChenlu.Chen@Sun.COM 			case ixgbe_mac_82598EB:
41589353SSamuel.Tu@Sun.COM 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
4159*13006SChenlu.Chen@Sun.COM 				break;
4160*13006SChenlu.Chen@Sun.COM 
4161*13006SChenlu.Chen@Sun.COM 			case ixgbe_mac_82599EB:
41629353SSamuel.Tu@Sun.COM 				ixgbe->eimc = IXGBE_82599_OTHER_INTR;
41639353SSamuel.Tu@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
4164*13006SChenlu.Chen@Sun.COM 				break;
4165*13006SChenlu.Chen@Sun.COM 
4166*13006SChenlu.Chen@Sun.COM 			default:
4167*13006SChenlu.Chen@Sun.COM 				break;
41689353SSamuel.Tu@Sun.COM 			}
41699353SSamuel.Tu@Sun.COM 			ixgbe_intr_other_work(ixgbe, eicr);
41708490SPaul.Guo@Sun.COM 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
41716621Sbt150084 		}
41726621Sbt150084 
41738490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
41748490SPaul.Guo@Sun.COM 
41756621Sbt150084 		result = DDI_INTR_CLAIMED;
41766621Sbt150084 	} else {
41778490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
41788490SPaul.Guo@Sun.COM 
41796621Sbt150084 		/*
41806621Sbt150084 		 * No interrupt cause bits set: don't claim this interrupt.
41816621Sbt150084 		 */
41826621Sbt150084 		result = DDI_INTR_UNCLAIMED;
41836621Sbt150084 	}
41846621Sbt150084 
41858490SPaul.Guo@Sun.COM 	/* re-enable the interrupts which were automasked */
41868490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
41876621Sbt150084 
41886621Sbt150084 	/*
41896621Sbt150084 	 * Do the following work outside of the gen_lock
41906621Sbt150084 	 */
41919353SSamuel.Tu@Sun.COM 	if (mp != NULL) {
41928275SEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
41938275SEric Cheng 		    rx_ring->ring_gen_num);
41949353SSamuel.Tu@Sun.COM 	}
41956621Sbt150084 
41966621Sbt150084 	if (tx_reschedule)  {
41976621Sbt150084 		tx_ring->reschedule = B_FALSE;
41988275SEric Cheng 		mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle);
41996621Sbt150084 		IXGBE_DEBUG_STAT(tx_ring->stat_reschedule);
42006621Sbt150084 	}
42016621Sbt150084 
42026621Sbt150084 	return (result);
42036621Sbt150084 }
42046621Sbt150084 
42056621Sbt150084 /*
42066621Sbt150084  * ixgbe_intr_msi - Interrupt handler for MSI.
42076621Sbt150084  */
42086621Sbt150084 static uint_t
ixgbe_intr_msi(void * arg1,void * arg2)42096621Sbt150084 ixgbe_intr_msi(void *arg1, void *arg2)
42106621Sbt150084 {
42116621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
42126621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
42136621Sbt150084 	uint32_t eicr;
42146621Sbt150084 
42158490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
42168490SPaul.Guo@Sun.COM 
42176621Sbt150084 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
42186621Sbt150084 
421911233SPaul.Guo@Sun.COM 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
422011233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
422111233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
422211233SPaul.Guo@Sun.COM 		return (DDI_INTR_CLAIMED);
422311233SPaul.Guo@Sun.COM 	}
422411233SPaul.Guo@Sun.COM 
42256621Sbt150084 	/*
42266621Sbt150084 	 * For MSI interrupt, we have only one vector,
42276621Sbt150084 	 * so we have only one rx ring and one tx ring enabled.
42286621Sbt150084 	 */
42296621Sbt150084 	ASSERT(ixgbe->num_rx_rings == 1);
42306621Sbt150084 	ASSERT(ixgbe->num_tx_rings == 1);
42316621Sbt150084 
42326621Sbt150084 	/*
42338275SEric Cheng 	 * For MSI interrupt, rx rings[0] will use RTxQ[0].
42346621Sbt150084 	 */
42358275SEric Cheng 	if (eicr & 0x1) {
42366621Sbt150084 		ixgbe_intr_rx_work(&ixgbe->rx_rings[0]);
42378275SEric Cheng 	}
42388275SEric Cheng 
42398275SEric Cheng 	/*
42408275SEric Cheng 	 * For MSI interrupt, tx rings[0] will use RTxQ[1].
42418275SEric Cheng 	 */
42428275SEric Cheng 	if (eicr & 0x2) {
42436621Sbt150084 		ixgbe_intr_tx_work(&ixgbe->tx_rings[0]);
42446621Sbt150084 	}
42456621Sbt150084 
42468490SPaul.Guo@Sun.COM 	/* any interrupt type other than tx/rx */
42478490SPaul.Guo@Sun.COM 	if (eicr & ixgbe->capab->other_intr) {
42488490SPaul.Guo@Sun.COM 		mutex_enter(&ixgbe->gen_lock);
4249*13006SChenlu.Chen@Sun.COM 		switch (hw->mac.type) {
4250*13006SChenlu.Chen@Sun.COM 		case ixgbe_mac_82598EB:
42519353SSamuel.Tu@Sun.COM 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
4252*13006SChenlu.Chen@Sun.COM 			break;
4253*13006SChenlu.Chen@Sun.COM 
4254*13006SChenlu.Chen@Sun.COM 		case ixgbe_mac_82599EB:
42559353SSamuel.Tu@Sun.COM 			ixgbe->eimc = IXGBE_82599_OTHER_INTR;
42569353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
4257*13006SChenlu.Chen@Sun.COM 			break;
4258*13006SChenlu.Chen@Sun.COM 
4259*13006SChenlu.Chen@Sun.COM 		default:
4260*13006SChenlu.Chen@Sun.COM 			break;
42619353SSamuel.Tu@Sun.COM 		}
42629353SSamuel.Tu@Sun.COM 		ixgbe_intr_other_work(ixgbe, eicr);
42638490SPaul.Guo@Sun.COM 		ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
42648490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
42656621Sbt150084 	}
42666621Sbt150084 
42678490SPaul.Guo@Sun.COM 	/* re-enable the interrupts which were automasked */
42688490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
42698490SPaul.Guo@Sun.COM 
42706621Sbt150084 	return (DDI_INTR_CLAIMED);
42716621Sbt150084 }
42726621Sbt150084 
42736621Sbt150084 /*
42749353SSamuel.Tu@Sun.COM  * ixgbe_intr_msix - Interrupt handler for MSI-X.
42756621Sbt150084  */
42766621Sbt150084 static uint_t
ixgbe_intr_msix(void * arg1,void * arg2)42779353SSamuel.Tu@Sun.COM ixgbe_intr_msix(void *arg1, void *arg2)
42786621Sbt150084 {
42799353SSamuel.Tu@Sun.COM 	ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1;
42808275SEric Cheng 	ixgbe_t *ixgbe = vect->ixgbe;
42819353SSamuel.Tu@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
42829353SSamuel.Tu@Sun.COM 	uint32_t eicr;
42838275SEric Cheng 	int r_idx = 0;
42846621Sbt150084 
42858490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
42868490SPaul.Guo@Sun.COM 
42876621Sbt150084 	/*
42888275SEric Cheng 	 * Clean each rx ring that has its bit set in the map
42896621Sbt150084 	 */
42906621Sbt150084 	r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1));
42916621Sbt150084 	while (r_idx >= 0) {
42926621Sbt150084 		ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]);
42936621Sbt150084 		r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
42946621Sbt150084 		    (ixgbe->num_rx_rings - 1));
42956621Sbt150084 	}
42966621Sbt150084 
42978275SEric Cheng 	/*
42988275SEric Cheng 	 * Clean each tx ring that has its bit set in the map
42998275SEric Cheng 	 */
43008275SEric Cheng 	r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1));
43018275SEric Cheng 	while (r_idx >= 0) {
43028275SEric Cheng 		ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]);
43038275SEric Cheng 		r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
43048275SEric Cheng 		    (ixgbe->num_tx_rings - 1));
43058275SEric Cheng 	}
43068275SEric Cheng 
43076621Sbt150084 
43086621Sbt150084 	/*
43099353SSamuel.Tu@Sun.COM 	 * Clean other interrupt (link change) that has its bit set in the map
43106621Sbt150084 	 */
43119353SSamuel.Tu@Sun.COM 	if (BT_TEST(vect->other_map, 0) == 1) {
43129353SSamuel.Tu@Sun.COM 		eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
43139353SSamuel.Tu@Sun.COM 
431411233SPaul.Guo@Sun.COM 		if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) !=
431511233SPaul.Guo@Sun.COM 		    DDI_FM_OK) {
431611233SPaul.Guo@Sun.COM 			ddi_fm_service_impact(ixgbe->dip,
431711233SPaul.Guo@Sun.COM 			    DDI_SERVICE_DEGRADED);
431811233SPaul.Guo@Sun.COM 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
431911233SPaul.Guo@Sun.COM 			return (DDI_INTR_CLAIMED);
432011233SPaul.Guo@Sun.COM 		}
432111233SPaul.Guo@Sun.COM 
43229353SSamuel.Tu@Sun.COM 		/*
4323*13006SChenlu.Chen@Sun.COM 		 * Check "other" cause bits: any interrupt type other than tx/rx
43249353SSamuel.Tu@Sun.COM 		 */
43259353SSamuel.Tu@Sun.COM 		if (eicr & ixgbe->capab->other_intr) {
4326*13006SChenlu.Chen@Sun.COM 			mutex_enter(&ixgbe->gen_lock);
4327*13006SChenlu.Chen@Sun.COM 			switch (hw->mac.type) {
4328*13006SChenlu.Chen@Sun.COM 			case ixgbe_mac_82598EB:
43299353SSamuel.Tu@Sun.COM 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
43309353SSamuel.Tu@Sun.COM 				ixgbe_intr_other_work(ixgbe, eicr);
4331*13006SChenlu.Chen@Sun.COM 				break;
4332*13006SChenlu.Chen@Sun.COM 
4333*13006SChenlu.Chen@Sun.COM 			case ixgbe_mac_82599EB:
4334*13006SChenlu.Chen@Sun.COM 				ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
4335*13006SChenlu.Chen@Sun.COM 				ixgbe_intr_other_work(ixgbe, eicr);
4336*13006SChenlu.Chen@Sun.COM 				break;
4337*13006SChenlu.Chen@Sun.COM 
4338*13006SChenlu.Chen@Sun.COM 			default:
4339*13006SChenlu.Chen@Sun.COM 				break;
43409353SSamuel.Tu@Sun.COM 			}
4341*13006SChenlu.Chen@Sun.COM 			mutex_exit(&ixgbe->gen_lock);
43429353SSamuel.Tu@Sun.COM 		}
43439353SSamuel.Tu@Sun.COM 
43449353SSamuel.Tu@Sun.COM 		/* re-enable the interrupts which were automasked */
43459353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
43466621Sbt150084 	}
43476621Sbt150084 
43486621Sbt150084 	return (DDI_INTR_CLAIMED);
43496621Sbt150084 }
43506621Sbt150084 
43516621Sbt150084 /*
43526621Sbt150084  * ixgbe_alloc_intrs - Allocate interrupts for the driver.
43536621Sbt150084  *
43546621Sbt150084  * Normal sequence is to try MSI-X; if not sucessful, try MSI;
43556621Sbt150084  * if not successful, try Legacy.
43566621Sbt150084  * ixgbe->intr_force can be used to force sequence to start with
43576621Sbt150084  * any of the 3 types.
43586621Sbt150084  * If MSI-X is not used, number of tx/rx rings is forced to 1.
43596621Sbt150084  */
43606621Sbt150084 static int
ixgbe_alloc_intrs(ixgbe_t * ixgbe)43616621Sbt150084 ixgbe_alloc_intrs(ixgbe_t *ixgbe)
43626621Sbt150084 {
43636621Sbt150084 	dev_info_t *devinfo;
43646621Sbt150084 	int intr_types;
43656621Sbt150084 	int rc;
43666621Sbt150084 
43676621Sbt150084 	devinfo = ixgbe->dip;
43686621Sbt150084 
43696621Sbt150084 	/*
43706621Sbt150084 	 * Get supported interrupt types
43716621Sbt150084 	 */
43726621Sbt150084 	rc = ddi_intr_get_supported_types(devinfo, &intr_types);
43736621Sbt150084 
43746621Sbt150084 	if (rc != DDI_SUCCESS) {
43756621Sbt150084 		ixgbe_log(ixgbe,
43766621Sbt150084 		    "Get supported interrupt types failed: %d", rc);
43776621Sbt150084 		return (IXGBE_FAILURE);
43786621Sbt150084 	}
43796621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types);
43806621Sbt150084 
43816621Sbt150084 	ixgbe->intr_type = 0;
43826621Sbt150084 
43836621Sbt150084 	/*
43846621Sbt150084 	 * Install MSI-X interrupts
43856621Sbt150084 	 */
43866621Sbt150084 	if ((intr_types & DDI_INTR_TYPE_MSIX) &&
43876621Sbt150084 	    (ixgbe->intr_force <= IXGBE_INTR_MSIX)) {
43886621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX);
43896621Sbt150084 		if (rc == IXGBE_SUCCESS)
43906621Sbt150084 			return (IXGBE_SUCCESS);
43916621Sbt150084 
43926621Sbt150084 		ixgbe_log(ixgbe,
43936621Sbt150084 		    "Allocate MSI-X failed, trying MSI interrupts...");
43946621Sbt150084 	}
43956621Sbt150084 
43966621Sbt150084 	/*
43978275SEric Cheng 	 * MSI-X not used, force rings and groups to 1
43986621Sbt150084 	 */
43996621Sbt150084 	ixgbe->num_rx_rings = 1;
44008275SEric Cheng 	ixgbe->num_rx_groups = 1;
44016621Sbt150084 	ixgbe->num_tx_rings = 1;
440211878SVenu.Iyer@Sun.COM 	ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
44036621Sbt150084 	ixgbe_log(ixgbe,
44048275SEric Cheng 	    "MSI-X not used, force rings and groups number to 1");
44056621Sbt150084 
44066621Sbt150084 	/*
44076621Sbt150084 	 * Install MSI interrupts
44086621Sbt150084 	 */
44096621Sbt150084 	if ((intr_types & DDI_INTR_TYPE_MSI) &&
44106621Sbt150084 	    (ixgbe->intr_force <= IXGBE_INTR_MSI)) {
44116621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI);
44126621Sbt150084 		if (rc == IXGBE_SUCCESS)
44136621Sbt150084 			return (IXGBE_SUCCESS);
44146621Sbt150084 
44156621Sbt150084 		ixgbe_log(ixgbe,
44166621Sbt150084 		    "Allocate MSI failed, trying Legacy interrupts...");
44176621Sbt150084 	}
44186621Sbt150084 
44196621Sbt150084 	/*
44206621Sbt150084 	 * Install legacy interrupts
44216621Sbt150084 	 */
44226621Sbt150084 	if (intr_types & DDI_INTR_TYPE_FIXED) {
44236621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED);
44246621Sbt150084 		if (rc == IXGBE_SUCCESS)
44256621Sbt150084 			return (IXGBE_SUCCESS);
44266621Sbt150084 
44276621Sbt150084 		ixgbe_log(ixgbe,
44286621Sbt150084 		    "Allocate Legacy interrupts failed");
44296621Sbt150084 	}
44306621Sbt150084 
44316621Sbt150084 	/*
44326621Sbt150084 	 * If none of the 3 types succeeded, return failure
44336621Sbt150084 	 */
44346621Sbt150084 	return (IXGBE_FAILURE);
44356621Sbt150084 }
44366621Sbt150084 
44376621Sbt150084 /*
44386621Sbt150084  * ixgbe_alloc_intr_handles - Allocate interrupt handles.
44396621Sbt150084  *
44406621Sbt150084  * For legacy and MSI, only 1 handle is needed.  For MSI-X,
44416621Sbt150084  * if fewer than 2 handles are available, return failure.
44428275SEric Cheng  * Upon success, this maps the vectors to rx and tx rings for
44438275SEric Cheng  * interrupts.
44446621Sbt150084  */
44456621Sbt150084 static int
ixgbe_alloc_intr_handles(ixgbe_t * ixgbe,int intr_type)44466621Sbt150084 ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type)
44476621Sbt150084 {
44486621Sbt150084 	dev_info_t *devinfo;
444911878SVenu.Iyer@Sun.COM 	int request, count, actual;
44508275SEric Cheng 	int minimum;
44516621Sbt150084 	int rc;
445211878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
44536621Sbt150084 
44546621Sbt150084 	devinfo = ixgbe->dip;
44556621Sbt150084 
44566621Sbt150084 	switch (intr_type) {
44576621Sbt150084 	case DDI_INTR_TYPE_FIXED:
44586621Sbt150084 		request = 1;	/* Request 1 legacy interrupt handle */
44596621Sbt150084 		minimum = 1;
44606621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy");
44616621Sbt150084 		break;
44626621Sbt150084 
44636621Sbt150084 	case DDI_INTR_TYPE_MSI:
44646621Sbt150084 		request = 1;	/* Request 1 MSI interrupt handle */
44656621Sbt150084 		minimum = 1;
44666621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI");
44676621Sbt150084 		break;
44686621Sbt150084 
44696621Sbt150084 	case DDI_INTR_TYPE_MSIX:
44706621Sbt150084 		/*
44716621Sbt150084 		 * Best number of vectors for the adapter is
447211878SVenu.Iyer@Sun.COM 		 * (# rx rings + # tx rings), however we will
447311878SVenu.Iyer@Sun.COM 		 * limit the request number.
44746621Sbt150084 		 */
447511878SVenu.Iyer@Sun.COM 		request = min(16, ixgbe->num_rx_rings + ixgbe->num_tx_rings);
44769353SSamuel.Tu@Sun.COM 		if (request > ixgbe->capab->max_ring_vect)
44779353SSamuel.Tu@Sun.COM 			request = ixgbe->capab->max_ring_vect;
447811878SVenu.Iyer@Sun.COM 		minimum = 1;
44796621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X");
44806621Sbt150084 		break;
44816621Sbt150084 
44826621Sbt150084 	default:
44836621Sbt150084 		ixgbe_log(ixgbe,
44846621Sbt150084 		    "invalid call to ixgbe_alloc_intr_handles(): %d\n",
44856621Sbt150084 		    intr_type);
44866621Sbt150084 		return (IXGBE_FAILURE);
44876621Sbt150084 	}
44886621Sbt150084 	IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d  minimum: %d",
44896621Sbt150084 	    request, minimum);
44906621Sbt150084 
44916621Sbt150084 	/*
44926621Sbt150084 	 * Get number of supported interrupts
44936621Sbt150084 	 */
44946621Sbt150084 	rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
44956621Sbt150084 	if ((rc != DDI_SUCCESS) || (count < minimum)) {
44966621Sbt150084 		ixgbe_log(ixgbe,
44976621Sbt150084 		    "Get interrupt number failed. Return: %d, count: %d",
44986621Sbt150084 		    rc, count);
44996621Sbt150084 		return (IXGBE_FAILURE);
45006621Sbt150084 	}
45016621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count);
45026621Sbt150084 
45036621Sbt150084 	actual = 0;
45046621Sbt150084 	ixgbe->intr_cnt = 0;
450511878SVenu.Iyer@Sun.COM 	ixgbe->intr_cnt_max = 0;
450611878SVenu.Iyer@Sun.COM 	ixgbe->intr_cnt_min = 0;
45076621Sbt150084 
45086621Sbt150084 	/*
45096621Sbt150084 	 * Allocate an array of interrupt handles
45106621Sbt150084 	 */
45116621Sbt150084 	ixgbe->intr_size = request * sizeof (ddi_intr_handle_t);
45126621Sbt150084 	ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP);
45136621Sbt150084 
45146621Sbt150084 	rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0,
45156621Sbt150084 	    request, &actual, DDI_INTR_ALLOC_NORMAL);
45166621Sbt150084 	if (rc != DDI_SUCCESS) {
45176621Sbt150084 		ixgbe_log(ixgbe, "Allocate interrupts failed. "
45186621Sbt150084 		    "return: %d, request: %d, actual: %d",
45196621Sbt150084 		    rc, request, actual);
45206621Sbt150084 		goto alloc_handle_fail;
45216621Sbt150084 	}
45226621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual);
45236621Sbt150084 
452411878SVenu.Iyer@Sun.COM 	/*
452511878SVenu.Iyer@Sun.COM 	 * upper/lower limit of interrupts
452611878SVenu.Iyer@Sun.COM 	 */
45276621Sbt150084 	ixgbe->intr_cnt = actual;
452811878SVenu.Iyer@Sun.COM 	ixgbe->intr_cnt_max = request;
452911878SVenu.Iyer@Sun.COM 	ixgbe->intr_cnt_min = minimum;
453011878SVenu.Iyer@Sun.COM 
453111878SVenu.Iyer@Sun.COM 	/*
453211878SVenu.Iyer@Sun.COM 	 * rss number per group should not exceed the rx interrupt number,
453311878SVenu.Iyer@Sun.COM 	 * else need to adjust rx ring number.
453411878SVenu.Iyer@Sun.COM 	 */
453511878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
453611878SVenu.Iyer@Sun.COM 	ASSERT((ixgbe->num_rx_rings % ixgbe->num_rx_groups) == 0);
4537*13006SChenlu.Chen@Sun.COM 	if (actual < ring_per_group) {
4538*13006SChenlu.Chen@Sun.COM 		ixgbe->num_rx_rings = ixgbe->num_rx_groups * actual;
453911878SVenu.Iyer@Sun.COM 		ixgbe_setup_vmdq_rss_conf(ixgbe);
454011878SVenu.Iyer@Sun.COM 	}
45416621Sbt150084 
45426621Sbt150084 	/*
45438275SEric Cheng 	 * Now we know the actual number of vectors.  Here we map the vector
45448275SEric Cheng 	 * to other, rx rings and tx ring.
45456621Sbt150084 	 */
45466621Sbt150084 	if (actual < minimum) {
45476621Sbt150084 		ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d",
45486621Sbt150084 		    actual);
45496621Sbt150084 		goto alloc_handle_fail;
45506621Sbt150084 	}
45516621Sbt150084 
45526621Sbt150084 	/*
45536621Sbt150084 	 * Get priority for first vector, assume remaining are all the same
45546621Sbt150084 	 */
45556621Sbt150084 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
45566621Sbt150084 	if (rc != DDI_SUCCESS) {
45576621Sbt150084 		ixgbe_log(ixgbe,
45586621Sbt150084 		    "Get interrupt priority failed: %d", rc);
45596621Sbt150084 		goto alloc_handle_fail;
45606621Sbt150084 	}
45616621Sbt150084 
45626621Sbt150084 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
45636621Sbt150084 	if (rc != DDI_SUCCESS) {
45646621Sbt150084 		ixgbe_log(ixgbe,
45656621Sbt150084 		    "Get interrupt cap failed: %d", rc);
45666621Sbt150084 		goto alloc_handle_fail;
45676621Sbt150084 	}
45686621Sbt150084 
45696621Sbt150084 	ixgbe->intr_type = intr_type;
45706621Sbt150084 
45716621Sbt150084 	return (IXGBE_SUCCESS);
45726621Sbt150084 
45736621Sbt150084 alloc_handle_fail:
45746621Sbt150084 	ixgbe_rem_intrs(ixgbe);
45756621Sbt150084 
45766621Sbt150084 	return (IXGBE_FAILURE);
45776621Sbt150084 }
45786621Sbt150084 
45796621Sbt150084 /*
45806621Sbt150084  * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type.
45816621Sbt150084  *
45826621Sbt150084  * Before adding the interrupt handlers, the interrupt vectors have
45836621Sbt150084  * been allocated, and the rx/tx rings have also been allocated.
45846621Sbt150084  */
45856621Sbt150084 static int
ixgbe_add_intr_handlers(ixgbe_t * ixgbe)45866621Sbt150084 ixgbe_add_intr_handlers(ixgbe_t *ixgbe)
45876621Sbt150084 {
45888275SEric Cheng 	int vector = 0;
45896621Sbt150084 	int rc;
45906621Sbt150084 
45916621Sbt150084 	switch (ixgbe->intr_type) {
45926621Sbt150084 	case DDI_INTR_TYPE_MSIX:
45936621Sbt150084 		/*
45949353SSamuel.Tu@Sun.COM 		 * Add interrupt handler for all vectors
45956621Sbt150084 		 */
45969353SSamuel.Tu@Sun.COM 		for (vector = 0; vector < ixgbe->intr_cnt; vector++) {
45976621Sbt150084 			/*
45986621Sbt150084 			 * install pointer to vect_map[vector]
45996621Sbt150084 			 */
46006621Sbt150084 			rc = ddi_intr_add_handler(ixgbe->htable[vector],
46019353SSamuel.Tu@Sun.COM 			    (ddi_intr_handler_t *)ixgbe_intr_msix,
46026621Sbt150084 			    (void *)&ixgbe->vect_map[vector], NULL);
46036621Sbt150084 
46046621Sbt150084 			if (rc != DDI_SUCCESS) {
46056621Sbt150084 				ixgbe_log(ixgbe,
460612003SPaul.Guo@Sun.COM 				    "Add interrupt handler failed. "
46078275SEric Cheng 				    "return: %d, vector: %d", rc, vector);
46086621Sbt150084 				for (vector--; vector >= 0; vector--) {
46096621Sbt150084 					(void) ddi_intr_remove_handler(
46106621Sbt150084 					    ixgbe->htable[vector]);
46116621Sbt150084 				}
46126621Sbt150084 				return (IXGBE_FAILURE);
46136621Sbt150084 			}
46146621Sbt150084 		}
46158275SEric Cheng 
46166621Sbt150084 		break;
46176621Sbt150084 
46186621Sbt150084 	case DDI_INTR_TYPE_MSI:
46196621Sbt150084 		/*
46206621Sbt150084 		 * Add interrupt handlers for the only vector
46216621Sbt150084 		 */
46226621Sbt150084 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
46236621Sbt150084 		    (ddi_intr_handler_t *)ixgbe_intr_msi,
46246621Sbt150084 		    (void *)ixgbe, NULL);
46256621Sbt150084 
46266621Sbt150084 		if (rc != DDI_SUCCESS) {
46276621Sbt150084 			ixgbe_log(ixgbe,
46286621Sbt150084 			    "Add MSI interrupt handler failed: %d", rc);
46296621Sbt150084 			return (IXGBE_FAILURE);
46306621Sbt150084 		}
46316621Sbt150084 
46326621Sbt150084 		break;
46336621Sbt150084 
46346621Sbt150084 	case DDI_INTR_TYPE_FIXED:
46356621Sbt150084 		/*
46366621Sbt150084 		 * Add interrupt handlers for the only vector
46376621Sbt150084 		 */
46386621Sbt150084 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
46396621Sbt150084 		    (ddi_intr_handler_t *)ixgbe_intr_legacy,
46406621Sbt150084 		    (void *)ixgbe, NULL);
46416621Sbt150084 
46426621Sbt150084 		if (rc != DDI_SUCCESS) {
46436621Sbt150084 			ixgbe_log(ixgbe,
46446621Sbt150084 			    "Add legacy interrupt handler failed: %d", rc);
46456621Sbt150084 			return (IXGBE_FAILURE);
46466621Sbt150084 		}
46476621Sbt150084 
46486621Sbt150084 		break;
46496621Sbt150084 
46506621Sbt150084 	default:
46516621Sbt150084 		return (IXGBE_FAILURE);
46526621Sbt150084 	}
46536621Sbt150084 
46546621Sbt150084 	return (IXGBE_SUCCESS);
46556621Sbt150084 }
46566621Sbt150084 
46576621Sbt150084 #pragma inline(ixgbe_map_rxring_to_vector)
46586621Sbt150084 /*
46596621Sbt150084  * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector.
46606621Sbt150084  */
46616621Sbt150084 static void
ixgbe_map_rxring_to_vector(ixgbe_t * ixgbe,int r_idx,int v_idx)46626621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx)
46636621Sbt150084 {
46646621Sbt150084 	/*
46656621Sbt150084 	 * Set bit in map
46666621Sbt150084 	 */
46676621Sbt150084 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
46686621Sbt150084 
46696621Sbt150084 	/*
46706621Sbt150084 	 * Count bits set
46716621Sbt150084 	 */
46726621Sbt150084 	ixgbe->vect_map[v_idx].rxr_cnt++;
46736621Sbt150084 
46746621Sbt150084 	/*
46756621Sbt150084 	 * Remember bit position
46766621Sbt150084 	 */
46778275SEric Cheng 	ixgbe->rx_rings[r_idx].intr_vector = v_idx;
46786621Sbt150084 	ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx;
46796621Sbt150084 }
46806621Sbt150084 
46816621Sbt150084 #pragma inline(ixgbe_map_txring_to_vector)
46826621Sbt150084 /*
46836621Sbt150084  * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector.
46846621Sbt150084  */
46856621Sbt150084 static void
ixgbe_map_txring_to_vector(ixgbe_t * ixgbe,int t_idx,int v_idx)46866621Sbt150084 ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx)
46876621Sbt150084 {
46886621Sbt150084 	/*
46896621Sbt150084 	 * Set bit in map
46906621Sbt150084 	 */
46916621Sbt150084 	BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx);
46926621Sbt150084 
46936621Sbt150084 	/*
46946621Sbt150084 	 * Count bits set
46956621Sbt150084 	 */
46966621Sbt150084 	ixgbe->vect_map[v_idx].txr_cnt++;
46976621Sbt150084 
46986621Sbt150084 	/*
46996621Sbt150084 	 * Remember bit position
47006621Sbt150084 	 */
47018275SEric Cheng 	ixgbe->tx_rings[t_idx].intr_vector = v_idx;
47026621Sbt150084 	ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx;
47036621Sbt150084 }
47046621Sbt150084 
47056621Sbt150084 /*
47068275SEric Cheng  * ixgbe_setup_ivar - Set the given entry in the given interrupt vector
47076621Sbt150084  * allocation register (IVAR).
47089353SSamuel.Tu@Sun.COM  * cause:
47099353SSamuel.Tu@Sun.COM  *   -1 : other cause
47109353SSamuel.Tu@Sun.COM  *    0 : rx
47119353SSamuel.Tu@Sun.COM  *    1 : tx
47126621Sbt150084  */
47136621Sbt150084 static void
ixgbe_setup_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,uint8_t msix_vector,int8_t cause)47149353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector,
47159353SSamuel.Tu@Sun.COM     int8_t cause)
47166621Sbt150084 {
47176621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
47186621Sbt150084 	u32 ivar, index;
47196621Sbt150084 
47209353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
47219353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
47229353SSamuel.Tu@Sun.COM 		msix_vector |= IXGBE_IVAR_ALLOC_VAL;
47239353SSamuel.Tu@Sun.COM 		if (cause == -1) {
47249353SSamuel.Tu@Sun.COM 			cause = 0;
47259353SSamuel.Tu@Sun.COM 		}
47269353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
47279353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
47289353SSamuel.Tu@Sun.COM 		ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3)));
47299353SSamuel.Tu@Sun.COM 		ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3)));
47309353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
47319353SSamuel.Tu@Sun.COM 		break;
4732*13006SChenlu.Chen@Sun.COM 
47339353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
47349353SSamuel.Tu@Sun.COM 		if (cause == -1) {
47359353SSamuel.Tu@Sun.COM 			/* other causes */
47369353SSamuel.Tu@Sun.COM 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
47379353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
47389353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
47399353SSamuel.Tu@Sun.COM 			ivar &= ~(0xFF << index);
47409353SSamuel.Tu@Sun.COM 			ivar |= (msix_vector << index);
47419353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
47429353SSamuel.Tu@Sun.COM 		} else {
47439353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
47449353SSamuel.Tu@Sun.COM 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
47459353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
47469353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
47479353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
47489353SSamuel.Tu@Sun.COM 			ivar &= ~(0xFF << index);
47499353SSamuel.Tu@Sun.COM 			ivar |= (msix_vector << index);
47509353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
47519353SSamuel.Tu@Sun.COM 			    ivar);
47529353SSamuel.Tu@Sun.COM 		}
47539353SSamuel.Tu@Sun.COM 		break;
4754*13006SChenlu.Chen@Sun.COM 
47559353SSamuel.Tu@Sun.COM 	default:
47569353SSamuel.Tu@Sun.COM 		break;
47579353SSamuel.Tu@Sun.COM 	}
47588275SEric Cheng }
47598275SEric Cheng 
47608275SEric Cheng /*
47618275SEric Cheng  * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of
47628275SEric Cheng  * given interrupt vector allocation register (IVAR).
47639353SSamuel.Tu@Sun.COM  * cause:
47649353SSamuel.Tu@Sun.COM  *   -1 : other cause
47659353SSamuel.Tu@Sun.COM  *    0 : rx
47669353SSamuel.Tu@Sun.COM  *    1 : tx
47678275SEric Cheng  */
47688275SEric Cheng static void
ixgbe_enable_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,int8_t cause)47699353SSamuel.Tu@Sun.COM ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
47708275SEric Cheng {
47718275SEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
47728275SEric Cheng 	u32 ivar, index;
47738275SEric Cheng 
47749353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
47759353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
47769353SSamuel.Tu@Sun.COM 		if (cause == -1) {
47779353SSamuel.Tu@Sun.COM 			cause = 0;
47789353SSamuel.Tu@Sun.COM 		}
47799353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
47809353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
47819353SSamuel.Tu@Sun.COM 		ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 *
47829353SSamuel.Tu@Sun.COM 		    (intr_alloc_entry & 0x3)));
47839353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
47849353SSamuel.Tu@Sun.COM 		break;
4785*13006SChenlu.Chen@Sun.COM 
47869353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
47879353SSamuel.Tu@Sun.COM 		if (cause == -1) {
47889353SSamuel.Tu@Sun.COM 			/* other causes */
47899353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
47909353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
47919353SSamuel.Tu@Sun.COM 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
47929353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
47939353SSamuel.Tu@Sun.COM 		} else {
47949353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
47959353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
47969353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
47979353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
47989353SSamuel.Tu@Sun.COM 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
47999353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
48009353SSamuel.Tu@Sun.COM 			    ivar);
48019353SSamuel.Tu@Sun.COM 		}
48029353SSamuel.Tu@Sun.COM 		break;
4803*13006SChenlu.Chen@Sun.COM 
48049353SSamuel.Tu@Sun.COM 	default:
48059353SSamuel.Tu@Sun.COM 		break;
48069353SSamuel.Tu@Sun.COM 	}
48078275SEric Cheng }
48088275SEric Cheng 
48098275SEric Cheng /*
48109353SSamuel.Tu@Sun.COM  * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of
48118275SEric Cheng  * given interrupt vector allocation register (IVAR).
48129353SSamuel.Tu@Sun.COM  * cause:
48139353SSamuel.Tu@Sun.COM  *   -1 : other cause
48149353SSamuel.Tu@Sun.COM  *    0 : rx
48159353SSamuel.Tu@Sun.COM  *    1 : tx
48168275SEric Cheng  */
48178275SEric Cheng static void
ixgbe_disable_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,int8_t cause)48189353SSamuel.Tu@Sun.COM ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
48198275SEric Cheng {
48208275SEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
48218275SEric Cheng 	u32 ivar, index;
48228275SEric Cheng 
48239353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
48249353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
48259353SSamuel.Tu@Sun.COM 		if (cause == -1) {
48269353SSamuel.Tu@Sun.COM 			cause = 0;
48279353SSamuel.Tu@Sun.COM 		}
48289353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
48299353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
48309353SSamuel.Tu@Sun.COM 		ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 *
48319353SSamuel.Tu@Sun.COM 		    (intr_alloc_entry & 0x3)));
48329353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
48339353SSamuel.Tu@Sun.COM 		break;
4834*13006SChenlu.Chen@Sun.COM 
48359353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
48369353SSamuel.Tu@Sun.COM 		if (cause == -1) {
48379353SSamuel.Tu@Sun.COM 			/* other causes */
48389353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
48399353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
48409353SSamuel.Tu@Sun.COM 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
48419353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
48429353SSamuel.Tu@Sun.COM 		} else {
48439353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
48449353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
48459353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
48469353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
48479353SSamuel.Tu@Sun.COM 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
48489353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
48499353SSamuel.Tu@Sun.COM 			    ivar);
48509353SSamuel.Tu@Sun.COM 		}
48519353SSamuel.Tu@Sun.COM 		break;
4852*13006SChenlu.Chen@Sun.COM 
48539353SSamuel.Tu@Sun.COM 	default:
48549353SSamuel.Tu@Sun.COM 		break;
48559353SSamuel.Tu@Sun.COM 	}
48566621Sbt150084 }
48576621Sbt150084 
48586621Sbt150084 /*
485911878SVenu.Iyer@Sun.COM  * Convert the rx ring index driver maintained to the rx ring index
486011878SVenu.Iyer@Sun.COM  * in h/w.
486111878SVenu.Iyer@Sun.COM  */
486211878SVenu.Iyer@Sun.COM static uint32_t
ixgbe_get_hw_rx_index(ixgbe_t * ixgbe,uint32_t sw_rx_index)486311878SVenu.Iyer@Sun.COM ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index)
486411878SVenu.Iyer@Sun.COM {
486511878SVenu.Iyer@Sun.COM 
486611878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
486711878SVenu.Iyer@Sun.COM 	uint32_t rx_ring_per_group, hw_rx_index;
486811878SVenu.Iyer@Sun.COM 
486911878SVenu.Iyer@Sun.COM 	if (ixgbe->classify_mode == IXGBE_CLASSIFY_RSS ||
487011878SVenu.Iyer@Sun.COM 	    ixgbe->classify_mode == IXGBE_CLASSIFY_NONE) {
487111878SVenu.Iyer@Sun.COM 		return (sw_rx_index);
487211878SVenu.Iyer@Sun.COM 	} else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ) {
4873*13006SChenlu.Chen@Sun.COM 		switch (hw->mac.type) {
4874*13006SChenlu.Chen@Sun.COM 		case ixgbe_mac_82598EB:
487511878SVenu.Iyer@Sun.COM 			return (sw_rx_index);
4876*13006SChenlu.Chen@Sun.COM 
4877*13006SChenlu.Chen@Sun.COM 		case ixgbe_mac_82599EB:
487811878SVenu.Iyer@Sun.COM 			return (sw_rx_index * 2);
4879*13006SChenlu.Chen@Sun.COM 
4880*13006SChenlu.Chen@Sun.COM 		default:
4881*13006SChenlu.Chen@Sun.COM 			break;
488211878SVenu.Iyer@Sun.COM 		}
488311878SVenu.Iyer@Sun.COM 	} else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) {
488411878SVenu.Iyer@Sun.COM 		rx_ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
488511878SVenu.Iyer@Sun.COM 
4886*13006SChenlu.Chen@Sun.COM 		switch (hw->mac.type) {
4887*13006SChenlu.Chen@Sun.COM 		case ixgbe_mac_82598EB:
488811878SVenu.Iyer@Sun.COM 			hw_rx_index = (sw_rx_index / rx_ring_per_group) *
488911878SVenu.Iyer@Sun.COM 			    16 + (sw_rx_index % rx_ring_per_group);
489011878SVenu.Iyer@Sun.COM 			return (hw_rx_index);
4891*13006SChenlu.Chen@Sun.COM 
4892*13006SChenlu.Chen@Sun.COM 		case ixgbe_mac_82599EB:
489311878SVenu.Iyer@Sun.COM 			if (ixgbe->num_rx_groups > 32) {
489411878SVenu.Iyer@Sun.COM 				hw_rx_index = (sw_rx_index /
489511878SVenu.Iyer@Sun.COM 				    rx_ring_per_group) * 2 +
489611878SVenu.Iyer@Sun.COM 				    (sw_rx_index % rx_ring_per_group);
489711878SVenu.Iyer@Sun.COM 			} else {
489811878SVenu.Iyer@Sun.COM 				hw_rx_index = (sw_rx_index /
489911878SVenu.Iyer@Sun.COM 				    rx_ring_per_group) * 4 +
490011878SVenu.Iyer@Sun.COM 				    (sw_rx_index % rx_ring_per_group);
490111878SVenu.Iyer@Sun.COM 			}
490211878SVenu.Iyer@Sun.COM 			return (hw_rx_index);
4903*13006SChenlu.Chen@Sun.COM 
4904*13006SChenlu.Chen@Sun.COM 		default:
4905*13006SChenlu.Chen@Sun.COM 			break;
490611878SVenu.Iyer@Sun.COM 		}
490711878SVenu.Iyer@Sun.COM 	}
490811878SVenu.Iyer@Sun.COM 
490911878SVenu.Iyer@Sun.COM 	/*
491011878SVenu.Iyer@Sun.COM 	 * Should never reach. Just to make compiler happy.
491111878SVenu.Iyer@Sun.COM 	 */
491211878SVenu.Iyer@Sun.COM 	return (sw_rx_index);
491311878SVenu.Iyer@Sun.COM }
491411878SVenu.Iyer@Sun.COM 
491511878SVenu.Iyer@Sun.COM /*
49169353SSamuel.Tu@Sun.COM  * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors.
49176621Sbt150084  *
49189353SSamuel.Tu@Sun.COM  * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt
49199353SSamuel.Tu@Sun.COM  * to vector[0 - (intr_cnt -1)].
49206621Sbt150084  */
49216621Sbt150084 static int
ixgbe_map_intrs_to_vectors(ixgbe_t * ixgbe)49229353SSamuel.Tu@Sun.COM ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe)
49236621Sbt150084 {
49246621Sbt150084 	int i, vector = 0;
49256621Sbt150084 
49266621Sbt150084 	/* initialize vector map */
49276621Sbt150084 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
49289353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->intr_cnt; i++) {
49299353SSamuel.Tu@Sun.COM 		ixgbe->vect_map[i].ixgbe = ixgbe;
49309353SSamuel.Tu@Sun.COM 	}
49316621Sbt150084 
49326621Sbt150084 	/*
49338275SEric Cheng 	 * non-MSI-X case is very simple: rx rings[0] on RTxQ[0],
49348275SEric Cheng 	 * tx rings[0] on RTxQ[1].
49356621Sbt150084 	 */
49366621Sbt150084 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
49376621Sbt150084 		ixgbe_map_rxring_to_vector(ixgbe, 0, 0);
49388275SEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, 0, 1);
49396621Sbt150084 		return (IXGBE_SUCCESS);
49406621Sbt150084 	}
49416621Sbt150084 
49426621Sbt150084 	/*
49439353SSamuel.Tu@Sun.COM 	 * Interrupts/vectors mapping for MSI-X
49446621Sbt150084 	 */
49456621Sbt150084 
49466621Sbt150084 	/*
49479353SSamuel.Tu@Sun.COM 	 * Map other interrupt to vector 0,
49489353SSamuel.Tu@Sun.COM 	 * Set bit in map and count the bits set.
49499353SSamuel.Tu@Sun.COM 	 */
49509353SSamuel.Tu@Sun.COM 	BT_SET(ixgbe->vect_map[vector].other_map, 0);
49519353SSamuel.Tu@Sun.COM 	ixgbe->vect_map[vector].other_cnt++;
49529353SSamuel.Tu@Sun.COM 
49539353SSamuel.Tu@Sun.COM 	/*
49549353SSamuel.Tu@Sun.COM 	 * Map rx ring interrupts to vectors
49556621Sbt150084 	 */
49568275SEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
49578275SEric Cheng 		ixgbe_map_rxring_to_vector(ixgbe, i, vector);
49589353SSamuel.Tu@Sun.COM 		vector = (vector +1) % ixgbe->intr_cnt;
49598275SEric Cheng 	}
49606621Sbt150084 
49616621Sbt150084 	/*
49629353SSamuel.Tu@Sun.COM 	 * Map tx ring interrupts to vectors
49636621Sbt150084 	 */
49648275SEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
49658275SEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, i, vector);
49669353SSamuel.Tu@Sun.COM 		vector = (vector +1) % ixgbe->intr_cnt;
49676621Sbt150084 	}
49686621Sbt150084 
49696621Sbt150084 	return (IXGBE_SUCCESS);
49706621Sbt150084 }
49716621Sbt150084 
49726621Sbt150084 /*
49736621Sbt150084  * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s).
49746621Sbt150084  *
49758275SEric Cheng  * This relies on ring/vector mapping already set up in the
49766621Sbt150084  * vect_map[] structures
49776621Sbt150084  */
49786621Sbt150084 static void
ixgbe_setup_adapter_vector(ixgbe_t * ixgbe)49796621Sbt150084 ixgbe_setup_adapter_vector(ixgbe_t *ixgbe)
49806621Sbt150084 {
49816621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
49829353SSamuel.Tu@Sun.COM 	ixgbe_intr_vector_t *vect;	/* vector bitmap */
49838275SEric Cheng 	int r_idx;	/* ring index */
49848275SEric Cheng 	int v_idx;	/* vector index */
498511878SVenu.Iyer@Sun.COM 	uint32_t hw_index;
49866621Sbt150084 
49876621Sbt150084 	/*
49886621Sbt150084 	 * Clear any previous entries
49896621Sbt150084 	 */
49909353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
49919353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
49929353SSamuel.Tu@Sun.COM 		for (v_idx = 0; v_idx < 25; v_idx++)
49939353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
49949353SSamuel.Tu@Sun.COM 		break;
4995*13006SChenlu.Chen@Sun.COM 
49969353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
49979353SSamuel.Tu@Sun.COM 		for (v_idx = 0; v_idx < 64; v_idx++)
49989353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
49999353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0);
50009353SSamuel.Tu@Sun.COM 		break;
5001*13006SChenlu.Chen@Sun.COM 
50029353SSamuel.Tu@Sun.COM 	default:
50039353SSamuel.Tu@Sun.COM 		break;
50049353SSamuel.Tu@Sun.COM 	}
50056621Sbt150084 
50066621Sbt150084 	/*
50078275SEric Cheng 	 * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and
50088275SEric Cheng 	 * tx rings[0] will use RTxQ[1].
50096621Sbt150084 	 */
50108275SEric Cheng 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
50119353SSamuel.Tu@Sun.COM 		ixgbe_setup_ivar(ixgbe, 0, 0, 0);
50129353SSamuel.Tu@Sun.COM 		ixgbe_setup_ivar(ixgbe, 0, 1, 1);
50138275SEric Cheng 		return;
50148275SEric Cheng 	}
50158275SEric Cheng 
50168275SEric Cheng 	/*
50179353SSamuel.Tu@Sun.COM 	 * For MSI-X interrupt, "Other" is always on vector[0].
50188275SEric Cheng 	 */
50199353SSamuel.Tu@Sun.COM 	ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1);
50206621Sbt150084 
50216621Sbt150084 	/*
50226621Sbt150084 	 * For each interrupt vector, populate the IVAR table
50236621Sbt150084 	 */
50246621Sbt150084 	for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) {
50256621Sbt150084 		vect = &ixgbe->vect_map[v_idx];
50266621Sbt150084 
50276621Sbt150084 		/*
50286621Sbt150084 		 * For each rx ring bit set
50296621Sbt150084 		 */
50306621Sbt150084 		r_idx = bt_getlowbit(vect->rx_map, 0,
50316621Sbt150084 		    (ixgbe->num_rx_rings - 1));
50326621Sbt150084 
50336621Sbt150084 		while (r_idx >= 0) {
503411878SVenu.Iyer@Sun.COM 			hw_index = ixgbe->rx_rings[r_idx].hw_index;
503511878SVenu.Iyer@Sun.COM 			ixgbe_setup_ivar(ixgbe, hw_index, v_idx, 0);
50366621Sbt150084 			r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
50376621Sbt150084 			    (ixgbe->num_rx_rings - 1));
50386621Sbt150084 		}
50396621Sbt150084 
50406621Sbt150084 		/*
50416621Sbt150084 		 * For each tx ring bit set
50426621Sbt150084 		 */
50436621Sbt150084 		r_idx = bt_getlowbit(vect->tx_map, 0,
50446621Sbt150084 		    (ixgbe->num_tx_rings - 1));
50456621Sbt150084 
50466621Sbt150084 		while (r_idx >= 0) {
50479353SSamuel.Tu@Sun.COM 			ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1);
50486621Sbt150084 			r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
50496621Sbt150084 			    (ixgbe->num_tx_rings - 1));
50506621Sbt150084 		}
50516621Sbt150084 	}
50526621Sbt150084 }
50536621Sbt150084 
50546621Sbt150084 /*
50556621Sbt150084  * ixgbe_rem_intr_handlers - Remove the interrupt handlers.
50566621Sbt150084  */
50576621Sbt150084 static void
ixgbe_rem_intr_handlers(ixgbe_t * ixgbe)50586621Sbt150084 ixgbe_rem_intr_handlers(ixgbe_t *ixgbe)
50596621Sbt150084 {
50606621Sbt150084 	int i;
50616621Sbt150084 	int rc;
50626621Sbt150084 
50636621Sbt150084 	for (i = 0; i < ixgbe->intr_cnt; i++) {
50646621Sbt150084 		rc = ddi_intr_remove_handler(ixgbe->htable[i]);
50656621Sbt150084 		if (rc != DDI_SUCCESS) {
50666621Sbt150084 			IXGBE_DEBUGLOG_1(ixgbe,
50676621Sbt150084 			    "Remove intr handler failed: %d", rc);
50686621Sbt150084 		}
50696621Sbt150084 	}
50706621Sbt150084 }
50716621Sbt150084 
50726621Sbt150084 /*
50736621Sbt150084  * ixgbe_rem_intrs - Remove the allocated interrupts.
50746621Sbt150084  */
50756621Sbt150084 static void
ixgbe_rem_intrs(ixgbe_t * ixgbe)50766621Sbt150084 ixgbe_rem_intrs(ixgbe_t *ixgbe)
50776621Sbt150084 {
50786621Sbt150084 	int i;
50796621Sbt150084 	int rc;
50806621Sbt150084 
50816621Sbt150084 	for (i = 0; i < ixgbe->intr_cnt; i++) {
50826621Sbt150084 		rc = ddi_intr_free(ixgbe->htable[i]);
50836621Sbt150084 		if (rc != DDI_SUCCESS) {
50846621Sbt150084 			IXGBE_DEBUGLOG_1(ixgbe,
50856621Sbt150084 			    "Free intr failed: %d", rc);
50866621Sbt150084 		}
50876621Sbt150084 	}
50886621Sbt150084 
50896621Sbt150084 	kmem_free(ixgbe->htable, ixgbe->intr_size);
50906621Sbt150084 	ixgbe->htable = NULL;
50916621Sbt150084 }
50926621Sbt150084 
50936621Sbt150084 /*
50946621Sbt150084  * ixgbe_enable_intrs - Enable all the ddi interrupts.
50956621Sbt150084  */
50966621Sbt150084 static int
ixgbe_enable_intrs(ixgbe_t * ixgbe)50976621Sbt150084 ixgbe_enable_intrs(ixgbe_t *ixgbe)
50986621Sbt150084 {
50996621Sbt150084 	int i;
51006621Sbt150084 	int rc;
51016621Sbt150084 
51026621Sbt150084 	/*
51036621Sbt150084 	 * Enable interrupts
51046621Sbt150084 	 */
51056621Sbt150084 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
51066621Sbt150084 		/*
51076621Sbt150084 		 * Call ddi_intr_block_enable() for MSI
51086621Sbt150084 		 */
51096621Sbt150084 		rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt);
51106621Sbt150084 		if (rc != DDI_SUCCESS) {
51116621Sbt150084 			ixgbe_log(ixgbe,
51126621Sbt150084 			    "Enable block intr failed: %d", rc);
51136621Sbt150084 			return (IXGBE_FAILURE);
51146621Sbt150084 		}
51156621Sbt150084 	} else {
51166621Sbt150084 		/*
51176621Sbt150084 		 * Call ddi_intr_enable() for Legacy/MSI non block enable
51186621Sbt150084 		 */
51196621Sbt150084 		for (i = 0; i < ixgbe->intr_cnt; i++) {
51206621Sbt150084 			rc = ddi_intr_enable(ixgbe->htable[i]);
51216621Sbt150084 			if (rc != DDI_SUCCESS) {
51226621Sbt150084 				ixgbe_log(ixgbe,
51236621Sbt150084 				    "Enable intr failed: %d", rc);
51246621Sbt150084 				return (IXGBE_FAILURE);
51256621Sbt150084 			}
51266621Sbt150084 		}
51276621Sbt150084 	}
51286621Sbt150084 
51296621Sbt150084 	return (IXGBE_SUCCESS);
51306621Sbt150084 }
51316621Sbt150084 
51326621Sbt150084 /*
51336621Sbt150084  * ixgbe_disable_intrs - Disable all the interrupts.
51346621Sbt150084  */
51356621Sbt150084 static int
ixgbe_disable_intrs(ixgbe_t * ixgbe)51366621Sbt150084 ixgbe_disable_intrs(ixgbe_t *ixgbe)
51376621Sbt150084 {
51386621Sbt150084 	int i;
51396621Sbt150084 	int rc;
51406621Sbt150084 
51416621Sbt150084 	/*
51426621Sbt150084 	 * Disable all interrupts
51436621Sbt150084 	 */
51446621Sbt150084 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
51456621Sbt150084 		rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt);
51466621Sbt150084 		if (rc != DDI_SUCCESS) {
51476621Sbt150084 			ixgbe_log(ixgbe,
51486621Sbt150084 			    "Disable block intr failed: %d", rc);
51496621Sbt150084 			return (IXGBE_FAILURE);
51506621Sbt150084 		}
51516621Sbt150084 	} else {
51526621Sbt150084 		for (i = 0; i < ixgbe->intr_cnt; i++) {
51536621Sbt150084 			rc = ddi_intr_disable(ixgbe->htable[i]);
51546621Sbt150084 			if (rc != DDI_SUCCESS) {
51556621Sbt150084 				ixgbe_log(ixgbe,
51566621Sbt150084 				    "Disable intr failed: %d", rc);
51576621Sbt150084 				return (IXGBE_FAILURE);
51586621Sbt150084 			}
51596621Sbt150084 		}
51606621Sbt150084 	}
51616621Sbt150084 
51626621Sbt150084 	return (IXGBE_SUCCESS);
51636621Sbt150084 }
51646621Sbt150084 
51656621Sbt150084 /*
51666621Sbt150084  * ixgbe_get_hw_state - Get and save parameters related to adapter hardware.
51676621Sbt150084  */
51686621Sbt150084 static void
ixgbe_get_hw_state(ixgbe_t * ixgbe)51696621Sbt150084 ixgbe_get_hw_state(ixgbe_t *ixgbe)
51706621Sbt150084 {
51716621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
51728490SPaul.Guo@Sun.COM 	ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
51738490SPaul.Guo@Sun.COM 	boolean_t link_up = B_FALSE;
51746621Sbt150084 	uint32_t pcs1g_anlp = 0;
51756621Sbt150084 	uint32_t pcs1g_ana = 0;
5176*13006SChenlu.Chen@Sun.COM 	boolean_t autoneg = B_FALSE;
51776621Sbt150084 
51786621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
51796621Sbt150084 	ixgbe->param_lp_1000fdx_cap = 0;
51806621Sbt150084 	ixgbe->param_lp_100fdx_cap  = 0;
51816621Sbt150084 
51828490SPaul.Guo@Sun.COM 	/* check for link, don't wait */
51838490SPaul.Guo@Sun.COM 	(void) ixgbe_check_link(hw, &speed, &link_up, false);
5184*13006SChenlu.Chen@Sun.COM 	pcs1g_ana = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
5185*13006SChenlu.Chen@Sun.COM 
51868490SPaul.Guo@Sun.COM 	if (link_up) {
51876621Sbt150084 		pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
51886621Sbt150084 
51896621Sbt150084 		ixgbe->param_lp_1000fdx_cap =
51906621Sbt150084 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
51916621Sbt150084 		ixgbe->param_lp_100fdx_cap =
51926621Sbt150084 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
51936621Sbt150084 	}
51946621Sbt150084 
5195*13006SChenlu.Chen@Sun.COM 	(void) ixgbe_get_link_capabilities(hw, &speed, &autoneg);
5196*13006SChenlu.Chen@Sun.COM 
5197*13006SChenlu.Chen@Sun.COM 	ixgbe->param_adv_1000fdx_cap = ((pcs1g_ana & IXGBE_PCS1GANA_FDC) &&
5198*13006SChenlu.Chen@Sun.COM 	    (speed & IXGBE_LINK_SPEED_1GB_FULL)) ? 1 : 0;
5199*13006SChenlu.Chen@Sun.COM 	ixgbe->param_adv_100fdx_cap = ((pcs1g_ana & IXGBE_PCS1GANA_FDC) &&
5200*13006SChenlu.Chen@Sun.COM 	    (speed & IXGBE_LINK_SPEED_100_FULL)) ? 1 : 0;
52016621Sbt150084 }
52026621Sbt150084 
52036621Sbt150084 /*
52046621Sbt150084  * ixgbe_get_driver_control - Notify that driver is in control of device.
52056621Sbt150084  */
52066621Sbt150084 static void
ixgbe_get_driver_control(struct ixgbe_hw * hw)52076621Sbt150084 ixgbe_get_driver_control(struct ixgbe_hw *hw)
52086621Sbt150084 {
52096621Sbt150084 	uint32_t ctrl_ext;
52106621Sbt150084 
52116621Sbt150084 	/*
52126621Sbt150084 	 * Notify firmware that driver is in control of device
52136621Sbt150084 	 */
52146621Sbt150084 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
52156621Sbt150084 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
52166621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
52176621Sbt150084 }
52186621Sbt150084 
52196621Sbt150084 /*
52206621Sbt150084  * ixgbe_release_driver_control - Notify that driver is no longer in control
52216621Sbt150084  * of device.
52226621Sbt150084  */
52236621Sbt150084 static void
ixgbe_release_driver_control(struct ixgbe_hw * hw)52246621Sbt150084 ixgbe_release_driver_control(struct ixgbe_hw *hw)
52256621Sbt150084 {
52266621Sbt150084 	uint32_t ctrl_ext;
52276621Sbt150084 
52286621Sbt150084 	/*
52296621Sbt150084 	 * Notify firmware that driver is no longer in control of device
52306621Sbt150084 	 */
52316621Sbt150084 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
52326621Sbt150084 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
52336621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
52346621Sbt150084 }
52356621Sbt150084 
52366621Sbt150084 /*
52376621Sbt150084  * ixgbe_atomic_reserve - Atomic decrease operation.
52386621Sbt150084  */
52396621Sbt150084 int
ixgbe_atomic_reserve(uint32_t * count_p,uint32_t n)52406621Sbt150084 ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n)
52416621Sbt150084 {
52426621Sbt150084 	uint32_t oldval;
52436621Sbt150084 	uint32_t newval;
52446621Sbt150084 
52456621Sbt150084 	/*
52466621Sbt150084 	 * ATOMICALLY
52476621Sbt150084 	 */
52486621Sbt150084 	do {
52496621Sbt150084 		oldval = *count_p;
52506621Sbt150084 		if (oldval < n)
52516621Sbt150084 			return (-1);
52526621Sbt150084 		newval = oldval - n;
52536621Sbt150084 	} while (atomic_cas_32(count_p, oldval, newval) != oldval);
52546621Sbt150084 
52556621Sbt150084 	return (newval);
52566621Sbt150084 }
52576621Sbt150084 
52586621Sbt150084 /*
52596621Sbt150084  * ixgbe_mc_table_itr - Traverse the entries in the multicast table.
52606621Sbt150084  */
52616621Sbt150084 static uint8_t *
ixgbe_mc_table_itr(struct ixgbe_hw * hw,uint8_t ** upd_ptr,uint32_t * vmdq)52626621Sbt150084 ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq)
52636621Sbt150084 {
52648490SPaul.Guo@Sun.COM 	uint8_t *addr = *upd_ptr;
52658490SPaul.Guo@Sun.COM 	uint8_t *new_ptr;
52668490SPaul.Guo@Sun.COM 
52676621Sbt150084 	_NOTE(ARGUNUSED(hw));
52686621Sbt150084 	_NOTE(ARGUNUSED(vmdq));
52696621Sbt150084 
52706621Sbt150084 	new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS;
52716621Sbt150084 	*upd_ptr = new_ptr;
52726621Sbt150084 	return (addr);
52736621Sbt150084 }
52746621Sbt150084 
52756621Sbt150084 /*
52766621Sbt150084  * FMA support
52776621Sbt150084  */
52786621Sbt150084 int
ixgbe_check_acc_handle(ddi_acc_handle_t handle)52796621Sbt150084 ixgbe_check_acc_handle(ddi_acc_handle_t handle)
52806621Sbt150084 {
52816621Sbt150084 	ddi_fm_error_t de;
52826621Sbt150084 
52836621Sbt150084 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
52846621Sbt150084 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
52856621Sbt150084 	return (de.fme_status);
52866621Sbt150084 }
52876621Sbt150084 
52886621Sbt150084 int
ixgbe_check_dma_handle(ddi_dma_handle_t handle)52896621Sbt150084 ixgbe_check_dma_handle(ddi_dma_handle_t handle)
52906621Sbt150084 {
52916621Sbt150084 	ddi_fm_error_t de;
52926621Sbt150084 
52936621Sbt150084 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
52946621Sbt150084 	return (de.fme_status);
52956621Sbt150084 }
52966621Sbt150084 
52976621Sbt150084 /*
52986621Sbt150084  * ixgbe_fm_error_cb - The IO fault service error handling callback function.
52996621Sbt150084  */
53006621Sbt150084 static int
ixgbe_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)53016621Sbt150084 ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
53026621Sbt150084 {
53036621Sbt150084 	_NOTE(ARGUNUSED(impl_data));
53046621Sbt150084 	/*
53056621Sbt150084 	 * as the driver can always deal with an error in any dma or
53066621Sbt150084 	 * access handle, we can just return the fme_status value.
53076621Sbt150084 	 */
53086621Sbt150084 	pci_ereport_post(dip, err, NULL);
53096621Sbt150084 	return (err->fme_status);
53106621Sbt150084 }
53116621Sbt150084 
53126621Sbt150084 static void
ixgbe_fm_init(ixgbe_t * ixgbe)53136621Sbt150084 ixgbe_fm_init(ixgbe_t *ixgbe)
53146621Sbt150084 {
53156621Sbt150084 	ddi_iblock_cookie_t iblk;
531611236SStephen.Hanson@Sun.COM 	int fma_dma_flag;
53176621Sbt150084 
53186621Sbt150084 	/*
53196621Sbt150084 	 * Only register with IO Fault Services if we have some capability
53206621Sbt150084 	 */
53216621Sbt150084 	if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
53226621Sbt150084 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
53236621Sbt150084 	} else {
53246621Sbt150084 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
53256621Sbt150084 	}
53266621Sbt150084 
53276621Sbt150084 	if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
53286621Sbt150084 		fma_dma_flag = 1;
53296621Sbt150084 	} else {
53306621Sbt150084 		fma_dma_flag = 0;
53316621Sbt150084 	}
53326621Sbt150084 
533311236SStephen.Hanson@Sun.COM 	ixgbe_set_fma_flags(fma_dma_flag);
53346621Sbt150084 
53356621Sbt150084 	if (ixgbe->fm_capabilities) {
53366621Sbt150084 
53376621Sbt150084 		/*
53386621Sbt150084 		 * Register capabilities with IO Fault Services
53396621Sbt150084 		 */
53406621Sbt150084 		ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk);
53416621Sbt150084 
53426621Sbt150084 		/*
53436621Sbt150084 		 * Initialize pci ereport capabilities if ereport capable
53446621Sbt150084 		 */
53456621Sbt150084 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
53466621Sbt150084 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
53476621Sbt150084 			pci_ereport_setup(ixgbe->dip);
53486621Sbt150084 
53496621Sbt150084 		/*
53506621Sbt150084 		 * Register error callback if error callback capable
53516621Sbt150084 		 */
53526621Sbt150084 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
53536621Sbt150084 			ddi_fm_handler_register(ixgbe->dip,
53546621Sbt150084 			    ixgbe_fm_error_cb, (void*) ixgbe);
53556621Sbt150084 	}
53566621Sbt150084 }
53576621Sbt150084 
53586621Sbt150084 static void
ixgbe_fm_fini(ixgbe_t * ixgbe)53596621Sbt150084 ixgbe_fm_fini(ixgbe_t *ixgbe)
53606621Sbt150084 {
53616621Sbt150084 	/*
53626621Sbt150084 	 * Only unregister FMA capabilities if they are registered
53636621Sbt150084 	 */
53646621Sbt150084 	if (ixgbe->fm_capabilities) {
53656621Sbt150084 
53666621Sbt150084 		/*
53676621Sbt150084 		 * Release any resources allocated by pci_ereport_setup()
53686621Sbt150084 		 */
53696621Sbt150084 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
53706621Sbt150084 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
53716621Sbt150084 			pci_ereport_teardown(ixgbe->dip);
53726621Sbt150084 
53736621Sbt150084 		/*
53746621Sbt150084 		 * Un-register error callback if error callback capable
53756621Sbt150084 		 */
53766621Sbt150084 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
53776621Sbt150084 			ddi_fm_handler_unregister(ixgbe->dip);
53786621Sbt150084 
53796621Sbt150084 		/*
53806621Sbt150084 		 * Unregister from IO Fault Service
53816621Sbt150084 		 */
53826621Sbt150084 		ddi_fm_fini(ixgbe->dip);
53836621Sbt150084 	}
53846621Sbt150084 }
53856621Sbt150084 
53866621Sbt150084 void
ixgbe_fm_ereport(ixgbe_t * ixgbe,char * detail)53876621Sbt150084 ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail)
53886621Sbt150084 {
53896621Sbt150084 	uint64_t ena;
53906621Sbt150084 	char buf[FM_MAX_CLASS];
53916621Sbt150084 
53926621Sbt150084 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
53936621Sbt150084 	ena = fm_ena_generate(0, FM_ENA_FMT1);
53946621Sbt150084 	if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) {
53956621Sbt150084 		ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP,
53966621Sbt150084 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
53976621Sbt150084 	}
53986621Sbt150084 }
53998275SEric Cheng 
54008275SEric Cheng static int
ixgbe_ring_start(mac_ring_driver_t rh,uint64_t mr_gen_num)54018275SEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
54028275SEric Cheng {
54038275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh;
54048275SEric Cheng 
54058275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
54068275SEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
54078275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
54088275SEric Cheng 	return (0);
54098275SEric Cheng }
54108275SEric Cheng 
54118275SEric Cheng /*
541211878SVenu.Iyer@Sun.COM  * Get the global ring index by a ring index within a group.
541311878SVenu.Iyer@Sun.COM  */
541411878SVenu.Iyer@Sun.COM static int
ixgbe_get_rx_ring_index(ixgbe_t * ixgbe,int gindex,int rindex)541511878SVenu.Iyer@Sun.COM ixgbe_get_rx_ring_index(ixgbe_t *ixgbe, int gindex, int rindex)
541611878SVenu.Iyer@Sun.COM {
541711878SVenu.Iyer@Sun.COM 	ixgbe_rx_ring_t *rx_ring;
541811878SVenu.Iyer@Sun.COM 	int i;
541911878SVenu.Iyer@Sun.COM 
542011878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
542111878SVenu.Iyer@Sun.COM 		rx_ring = &ixgbe->rx_rings[i];
542211878SVenu.Iyer@Sun.COM 		if (rx_ring->group_index == gindex)
542311878SVenu.Iyer@Sun.COM 			rindex--;
542411878SVenu.Iyer@Sun.COM 		if (rindex < 0)
542511878SVenu.Iyer@Sun.COM 			return (i);
542611878SVenu.Iyer@Sun.COM 	}
542711878SVenu.Iyer@Sun.COM 
542811878SVenu.Iyer@Sun.COM 	return (-1);
542911878SVenu.Iyer@Sun.COM }
543011878SVenu.Iyer@Sun.COM 
543111878SVenu.Iyer@Sun.COM /*
54328275SEric Cheng  * Callback funtion for MAC layer to register all rings.
54338275SEric Cheng  */
54348275SEric Cheng /* ARGSUSED */
54358275SEric Cheng void
ixgbe_fill_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)543611878SVenu.Iyer@Sun.COM ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index,
54378275SEric Cheng     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
54388275SEric Cheng {
54398275SEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
54408275SEric Cheng 	mac_intr_t *mintr = &infop->mri_intr;
54418275SEric Cheng 
54428275SEric Cheng 	switch (rtype) {
54438275SEric Cheng 	case MAC_RING_TYPE_RX: {
544411878SVenu.Iyer@Sun.COM 		/*
544511878SVenu.Iyer@Sun.COM 		 * 'index' is the ring index within the group.
544611878SVenu.Iyer@Sun.COM 		 * Need to get the global ring index by searching in groups.
544711878SVenu.Iyer@Sun.COM 		 */
544811878SVenu.Iyer@Sun.COM 		int global_ring_index = ixgbe_get_rx_ring_index(
544911878SVenu.Iyer@Sun.COM 		    ixgbe, group_index, ring_index);
545011878SVenu.Iyer@Sun.COM 
545111878SVenu.Iyer@Sun.COM 		ASSERT(global_ring_index >= 0);
545211878SVenu.Iyer@Sun.COM 
545311878SVenu.Iyer@Sun.COM 		ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[global_ring_index];
54548275SEric Cheng 		rx_ring->ring_handle = rh;
54558275SEric Cheng 
54568275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
54578275SEric Cheng 		infop->mri_start = ixgbe_ring_start;
54588275SEric Cheng 		infop->mri_stop = NULL;
54598275SEric Cheng 		infop->mri_poll = ixgbe_ring_rx_poll;
546011878SVenu.Iyer@Sun.COM 		infop->mri_stat = ixgbe_rx_ring_stat;
54618275SEric Cheng 
54628275SEric Cheng 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
54638275SEric Cheng 		mintr->mi_enable = ixgbe_rx_ring_intr_enable;
54648275SEric Cheng 		mintr->mi_disable = ixgbe_rx_ring_intr_disable;
546511878SVenu.Iyer@Sun.COM 		if (ixgbe->intr_type &
546611878SVenu.Iyer@Sun.COM 		    (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
546711878SVenu.Iyer@Sun.COM 			mintr->mi_ddi_handle =
546811878SVenu.Iyer@Sun.COM 			    ixgbe->htable[rx_ring->intr_vector];
546911878SVenu.Iyer@Sun.COM 		}
54708275SEric Cheng 
54718275SEric Cheng 		break;
54728275SEric Cheng 	}
54738275SEric Cheng 	case MAC_RING_TYPE_TX: {
547411878SVenu.Iyer@Sun.COM 		ASSERT(group_index == -1);
54758275SEric Cheng 		ASSERT(ring_index < ixgbe->num_tx_rings);
54768275SEric Cheng 
54778275SEric Cheng 		ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index];
54788275SEric Cheng 		tx_ring->ring_handle = rh;
54798275SEric Cheng 
54808275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
54818275SEric Cheng 		infop->mri_start = NULL;
54828275SEric Cheng 		infop->mri_stop = NULL;
54838275SEric Cheng 		infop->mri_tx = ixgbe_ring_tx;
548411878SVenu.Iyer@Sun.COM 		infop->mri_stat = ixgbe_tx_ring_stat;
548511878SVenu.Iyer@Sun.COM 		if (ixgbe->intr_type &
548611878SVenu.Iyer@Sun.COM 		    (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
548711878SVenu.Iyer@Sun.COM 			mintr->mi_ddi_handle =
548811878SVenu.Iyer@Sun.COM 			    ixgbe->htable[tx_ring->intr_vector];
548911878SVenu.Iyer@Sun.COM 		}
54908275SEric Cheng 		break;
54918275SEric Cheng 	}
54928275SEric Cheng 	default:
54938275SEric Cheng 		break;
54948275SEric Cheng 	}
54958275SEric Cheng }
54968275SEric Cheng 
54978275SEric Cheng /*
54988275SEric Cheng  * Callback funtion for MAC layer to register all groups.
54998275SEric Cheng  */
55008275SEric Cheng void
ixgbe_fill_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)55018275SEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index,
55028275SEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
55038275SEric Cheng {
55048275SEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
55058275SEric Cheng 
55068275SEric Cheng 	switch (rtype) {
55078275SEric Cheng 	case MAC_RING_TYPE_RX: {
55088275SEric Cheng 		ixgbe_rx_group_t *rx_group;
55098275SEric Cheng 
55108275SEric Cheng 		rx_group = &ixgbe->rx_groups[index];
55118275SEric Cheng 		rx_group->group_handle = gh;
55128275SEric Cheng 
55138275SEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_group;
55148275SEric Cheng 		infop->mgi_start = NULL;
55158275SEric Cheng 		infop->mgi_stop = NULL;
55168275SEric Cheng 		infop->mgi_addmac = ixgbe_addmac;
55178275SEric Cheng 		infop->mgi_remmac = ixgbe_remmac;
55188275SEric Cheng 		infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups);
55198275SEric Cheng 
55208275SEric Cheng 		break;
55218275SEric Cheng 	}
55228275SEric Cheng 	case MAC_RING_TYPE_TX:
55238275SEric Cheng 		break;
55248275SEric Cheng 	default:
55258275SEric Cheng 		break;
55268275SEric Cheng 	}
55278275SEric Cheng }
55288275SEric Cheng 
55298275SEric Cheng /*
55308275SEric Cheng  * Enable interrupt on the specificed rx ring.
55318275SEric Cheng  */
55328275SEric Cheng int
ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)55338275SEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)
55348275SEric Cheng {
55358275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
55368275SEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
55378275SEric Cheng 	int r_idx = rx_ring->index;
553811878SVenu.Iyer@Sun.COM 	int hw_r_idx = rx_ring->hw_index;
55398275SEric Cheng 	int v_idx = rx_ring->intr_vector;
55408275SEric Cheng 
55418275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
554211878SVenu.Iyer@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
554311878SVenu.Iyer@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
554411878SVenu.Iyer@Sun.COM 		/*
554511878SVenu.Iyer@Sun.COM 		 * Simply return 0.
554611878SVenu.Iyer@Sun.COM 		 * Interrupts are being adjusted. ixgbe_intr_adjust()
554711878SVenu.Iyer@Sun.COM 		 * will eventually re-enable the interrupt when it's
554811878SVenu.Iyer@Sun.COM 		 * done with the adjustment.
554911878SVenu.Iyer@Sun.COM 		 */
555011878SVenu.Iyer@Sun.COM 		return (0);
555111878SVenu.Iyer@Sun.COM 	}
55528275SEric Cheng 
55538275SEric Cheng 	/*
55548275SEric Cheng 	 * To enable interrupt by setting the VAL bit of given interrupt
55558275SEric Cheng 	 * vector allocation register (IVAR).
55568275SEric Cheng 	 */
555711878SVenu.Iyer@Sun.COM 	ixgbe_enable_ivar(ixgbe, hw_r_idx, 0);
55588275SEric Cheng 
55598275SEric Cheng 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
556010305SPaul.Guo@Sun.COM 
556110305SPaul.Guo@Sun.COM 	/*
556212003SPaul.Guo@Sun.COM 	 * Trigger a Rx interrupt on this ring
556310305SPaul.Guo@Sun.COM 	 */
556410305SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx));
556510305SPaul.Guo@Sun.COM 	IXGBE_WRITE_FLUSH(&ixgbe->hw);
556610305SPaul.Guo@Sun.COM 
55678275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
55688275SEric Cheng 
55698275SEric Cheng 	return (0);
55708275SEric Cheng }
55718275SEric Cheng 
55728275SEric Cheng /*
55738275SEric Cheng  * Disable interrupt on the specificed rx ring.
55748275SEric Cheng  */
55758275SEric Cheng int
ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)55768275SEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)
55778275SEric Cheng {
55788275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
55798275SEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
55808275SEric Cheng 	int r_idx = rx_ring->index;
558111878SVenu.Iyer@Sun.COM 	int hw_r_idx = rx_ring->hw_index;
55828275SEric Cheng 	int v_idx = rx_ring->intr_vector;
55838275SEric Cheng 
55848275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
558511878SVenu.Iyer@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
558611878SVenu.Iyer@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
558711878SVenu.Iyer@Sun.COM 		/*
558811878SVenu.Iyer@Sun.COM 		 * Simply return 0.
558911878SVenu.Iyer@Sun.COM 		 * In the rare case where an interrupt is being
559011878SVenu.Iyer@Sun.COM 		 * disabled while interrupts are being adjusted,
559111878SVenu.Iyer@Sun.COM 		 * we don't fail the operation. No interrupts will
559211878SVenu.Iyer@Sun.COM 		 * be generated while they are adjusted, and
559311878SVenu.Iyer@Sun.COM 		 * ixgbe_intr_adjust() will cause the interrupts
559411878SVenu.Iyer@Sun.COM 		 * to be re-enabled once it completes. Note that
559511878SVenu.Iyer@Sun.COM 		 * in this case, packets may be delivered to the
559611878SVenu.Iyer@Sun.COM 		 * stack via interrupts before xgbe_rx_ring_intr_enable()
559711878SVenu.Iyer@Sun.COM 		 * is called again. This is acceptable since interrupt
559811878SVenu.Iyer@Sun.COM 		 * adjustment is infrequent, and the stack will be
559911878SVenu.Iyer@Sun.COM 		 * able to handle these packets.
560011878SVenu.Iyer@Sun.COM 		 */
560111878SVenu.Iyer@Sun.COM 		return (0);
560211878SVenu.Iyer@Sun.COM 	}
56038275SEric Cheng 
56048275SEric Cheng 	/*
56058275SEric Cheng 	 * To disable interrupt by clearing the VAL bit of given interrupt
56068275SEric Cheng 	 * vector allocation register (IVAR).
56078275SEric Cheng 	 */
560811878SVenu.Iyer@Sun.COM 	ixgbe_disable_ivar(ixgbe, hw_r_idx, 0);
56098275SEric Cheng 
56108275SEric Cheng 	BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx);
56118275SEric Cheng 
56128275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
56138275SEric Cheng 
56148275SEric Cheng 	return (0);
56158275SEric Cheng }
56168275SEric Cheng 
56178275SEric Cheng /*
56188275SEric Cheng  * Add a mac address.
56198275SEric Cheng  */
56208275SEric Cheng static int
ixgbe_addmac(void * arg,const uint8_t * mac_addr)56218275SEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr)
56228275SEric Cheng {
56238275SEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
56248275SEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
562511878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
562611878SVenu.Iyer@Sun.COM 	int slot, i;
56278275SEric Cheng 
56288275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
56298275SEric Cheng 
56308275SEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
56318275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
56328275SEric Cheng 		return (ECANCELED);
56338275SEric Cheng 	}
56348275SEric Cheng 
56358275SEric Cheng 	if (ixgbe->unicst_avail == 0) {
56368275SEric Cheng 		/* no slots available */
56378275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
56388275SEric Cheng 		return (ENOSPC);
56398275SEric Cheng 	}
56408275SEric Cheng 
564111878SVenu.Iyer@Sun.COM 	/*
564211878SVenu.Iyer@Sun.COM 	 * The first ixgbe->num_rx_groups slots are reserved for each respective
564311878SVenu.Iyer@Sun.COM 	 * group. The rest slots are shared by all groups. While adding a
564411878SVenu.Iyer@Sun.COM 	 * MAC address, reserved slots are firstly checked then the shared
564511878SVenu.Iyer@Sun.COM 	 * slots are searched.
564611878SVenu.Iyer@Sun.COM 	 */
564711878SVenu.Iyer@Sun.COM 	slot = -1;
564811878SVenu.Iyer@Sun.COM 	if (ixgbe->unicst_addr[rx_group->index].mac.set == 1) {
564911878SVenu.Iyer@Sun.COM 		for (i = ixgbe->num_rx_groups; i < ixgbe->unicst_total; i++) {
565011878SVenu.Iyer@Sun.COM 			if (ixgbe->unicst_addr[i].mac.set == 0) {
565111878SVenu.Iyer@Sun.COM 				slot = i;
565211878SVenu.Iyer@Sun.COM 				break;
565311878SVenu.Iyer@Sun.COM 			}
565411878SVenu.Iyer@Sun.COM 		}
565511878SVenu.Iyer@Sun.COM 	} else {
565611878SVenu.Iyer@Sun.COM 		slot = rx_group->index;
565711878SVenu.Iyer@Sun.COM 	}
565811878SVenu.Iyer@Sun.COM 
565911878SVenu.Iyer@Sun.COM 	if (slot == -1) {
566011878SVenu.Iyer@Sun.COM 		/* no slots available */
566111878SVenu.Iyer@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
566211878SVenu.Iyer@Sun.COM 		return (ENOSPC);
566311878SVenu.Iyer@Sun.COM 	}
566411878SVenu.Iyer@Sun.COM 
566511878SVenu.Iyer@Sun.COM 	bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
566611878SVenu.Iyer@Sun.COM 	(void) ixgbe_set_rar(hw, slot, ixgbe->unicst_addr[slot].mac.addr,
566711878SVenu.Iyer@Sun.COM 	    rx_group->index, IXGBE_RAH_AV);
566811878SVenu.Iyer@Sun.COM 	ixgbe->unicst_addr[slot].mac.set = 1;
566911878SVenu.Iyer@Sun.COM 	ixgbe->unicst_addr[slot].mac.group_index = rx_group->index;
567011878SVenu.Iyer@Sun.COM 	ixgbe->unicst_avail--;
56718275SEric Cheng 
56728275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
56738275SEric Cheng 
567411878SVenu.Iyer@Sun.COM 	return (0);
56758275SEric Cheng }
56768275SEric Cheng 
56778275SEric Cheng /*
56788275SEric Cheng  * Remove a mac address.
56798275SEric Cheng  */
56808275SEric Cheng static int
ixgbe_remmac(void * arg,const uint8_t * mac_addr)56818275SEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr)
56828275SEric Cheng {
56838275SEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
56848275SEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
568511878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
56868275SEric Cheng 	int slot;
56878275SEric Cheng 
56888275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
56898275SEric Cheng 
56908275SEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
56918275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
56928275SEric Cheng 		return (ECANCELED);
56938275SEric Cheng 	}
56948275SEric Cheng 
56958275SEric Cheng 	slot = ixgbe_unicst_find(ixgbe, mac_addr);
56968275SEric Cheng 	if (slot == -1) {
56978275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
56988275SEric Cheng 		return (EINVAL);
56998275SEric Cheng 	}
57008275SEric Cheng 
57018275SEric Cheng 	if (ixgbe->unicst_addr[slot].mac.set == 0) {
57028275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
57038275SEric Cheng 		return (EINVAL);
57048275SEric Cheng 	}
57058275SEric Cheng 
57068275SEric Cheng 	bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
570711878SVenu.Iyer@Sun.COM 	(void) ixgbe_clear_rar(hw, slot);
570811878SVenu.Iyer@Sun.COM 	ixgbe->unicst_addr[slot].mac.set = 0;
570911878SVenu.Iyer@Sun.COM 	ixgbe->unicst_avail++;
57108275SEric Cheng 
57118275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
57128275SEric Cheng 
571311878SVenu.Iyer@Sun.COM 	return (0);
57148275SEric Cheng }
5715