xref: /titanic_52/usr/src/uts/common/io/ixgbe/ixgbe_main.c (revision 59596c01ca1b980a016d25670874f53e64c27ec0)
19da57d7bSbt150084 /*
29da57d7bSbt150084  * CDDL HEADER START
39da57d7bSbt150084  *
49da57d7bSbt150084  * The contents of this file are subject to the terms of the
59da57d7bSbt150084  * Common Development and Distribution License (the "License").
69da57d7bSbt150084  * You may not use this file except in compliance with the License.
79da57d7bSbt150084  *
819397407SSherry Moore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
919397407SSherry Moore  * or http://www.opensolaris.org/os/licensing.
109da57d7bSbt150084  * See the License for the specific language governing permissions
119da57d7bSbt150084  * and limitations under the License.
129da57d7bSbt150084  *
1319397407SSherry Moore  * When distributing Covered Code, include this CDDL HEADER in each
1419397407SSherry Moore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159da57d7bSbt150084  * If applicable, add the following below this CDDL HEADER, with the
169da57d7bSbt150084  * fields enclosed by brackets "[]" replaced with your own identifying
179da57d7bSbt150084  * information: Portions Copyright [yyyy] [name of copyright owner]
189da57d7bSbt150084  *
199da57d7bSbt150084  * CDDL HEADER END
209da57d7bSbt150084  */
219da57d7bSbt150084 
229da57d7bSbt150084 /*
2300f1c25aSchenlu chen - Sun Microsystems - Beijing China  * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
2400f1c25aSchenlu chen - Sun Microsystems - Beijing China  */
2500f1c25aSchenlu chen - Sun Microsystems - Beijing China 
2600f1c25aSchenlu chen - Sun Microsystems - Beijing China /*
2700f1c25aSchenlu chen - Sun Microsystems - Beijing China  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28*59596c01SRobert Mustacchi  * Copyright (c) 2017, Joyent, Inc.
2969b5a878SDan McDonald  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
3043fab1a9SSaso Kiselkov  * Copyright (c) 2013 Saso Kiselkov. All rights reserved.
318c430e59SSaso Kiselkov  * Copyright (c) 2013 OSN Online Service Nuernberg GmbH. All rights reserved.
327e579c30SDale Ghent  * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
3319397407SSherry Moore  */
3419397407SSherry Moore 
359da57d7bSbt150084 #include "ixgbe_sw.h"
369da57d7bSbt150084 
37ffd8e883SWinson Wang - Sun Microsystems - Beijing China static char ixgbe_ident[] = "Intel 10Gb Ethernet";
389da57d7bSbt150084 
399da57d7bSbt150084 /*
409da57d7bSbt150084  * Local function protoypes
419da57d7bSbt150084  */
429da57d7bSbt150084 static int ixgbe_register_mac(ixgbe_t *);
439da57d7bSbt150084 static int ixgbe_identify_hardware(ixgbe_t *);
449da57d7bSbt150084 static int ixgbe_regs_map(ixgbe_t *);
459da57d7bSbt150084 static void ixgbe_init_properties(ixgbe_t *);
469da57d7bSbt150084 static int ixgbe_init_driver_settings(ixgbe_t *);
479da57d7bSbt150084 static void ixgbe_init_locks(ixgbe_t *);
489da57d7bSbt150084 static void ixgbe_destroy_locks(ixgbe_t *);
499da57d7bSbt150084 static int ixgbe_init(ixgbe_t *);
509da57d7bSbt150084 static int ixgbe_chip_start(ixgbe_t *);
519da57d7bSbt150084 static void ixgbe_chip_stop(ixgbe_t *);
529da57d7bSbt150084 static int ixgbe_reset(ixgbe_t *);
539da57d7bSbt150084 static void ixgbe_tx_clean(ixgbe_t *);
549da57d7bSbt150084 static boolean_t ixgbe_tx_drain(ixgbe_t *);
559da57d7bSbt150084 static boolean_t ixgbe_rx_drain(ixgbe_t *);
569da57d7bSbt150084 static int ixgbe_alloc_rings(ixgbe_t *);
579da57d7bSbt150084 static void ixgbe_free_rings(ixgbe_t *);
58ea65739eSchenlu chen - Sun Microsystems - Beijing China static int ixgbe_alloc_rx_data(ixgbe_t *);
59ea65739eSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_free_rx_data(ixgbe_t *);
609da57d7bSbt150084 static void ixgbe_setup_rings(ixgbe_t *);
619da57d7bSbt150084 static void ixgbe_setup_rx(ixgbe_t *);
629da57d7bSbt150084 static void ixgbe_setup_tx(ixgbe_t *);
639da57d7bSbt150084 static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *);
649da57d7bSbt150084 static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *);
659da57d7bSbt150084 static void ixgbe_setup_rss(ixgbe_t *);
660dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq(ixgbe_t *);
670dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq_rss(ixgbe_t *);
687e579c30SDale Ghent static void ixgbe_setup_rss_table(ixgbe_t *);
699da57d7bSbt150084 static void ixgbe_init_unicst(ixgbe_t *);
70da14cebeSEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *);
719da57d7bSbt150084 static void ixgbe_setup_multicst(ixgbe_t *);
729da57d7bSbt150084 static void ixgbe_get_hw_state(ixgbe_t *);
730dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe);
749da57d7bSbt150084 static void ixgbe_get_conf(ixgbe_t *);
75ea65739eSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_init_params(ixgbe_t *);
769da57d7bSbt150084 static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int);
7762e6e1adSPaul Guo static void ixgbe_driver_link_check(ixgbe_t *);
7873cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_sfp_check(void *);
795b6dd21fSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_overtemp_check(void *);
807e579c30SDale Ghent static void ixgbe_phy_check(void *);
8162e6e1adSPaul Guo static void ixgbe_link_timer(void *);
829da57d7bSbt150084 static void ixgbe_local_timer(void *);
839da57d7bSbt150084 static void ixgbe_arm_watchdog_timer(ixgbe_t *);
849da57d7bSbt150084 static void ixgbe_restart_watchdog_timer(ixgbe_t *);
859da57d7bSbt150084 static void ixgbe_disable_adapter_interrupts(ixgbe_t *);
869da57d7bSbt150084 static void ixgbe_enable_adapter_interrupts(ixgbe_t *);
879da57d7bSbt150084 static boolean_t is_valid_mac_addr(uint8_t *);
889da57d7bSbt150084 static boolean_t ixgbe_stall_check(ixgbe_t *);
899da57d7bSbt150084 static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t);
909da57d7bSbt150084 static void ixgbe_set_internal_mac_loopback(ixgbe_t *);
919da57d7bSbt150084 static boolean_t ixgbe_find_mac_address(ixgbe_t *);
929da57d7bSbt150084 static int ixgbe_alloc_intrs(ixgbe_t *);
939da57d7bSbt150084 static int ixgbe_alloc_intr_handles(ixgbe_t *, int);
949da57d7bSbt150084 static int ixgbe_add_intr_handlers(ixgbe_t *);
959da57d7bSbt150084 static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int);
969da57d7bSbt150084 static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int);
9773cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t);
9873cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t);
9973cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t);
1000dc2366fSVenugopal Iyer static uint32_t ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index);
10173cd555cSBin Tu - Sun Microsystems - Beijing China static int ixgbe_map_intrs_to_vectors(ixgbe_t *);
1029da57d7bSbt150084 static void ixgbe_setup_adapter_vector(ixgbe_t *);
1039da57d7bSbt150084 static void ixgbe_rem_intr_handlers(ixgbe_t *);
1049da57d7bSbt150084 static void ixgbe_rem_intrs(ixgbe_t *);
1059da57d7bSbt150084 static int ixgbe_enable_intrs(ixgbe_t *);
1069da57d7bSbt150084 static int ixgbe_disable_intrs(ixgbe_t *);
1079da57d7bSbt150084 static uint_t ixgbe_intr_legacy(void *, void *);
1089da57d7bSbt150084 static uint_t ixgbe_intr_msi(void *, void *);
10973cd555cSBin Tu - Sun Microsystems - Beijing China static uint_t ixgbe_intr_msix(void *, void *);
1109da57d7bSbt150084 static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *);
1119da57d7bSbt150084 static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *);
11213740cb2SPaul Guo static void ixgbe_intr_other_work(ixgbe_t *, uint32_t);
1139da57d7bSbt150084 static void ixgbe_get_driver_control(struct ixgbe_hw *);
114da14cebeSEric Cheng static int ixgbe_addmac(void *, const uint8_t *);
115da14cebeSEric Cheng static int ixgbe_remmac(void *, const uint8_t *);
1169da57d7bSbt150084 static void ixgbe_release_driver_control(struct ixgbe_hw *);
1179da57d7bSbt150084 
1189da57d7bSbt150084 static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t);
1199da57d7bSbt150084 static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t);
1209da57d7bSbt150084 static int ixgbe_resume(dev_info_t *);
1219da57d7bSbt150084 static int ixgbe_suspend(dev_info_t *);
1228c430e59SSaso Kiselkov static int ixgbe_quiesce(dev_info_t *);
1239da57d7bSbt150084 static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *);
1249da57d7bSbt150084 static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *);
1250dc2366fSVenugopal Iyer static int ixgbe_cbfunc(dev_info_t *, ddi_cb_action_t, void *, void *, void *);
1260dc2366fSVenugopal Iyer static int ixgbe_intr_cb_register(ixgbe_t *);
1270dc2366fSVenugopal Iyer static int ixgbe_intr_adjust(ixgbe_t *, ddi_cb_action_t, int);
1289da57d7bSbt150084 
1299da57d7bSbt150084 static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
1309da57d7bSbt150084     const void *impl_data);
1319da57d7bSbt150084 static void ixgbe_fm_init(ixgbe_t *);
1329da57d7bSbt150084 static void ixgbe_fm_fini(ixgbe_t *);
1339da57d7bSbt150084 
1340dc2366fSVenugopal Iyer char *ixgbe_priv_props[] = {
1350dc2366fSVenugopal Iyer 	"_tx_copy_thresh",
1360dc2366fSVenugopal Iyer 	"_tx_recycle_thresh",
1370dc2366fSVenugopal Iyer 	"_tx_overload_thresh",
1380dc2366fSVenugopal Iyer 	"_tx_resched_thresh",
1390dc2366fSVenugopal Iyer 	"_rx_copy_thresh",
1400dc2366fSVenugopal Iyer 	"_rx_limit_per_intr",
1410dc2366fSVenugopal Iyer 	"_intr_throttling",
1420dc2366fSVenugopal Iyer 	"_adv_pause_cap",
1430dc2366fSVenugopal Iyer 	"_adv_asym_pause_cap",
1440dc2366fSVenugopal Iyer 	NULL
145ea65739eSchenlu chen - Sun Microsystems - Beijing China };
146ea65739eSchenlu chen - Sun Microsystems - Beijing China 
147ea65739eSchenlu chen - Sun Microsystems - Beijing China #define	IXGBE_MAX_PRIV_PROPS \
148ea65739eSchenlu chen - Sun Microsystems - Beijing China 	(sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t))
149ea65739eSchenlu chen - Sun Microsystems - Beijing China 
1509da57d7bSbt150084 static struct cb_ops ixgbe_cb_ops = {
1519da57d7bSbt150084 	nulldev,		/* cb_open */
1529da57d7bSbt150084 	nulldev,		/* cb_close */
1539da57d7bSbt150084 	nodev,			/* cb_strategy */
1549da57d7bSbt150084 	nodev,			/* cb_print */
1559da57d7bSbt150084 	nodev,			/* cb_dump */
1569da57d7bSbt150084 	nodev,			/* cb_read */
1579da57d7bSbt150084 	nodev,			/* cb_write */
1589da57d7bSbt150084 	nodev,			/* cb_ioctl */
1599da57d7bSbt150084 	nodev,			/* cb_devmap */
1609da57d7bSbt150084 	nodev,			/* cb_mmap */
1619da57d7bSbt150084 	nodev,			/* cb_segmap */
1629da57d7bSbt150084 	nochpoll,		/* cb_chpoll */
1639da57d7bSbt150084 	ddi_prop_op,		/* cb_prop_op */
1649da57d7bSbt150084 	NULL,			/* cb_stream */
1659da57d7bSbt150084 	D_MP | D_HOTPLUG,	/* cb_flag */
1669da57d7bSbt150084 	CB_REV,			/* cb_rev */
1679da57d7bSbt150084 	nodev,			/* cb_aread */
1689da57d7bSbt150084 	nodev			/* cb_awrite */
1699da57d7bSbt150084 };
1709da57d7bSbt150084 
1719da57d7bSbt150084 static struct dev_ops ixgbe_dev_ops = {
1729da57d7bSbt150084 	DEVO_REV,		/* devo_rev */
1739da57d7bSbt150084 	0,			/* devo_refcnt */
1749da57d7bSbt150084 	NULL,			/* devo_getinfo */
1759da57d7bSbt150084 	nulldev,		/* devo_identify */
1769da57d7bSbt150084 	nulldev,		/* devo_probe */
1779da57d7bSbt150084 	ixgbe_attach,		/* devo_attach */
1789da57d7bSbt150084 	ixgbe_detach,		/* devo_detach */
1799da57d7bSbt150084 	nodev,			/* devo_reset */
1809da57d7bSbt150084 	&ixgbe_cb_ops,		/* devo_cb_ops */
1819da57d7bSbt150084 	NULL,			/* devo_bus_ops */
18219397407SSherry Moore 	ddi_power,		/* devo_power */
1838c430e59SSaso Kiselkov 	ixgbe_quiesce,		/* devo_quiesce */
1849da57d7bSbt150084 };
1859da57d7bSbt150084 
1869da57d7bSbt150084 static struct modldrv ixgbe_modldrv = {
1879da57d7bSbt150084 	&mod_driverops,		/* Type of module.  This one is a driver */
188ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	ixgbe_ident,		/* Discription string */
1899da57d7bSbt150084 	&ixgbe_dev_ops		/* driver ops */
1909da57d7bSbt150084 };
1919da57d7bSbt150084 
1929da57d7bSbt150084 static struct modlinkage ixgbe_modlinkage = {
1939da57d7bSbt150084 	MODREV_1, &ixgbe_modldrv, NULL
1949da57d7bSbt150084 };
1959da57d7bSbt150084 
1969da57d7bSbt150084 /*
1979da57d7bSbt150084  * Access attributes for register mapping
1989da57d7bSbt150084  */
1999da57d7bSbt150084 ddi_device_acc_attr_t ixgbe_regs_acc_attr = {
200837c1ac4SStephen Hanson 	DDI_DEVICE_ATTR_V1,
2019da57d7bSbt150084 	DDI_STRUCTURE_LE_ACC,
2029da57d7bSbt150084 	DDI_STRICTORDER_ACC,
2039da57d7bSbt150084 	DDI_FLAGERR_ACC
2049da57d7bSbt150084 };
2059da57d7bSbt150084 
2069da57d7bSbt150084 /*
2079da57d7bSbt150084  * Loopback property
2089da57d7bSbt150084  */
2099da57d7bSbt150084 static lb_property_t lb_normal = {
2109da57d7bSbt150084 	normal,	"normal", IXGBE_LB_NONE
2119da57d7bSbt150084 };
2129da57d7bSbt150084 
2139da57d7bSbt150084 static lb_property_t lb_mac = {
2149da57d7bSbt150084 	internal, "MAC", IXGBE_LB_INTERNAL_MAC
2159da57d7bSbt150084 };
2169da57d7bSbt150084 
2171fedc51fSWinson Wang - Sun Microsystems - Beijing China static lb_property_t lb_external = {
2181fedc51fSWinson Wang - Sun Microsystems - Beijing China 	external, "External", IXGBE_LB_EXTERNAL
2191fedc51fSWinson Wang - Sun Microsystems - Beijing China };
2201fedc51fSWinson Wang - Sun Microsystems - Beijing China 
221ea65739eSchenlu chen - Sun Microsystems - Beijing China #define	IXGBE_M_CALLBACK_FLAGS \
2220dc2366fSVenugopal Iyer 	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
2239da57d7bSbt150084 
2249da57d7bSbt150084 static mac_callbacks_t ixgbe_m_callbacks = {
2259da57d7bSbt150084 	IXGBE_M_CALLBACK_FLAGS,
2269da57d7bSbt150084 	ixgbe_m_stat,
2279da57d7bSbt150084 	ixgbe_m_start,
2289da57d7bSbt150084 	ixgbe_m_stop,
2299da57d7bSbt150084 	ixgbe_m_promisc,
2309da57d7bSbt150084 	ixgbe_m_multicst,
231da14cebeSEric Cheng 	NULL,
2329da57d7bSbt150084 	NULL,
2330dc2366fSVenugopal Iyer 	NULL,
2349da57d7bSbt150084 	ixgbe_m_ioctl,
235ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_m_getcapab,
236ea65739eSchenlu chen - Sun Microsystems - Beijing China 	NULL,
237ea65739eSchenlu chen - Sun Microsystems - Beijing China 	NULL,
238ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_m_setprop,
2390dc2366fSVenugopal Iyer 	ixgbe_m_getprop,
2400dc2366fSVenugopal Iyer 	ixgbe_m_propinfo
2419da57d7bSbt150084 };
2429da57d7bSbt150084 
2439da57d7bSbt150084 /*
24413740cb2SPaul Guo  * Initialize capabilities of each supported adapter type
24513740cb2SPaul Guo  */
24613740cb2SPaul Guo static adapter_info_t ixgbe_82598eb_cap = {
24713740cb2SPaul Guo 	64,		/* maximum number of rx queues */
24813740cb2SPaul Guo 	1,		/* minimum number of rx queues */
2490dc2366fSVenugopal Iyer 	64,		/* default number of rx queues */
2500dc2366fSVenugopal Iyer 	16,		/* maximum number of rx groups */
2510dc2366fSVenugopal Iyer 	1,		/* minimum number of rx groups */
2520dc2366fSVenugopal Iyer 	1,		/* default number of rx groups */
25313740cb2SPaul Guo 	32,		/* maximum number of tx queues */
25413740cb2SPaul Guo 	1,		/* minimum number of tx queues */
25513740cb2SPaul Guo 	8,		/* default number of tx queues */
2561fedc51fSWinson Wang - Sun Microsystems - Beijing China 	16366,		/* maximum MTU size */
257ea65739eSchenlu chen - Sun Microsystems - Beijing China 	0xFFFF,		/* maximum interrupt throttle rate */
258ea65739eSchenlu chen - Sun Microsystems - Beijing China 	0,		/* minimum interrupt throttle rate */
259ea65739eSchenlu chen - Sun Microsystems - Beijing China 	200,		/* default interrupt throttle rate */
26013740cb2SPaul Guo 	18,		/* maximum total msix vectors */
26113740cb2SPaul Guo 	16,		/* maximum number of ring vectors */
26213740cb2SPaul Guo 	2,		/* maximum number of other vectors */
26313740cb2SPaul Guo 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
2645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	0,		/* "other" interrupt types enable mask */
26513740cb2SPaul Guo 	(IXGBE_FLAG_DCA_CAPABLE	/* capability flags */
26613740cb2SPaul Guo 	| IXGBE_FLAG_RSS_CAPABLE
26713740cb2SPaul Guo 	| IXGBE_FLAG_VMDQ_CAPABLE)
26813740cb2SPaul Guo };
26913740cb2SPaul Guo 
27073cd555cSBin Tu - Sun Microsystems - Beijing China static adapter_info_t ixgbe_82599eb_cap = {
27173cd555cSBin Tu - Sun Microsystems - Beijing China 	128,		/* maximum number of rx queues */
27273cd555cSBin Tu - Sun Microsystems - Beijing China 	1,		/* minimum number of rx queues */
2730dc2366fSVenugopal Iyer 	128,		/* default number of rx queues */
2740dc2366fSVenugopal Iyer 	64,		/* maximum number of rx groups */
2750dc2366fSVenugopal Iyer 	1,		/* minimum number of rx groups */
2760dc2366fSVenugopal Iyer 	1,		/* default number of rx groups */
27773cd555cSBin Tu - Sun Microsystems - Beijing China 	128,		/* maximum number of tx queues */
27873cd555cSBin Tu - Sun Microsystems - Beijing China 	1,		/* minimum number of tx queues */
27973cd555cSBin Tu - Sun Microsystems - Beijing China 	8,		/* default number of tx queues */
2801fedc51fSWinson Wang - Sun Microsystems - Beijing China 	15500,		/* maximum MTU size */
281ea65739eSchenlu chen - Sun Microsystems - Beijing China 	0xFF8,		/* maximum interrupt throttle rate */
282ea65739eSchenlu chen - Sun Microsystems - Beijing China 	0,		/* minimum interrupt throttle rate */
283ea65739eSchenlu chen - Sun Microsystems - Beijing China 	200,		/* default interrupt throttle rate */
28473cd555cSBin Tu - Sun Microsystems - Beijing China 	64,		/* maximum total msix vectors */
28573cd555cSBin Tu - Sun Microsystems - Beijing China 	16,		/* maximum number of ring vectors */
28673cd555cSBin Tu - Sun Microsystems - Beijing China 	2,		/* maximum number of other vectors */
2875b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(IXGBE_EICR_LSC
2885b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_EICR_GPI_SDP1
2895b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_EICR_GPI_SDP2), /* "other" interrupt types handled */
2905b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
2915b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(IXGBE_SDP1_GPIEN
2925b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_SDP2_GPIEN), /* "other" interrupt types enable mask */
2935b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
2945b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(IXGBE_FLAG_DCA_CAPABLE
29573cd555cSBin Tu - Sun Microsystems - Beijing China 	| IXGBE_FLAG_RSS_CAPABLE
296ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	| IXGBE_FLAG_VMDQ_CAPABLE
2975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_FLAG_RSC_CAPABLE
2985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_FLAG_SFP_PLUG_CAPABLE) /* capability flags */
29973cd555cSBin Tu - Sun Microsystems - Beijing China };
30073cd555cSBin Tu - Sun Microsystems - Beijing China 
30169b5a878SDan McDonald static adapter_info_t ixgbe_X540_cap = {
30269b5a878SDan McDonald 	128,		/* maximum number of rx queues */
30369b5a878SDan McDonald 	1,		/* minimum number of rx queues */
30469b5a878SDan McDonald 	128,		/* default number of rx queues */
30569b5a878SDan McDonald 	64,		/* maximum number of rx groups */
30669b5a878SDan McDonald 	1,		/* minimum number of rx groups */
30769b5a878SDan McDonald 	1,		/* default number of rx groups */
30869b5a878SDan McDonald 	128,		/* maximum number of tx queues */
30969b5a878SDan McDonald 	1,		/* minimum number of tx queues */
31069b5a878SDan McDonald 	8,		/* default number of tx queues */
31169b5a878SDan McDonald 	15500,		/* maximum MTU size */
31269b5a878SDan McDonald 	0xFF8,		/* maximum interrupt throttle rate */
31369b5a878SDan McDonald 	0,		/* minimum interrupt throttle rate */
31469b5a878SDan McDonald 	200,		/* default interrupt throttle rate */
31569b5a878SDan McDonald 	64,		/* maximum total msix vectors */
31669b5a878SDan McDonald 	16,		/* maximum number of ring vectors */
31769b5a878SDan McDonald 	2,		/* maximum number of other vectors */
31869b5a878SDan McDonald 	(IXGBE_EICR_LSC
3197e579c30SDale Ghent 	| IXGBE_EICR_GPI_SDP1_X540
3207e579c30SDale Ghent 	| IXGBE_EICR_GPI_SDP2_X540), /* "other" interrupt types handled */
32169b5a878SDan McDonald 
3227e579c30SDale Ghent 	(IXGBE_SDP1_GPIEN_X540
3237e579c30SDale Ghent 	| IXGBE_SDP2_GPIEN_X540), /* "other" interrupt types enable mask */
32469b5a878SDan McDonald 
32569b5a878SDan McDonald 	(IXGBE_FLAG_DCA_CAPABLE
32669b5a878SDan McDonald 	| IXGBE_FLAG_RSS_CAPABLE
32769b5a878SDan McDonald 	| IXGBE_FLAG_VMDQ_CAPABLE
32869b5a878SDan McDonald 	| IXGBE_FLAG_RSC_CAPABLE) /* capability flags */
32969b5a878SDan McDonald };
33069b5a878SDan McDonald 
3317e579c30SDale Ghent static adapter_info_t ixgbe_X550_cap = {
3327e579c30SDale Ghent 	128,		/* maximum number of rx queues */
3337e579c30SDale Ghent 	1,		/* minimum number of rx queues */
3347e579c30SDale Ghent 	128,		/* default number of rx queues */
3357e579c30SDale Ghent 	64,		/* maximum number of rx groups */
3367e579c30SDale Ghent 	1,		/* minimum number of rx groups */
3377e579c30SDale Ghent 	1,		/* default number of rx groups */
3387e579c30SDale Ghent 	128,		/* maximum number of tx queues */
3397e579c30SDale Ghent 	1,		/* minimum number of tx queues */
3407e579c30SDale Ghent 	8,		/* default number of tx queues */
3417e579c30SDale Ghent 	15500,		/* maximum MTU size */
3427e579c30SDale Ghent 	0xFF8,		/* maximum interrupt throttle rate */
3437e579c30SDale Ghent 	0,		/* minimum interrupt throttle rate */
3447e579c30SDale Ghent 	0x200,		/* default interrupt throttle rate */
3457e579c30SDale Ghent 	64,		/* maximum total msix vectors */
3467e579c30SDale Ghent 	16,		/* maximum number of ring vectors */
3477e579c30SDale Ghent 	2,		/* maximum number of other vectors */
3487e579c30SDale Ghent 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
3497e579c30SDale Ghent 	0,		/* "other" interrupt types enable mask */
3507e579c30SDale Ghent 	(IXGBE_FLAG_RSS_CAPABLE
3517e579c30SDale Ghent 	| IXGBE_FLAG_VMDQ_CAPABLE
3527e579c30SDale Ghent 	| IXGBE_FLAG_RSC_CAPABLE) /* capability flags */
3537e579c30SDale Ghent };
3547e579c30SDale Ghent 
35513740cb2SPaul Guo /*
3569da57d7bSbt150084  * Module Initialization Functions.
3579da57d7bSbt150084  */
3589da57d7bSbt150084 
3599da57d7bSbt150084 int
3609da57d7bSbt150084 _init(void)
3619da57d7bSbt150084 {
3629da57d7bSbt150084 	int status;
3639da57d7bSbt150084 
3649da57d7bSbt150084 	mac_init_ops(&ixgbe_dev_ops, MODULE_NAME);
3659da57d7bSbt150084 
3669da57d7bSbt150084 	status = mod_install(&ixgbe_modlinkage);
3679da57d7bSbt150084 
3689da57d7bSbt150084 	if (status != DDI_SUCCESS) {
3699da57d7bSbt150084 		mac_fini_ops(&ixgbe_dev_ops);
3709da57d7bSbt150084 	}
3719da57d7bSbt150084 
3729da57d7bSbt150084 	return (status);
3739da57d7bSbt150084 }
3749da57d7bSbt150084 
3759da57d7bSbt150084 int
3769da57d7bSbt150084 _fini(void)
3779da57d7bSbt150084 {
3789da57d7bSbt150084 	int status;
3799da57d7bSbt150084 
3809da57d7bSbt150084 	status = mod_remove(&ixgbe_modlinkage);
3819da57d7bSbt150084 
3829da57d7bSbt150084 	if (status == DDI_SUCCESS) {
3839da57d7bSbt150084 		mac_fini_ops(&ixgbe_dev_ops);
3849da57d7bSbt150084 	}
3859da57d7bSbt150084 
3869da57d7bSbt150084 	return (status);
3879da57d7bSbt150084 }
3889da57d7bSbt150084 
3899da57d7bSbt150084 int
3909da57d7bSbt150084 _info(struct modinfo *modinfop)
3919da57d7bSbt150084 {
3929da57d7bSbt150084 	int status;
3939da57d7bSbt150084 
3949da57d7bSbt150084 	status = mod_info(&ixgbe_modlinkage, modinfop);
3959da57d7bSbt150084 
3969da57d7bSbt150084 	return (status);
3979da57d7bSbt150084 }
3989da57d7bSbt150084 
3999da57d7bSbt150084 /*
4009da57d7bSbt150084  * ixgbe_attach - Driver attach.
4019da57d7bSbt150084  *
4029da57d7bSbt150084  * This function is the device specific initialization entry
4039da57d7bSbt150084  * point. This entry point is required and must be written.
4049da57d7bSbt150084  * The DDI_ATTACH command must be provided in the attach entry
4059da57d7bSbt150084  * point. When attach() is called with cmd set to DDI_ATTACH,
4069da57d7bSbt150084  * all normal kernel services (such as kmem_alloc(9F)) are
4079da57d7bSbt150084  * available for use by the driver.
4089da57d7bSbt150084  *
4099da57d7bSbt150084  * The attach() function will be called once for each instance
4109da57d7bSbt150084  * of  the  device  on  the  system with cmd set to DDI_ATTACH.
4119da57d7bSbt150084  * Until attach() succeeds, the only driver entry points which
4129da57d7bSbt150084  * may be called are open(9E) and getinfo(9E).
4139da57d7bSbt150084  */
4149da57d7bSbt150084 static int
4159da57d7bSbt150084 ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
4169da57d7bSbt150084 {
4179da57d7bSbt150084 	ixgbe_t *ixgbe;
4189da57d7bSbt150084 	struct ixgbe_osdep *osdep;
4199da57d7bSbt150084 	struct ixgbe_hw *hw;
4209da57d7bSbt150084 	int instance;
42113740cb2SPaul Guo 	char taskqname[32];
4229da57d7bSbt150084 
4239da57d7bSbt150084 	/*
4249da57d7bSbt150084 	 * Check the command and perform corresponding operations
4259da57d7bSbt150084 	 */
4269da57d7bSbt150084 	switch (cmd) {
4279da57d7bSbt150084 	default:
4289da57d7bSbt150084 		return (DDI_FAILURE);
4299da57d7bSbt150084 
4309da57d7bSbt150084 	case DDI_RESUME:
4319da57d7bSbt150084 		return (ixgbe_resume(devinfo));
4329da57d7bSbt150084 
4339da57d7bSbt150084 	case DDI_ATTACH:
4349da57d7bSbt150084 		break;
4359da57d7bSbt150084 	}
4369da57d7bSbt150084 
4379da57d7bSbt150084 	/* Get the device instance */
4389da57d7bSbt150084 	instance = ddi_get_instance(devinfo);
4399da57d7bSbt150084 
4409da57d7bSbt150084 	/* Allocate memory for the instance data structure */
4419da57d7bSbt150084 	ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP);
4429da57d7bSbt150084 
4439da57d7bSbt150084 	ixgbe->dip = devinfo;
4449da57d7bSbt150084 	ixgbe->instance = instance;
4459da57d7bSbt150084 
4469da57d7bSbt150084 	hw = &ixgbe->hw;
4479da57d7bSbt150084 	osdep = &ixgbe->osdep;
4489da57d7bSbt150084 	hw->back = osdep;
4499da57d7bSbt150084 	osdep->ixgbe = ixgbe;
4509da57d7bSbt150084 
4519da57d7bSbt150084 	/* Attach the instance pointer to the dev_info data structure */
4529da57d7bSbt150084 	ddi_set_driver_private(devinfo, ixgbe);
4539da57d7bSbt150084 
4549da57d7bSbt150084 	/*
4557e579c30SDale Ghent 	 * Initialize for FMA support
4569da57d7bSbt150084 	 */
457c971fb7eSgg161487 	ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE,
4589da57d7bSbt150084 	    0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
4599da57d7bSbt150084 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
4609da57d7bSbt150084 	ixgbe_fm_init(ixgbe);
4619da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT;
4629da57d7bSbt150084 
4639da57d7bSbt150084 	/*
4649da57d7bSbt150084 	 * Map PCI config space registers
4659da57d7bSbt150084 	 */
4669da57d7bSbt150084 	if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
4679da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to map PCI configurations");
4689da57d7bSbt150084 		goto attach_fail;
4699da57d7bSbt150084 	}
4709da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
4719da57d7bSbt150084 
4729da57d7bSbt150084 	/*
4739da57d7bSbt150084 	 * Identify the chipset family
4749da57d7bSbt150084 	 */
4759da57d7bSbt150084 	if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) {
4769da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to identify hardware");
4779da57d7bSbt150084 		goto attach_fail;
4789da57d7bSbt150084 	}
4799da57d7bSbt150084 
4809da57d7bSbt150084 	/*
4819da57d7bSbt150084 	 * Map device registers
4829da57d7bSbt150084 	 */
4839da57d7bSbt150084 	if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) {
4849da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to map device registers");
4859da57d7bSbt150084 		goto attach_fail;
4869da57d7bSbt150084 	}
4879da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP;
4889da57d7bSbt150084 
4899da57d7bSbt150084 	/*
4909da57d7bSbt150084 	 * Initialize driver parameters
4919da57d7bSbt150084 	 */
4929da57d7bSbt150084 	ixgbe_init_properties(ixgbe);
4939da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS;
4949da57d7bSbt150084 
4959da57d7bSbt150084 	/*
4960dc2366fSVenugopal Iyer 	 * Register interrupt callback
4970dc2366fSVenugopal Iyer 	 */
4980dc2366fSVenugopal Iyer 	if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) {
4990dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe, "Failed to register interrupt callback");
5000dc2366fSVenugopal Iyer 		goto attach_fail;
5010dc2366fSVenugopal Iyer 	}
5020dc2366fSVenugopal Iyer 
5030dc2366fSVenugopal Iyer 	/*
5049da57d7bSbt150084 	 * Allocate interrupts
5059da57d7bSbt150084 	 */
5069da57d7bSbt150084 	if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) {
5079da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to allocate interrupts");
5089da57d7bSbt150084 		goto attach_fail;
5099da57d7bSbt150084 	}
5109da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
5119da57d7bSbt150084 
5129da57d7bSbt150084 	/*
5139da57d7bSbt150084 	 * Allocate rx/tx rings based on the ring numbers.
5149da57d7bSbt150084 	 * The actual numbers of rx/tx rings are decided by the number of
5159da57d7bSbt150084 	 * allocated interrupt vectors, so we should allocate the rings after
5169da57d7bSbt150084 	 * interrupts are allocated.
5179da57d7bSbt150084 	 */
5189da57d7bSbt150084 	if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) {
5199da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to allocate rx and tx rings");
5209da57d7bSbt150084 		goto attach_fail;
5219da57d7bSbt150084 	}
5229da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS;
5239da57d7bSbt150084 
5249da57d7bSbt150084 	/*
5259da57d7bSbt150084 	 * Map rings to interrupt vectors
5269da57d7bSbt150084 	 */
52773cd555cSBin Tu - Sun Microsystems - Beijing China 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
52873cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe, "Failed to map interrupts to vectors");
5299da57d7bSbt150084 		goto attach_fail;
5309da57d7bSbt150084 	}
5319da57d7bSbt150084 
5329da57d7bSbt150084 	/*
5339da57d7bSbt150084 	 * Add interrupt handlers
5349da57d7bSbt150084 	 */
5359da57d7bSbt150084 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
5369da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to add interrupt handlers");
5379da57d7bSbt150084 		goto attach_fail;
5389da57d7bSbt150084 	}
5399da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
5409da57d7bSbt150084 
5419da57d7bSbt150084 	/*
54262e6e1adSPaul Guo 	 * Create a taskq for sfp-change
54313740cb2SPaul Guo 	 */
5445b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(void) sprintf(taskqname, "ixgbe%d_sfp_taskq", instance);
54562e6e1adSPaul Guo 	if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname,
54613740cb2SPaul Guo 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
5475b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe, "sfp_taskq create failed");
54813740cb2SPaul Guo 		goto attach_fail;
54913740cb2SPaul Guo 	}
55062e6e1adSPaul Guo 	ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ;
55113740cb2SPaul Guo 
55213740cb2SPaul Guo 	/*
5535b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Create a taskq for over-temp
5545b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
5555b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(void) sprintf(taskqname, "ixgbe%d_overtemp_taskq", instance);
5565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if ((ixgbe->overtemp_taskq = ddi_taskq_create(devinfo, taskqname,
5575b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
5585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe, "overtemp_taskq create failed");
5595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto attach_fail;
5605b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
5615b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->attach_progress |= ATTACH_PROGRESS_OVERTEMP_TASKQ;
5625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
5635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
5647e579c30SDale Ghent 	 * Create a taskq for processing external PHY interrupts
5657e579c30SDale Ghent 	 */
5667e579c30SDale Ghent 	(void) sprintf(taskqname, "ixgbe%d_phy_taskq", instance);
5677e579c30SDale Ghent 	if ((ixgbe->phy_taskq = ddi_taskq_create(devinfo, taskqname,
5687e579c30SDale Ghent 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
5697e579c30SDale Ghent 		ixgbe_error(ixgbe, "phy_taskq create failed");
5707e579c30SDale Ghent 		goto attach_fail;
5717e579c30SDale Ghent 	}
5727e579c30SDale Ghent 	ixgbe->attach_progress |= ATTACH_PROGRESS_PHY_TASKQ;
5737e579c30SDale Ghent 
5747e579c30SDale Ghent 	/*
5759da57d7bSbt150084 	 * Initialize driver parameters
5769da57d7bSbt150084 	 */
5779da57d7bSbt150084 	if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) {
5789da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to initialize driver settings");
5799da57d7bSbt150084 		goto attach_fail;
5809da57d7bSbt150084 	}
5819da57d7bSbt150084 
5829da57d7bSbt150084 	/*
5839da57d7bSbt150084 	 * Initialize mutexes for this device.
5849da57d7bSbt150084 	 * Do this before enabling the interrupt handler and
5859da57d7bSbt150084 	 * register the softint to avoid the condition where
5869da57d7bSbt150084 	 * interrupt handler can try using uninitialized mutex.
5879da57d7bSbt150084 	 */
5889da57d7bSbt150084 	ixgbe_init_locks(ixgbe);
5899da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS;
5909da57d7bSbt150084 
5919da57d7bSbt150084 	/*
5929da57d7bSbt150084 	 * Initialize chipset hardware
5939da57d7bSbt150084 	 */
5949da57d7bSbt150084 	if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) {
5959da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to initialize adapter");
5969da57d7bSbt150084 		goto attach_fail;
5979da57d7bSbt150084 	}
59862e6e1adSPaul Guo 	ixgbe->link_check_complete = B_FALSE;
59962e6e1adSPaul Guo 	ixgbe->link_check_hrtime = gethrtime() +
60062e6e1adSPaul Guo 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
6019da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_INIT;
6029da57d7bSbt150084 
6039da57d7bSbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) {
6049da57d7bSbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
6059da57d7bSbt150084 		goto attach_fail;
6069da57d7bSbt150084 	}
6079da57d7bSbt150084 
6089da57d7bSbt150084 	/*
6097e579c30SDale Ghent 	 * Initialize adapter capabilities
6107e579c30SDale Ghent 	 */
6117e579c30SDale Ghent 	ixgbe_init_params(ixgbe);
6127e579c30SDale Ghent 
6137e579c30SDale Ghent 	/*
6149da57d7bSbt150084 	 * Initialize statistics
6159da57d7bSbt150084 	 */
6169da57d7bSbt150084 	if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) {
6179da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to initialize statistics");
6189da57d7bSbt150084 		goto attach_fail;
6199da57d7bSbt150084 	}
6209da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_STATS;
6219da57d7bSbt150084 
6229da57d7bSbt150084 	/*
6239da57d7bSbt150084 	 * Register the driver to the MAC
6249da57d7bSbt150084 	 */
6259da57d7bSbt150084 	if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) {
6269da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to register MAC");
6279da57d7bSbt150084 		goto attach_fail;
6289da57d7bSbt150084 	}
62913740cb2SPaul Guo 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
6309da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_MAC;
6319da57d7bSbt150084 
63262e6e1adSPaul Guo 	ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe,
63362e6e1adSPaul Guo 	    IXGBE_CYCLIC_PERIOD, DDI_IPL_0);
63462e6e1adSPaul Guo 	if (ixgbe->periodic_id == 0) {
63562e6e1adSPaul Guo 		ixgbe_error(ixgbe, "Failed to add the link check timer");
63662e6e1adSPaul Guo 		goto attach_fail;
63762e6e1adSPaul Guo 	}
63862e6e1adSPaul Guo 	ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER;
63962e6e1adSPaul Guo 
6409da57d7bSbt150084 	/*
6419da57d7bSbt150084 	 * Now that mutex locks are initialized, and the chip is also
6429da57d7bSbt150084 	 * initialized, enable interrupts.
6439da57d7bSbt150084 	 */
6449da57d7bSbt150084 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
6459da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to enable DDI interrupts");
6469da57d7bSbt150084 		goto attach_fail;
6479da57d7bSbt150084 	}
6489da57d7bSbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
6499da57d7bSbt150084 
6507e579c30SDale Ghent 	ixgbe_log(ixgbe, "%s", ixgbe_ident);
65162e6e1adSPaul Guo 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED);
6529da57d7bSbt150084 
6539da57d7bSbt150084 	return (DDI_SUCCESS);
6549da57d7bSbt150084 
6559da57d7bSbt150084 attach_fail:
6569da57d7bSbt150084 	ixgbe_unconfigure(devinfo, ixgbe);
6579da57d7bSbt150084 	return (DDI_FAILURE);
6589da57d7bSbt150084 }
6599da57d7bSbt150084 
6609da57d7bSbt150084 /*
6619da57d7bSbt150084  * ixgbe_detach - Driver detach.
6629da57d7bSbt150084  *
6639da57d7bSbt150084  * The detach() function is the complement of the attach routine.
6649da57d7bSbt150084  * If cmd is set to DDI_DETACH, detach() is used to remove  the
6659da57d7bSbt150084  * state  associated  with  a  given  instance of a device node
6669da57d7bSbt150084  * prior to the removal of that instance from the system.
6679da57d7bSbt150084  *
6689da57d7bSbt150084  * The detach() function will be called once for each  instance
6699da57d7bSbt150084  * of the device for which there has been a successful attach()
6709da57d7bSbt150084  * once there are no longer  any  opens  on  the  device.
6719da57d7bSbt150084  *
6729da57d7bSbt150084  * Interrupts routine are disabled, All memory allocated by this
6739da57d7bSbt150084  * driver are freed.
6749da57d7bSbt150084  */
6759da57d7bSbt150084 static int
6769da57d7bSbt150084 ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
6779da57d7bSbt150084 {
6789da57d7bSbt150084 	ixgbe_t *ixgbe;
6799da57d7bSbt150084 
6809da57d7bSbt150084 	/*
6819da57d7bSbt150084 	 * Check detach command
6829da57d7bSbt150084 	 */
6839da57d7bSbt150084 	switch (cmd) {
6849da57d7bSbt150084 	default:
6859da57d7bSbt150084 		return (DDI_FAILURE);
6869da57d7bSbt150084 
6879da57d7bSbt150084 	case DDI_SUSPEND:
6889da57d7bSbt150084 		return (ixgbe_suspend(devinfo));
6899da57d7bSbt150084 
6909da57d7bSbt150084 	case DDI_DETACH:
6919da57d7bSbt150084 		break;
6929da57d7bSbt150084 	}
6939da57d7bSbt150084 
6949da57d7bSbt150084 	/*
6959da57d7bSbt150084 	 * Get the pointer to the driver private data structure
6969da57d7bSbt150084 	 */
6979da57d7bSbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
6989da57d7bSbt150084 	if (ixgbe == NULL)
6999da57d7bSbt150084 		return (DDI_FAILURE);
7009da57d7bSbt150084 
7019da57d7bSbt150084 	/*
7029da57d7bSbt150084 	 * If the device is still running, it needs to be stopped first.
7039da57d7bSbt150084 	 * This check is necessary because under some specific circumstances,
7049da57d7bSbt150084 	 * the detach routine can be called without stopping the interface
7059da57d7bSbt150084 	 * first.
7069da57d7bSbt150084 	 */
7079da57d7bSbt150084 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
70862e6e1adSPaul Guo 		atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
70962e6e1adSPaul Guo 		mutex_enter(&ixgbe->gen_lock);
710ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_stop(ixgbe, B_TRUE);
7119da57d7bSbt150084 		mutex_exit(&ixgbe->gen_lock);
7129da57d7bSbt150084 		/* Disable and stop the watchdog timer */
7139da57d7bSbt150084 		ixgbe_disable_watchdog_timer(ixgbe);
71462e6e1adSPaul Guo 	}
7159da57d7bSbt150084 
7169da57d7bSbt150084 	/*
7179da57d7bSbt150084 	 * Check if there are still rx buffers held by the upper layer.
7189da57d7bSbt150084 	 * If so, fail the detach.
7199da57d7bSbt150084 	 */
7209da57d7bSbt150084 	if (!ixgbe_rx_drain(ixgbe))
7219da57d7bSbt150084 		return (DDI_FAILURE);
7229da57d7bSbt150084 
7239da57d7bSbt150084 	/*
7249da57d7bSbt150084 	 * Do the remaining unconfigure routines
7259da57d7bSbt150084 	 */
7269da57d7bSbt150084 	ixgbe_unconfigure(devinfo, ixgbe);
7279da57d7bSbt150084 
7289da57d7bSbt150084 	return (DDI_SUCCESS);
7299da57d7bSbt150084 }
7309da57d7bSbt150084 
7318c430e59SSaso Kiselkov /*
7328c430e59SSaso Kiselkov  * quiesce(9E) entry point.
7338c430e59SSaso Kiselkov  *
7348c430e59SSaso Kiselkov  * This function is called when the system is single-threaded at high
7358c430e59SSaso Kiselkov  * PIL with preemption disabled. Therefore, this function must not be
7368c430e59SSaso Kiselkov  * blocked.
7378c430e59SSaso Kiselkov  *
7388c430e59SSaso Kiselkov  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
7398c430e59SSaso Kiselkov  * DDI_FAILURE indicates an error condition and should almost never happen.
7408c430e59SSaso Kiselkov  */
7418c430e59SSaso Kiselkov static int
7428c430e59SSaso Kiselkov ixgbe_quiesce(dev_info_t *devinfo)
7438c430e59SSaso Kiselkov {
7448c430e59SSaso Kiselkov 	ixgbe_t *ixgbe;
7458c430e59SSaso Kiselkov 	struct ixgbe_hw *hw;
7468c430e59SSaso Kiselkov 
7478c430e59SSaso Kiselkov 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
7488c430e59SSaso Kiselkov 
7498c430e59SSaso Kiselkov 	if (ixgbe == NULL)
7508c430e59SSaso Kiselkov 		return (DDI_FAILURE);
7518c430e59SSaso Kiselkov 
7528c430e59SSaso Kiselkov 	hw = &ixgbe->hw;
7538c430e59SSaso Kiselkov 
7548c430e59SSaso Kiselkov 	/*
7558c430e59SSaso Kiselkov 	 * Disable the adapter interrupts
7568c430e59SSaso Kiselkov 	 */
7578c430e59SSaso Kiselkov 	ixgbe_disable_adapter_interrupts(ixgbe);
7588c430e59SSaso Kiselkov 
7598c430e59SSaso Kiselkov 	/*
7608c430e59SSaso Kiselkov 	 * Tell firmware driver is no longer in control
7618c430e59SSaso Kiselkov 	 */
7628c430e59SSaso Kiselkov 	ixgbe_release_driver_control(hw);
7638c430e59SSaso Kiselkov 
7648c430e59SSaso Kiselkov 	/*
7658c430e59SSaso Kiselkov 	 * Reset the chipset
7668c430e59SSaso Kiselkov 	 */
7678c430e59SSaso Kiselkov 	(void) ixgbe_reset_hw(hw);
7688c430e59SSaso Kiselkov 
7698c430e59SSaso Kiselkov 	/*
7708c430e59SSaso Kiselkov 	 * Reset PHY
7718c430e59SSaso Kiselkov 	 */
7728c430e59SSaso Kiselkov 	(void) ixgbe_reset_phy(hw);
7738c430e59SSaso Kiselkov 
7748c430e59SSaso Kiselkov 	return (DDI_SUCCESS);
7758c430e59SSaso Kiselkov }
7768c430e59SSaso Kiselkov 
7779da57d7bSbt150084 static void
7789da57d7bSbt150084 ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe)
7799da57d7bSbt150084 {
7809da57d7bSbt150084 	/*
7819da57d7bSbt150084 	 * Disable interrupt
7829da57d7bSbt150084 	 */
7839da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
7849da57d7bSbt150084 		(void) ixgbe_disable_intrs(ixgbe);
7859da57d7bSbt150084 	}
7869da57d7bSbt150084 
7879da57d7bSbt150084 	/*
78862e6e1adSPaul Guo 	 * remove the link check timer
78962e6e1adSPaul Guo 	 */
79062e6e1adSPaul Guo 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) {
79162e6e1adSPaul Guo 		if (ixgbe->periodic_id != NULL) {
79262e6e1adSPaul Guo 			ddi_periodic_delete(ixgbe->periodic_id);
79362e6e1adSPaul Guo 			ixgbe->periodic_id = NULL;
79462e6e1adSPaul Guo 		}
79562e6e1adSPaul Guo 	}
79662e6e1adSPaul Guo 
79762e6e1adSPaul Guo 	/*
7989da57d7bSbt150084 	 * Unregister MAC
7999da57d7bSbt150084 	 */
8009da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) {
8019da57d7bSbt150084 		(void) mac_unregister(ixgbe->mac_hdl);
8029da57d7bSbt150084 	}
8039da57d7bSbt150084 
8049da57d7bSbt150084 	/*
8059da57d7bSbt150084 	 * Free statistics
8069da57d7bSbt150084 	 */
8079da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) {
8089da57d7bSbt150084 		kstat_delete((kstat_t *)ixgbe->ixgbe_ks);
8099da57d7bSbt150084 	}
8109da57d7bSbt150084 
8119da57d7bSbt150084 	/*
8129da57d7bSbt150084 	 * Remove interrupt handlers
8139da57d7bSbt150084 	 */
8149da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
8159da57d7bSbt150084 		ixgbe_rem_intr_handlers(ixgbe);
8169da57d7bSbt150084 	}
8179da57d7bSbt150084 
8189da57d7bSbt150084 	/*
81962e6e1adSPaul Guo 	 * Remove taskq for sfp-status-change
82013740cb2SPaul Guo 	 */
82162e6e1adSPaul Guo 	if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) {
82262e6e1adSPaul Guo 		ddi_taskq_destroy(ixgbe->sfp_taskq);
82313740cb2SPaul Guo 	}
82413740cb2SPaul Guo 
82513740cb2SPaul Guo 	/*
8265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Remove taskq for over-temp
8275b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
8285b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->attach_progress & ATTACH_PROGRESS_OVERTEMP_TASKQ) {
8295b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ddi_taskq_destroy(ixgbe->overtemp_taskq);
8305b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
8315b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
8325b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
8337e579c30SDale Ghent 	 * Remove taskq for external PHYs
8347e579c30SDale Ghent 	 */
8357e579c30SDale Ghent 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PHY_TASKQ) {
8367e579c30SDale Ghent 		ddi_taskq_destroy(ixgbe->phy_taskq);
8377e579c30SDale Ghent 	}
8387e579c30SDale Ghent 
8397e579c30SDale Ghent 	/*
8409da57d7bSbt150084 	 * Remove interrupts
8419da57d7bSbt150084 	 */
8429da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) {
8439da57d7bSbt150084 		ixgbe_rem_intrs(ixgbe);
8449da57d7bSbt150084 	}
8459da57d7bSbt150084 
8469da57d7bSbt150084 	/*
8470dc2366fSVenugopal Iyer 	 * Unregister interrupt callback handler
8480dc2366fSVenugopal Iyer 	 */
84965e6526dSRobert Mustacchi 	if (ixgbe->cb_hdl != NULL) {
8500dc2366fSVenugopal Iyer 		(void) ddi_cb_unregister(ixgbe->cb_hdl);
85165e6526dSRobert Mustacchi 	}
8520dc2366fSVenugopal Iyer 
8530dc2366fSVenugopal Iyer 	/*
8549da57d7bSbt150084 	 * Remove driver properties
8559da57d7bSbt150084 	 */
8569da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) {
8579da57d7bSbt150084 		(void) ddi_prop_remove_all(devinfo);
8589da57d7bSbt150084 	}
8599da57d7bSbt150084 
8609da57d7bSbt150084 	/*
8619da57d7bSbt150084 	 * Stop the chipset
8629da57d7bSbt150084 	 */
8639da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) {
8649da57d7bSbt150084 		mutex_enter(&ixgbe->gen_lock);
8659da57d7bSbt150084 		ixgbe_chip_stop(ixgbe);
8669da57d7bSbt150084 		mutex_exit(&ixgbe->gen_lock);
8679da57d7bSbt150084 	}
8689da57d7bSbt150084 
8699da57d7bSbt150084 	/*
8709da57d7bSbt150084 	 * Free register handle
8719da57d7bSbt150084 	 */
8729da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
8739da57d7bSbt150084 		if (ixgbe->osdep.reg_handle != NULL)
8749da57d7bSbt150084 			ddi_regs_map_free(&ixgbe->osdep.reg_handle);
8759da57d7bSbt150084 	}
8769da57d7bSbt150084 
8779da57d7bSbt150084 	/*
8789da57d7bSbt150084 	 * Free PCI config handle
8799da57d7bSbt150084 	 */
8809da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) {
8819da57d7bSbt150084 		if (ixgbe->osdep.cfg_handle != NULL)
8829da57d7bSbt150084 			pci_config_teardown(&ixgbe->osdep.cfg_handle);
8839da57d7bSbt150084 	}
8849da57d7bSbt150084 
8859da57d7bSbt150084 	/*
8869da57d7bSbt150084 	 * Free locks
8879da57d7bSbt150084 	 */
8889da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) {
8899da57d7bSbt150084 		ixgbe_destroy_locks(ixgbe);
8909da57d7bSbt150084 	}
8919da57d7bSbt150084 
8929da57d7bSbt150084 	/*
8939da57d7bSbt150084 	 * Free the rx/tx rings
8949da57d7bSbt150084 	 */
8959da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) {
8969da57d7bSbt150084 		ixgbe_free_rings(ixgbe);
8979da57d7bSbt150084 	}
8989da57d7bSbt150084 
8999da57d7bSbt150084 	/*
9009da57d7bSbt150084 	 * Unregister FMA capabilities
9019da57d7bSbt150084 	 */
9029da57d7bSbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) {
9039da57d7bSbt150084 		ixgbe_fm_fini(ixgbe);
9049da57d7bSbt150084 	}
9059da57d7bSbt150084 
9069da57d7bSbt150084 	/*
9079da57d7bSbt150084 	 * Free the driver data structure
9089da57d7bSbt150084 	 */
9099da57d7bSbt150084 	kmem_free(ixgbe, sizeof (ixgbe_t));
9109da57d7bSbt150084 
9119da57d7bSbt150084 	ddi_set_driver_private(devinfo, NULL);
9129da57d7bSbt150084 }
9139da57d7bSbt150084 
9149da57d7bSbt150084 /*
9159da57d7bSbt150084  * ixgbe_register_mac - Register the driver and its function pointers with
9169da57d7bSbt150084  * the GLD interface.
9179da57d7bSbt150084  */
9189da57d7bSbt150084 static int
9199da57d7bSbt150084 ixgbe_register_mac(ixgbe_t *ixgbe)
9209da57d7bSbt150084 {
9219da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
9229da57d7bSbt150084 	mac_register_t *mac;
9239da57d7bSbt150084 	int status;
9249da57d7bSbt150084 
9259da57d7bSbt150084 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
9269da57d7bSbt150084 		return (IXGBE_FAILURE);
9279da57d7bSbt150084 
9289da57d7bSbt150084 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
9299da57d7bSbt150084 	mac->m_driver = ixgbe;
9309da57d7bSbt150084 	mac->m_dip = ixgbe->dip;
9319da57d7bSbt150084 	mac->m_src_addr = hw->mac.addr;
9329da57d7bSbt150084 	mac->m_callbacks = &ixgbe_m_callbacks;
9339da57d7bSbt150084 	mac->m_min_sdu = 0;
9349da57d7bSbt150084 	mac->m_max_sdu = ixgbe->default_mtu;
9359da57d7bSbt150084 	mac->m_margin = VLAN_TAGSZ;
936ea65739eSchenlu chen - Sun Microsystems - Beijing China 	mac->m_priv_props = ixgbe_priv_props;
937da14cebeSEric Cheng 	mac->m_v12n = MAC_VIRT_LEVEL1;
9389da57d7bSbt150084 
9399da57d7bSbt150084 	status = mac_register(mac, &ixgbe->mac_hdl);
9409da57d7bSbt150084 
9419da57d7bSbt150084 	mac_free(mac);
9429da57d7bSbt150084 
9439da57d7bSbt150084 	return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE);
9449da57d7bSbt150084 }
9459da57d7bSbt150084 
9469da57d7bSbt150084 /*
9479da57d7bSbt150084  * ixgbe_identify_hardware - Identify the type of the chipset.
9489da57d7bSbt150084  */
9499da57d7bSbt150084 static int
9509da57d7bSbt150084 ixgbe_identify_hardware(ixgbe_t *ixgbe)
9519da57d7bSbt150084 {
9529da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
9539da57d7bSbt150084 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
9549da57d7bSbt150084 
9559da57d7bSbt150084 	/*
9569da57d7bSbt150084 	 * Get the device id
9579da57d7bSbt150084 	 */
9589da57d7bSbt150084 	hw->vendor_id =
9599da57d7bSbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
9609da57d7bSbt150084 	hw->device_id =
9619da57d7bSbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
9629da57d7bSbt150084 	hw->revision_id =
9639da57d7bSbt150084 	    pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
9649da57d7bSbt150084 	hw->subsystem_device_id =
9659da57d7bSbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
9669da57d7bSbt150084 	hw->subsystem_vendor_id =
9679da57d7bSbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
9689da57d7bSbt150084 
96913740cb2SPaul Guo 	/*
97013740cb2SPaul Guo 	 * Set the mac type of the adapter based on the device id
97113740cb2SPaul Guo 	 */
97213740cb2SPaul Guo 	if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) {
97313740cb2SPaul Guo 		return (IXGBE_FAILURE);
97413740cb2SPaul Guo 	}
97513740cb2SPaul Guo 
97613740cb2SPaul Guo 	/*
97713740cb2SPaul Guo 	 * Install adapter capabilities
97813740cb2SPaul Guo 	 */
97913740cb2SPaul Guo 	switch (hw->mac.type) {
98013740cb2SPaul Guo 	case ixgbe_mac_82598EB:
98119843f01SPaul Guo 		IXGBE_DEBUGLOG_0(ixgbe, "identify 82598 adapter\n");
98213740cb2SPaul Guo 		ixgbe->capab = &ixgbe_82598eb_cap;
98313740cb2SPaul Guo 
98413740cb2SPaul Guo 		if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) {
98513740cb2SPaul Guo 			ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
98613740cb2SPaul Guo 			ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1;
9875b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe->capab->other_gpie |= IXGBE_SDP1_GPIEN;
98813740cb2SPaul Guo 		}
98973cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
9905b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
99173cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
99219843f01SPaul Guo 		IXGBE_DEBUGLOG_0(ixgbe, "identify 82599 adapter\n");
99373cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe->capab = &ixgbe_82599eb_cap;
99473cd555cSBin Tu - Sun Microsystems - Beijing China 
9955b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM) {
9965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe->capab->flags |= IXGBE_FLAG_TEMP_SENSOR_CAPABLE;
9975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP0;
9985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN;
9995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
100013740cb2SPaul Guo 		break;
10015b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
100269b5a878SDan McDonald 	case ixgbe_mac_X540:
100369b5a878SDan McDonald 		IXGBE_DEBUGLOG_0(ixgbe, "identify X540 adapter\n");
100469b5a878SDan McDonald 		ixgbe->capab = &ixgbe_X540_cap;
100569b5a878SDan McDonald 		/*
100669b5a878SDan McDonald 		 * For now, X540 is all set in its capab structure.
100769b5a878SDan McDonald 		 * As other X540 variants show up, things can change here.
100869b5a878SDan McDonald 		 */
100969b5a878SDan McDonald 		break;
101069b5a878SDan McDonald 
10117e579c30SDale Ghent 	case ixgbe_mac_X550:
10127e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
10137e579c30SDale Ghent 		IXGBE_DEBUGLOG_0(ixgbe, "identify X550 adapter\n");
10147e579c30SDale Ghent 		ixgbe->capab = &ixgbe_X550_cap;
10157e579c30SDale Ghent 
10167e579c30SDale Ghent 		if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
10177e579c30SDale Ghent 			ixgbe->capab->flags |= IXGBE_FLAG_SFP_PLUG_CAPABLE;
10187e579c30SDale Ghent 
10197e579c30SDale Ghent 		/*
10207e579c30SDale Ghent 		 * Link detection on X552 SFP+ and X552/X557-AT
10217e579c30SDale Ghent 		 */
10227e579c30SDale Ghent 		if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
10237e579c30SDale Ghent 		    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
10247e579c30SDale Ghent 			ixgbe->capab->other_intr |=
10257e579c30SDale Ghent 			    IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
10267e579c30SDale Ghent 			ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN_X540;
10277e579c30SDale Ghent 		}
10287e579c30SDale Ghent 		break;
10297e579c30SDale Ghent 
103013740cb2SPaul Guo 	default:
103119843f01SPaul Guo 		IXGBE_DEBUGLOG_1(ixgbe,
103213740cb2SPaul Guo 		    "adapter not supported in ixgbe_identify_hardware(): %d\n",
103313740cb2SPaul Guo 		    hw->mac.type);
103413740cb2SPaul Guo 		return (IXGBE_FAILURE);
103513740cb2SPaul Guo 	}
103613740cb2SPaul Guo 
10379da57d7bSbt150084 	return (IXGBE_SUCCESS);
10389da57d7bSbt150084 }
10399da57d7bSbt150084 
10409da57d7bSbt150084 /*
10419da57d7bSbt150084  * ixgbe_regs_map - Map the device registers.
10429da57d7bSbt150084  *
10439da57d7bSbt150084  */
10449da57d7bSbt150084 static int
10459da57d7bSbt150084 ixgbe_regs_map(ixgbe_t *ixgbe)
10469da57d7bSbt150084 {
10479da57d7bSbt150084 	dev_info_t *devinfo = ixgbe->dip;
10489da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
10499da57d7bSbt150084 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
10509da57d7bSbt150084 	off_t mem_size;
10519da57d7bSbt150084 
10529da57d7bSbt150084 	/*
10539da57d7bSbt150084 	 * First get the size of device registers to be mapped.
10549da57d7bSbt150084 	 */
105573cd555cSBin Tu - Sun Microsystems - Beijing China 	if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size)
105673cd555cSBin Tu - Sun Microsystems - Beijing China 	    != DDI_SUCCESS) {
10579da57d7bSbt150084 		return (IXGBE_FAILURE);
10589da57d7bSbt150084 	}
10599da57d7bSbt150084 
10609da57d7bSbt150084 	/*
10619da57d7bSbt150084 	 * Call ddi_regs_map_setup() to map registers
10629da57d7bSbt150084 	 */
106373cd555cSBin Tu - Sun Microsystems - Beijing China 	if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET,
10649da57d7bSbt150084 	    (caddr_t *)&hw->hw_addr, 0,
10659da57d7bSbt150084 	    mem_size, &ixgbe_regs_acc_attr,
10669da57d7bSbt150084 	    &osdep->reg_handle)) != DDI_SUCCESS) {
10679da57d7bSbt150084 		return (IXGBE_FAILURE);
10689da57d7bSbt150084 	}
10699da57d7bSbt150084 
10709da57d7bSbt150084 	return (IXGBE_SUCCESS);
10719da57d7bSbt150084 }
10729da57d7bSbt150084 
10739da57d7bSbt150084 /*
10749da57d7bSbt150084  * ixgbe_init_properties - Initialize driver properties.
10759da57d7bSbt150084  */
10769da57d7bSbt150084 static void
10779da57d7bSbt150084 ixgbe_init_properties(ixgbe_t *ixgbe)
10789da57d7bSbt150084 {
10799da57d7bSbt150084 	/*
10809da57d7bSbt150084 	 * Get conf file properties, including link settings
10819da57d7bSbt150084 	 * jumbo frames, ring number, descriptor number, etc.
10829da57d7bSbt150084 	 */
10839da57d7bSbt150084 	ixgbe_get_conf(ixgbe);
10849da57d7bSbt150084 }
10859da57d7bSbt150084 
10869da57d7bSbt150084 /*
10879da57d7bSbt150084  * ixgbe_init_driver_settings - Initialize driver settings.
10889da57d7bSbt150084  *
10899da57d7bSbt150084  * The settings include hardware function pointers, bus information,
10909da57d7bSbt150084  * rx/tx rings settings, link state, and any other parameters that
10919da57d7bSbt150084  * need to be setup during driver initialization.
10929da57d7bSbt150084  */
10939da57d7bSbt150084 static int
10949da57d7bSbt150084 ixgbe_init_driver_settings(ixgbe_t *ixgbe)
10959da57d7bSbt150084 {
10969da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
1097da14cebeSEric Cheng 	dev_info_t *devinfo = ixgbe->dip;
10989da57d7bSbt150084 	ixgbe_rx_ring_t *rx_ring;
10990dc2366fSVenugopal Iyer 	ixgbe_rx_group_t *rx_group;
11009da57d7bSbt150084 	ixgbe_tx_ring_t *tx_ring;
11019da57d7bSbt150084 	uint32_t rx_size;
11029da57d7bSbt150084 	uint32_t tx_size;
11030dc2366fSVenugopal Iyer 	uint32_t ring_per_group;
11049da57d7bSbt150084 	int i;
11059da57d7bSbt150084 
11069da57d7bSbt150084 	/*
11079da57d7bSbt150084 	 * Initialize chipset specific hardware function pointers
11089da57d7bSbt150084 	 */
11099da57d7bSbt150084 	if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) {
11109da57d7bSbt150084 		return (IXGBE_FAILURE);
11119da57d7bSbt150084 	}
11129da57d7bSbt150084 
11139da57d7bSbt150084 	/*
1114da14cebeSEric Cheng 	 * Get the system page size
1115da14cebeSEric Cheng 	 */
1116da14cebeSEric Cheng 	ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1);
1117da14cebeSEric Cheng 
1118da14cebeSEric Cheng 	/*
11199da57d7bSbt150084 	 * Set rx buffer size
11209da57d7bSbt150084 	 *
11219da57d7bSbt150084 	 * The IP header alignment room is counted in the calculation.
11229da57d7bSbt150084 	 * The rx buffer size is in unit of 1K that is required by the
11239da57d7bSbt150084 	 * chipset hardware.
11249da57d7bSbt150084 	 */
11259da57d7bSbt150084 	rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
11269da57d7bSbt150084 	ixgbe->rx_buf_size = ((rx_size >> 10) +
11279da57d7bSbt150084 	    ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
11289da57d7bSbt150084 
11299da57d7bSbt150084 	/*
11309da57d7bSbt150084 	 * Set tx buffer size
11319da57d7bSbt150084 	 */
11329da57d7bSbt150084 	tx_size = ixgbe->max_frame_size;
11339da57d7bSbt150084 	ixgbe->tx_buf_size = ((tx_size >> 10) +
11349da57d7bSbt150084 	    ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
11359da57d7bSbt150084 
11369da57d7bSbt150084 	/*
11370dc2366fSVenugopal Iyer 	 * Initialize rx/tx rings/groups parameters
11389da57d7bSbt150084 	 */
11390dc2366fSVenugopal Iyer 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
11409da57d7bSbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
11419da57d7bSbt150084 		rx_ring = &ixgbe->rx_rings[i];
11429da57d7bSbt150084 		rx_ring->index = i;
11439da57d7bSbt150084 		rx_ring->ixgbe = ixgbe;
11440dc2366fSVenugopal Iyer 		rx_ring->group_index = i / ring_per_group;
11450dc2366fSVenugopal Iyer 		rx_ring->hw_index = ixgbe_get_hw_rx_index(ixgbe, i);
11460dc2366fSVenugopal Iyer 	}
11470dc2366fSVenugopal Iyer 
11480dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_rx_groups; i++) {
11490dc2366fSVenugopal Iyer 		rx_group = &ixgbe->rx_groups[i];
11500dc2366fSVenugopal Iyer 		rx_group->index = i;
11510dc2366fSVenugopal Iyer 		rx_group->ixgbe = ixgbe;
11529da57d7bSbt150084 	}
11539da57d7bSbt150084 
11549da57d7bSbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
11559da57d7bSbt150084 		tx_ring = &ixgbe->tx_rings[i];
11569da57d7bSbt150084 		tx_ring->index = i;
11579da57d7bSbt150084 		tx_ring->ixgbe = ixgbe;
11589da57d7bSbt150084 		if (ixgbe->tx_head_wb_enable)
11599da57d7bSbt150084 			tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb;
11609da57d7bSbt150084 		else
11619da57d7bSbt150084 			tx_ring->tx_recycle = ixgbe_tx_recycle_legacy;
11629da57d7bSbt150084 
11639da57d7bSbt150084 		tx_ring->ring_size = ixgbe->tx_ring_size;
11649da57d7bSbt150084 		tx_ring->free_list_size = ixgbe->tx_ring_size +
11659da57d7bSbt150084 		    (ixgbe->tx_ring_size >> 1);
11669da57d7bSbt150084 	}
11679da57d7bSbt150084 
11689da57d7bSbt150084 	/*
11699da57d7bSbt150084 	 * Initialize values of interrupt throttling rate
11709da57d7bSbt150084 	 */
117173cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 1; i < MAX_INTR_VECTOR; i++)
11729da57d7bSbt150084 		ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0];
11739da57d7bSbt150084 
11749da57d7bSbt150084 	/*
11759da57d7bSbt150084 	 * The initial link state should be "unknown"
11769da57d7bSbt150084 	 */
11779da57d7bSbt150084 	ixgbe->link_state = LINK_STATE_UNKNOWN;
117873cd555cSBin Tu - Sun Microsystems - Beijing China 
11799da57d7bSbt150084 	return (IXGBE_SUCCESS);
11809da57d7bSbt150084 }
11819da57d7bSbt150084 
11829da57d7bSbt150084 /*
11839da57d7bSbt150084  * ixgbe_init_locks - Initialize locks.
11849da57d7bSbt150084  */
11859da57d7bSbt150084 static void
11869da57d7bSbt150084 ixgbe_init_locks(ixgbe_t *ixgbe)
11879da57d7bSbt150084 {
11889da57d7bSbt150084 	ixgbe_rx_ring_t *rx_ring;
11899da57d7bSbt150084 	ixgbe_tx_ring_t *tx_ring;
11909da57d7bSbt150084 	int i;
11919da57d7bSbt150084 
11929da57d7bSbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
11939da57d7bSbt150084 		rx_ring = &ixgbe->rx_rings[i];
11949da57d7bSbt150084 		mutex_init(&rx_ring->rx_lock, NULL,
11959da57d7bSbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
11969da57d7bSbt150084 	}
11979da57d7bSbt150084 
11989da57d7bSbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
11999da57d7bSbt150084 		tx_ring = &ixgbe->tx_rings[i];
12009da57d7bSbt150084 		mutex_init(&tx_ring->tx_lock, NULL,
12019da57d7bSbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12029da57d7bSbt150084 		mutex_init(&tx_ring->recycle_lock, NULL,
12039da57d7bSbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12049da57d7bSbt150084 		mutex_init(&tx_ring->tcb_head_lock, NULL,
12059da57d7bSbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12069da57d7bSbt150084 		mutex_init(&tx_ring->tcb_tail_lock, NULL,
12079da57d7bSbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12089da57d7bSbt150084 	}
12099da57d7bSbt150084 
12109da57d7bSbt150084 	mutex_init(&ixgbe->gen_lock, NULL,
12119da57d7bSbt150084 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12129da57d7bSbt150084 
12139da57d7bSbt150084 	mutex_init(&ixgbe->watchdog_lock, NULL,
12149da57d7bSbt150084 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12159da57d7bSbt150084 }
12169da57d7bSbt150084 
12179da57d7bSbt150084 /*
12189da57d7bSbt150084  * ixgbe_destroy_locks - Destroy locks.
12199da57d7bSbt150084  */
12209da57d7bSbt150084 static void
12219da57d7bSbt150084 ixgbe_destroy_locks(ixgbe_t *ixgbe)
12229da57d7bSbt150084 {
12239da57d7bSbt150084 	ixgbe_rx_ring_t *rx_ring;
12249da57d7bSbt150084 	ixgbe_tx_ring_t *tx_ring;
12259da57d7bSbt150084 	int i;
12269da57d7bSbt150084 
12279da57d7bSbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
12289da57d7bSbt150084 		rx_ring = &ixgbe->rx_rings[i];
12299da57d7bSbt150084 		mutex_destroy(&rx_ring->rx_lock);
12309da57d7bSbt150084 	}
12319da57d7bSbt150084 
12329da57d7bSbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
12339da57d7bSbt150084 		tx_ring = &ixgbe->tx_rings[i];
12349da57d7bSbt150084 		mutex_destroy(&tx_ring->tx_lock);
12359da57d7bSbt150084 		mutex_destroy(&tx_ring->recycle_lock);
12369da57d7bSbt150084 		mutex_destroy(&tx_ring->tcb_head_lock);
12379da57d7bSbt150084 		mutex_destroy(&tx_ring->tcb_tail_lock);
12389da57d7bSbt150084 	}
12399da57d7bSbt150084 
12409da57d7bSbt150084 	mutex_destroy(&ixgbe->gen_lock);
12419da57d7bSbt150084 	mutex_destroy(&ixgbe->watchdog_lock);
12429da57d7bSbt150084 }
12439da57d7bSbt150084 
12449da57d7bSbt150084 static int
12459da57d7bSbt150084 ixgbe_resume(dev_info_t *devinfo)
12469da57d7bSbt150084 {
12479da57d7bSbt150084 	ixgbe_t *ixgbe;
124862e6e1adSPaul Guo 	int i;
12499da57d7bSbt150084 
12509da57d7bSbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
12519da57d7bSbt150084 	if (ixgbe == NULL)
12529da57d7bSbt150084 		return (DDI_FAILURE);
12539da57d7bSbt150084 
12549da57d7bSbt150084 	mutex_enter(&ixgbe->gen_lock);
12559da57d7bSbt150084 
12569da57d7bSbt150084 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
1257ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
12589da57d7bSbt150084 			mutex_exit(&ixgbe->gen_lock);
12599da57d7bSbt150084 			return (DDI_FAILURE);
12609da57d7bSbt150084 		}
12619da57d7bSbt150084 
12629da57d7bSbt150084 		/*
12639da57d7bSbt150084 		 * Enable and start the watchdog timer
12649da57d7bSbt150084 		 */
12659da57d7bSbt150084 		ixgbe_enable_watchdog_timer(ixgbe);
12669da57d7bSbt150084 	}
12679da57d7bSbt150084 
126862e6e1adSPaul Guo 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED);
126962e6e1adSPaul Guo 
127062e6e1adSPaul Guo 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
127162e6e1adSPaul Guo 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
127262e6e1adSPaul Guo 			mac_tx_ring_update(ixgbe->mac_hdl,
127362e6e1adSPaul Guo 			    ixgbe->tx_rings[i].ring_handle);
127462e6e1adSPaul Guo 		}
127562e6e1adSPaul Guo 	}
12769da57d7bSbt150084 
12779da57d7bSbt150084 	mutex_exit(&ixgbe->gen_lock);
12789da57d7bSbt150084 
12799da57d7bSbt150084 	return (DDI_SUCCESS);
12809da57d7bSbt150084 }
12819da57d7bSbt150084 
12829da57d7bSbt150084 static int
12839da57d7bSbt150084 ixgbe_suspend(dev_info_t *devinfo)
12849da57d7bSbt150084 {
12859da57d7bSbt150084 	ixgbe_t *ixgbe;
12869da57d7bSbt150084 
12879da57d7bSbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
12889da57d7bSbt150084 	if (ixgbe == NULL)
12899da57d7bSbt150084 		return (DDI_FAILURE);
12909da57d7bSbt150084 
12919da57d7bSbt150084 	mutex_enter(&ixgbe->gen_lock);
12929da57d7bSbt150084 
129362e6e1adSPaul Guo 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED);
1294ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
1295ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&ixgbe->gen_lock);
1296ea65739eSchenlu chen - Sun Microsystems - Beijing China 		return (DDI_SUCCESS);
1297ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
1298ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_stop(ixgbe, B_FALSE);
12999da57d7bSbt150084 
13009da57d7bSbt150084 	mutex_exit(&ixgbe->gen_lock);
13019da57d7bSbt150084 
13029da57d7bSbt150084 	/*
13039da57d7bSbt150084 	 * Disable and stop the watchdog timer
13049da57d7bSbt150084 	 */
13059da57d7bSbt150084 	ixgbe_disable_watchdog_timer(ixgbe);
13069da57d7bSbt150084 
13079da57d7bSbt150084 	return (DDI_SUCCESS);
13089da57d7bSbt150084 }
13099da57d7bSbt150084 
13109da57d7bSbt150084 /*
13119da57d7bSbt150084  * ixgbe_init - Initialize the device.
13129da57d7bSbt150084  */
13139da57d7bSbt150084 static int
13149da57d7bSbt150084 ixgbe_init(ixgbe_t *ixgbe)
13159da57d7bSbt150084 {
13169da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
131769c76190SKeith M Wesolowski 	u8 pbanum[IXGBE_PBANUM_LENGTH];
13187e579c30SDale Ghent 	int rv;
13199da57d7bSbt150084 
13209da57d7bSbt150084 	mutex_enter(&ixgbe->gen_lock);
13219da57d7bSbt150084 
13229da57d7bSbt150084 	/*
13237e579c30SDale Ghent 	 * Configure/Initialize hardware
13249da57d7bSbt150084 	 */
13257e579c30SDale Ghent 	rv = ixgbe_init_hw(hw);
13267e579c30SDale Ghent 	if (rv != IXGBE_SUCCESS) {
13277e579c30SDale Ghent 		switch (rv) {
13287e579c30SDale Ghent 
13297e579c30SDale Ghent 		/*
13307e579c30SDale Ghent 		 * The first three errors are not prohibitive to us progressing
13317e579c30SDale Ghent 		 * further, and are maily advisory in nature. In the case of a
13327e579c30SDale Ghent 		 * SFP module not being present or not deemed supported by the
13337e579c30SDale Ghent 		 * common code, we adivse the operator of this fact but carry on
13347e579c30SDale Ghent 		 * instead of failing hard, as SFPs can be inserted or replaced
13357e579c30SDale Ghent 		 * while the driver is running. In the case of a unknown error,
13367e579c30SDale Ghent 		 * we fail-hard, logging the reason and emitting a FMA event.
13377e579c30SDale Ghent 		 */
13387e579c30SDale Ghent 		case IXGBE_ERR_EEPROM_VERSION:
13397e579c30SDale Ghent 			ixgbe_error(ixgbe,
13407e579c30SDale Ghent 			    "This Intel 10Gb Ethernet device is pre-release and"
13417e579c30SDale Ghent 			    " contains outdated firmware. Please contact your"
13427e579c30SDale Ghent 			    " hardware vendor for a replacement.");
13437e579c30SDale Ghent 			break;
13447e579c30SDale Ghent 		case IXGBE_ERR_SFP_NOT_PRESENT:
13457e579c30SDale Ghent 			ixgbe_error(ixgbe,
13467e579c30SDale Ghent 			    "No SFP+ module detected on this interface. Please "
13477e579c30SDale Ghent 			    "install a supported SFP+ module for this "
13487e579c30SDale Ghent 			    "interface to become operational.");
13497e579c30SDale Ghent 			break;
13507e579c30SDale Ghent 		case IXGBE_ERR_SFP_NOT_SUPPORTED:
13517e579c30SDale Ghent 			ixgbe_error(ixgbe,
13527e579c30SDale Ghent 			    "Unsupported SFP+ module detected. Please replace "
13537e579c30SDale Ghent 			    "it with a supported SFP+ module per Intel "
13547e579c30SDale Ghent 			    "documentation, or bypass this check with "
13557e579c30SDale Ghent 			    "allow_unsupported_sfp=1 in ixgbe.conf.");
13567e579c30SDale Ghent 			break;
13577e579c30SDale Ghent 		default:
13587e579c30SDale Ghent 			ixgbe_error(ixgbe,
13597e579c30SDale Ghent 			    "Failed to initialize hardware. ixgbe_init_hw "
13607e579c30SDale Ghent 			    "returned %d", rv);
13619da57d7bSbt150084 			ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
13629da57d7bSbt150084 			goto init_fail;
13639da57d7bSbt150084 		}
13647e579c30SDale Ghent 	}
13659da57d7bSbt150084 
13669da57d7bSbt150084 	/*
13679da57d7bSbt150084 	 * Need to init eeprom before validating the checksum.
13689da57d7bSbt150084 	 */
13699da57d7bSbt150084 	if (ixgbe_init_eeprom_params(hw) < 0) {
13709da57d7bSbt150084 		ixgbe_error(ixgbe,
13719da57d7bSbt150084 		    "Unable to intitialize the eeprom interface.");
13729da57d7bSbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
13739da57d7bSbt150084 		goto init_fail;
13749da57d7bSbt150084 	}
13759da57d7bSbt150084 
13769da57d7bSbt150084 	/*
13779da57d7bSbt150084 	 * NVM validation
13789da57d7bSbt150084 	 */
13799da57d7bSbt150084 	if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
13809da57d7bSbt150084 		/*
13819da57d7bSbt150084 		 * Some PCI-E parts fail the first check due to
13829da57d7bSbt150084 		 * the link being in sleep state.  Call it again,
13839da57d7bSbt150084 		 * if it fails a second time it's a real issue.
13849da57d7bSbt150084 		 */
13859da57d7bSbt150084 		if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
13869da57d7bSbt150084 			ixgbe_error(ixgbe,
13879da57d7bSbt150084 			    "Invalid NVM checksum. Please contact "
13889da57d7bSbt150084 			    "the vendor to update the NVM.");
13899da57d7bSbt150084 			ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
13909da57d7bSbt150084 			goto init_fail;
13919da57d7bSbt150084 		}
13929da57d7bSbt150084 	}
13939da57d7bSbt150084 
13949da57d7bSbt150084 	/*
13959da57d7bSbt150084 	 * Setup default flow control thresholds - enable/disable
13969da57d7bSbt150084 	 * & flow control type is controlled by ixgbe.conf
13979da57d7bSbt150084 	 */
139869b5a878SDan McDonald 	hw->fc.high_water[0] = DEFAULT_FCRTH;
139969b5a878SDan McDonald 	hw->fc.low_water[0] = DEFAULT_FCRTL;
14009da57d7bSbt150084 	hw->fc.pause_time = DEFAULT_FCPAUSE;
14019da57d7bSbt150084 	hw->fc.send_xon = B_TRUE;
14029da57d7bSbt150084 
14039da57d7bSbt150084 	/*
14047e579c30SDale Ghent 	 * Initialize flow control
14057e579c30SDale Ghent 	 */
14067e579c30SDale Ghent 	(void) ixgbe_start_hw(hw);
14077e579c30SDale Ghent 
14087e579c30SDale Ghent 	/*
14099da57d7bSbt150084 	 * Initialize link settings
14109da57d7bSbt150084 	 */
14119da57d7bSbt150084 	(void) ixgbe_driver_setup_link(ixgbe, B_FALSE);
14129da57d7bSbt150084 
14139da57d7bSbt150084 	/*
14149da57d7bSbt150084 	 * Initialize the chipset hardware
14159da57d7bSbt150084 	 */
14169da57d7bSbt150084 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
14179da57d7bSbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
14189da57d7bSbt150084 		goto init_fail;
14199da57d7bSbt150084 	}
14209da57d7bSbt150084 
142169c76190SKeith M Wesolowski 	/*
142269c76190SKeith M Wesolowski 	 * Read identifying information and place in devinfo.
142369c76190SKeith M Wesolowski 	 */
142469c76190SKeith M Wesolowski 	pbanum[0] = '\0';
142569c76190SKeith M Wesolowski 	(void) ixgbe_read_pba_string(hw, pbanum, sizeof (pbanum));
142669c76190SKeith M Wesolowski 	if (*pbanum != '\0') {
142769c76190SKeith M Wesolowski 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, ixgbe->dip,
142869c76190SKeith M Wesolowski 		    "printed-board-assembly", (char *)pbanum);
142969c76190SKeith M Wesolowski 	}
143069c76190SKeith M Wesolowski 
14319da57d7bSbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
14329da57d7bSbt150084 		goto init_fail;
14339da57d7bSbt150084 	}
14349da57d7bSbt150084 
14359da57d7bSbt150084 	mutex_exit(&ixgbe->gen_lock);
14369da57d7bSbt150084 	return (IXGBE_SUCCESS);
14379da57d7bSbt150084 
14389da57d7bSbt150084 init_fail:
14399da57d7bSbt150084 	/*
14409da57d7bSbt150084 	 * Reset PHY
14419da57d7bSbt150084 	 */
14429da57d7bSbt150084 	(void) ixgbe_reset_phy(hw);
14439da57d7bSbt150084 
14449da57d7bSbt150084 	mutex_exit(&ixgbe->gen_lock);
14459da57d7bSbt150084 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
14469da57d7bSbt150084 	return (IXGBE_FAILURE);
14479da57d7bSbt150084 }
14489da57d7bSbt150084 
14499da57d7bSbt150084 /*
14509da57d7bSbt150084  * ixgbe_chip_start - Initialize and start the chipset hardware.
14519da57d7bSbt150084  */
14529da57d7bSbt150084 static int
14539da57d7bSbt150084 ixgbe_chip_start(ixgbe_t *ixgbe)
14549da57d7bSbt150084 {
14559da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
14567e579c30SDale Ghent 	int i;
14579da57d7bSbt150084 
14589da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
14599da57d7bSbt150084 
14609da57d7bSbt150084 	/*
14619da57d7bSbt150084 	 * Get the mac address
14629da57d7bSbt150084 	 * This function should handle SPARC case correctly.
14639da57d7bSbt150084 	 */
14649da57d7bSbt150084 	if (!ixgbe_find_mac_address(ixgbe)) {
14659da57d7bSbt150084 		ixgbe_error(ixgbe, "Failed to get the mac address");
14669da57d7bSbt150084 		return (IXGBE_FAILURE);
14679da57d7bSbt150084 	}
14689da57d7bSbt150084 
14699da57d7bSbt150084 	/*
14709da57d7bSbt150084 	 * Validate the mac address
14719da57d7bSbt150084 	 */
14729da57d7bSbt150084 	(void) ixgbe_init_rx_addrs(hw);
14739da57d7bSbt150084 	if (!is_valid_mac_addr(hw->mac.addr)) {
14749da57d7bSbt150084 		ixgbe_error(ixgbe, "Invalid mac address");
14759da57d7bSbt150084 		return (IXGBE_FAILURE);
14769da57d7bSbt150084 	}
14779da57d7bSbt150084 
14789da57d7bSbt150084 	/*
147919843f01SPaul Guo 	 * Re-enable relaxed ordering for performance.  It is disabled
148019843f01SPaul Guo 	 * by default in the hardware init.
148119843f01SPaul Guo 	 */
14825b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->relax_order_enable == B_TRUE)
148319843f01SPaul Guo 		ixgbe_enable_relaxed_ordering(hw);
148419843f01SPaul Guo 
148519843f01SPaul Guo 	/*
14869da57d7bSbt150084 	 * Setup adapter interrupt vectors
14879da57d7bSbt150084 	 */
14889da57d7bSbt150084 	ixgbe_setup_adapter_vector(ixgbe);
14899da57d7bSbt150084 
14909da57d7bSbt150084 	/*
14919da57d7bSbt150084 	 * Initialize unicast addresses.
14929da57d7bSbt150084 	 */
14939da57d7bSbt150084 	ixgbe_init_unicst(ixgbe);
14949da57d7bSbt150084 
14959da57d7bSbt150084 	/*
14969da57d7bSbt150084 	 * Setup and initialize the mctable structures.
14979da57d7bSbt150084 	 */
14989da57d7bSbt150084 	ixgbe_setup_multicst(ixgbe);
14999da57d7bSbt150084 
15009da57d7bSbt150084 	/*
15019da57d7bSbt150084 	 * Set interrupt throttling rate
15029da57d7bSbt150084 	 */
150373cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->intr_cnt; i++) {
15049da57d7bSbt150084 		IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]);
150573cd555cSBin Tu - Sun Microsystems - Beijing China 	}
15069da57d7bSbt150084 
15079da57d7bSbt150084 	/*
15087e579c30SDale Ghent 	 * Disable Wake-on-LAN
15097e579c30SDale Ghent 	 */
15107e579c30SDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_WUC, 0);
15117e579c30SDale Ghent 
15127e579c30SDale Ghent 	/*
15137e579c30SDale Ghent 	 * Some adapters offer Energy Efficient Ethernet (EEE) support.
15147e579c30SDale Ghent 	 * Due to issues with EEE in e1000g/igb, we disable this by default
15157e579c30SDale Ghent 	 * as a precautionary measure.
15167e579c30SDale Ghent 	 *
15177e579c30SDale Ghent 	 * Currently, the only known adapter which supports EEE in the ixgbe
15187e579c30SDale Ghent 	 * line is 8086,15AB (IXGBE_DEV_ID_X550EM_X_KR), and only after the
15197e579c30SDale Ghent 	 * first revision of it, as well as any X550 with MAC type 6 (non-EM)
15207e579c30SDale Ghent 	 */
15217e579c30SDale Ghent 	(void) ixgbe_setup_eee(hw, B_FALSE);
15227e579c30SDale Ghent 
15237e579c30SDale Ghent 	/*
15247e579c30SDale Ghent 	 * Turn on any present SFP Tx laser
15257e579c30SDale Ghent 	 */
15267e579c30SDale Ghent 	ixgbe_enable_tx_laser(hw);
15277e579c30SDale Ghent 
15287e579c30SDale Ghent 	/*
15297e579c30SDale Ghent 	 * Power on the PHY
15307e579c30SDale Ghent 	 */
15317e579c30SDale Ghent 	(void) ixgbe_set_phy_power(hw, B_TRUE);
15327e579c30SDale Ghent 
15337e579c30SDale Ghent 	/*
15347e579c30SDale Ghent 	 * Save the state of the PHY
15359da57d7bSbt150084 	 */
15369da57d7bSbt150084 	ixgbe_get_hw_state(ixgbe);
15379da57d7bSbt150084 
15389da57d7bSbt150084 	/*
15399da57d7bSbt150084 	 * Make sure driver has control
15409da57d7bSbt150084 	 */
15419da57d7bSbt150084 	ixgbe_get_driver_control(hw);
15429da57d7bSbt150084 
15439da57d7bSbt150084 	return (IXGBE_SUCCESS);
15449da57d7bSbt150084 }
15459da57d7bSbt150084 
15469da57d7bSbt150084 /*
15479da57d7bSbt150084  * ixgbe_chip_stop - Stop the chipset hardware
15489da57d7bSbt150084  */
15499da57d7bSbt150084 static void
15509da57d7bSbt150084 ixgbe_chip_stop(ixgbe_t *ixgbe)
15519da57d7bSbt150084 {
15529da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
15537e579c30SDale Ghent 	int rv;
15549da57d7bSbt150084 
15559da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
15569da57d7bSbt150084 
15579da57d7bSbt150084 	/*
15587e579c30SDale Ghent 	 * Stop interupt generation and disable Tx unit
15599da57d7bSbt150084 	 */
15607e579c30SDale Ghent 	hw->adapter_stopped = B_FALSE;
15617e579c30SDale Ghent 	(void) ixgbe_stop_adapter(hw);
15629da57d7bSbt150084 
15639da57d7bSbt150084 	/*
15649da57d7bSbt150084 	 * Reset the chipset
15659da57d7bSbt150084 	 */
15669da57d7bSbt150084 	(void) ixgbe_reset_hw(hw);
15679da57d7bSbt150084 
15689da57d7bSbt150084 	/*
15699da57d7bSbt150084 	 * Reset PHY
15709da57d7bSbt150084 	 */
15719da57d7bSbt150084 	(void) ixgbe_reset_phy(hw);
15727e579c30SDale Ghent 
15737e579c30SDale Ghent 	/*
15747e579c30SDale Ghent 	 * Enter LPLU (Low Power, Link Up) mode, if available. Avoid resetting
15757e579c30SDale Ghent 	 * the PHY while doing so. Else, just power down the PHY.
15767e579c30SDale Ghent 	 */
15777e579c30SDale Ghent 	if (hw->phy.ops.enter_lplu != NULL) {
15787e579c30SDale Ghent 		hw->phy.reset_disable = B_TRUE;
15797e579c30SDale Ghent 		rv = hw->phy.ops.enter_lplu(hw);
15807e579c30SDale Ghent 		if (rv != IXGBE_SUCCESS)
15817e579c30SDale Ghent 			ixgbe_error(ixgbe, "Error while entering LPLU: %d", rv);
15827e579c30SDale Ghent 		hw->phy.reset_disable = B_FALSE;
15837e579c30SDale Ghent 	} else {
15847e579c30SDale Ghent 		(void) ixgbe_set_phy_power(hw, B_FALSE);
15857e579c30SDale Ghent 	}
15867e579c30SDale Ghent 
15877e579c30SDale Ghent 	/*
15887e579c30SDale Ghent 	 * Turn off any present SFP Tx laser
15897e579c30SDale Ghent 	 * Expected for health and safety reasons
15907e579c30SDale Ghent 	 */
15917e579c30SDale Ghent 	ixgbe_disable_tx_laser(hw);
15927e579c30SDale Ghent 
15937e579c30SDale Ghent 	/*
15947e579c30SDale Ghent 	 * Tell firmware driver is no longer in control
15957e579c30SDale Ghent 	 */
15967e579c30SDale Ghent 	ixgbe_release_driver_control(hw);
15977e579c30SDale Ghent 
15989da57d7bSbt150084 }
15999da57d7bSbt150084 
16009da57d7bSbt150084 /*
16019da57d7bSbt150084  * ixgbe_reset - Reset the chipset and re-start the driver.
16029da57d7bSbt150084  *
16039da57d7bSbt150084  * It involves stopping and re-starting the chipset,
16049da57d7bSbt150084  * and re-configuring the rx/tx rings.
16059da57d7bSbt150084  */
16069da57d7bSbt150084 static int
16079da57d7bSbt150084 ixgbe_reset(ixgbe_t *ixgbe)
16089da57d7bSbt150084 {
160962e6e1adSPaul Guo 	int i;
161062e6e1adSPaul Guo 
1611ea65739eSchenlu chen - Sun Microsystems - Beijing China 	/*
1612ea65739eSchenlu chen - Sun Microsystems - Beijing China 	 * Disable and stop the watchdog timer
1613ea65739eSchenlu chen - Sun Microsystems - Beijing China 	 */
1614ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_disable_watchdog_timer(ixgbe);
16159da57d7bSbt150084 
16169da57d7bSbt150084 	mutex_enter(&ixgbe->gen_lock);
16179da57d7bSbt150084 
16189da57d7bSbt150084 	ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED);
161962e6e1adSPaul Guo 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
16209da57d7bSbt150084 
1621ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_stop(ixgbe, B_FALSE);
16229da57d7bSbt150084 
1623ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
1624ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&ixgbe->gen_lock);
1625ea65739eSchenlu chen - Sun Microsystems - Beijing China 		return (IXGBE_FAILURE);
16269da57d7bSbt150084 	}
16279da57d7bSbt150084 
162862e6e1adSPaul Guo 	/*
162962e6e1adSPaul Guo 	 * After resetting, need to recheck the link status.
163062e6e1adSPaul Guo 	 */
163162e6e1adSPaul Guo 	ixgbe->link_check_complete = B_FALSE;
163262e6e1adSPaul Guo 	ixgbe->link_check_hrtime = gethrtime() +
163362e6e1adSPaul Guo 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
163462e6e1adSPaul Guo 
163562e6e1adSPaul Guo 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED);
163662e6e1adSPaul Guo 
163762e6e1adSPaul Guo 	if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) {
163862e6e1adSPaul Guo 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
163962e6e1adSPaul Guo 			mac_tx_ring_update(ixgbe->mac_hdl,
164062e6e1adSPaul Guo 			    ixgbe->tx_rings[i].ring_handle);
164162e6e1adSPaul Guo 		}
164262e6e1adSPaul Guo 	}
164362e6e1adSPaul Guo 
16449da57d7bSbt150084 	mutex_exit(&ixgbe->gen_lock);
16459da57d7bSbt150084 
1646ea65739eSchenlu chen - Sun Microsystems - Beijing China 	/*
1647ea65739eSchenlu chen - Sun Microsystems - Beijing China 	 * Enable and start the watchdog timer
1648ea65739eSchenlu chen - Sun Microsystems - Beijing China 	 */
1649ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_enable_watchdog_timer(ixgbe);
1650ea65739eSchenlu chen - Sun Microsystems - Beijing China 
16519da57d7bSbt150084 	return (IXGBE_SUCCESS);
16529da57d7bSbt150084 }
16539da57d7bSbt150084 
16549da57d7bSbt150084 /*
16559da57d7bSbt150084  * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources.
16569da57d7bSbt150084  */
16579da57d7bSbt150084 static void
16589da57d7bSbt150084 ixgbe_tx_clean(ixgbe_t *ixgbe)
16599da57d7bSbt150084 {
16609da57d7bSbt150084 	ixgbe_tx_ring_t *tx_ring;
16619da57d7bSbt150084 	tx_control_block_t *tcb;
16629da57d7bSbt150084 	link_list_t pending_list;
16639da57d7bSbt150084 	uint32_t desc_num;
16649da57d7bSbt150084 	int i, j;
16659da57d7bSbt150084 
16669da57d7bSbt150084 	LINK_LIST_INIT(&pending_list);
16679da57d7bSbt150084 
16689da57d7bSbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
16699da57d7bSbt150084 		tx_ring = &ixgbe->tx_rings[i];
16709da57d7bSbt150084 
16719da57d7bSbt150084 		mutex_enter(&tx_ring->recycle_lock);
16729da57d7bSbt150084 
16739da57d7bSbt150084 		/*
16749da57d7bSbt150084 		 * Clean the pending tx data - the pending packets in the
16759da57d7bSbt150084 		 * work_list that have no chances to be transmitted again.
16769da57d7bSbt150084 		 *
16779da57d7bSbt150084 		 * We must ensure the chipset is stopped or the link is down
16789da57d7bSbt150084 		 * before cleaning the transmit packets.
16799da57d7bSbt150084 		 */
16809da57d7bSbt150084 		desc_num = 0;
16819da57d7bSbt150084 		for (j = 0; j < tx_ring->ring_size; j++) {
16829da57d7bSbt150084 			tcb = tx_ring->work_list[j];
16839da57d7bSbt150084 			if (tcb != NULL) {
16849da57d7bSbt150084 				desc_num += tcb->desc_num;
16859da57d7bSbt150084 
16869da57d7bSbt150084 				tx_ring->work_list[j] = NULL;
16879da57d7bSbt150084 
16889da57d7bSbt150084 				ixgbe_free_tcb(tcb);
16899da57d7bSbt150084 
16909da57d7bSbt150084 				LIST_PUSH_TAIL(&pending_list, &tcb->link);
16919da57d7bSbt150084 			}
16929da57d7bSbt150084 		}
16939da57d7bSbt150084 
16949da57d7bSbt150084 		if (desc_num > 0) {
16959da57d7bSbt150084 			atomic_add_32(&tx_ring->tbd_free, desc_num);
16969da57d7bSbt150084 			ASSERT(tx_ring->tbd_free == tx_ring->ring_size);
16979da57d7bSbt150084 
16989da57d7bSbt150084 			/*
16999da57d7bSbt150084 			 * Reset the head and tail pointers of the tbd ring;
17009da57d7bSbt150084 			 * Reset the writeback head if it's enable.
17019da57d7bSbt150084 			 */
17029da57d7bSbt150084 			tx_ring->tbd_head = 0;
17039da57d7bSbt150084 			tx_ring->tbd_tail = 0;
17049da57d7bSbt150084 			if (ixgbe->tx_head_wb_enable)
17059da57d7bSbt150084 				*tx_ring->tbd_head_wb = 0;
17069da57d7bSbt150084 
17079da57d7bSbt150084 			IXGBE_WRITE_REG(&ixgbe->hw,
17089da57d7bSbt150084 			    IXGBE_TDH(tx_ring->index), 0);
17099da57d7bSbt150084 			IXGBE_WRITE_REG(&ixgbe->hw,
17109da57d7bSbt150084 			    IXGBE_TDT(tx_ring->index), 0);
17119da57d7bSbt150084 		}
17129da57d7bSbt150084 
17139da57d7bSbt150084 		mutex_exit(&tx_ring->recycle_lock);
17149da57d7bSbt150084 
17159da57d7bSbt150084 		/*
17169da57d7bSbt150084 		 * Add the tx control blocks in the pending list to
17179da57d7bSbt150084 		 * the free list.
17189da57d7bSbt150084 		 */
17199da57d7bSbt150084 		ixgbe_put_free_list(tx_ring, &pending_list);
17209da57d7bSbt150084 	}
17219da57d7bSbt150084 }
17229da57d7bSbt150084 
17239da57d7bSbt150084 /*
17249da57d7bSbt150084  * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be
17259da57d7bSbt150084  * transmitted.
17269da57d7bSbt150084  */
17279da57d7bSbt150084 static boolean_t
17289da57d7bSbt150084 ixgbe_tx_drain(ixgbe_t *ixgbe)
17299da57d7bSbt150084 {
17309da57d7bSbt150084 	ixgbe_tx_ring_t *tx_ring;
17319da57d7bSbt150084 	boolean_t done;
17329da57d7bSbt150084 	int i, j;
17339da57d7bSbt150084 
17349da57d7bSbt150084 	/*
17359da57d7bSbt150084 	 * Wait for a specific time to allow pending tx packets
17369da57d7bSbt150084 	 * to be transmitted.
17379da57d7bSbt150084 	 *
17389da57d7bSbt150084 	 * Check the counter tbd_free to see if transmission is done.
17399da57d7bSbt150084 	 * No lock protection is needed here.
17409da57d7bSbt150084 	 *
17419da57d7bSbt150084 	 * Return B_TRUE if all pending packets have been transmitted;
17429da57d7bSbt150084 	 * Otherwise return B_FALSE;
17439da57d7bSbt150084 	 */
17449da57d7bSbt150084 	for (i = 0; i < TX_DRAIN_TIME; i++) {
17459da57d7bSbt150084 
17469da57d7bSbt150084 		done = B_TRUE;
17479da57d7bSbt150084 		for (j = 0; j < ixgbe->num_tx_rings; j++) {
17489da57d7bSbt150084 			tx_ring = &ixgbe->tx_rings[j];
17499da57d7bSbt150084 			done = done &&
17509da57d7bSbt150084 			    (tx_ring->tbd_free == tx_ring->ring_size);
17519da57d7bSbt150084 		}
17529da57d7bSbt150084 
17539da57d7bSbt150084 		if (done)
17549da57d7bSbt150084 			break;
17559da57d7bSbt150084 
17569da57d7bSbt150084 		msec_delay(1);
17579da57d7bSbt150084 	}
17589da57d7bSbt150084 
17599da57d7bSbt150084 	return (done);
17609da57d7bSbt150084 }
17619da57d7bSbt150084 
17629da57d7bSbt150084 /*
17639da57d7bSbt150084  * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer.
17649da57d7bSbt150084  */
17659da57d7bSbt150084 static boolean_t
17669da57d7bSbt150084 ixgbe_rx_drain(ixgbe_t *ixgbe)
17679da57d7bSbt150084 {
1768ea65739eSchenlu chen - Sun Microsystems - Beijing China 	boolean_t done = B_TRUE;
1769ea65739eSchenlu chen - Sun Microsystems - Beijing China 	int i;
17709da57d7bSbt150084 
17719da57d7bSbt150084 	/*
17729da57d7bSbt150084 	 * Polling the rx free list to check if those rx buffers held by
17739da57d7bSbt150084 	 * the upper layer are released.
17749da57d7bSbt150084 	 *
17759da57d7bSbt150084 	 * Check the counter rcb_free to see if all pending buffers are
17769da57d7bSbt150084 	 * released. No lock protection is needed here.
17779da57d7bSbt150084 	 *
17789da57d7bSbt150084 	 * Return B_TRUE if all pending buffers have been released;
17799da57d7bSbt150084 	 * Otherwise return B_FALSE;
17809da57d7bSbt150084 	 */
17819da57d7bSbt150084 	for (i = 0; i < RX_DRAIN_TIME; i++) {
1782ea65739eSchenlu chen - Sun Microsystems - Beijing China 		done = (ixgbe->rcb_pending == 0);
17839da57d7bSbt150084 
17849da57d7bSbt150084 		if (done)
17859da57d7bSbt150084 			break;
17869da57d7bSbt150084 
17879da57d7bSbt150084 		msec_delay(1);
17889da57d7bSbt150084 	}
17899da57d7bSbt150084 
17909da57d7bSbt150084 	return (done);
17919da57d7bSbt150084 }
17929da57d7bSbt150084 
17939da57d7bSbt150084 /*
17949da57d7bSbt150084  * ixgbe_start - Start the driver/chipset.
17959da57d7bSbt150084  */
17969da57d7bSbt150084 int
1797ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer)
17989da57d7bSbt150084 {
17997e579c30SDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
18009da57d7bSbt150084 	int i;
18019da57d7bSbt150084 
18029da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
18039da57d7bSbt150084 
1804ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (alloc_buffer) {
1805ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) {
1806ea65739eSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_error(ixgbe,
1807ea65739eSchenlu chen - Sun Microsystems - Beijing China 			    "Failed to allocate software receive rings");
1808ea65739eSchenlu chen - Sun Microsystems - Beijing China 			return (IXGBE_FAILURE);
1809ea65739eSchenlu chen - Sun Microsystems - Beijing China 		}
1810ea65739eSchenlu chen - Sun Microsystems - Beijing China 
1811ea65739eSchenlu chen - Sun Microsystems - Beijing China 		/* Allocate buffers for all the rx/tx rings */
1812ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) {
1813ea65739eSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_error(ixgbe, "Failed to allocate DMA resource");
1814ea65739eSchenlu chen - Sun Microsystems - Beijing China 			return (IXGBE_FAILURE);
1815ea65739eSchenlu chen - Sun Microsystems - Beijing China 		}
1816ea65739eSchenlu chen - Sun Microsystems - Beijing China 
1817ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->tx_ring_init = B_TRUE;
1818ea65739eSchenlu chen - Sun Microsystems - Beijing China 	} else {
1819ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->tx_ring_init = B_FALSE;
1820ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
1821ea65739eSchenlu chen - Sun Microsystems - Beijing China 
18229da57d7bSbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++)
18239da57d7bSbt150084 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
18249da57d7bSbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++)
18259da57d7bSbt150084 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
18269da57d7bSbt150084 
18279da57d7bSbt150084 	/*
18289da57d7bSbt150084 	 * Start the chipset hardware
18299da57d7bSbt150084 	 */
18309da57d7bSbt150084 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
18319da57d7bSbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
18329da57d7bSbt150084 		goto start_failure;
18339da57d7bSbt150084 	}
18349da57d7bSbt150084 
18357e579c30SDale Ghent 	/*
18367e579c30SDale Ghent 	 * Configure link now for X550
18377e579c30SDale Ghent 	 *
18387e579c30SDale Ghent 	 * X550 possesses a LPLU (Low-Power Link Up) mode which keeps the
18397e579c30SDale Ghent 	 * resting state of the adapter at a 1Gb FDX speed. Prior to the X550,
18407e579c30SDale Ghent 	 * the resting state of the link would be the maximum speed that
18417e579c30SDale Ghent 	 * autonegotiation will allow (usually 10Gb, infrastructure allowing)
18427e579c30SDale Ghent 	 * so we never bothered with explicitly setting the link to 10Gb as it
18437e579c30SDale Ghent 	 * would already be at that state on driver attach. With X550, we must
18447e579c30SDale Ghent 	 * trigger a re-negotiation of the link in order to switch from a LPLU
18457e579c30SDale Ghent 	 * 1Gb link to 10Gb (cable and link partner permitting.)
18467e579c30SDale Ghent 	 */
18477e579c30SDale Ghent 	if (hw->mac.type == ixgbe_mac_X550 ||
18487e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550EM_x) {
18497e579c30SDale Ghent 		(void) ixgbe_driver_setup_link(ixgbe, B_TRUE);
18507e579c30SDale Ghent 		ixgbe_get_hw_state(ixgbe);
18517e579c30SDale Ghent 	}
18527e579c30SDale Ghent 
18539da57d7bSbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
18549da57d7bSbt150084 		goto start_failure;
18559da57d7bSbt150084 	}
18569da57d7bSbt150084 
18579da57d7bSbt150084 	/*
18589da57d7bSbt150084 	 * Setup the rx/tx rings
18599da57d7bSbt150084 	 */
18609da57d7bSbt150084 	ixgbe_setup_rings(ixgbe);
18619da57d7bSbt150084 
18629da57d7bSbt150084 	/*
186362e6e1adSPaul Guo 	 * ixgbe_start() will be called when resetting, however if reset
18645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * happens, we need to clear the ERROR, STALL and OVERTEMP flags
18655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * before enabling the interrupts.
186662e6e1adSPaul Guo 	 */
18675b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR
18685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    | IXGBE_STALL| IXGBE_OVERTEMP));
186962e6e1adSPaul Guo 
187062e6e1adSPaul Guo 	/*
18719da57d7bSbt150084 	 * Enable adapter interrupts
18729da57d7bSbt150084 	 * The interrupts must be enabled after the driver state is START
18739da57d7bSbt150084 	 */
18749da57d7bSbt150084 	ixgbe_enable_adapter_interrupts(ixgbe);
18759da57d7bSbt150084 
18769da57d7bSbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
18779da57d7bSbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
18789da57d7bSbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
18799da57d7bSbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
18809da57d7bSbt150084 
18819da57d7bSbt150084 	return (IXGBE_SUCCESS);
18829da57d7bSbt150084 
18839da57d7bSbt150084 start_failure:
18849da57d7bSbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
18859da57d7bSbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
18869da57d7bSbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
18879da57d7bSbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
18889da57d7bSbt150084 
18899da57d7bSbt150084 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
18909da57d7bSbt150084 
18919da57d7bSbt150084 	return (IXGBE_FAILURE);
18929da57d7bSbt150084 }
18939da57d7bSbt150084 
18949da57d7bSbt150084 /*
18959da57d7bSbt150084  * ixgbe_stop - Stop the driver/chipset.
18969da57d7bSbt150084  */
18979da57d7bSbt150084 void
1898ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer)
18999da57d7bSbt150084 {
19009da57d7bSbt150084 	int i;
19019da57d7bSbt150084 
19029da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
19039da57d7bSbt150084 
19049da57d7bSbt150084 	/*
19059da57d7bSbt150084 	 * Disable the adapter interrupts
19069da57d7bSbt150084 	 */
19079da57d7bSbt150084 	ixgbe_disable_adapter_interrupts(ixgbe);
19089da57d7bSbt150084 
19099da57d7bSbt150084 	/*
19109da57d7bSbt150084 	 * Drain the pending tx packets
19119da57d7bSbt150084 	 */
19129da57d7bSbt150084 	(void) ixgbe_tx_drain(ixgbe);
19139da57d7bSbt150084 
19149da57d7bSbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++)
19159da57d7bSbt150084 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
19169da57d7bSbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++)
19179da57d7bSbt150084 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
19189da57d7bSbt150084 
19199da57d7bSbt150084 	/*
19209da57d7bSbt150084 	 * Stop the chipset hardware
19219da57d7bSbt150084 	 */
19229da57d7bSbt150084 	ixgbe_chip_stop(ixgbe);
19239da57d7bSbt150084 
19249da57d7bSbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
19259da57d7bSbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
19269da57d7bSbt150084 	}
19279da57d7bSbt150084 
19289da57d7bSbt150084 	/*
19299da57d7bSbt150084 	 * Clean the pending tx data/resources
19309da57d7bSbt150084 	 */
19319da57d7bSbt150084 	ixgbe_tx_clean(ixgbe);
19329da57d7bSbt150084 
19339da57d7bSbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
19349da57d7bSbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
19359da57d7bSbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
19369da57d7bSbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
1937ea65739eSchenlu chen - Sun Microsystems - Beijing China 
1938ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->link_state == LINK_STATE_UP) {
1939ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->link_state = LINK_STATE_UNKNOWN;
1940ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
1941ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
1942ea65739eSchenlu chen - Sun Microsystems - Beijing China 
1943ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (free_buffer) {
1944ea65739eSchenlu chen - Sun Microsystems - Beijing China 		/*
1945ea65739eSchenlu chen - Sun Microsystems - Beijing China 		 * Release the DMA/memory resources of rx/tx rings
1946ea65739eSchenlu chen - Sun Microsystems - Beijing China 		 */
1947ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_free_dma(ixgbe);
1948ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_free_rx_data(ixgbe);
1949ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
19509da57d7bSbt150084 }
19519da57d7bSbt150084 
19529da57d7bSbt150084 /*
19530dc2366fSVenugopal Iyer  * ixgbe_cbfunc - Driver interface for generic DDI callbacks
19540dc2366fSVenugopal Iyer  */
19550dc2366fSVenugopal Iyer /* ARGSUSED */
19560dc2366fSVenugopal Iyer static int
19570dc2366fSVenugopal Iyer ixgbe_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
19580dc2366fSVenugopal Iyer     void *arg1, void *arg2)
19590dc2366fSVenugopal Iyer {
19600dc2366fSVenugopal Iyer 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
19610dc2366fSVenugopal Iyer 
19620dc2366fSVenugopal Iyer 	switch (cbaction) {
19630dc2366fSVenugopal Iyer 	/* IRM callback */
19640dc2366fSVenugopal Iyer 	int count;
19650dc2366fSVenugopal Iyer 	case DDI_CB_INTR_ADD:
19660dc2366fSVenugopal Iyer 	case DDI_CB_INTR_REMOVE:
19670dc2366fSVenugopal Iyer 		count = (int)(uintptr_t)cbarg;
19680dc2366fSVenugopal Iyer 		ASSERT(ixgbe->intr_type == DDI_INTR_TYPE_MSIX);
19690dc2366fSVenugopal Iyer 		DTRACE_PROBE2(ixgbe__irm__callback, int, count,
19700dc2366fSVenugopal Iyer 		    int, ixgbe->intr_cnt);
19710dc2366fSVenugopal Iyer 		if (ixgbe_intr_adjust(ixgbe, cbaction, count) !=
19720dc2366fSVenugopal Iyer 		    DDI_SUCCESS) {
19730dc2366fSVenugopal Iyer 			ixgbe_error(ixgbe,
19740dc2366fSVenugopal Iyer 			    "IRM CB: Failed to adjust interrupts");
19750dc2366fSVenugopal Iyer 			goto cb_fail;
19760dc2366fSVenugopal Iyer 		}
19770dc2366fSVenugopal Iyer 		break;
19780dc2366fSVenugopal Iyer 	default:
19790dc2366fSVenugopal Iyer 		IXGBE_DEBUGLOG_1(ixgbe, "DDI CB: action 0x%x NOT supported",
19800dc2366fSVenugopal Iyer 		    cbaction);
19810dc2366fSVenugopal Iyer 		return (DDI_ENOTSUP);
19820dc2366fSVenugopal Iyer 	}
19830dc2366fSVenugopal Iyer 	return (DDI_SUCCESS);
19840dc2366fSVenugopal Iyer cb_fail:
19850dc2366fSVenugopal Iyer 	return (DDI_FAILURE);
19860dc2366fSVenugopal Iyer }
19870dc2366fSVenugopal Iyer 
19880dc2366fSVenugopal Iyer /*
19890dc2366fSVenugopal Iyer  * ixgbe_intr_adjust - Adjust interrupt to respond to IRM request.
19900dc2366fSVenugopal Iyer  */
19910dc2366fSVenugopal Iyer static int
19920dc2366fSVenugopal Iyer ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count)
19930dc2366fSVenugopal Iyer {
19940dc2366fSVenugopal Iyer 	int i, rc, actual;
19950dc2366fSVenugopal Iyer 
19960dc2366fSVenugopal Iyer 	if (count == 0)
19970dc2366fSVenugopal Iyer 		return (DDI_SUCCESS);
19980dc2366fSVenugopal Iyer 
19990dc2366fSVenugopal Iyer 	if ((cbaction == DDI_CB_INTR_ADD &&
20000dc2366fSVenugopal Iyer 	    ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) ||
20010dc2366fSVenugopal Iyer 	    (cbaction == DDI_CB_INTR_REMOVE &&
20020dc2366fSVenugopal Iyer 	    ixgbe->intr_cnt - count < ixgbe->intr_cnt_min))
20030dc2366fSVenugopal Iyer 		return (DDI_FAILURE);
20040dc2366fSVenugopal Iyer 
20050dc2366fSVenugopal Iyer 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
20060dc2366fSVenugopal Iyer 		return (DDI_FAILURE);
20070dc2366fSVenugopal Iyer 	}
20080dc2366fSVenugopal Iyer 
20090dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_rx_rings; i++)
20100dc2366fSVenugopal Iyer 		mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL);
20110dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_tx_rings; i++)
20120dc2366fSVenugopal Iyer 		mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL);
20130dc2366fSVenugopal Iyer 
20140dc2366fSVenugopal Iyer 	mutex_enter(&ixgbe->gen_lock);
20150dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state &= ~IXGBE_STARTED;
20160dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST;
20170dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state |= IXGBE_SUSPENDED;
20180dc2366fSVenugopal Iyer 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
20190dc2366fSVenugopal Iyer 
20200dc2366fSVenugopal Iyer 	ixgbe_stop(ixgbe, B_FALSE);
20210dc2366fSVenugopal Iyer 	/*
20220dc2366fSVenugopal Iyer 	 * Disable interrupts
20230dc2366fSVenugopal Iyer 	 */
20240dc2366fSVenugopal Iyer 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
20250dc2366fSVenugopal Iyer 		rc = ixgbe_disable_intrs(ixgbe);
20260dc2366fSVenugopal Iyer 		ASSERT(rc == IXGBE_SUCCESS);
20270dc2366fSVenugopal Iyer 	}
20280dc2366fSVenugopal Iyer 	ixgbe->attach_progress &= ~ATTACH_PROGRESS_ENABLE_INTR;
20290dc2366fSVenugopal Iyer 
20300dc2366fSVenugopal Iyer 	/*
20310dc2366fSVenugopal Iyer 	 * Remove interrupt handlers
20320dc2366fSVenugopal Iyer 	 */
20330dc2366fSVenugopal Iyer 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
20340dc2366fSVenugopal Iyer 		ixgbe_rem_intr_handlers(ixgbe);
20350dc2366fSVenugopal Iyer 	}
20360dc2366fSVenugopal Iyer 	ixgbe->attach_progress &= ~ATTACH_PROGRESS_ADD_INTR;
20370dc2366fSVenugopal Iyer 
20380dc2366fSVenugopal Iyer 	/*
20390dc2366fSVenugopal Iyer 	 * Clear vect_map
20400dc2366fSVenugopal Iyer 	 */
20410dc2366fSVenugopal Iyer 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
20420dc2366fSVenugopal Iyer 	switch (cbaction) {
20430dc2366fSVenugopal Iyer 	case DDI_CB_INTR_ADD:
20440dc2366fSVenugopal Iyer 		rc = ddi_intr_alloc(ixgbe->dip, ixgbe->htable,
20450dc2366fSVenugopal Iyer 		    DDI_INTR_TYPE_MSIX, ixgbe->intr_cnt, count, &actual,
20460dc2366fSVenugopal Iyer 		    DDI_INTR_ALLOC_NORMAL);
20470dc2366fSVenugopal Iyer 		if (rc != DDI_SUCCESS || actual != count) {
20480dc2366fSVenugopal Iyer 			ixgbe_log(ixgbe, "Adjust interrupts failed."
20490dc2366fSVenugopal Iyer 			    "return: %d, irm cb size: %d, actual: %d",
20500dc2366fSVenugopal Iyer 			    rc, count, actual);
20510dc2366fSVenugopal Iyer 			goto intr_adjust_fail;
20520dc2366fSVenugopal Iyer 		}
20530dc2366fSVenugopal Iyer 		ixgbe->intr_cnt += count;
20540dc2366fSVenugopal Iyer 		break;
20550dc2366fSVenugopal Iyer 
20560dc2366fSVenugopal Iyer 	case DDI_CB_INTR_REMOVE:
20570dc2366fSVenugopal Iyer 		for (i = ixgbe->intr_cnt - count;
20580dc2366fSVenugopal Iyer 		    i < ixgbe->intr_cnt; i ++) {
20590dc2366fSVenugopal Iyer 			rc = ddi_intr_free(ixgbe->htable[i]);
20600dc2366fSVenugopal Iyer 			ixgbe->htable[i] = NULL;
20610dc2366fSVenugopal Iyer 			if (rc != DDI_SUCCESS) {
20620dc2366fSVenugopal Iyer 				ixgbe_log(ixgbe, "Adjust interrupts failed."
20630dc2366fSVenugopal Iyer 				    "return: %d, irm cb size: %d, actual: %d",
20640dc2366fSVenugopal Iyer 				    rc, count, actual);
20650dc2366fSVenugopal Iyer 				goto intr_adjust_fail;
20660dc2366fSVenugopal Iyer 			}
20670dc2366fSVenugopal Iyer 		}
20680dc2366fSVenugopal Iyer 		ixgbe->intr_cnt -= count;
20690dc2366fSVenugopal Iyer 		break;
20700dc2366fSVenugopal Iyer 	}
20710dc2366fSVenugopal Iyer 
20720dc2366fSVenugopal Iyer 	/*
20730dc2366fSVenugopal Iyer 	 * Get priority for first vector, assume remaining are all the same
20740dc2366fSVenugopal Iyer 	 */
20750dc2366fSVenugopal Iyer 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
20760dc2366fSVenugopal Iyer 	if (rc != DDI_SUCCESS) {
20770dc2366fSVenugopal Iyer 		ixgbe_log(ixgbe,
20780dc2366fSVenugopal Iyer 		    "Get interrupt priority failed: %d", rc);
20790dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
20800dc2366fSVenugopal Iyer 	}
20810dc2366fSVenugopal Iyer 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
20820dc2366fSVenugopal Iyer 	if (rc != DDI_SUCCESS) {
20830dc2366fSVenugopal Iyer 		ixgbe_log(ixgbe, "Get interrupt cap failed: %d", rc);
20840dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
20850dc2366fSVenugopal Iyer 	}
20860dc2366fSVenugopal Iyer 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
20870dc2366fSVenugopal Iyer 
20880dc2366fSVenugopal Iyer 	/*
20890dc2366fSVenugopal Iyer 	 * Map rings to interrupt vectors
20900dc2366fSVenugopal Iyer 	 */
20910dc2366fSVenugopal Iyer 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
20920dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe,
20930dc2366fSVenugopal Iyer 		    "IRM CB: Failed to map interrupts to vectors");
20940dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
20950dc2366fSVenugopal Iyer 	}
20960dc2366fSVenugopal Iyer 
20970dc2366fSVenugopal Iyer 	/*
20980dc2366fSVenugopal Iyer 	 * Add interrupt handlers
20990dc2366fSVenugopal Iyer 	 */
21000dc2366fSVenugopal Iyer 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
21010dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe, "IRM CB: Failed to add interrupt handlers");
21020dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
21030dc2366fSVenugopal Iyer 	}
21040dc2366fSVenugopal Iyer 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
21050dc2366fSVenugopal Iyer 
21060dc2366fSVenugopal Iyer 	/*
21070dc2366fSVenugopal Iyer 	 * Now that mutex locks are initialized, and the chip is also
21080dc2366fSVenugopal Iyer 	 * initialized, enable interrupts.
21090dc2366fSVenugopal Iyer 	 */
21100dc2366fSVenugopal Iyer 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
21110dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts");
21120dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
21130dc2366fSVenugopal Iyer 	}
21140dc2366fSVenugopal Iyer 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
21150dc2366fSVenugopal Iyer 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
21160dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe, "IRM CB: Failed to start");
21170dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
21180dc2366fSVenugopal Iyer 	}
21190dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST;
21200dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED;
21210dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state |= IXGBE_STARTED;
21220dc2366fSVenugopal Iyer 	mutex_exit(&ixgbe->gen_lock);
21230dc2366fSVenugopal Iyer 
21240dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
21250dc2366fSVenugopal Iyer 		mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle,
21260dc2366fSVenugopal Iyer 		    ixgbe->htable[ixgbe->rx_rings[i].intr_vector]);
21270dc2366fSVenugopal Iyer 	}
21280dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
21290dc2366fSVenugopal Iyer 		mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle,
21300dc2366fSVenugopal Iyer 		    ixgbe->htable[ixgbe->tx_rings[i].intr_vector]);
21310dc2366fSVenugopal Iyer 	}
21320dc2366fSVenugopal Iyer 
21330dc2366fSVenugopal Iyer 	/* Wakeup all Tx rings */
21340dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
21350dc2366fSVenugopal Iyer 		mac_tx_ring_update(ixgbe->mac_hdl,
21360dc2366fSVenugopal Iyer 		    ixgbe->tx_rings[i].ring_handle);
21370dc2366fSVenugopal Iyer 	}
21380dc2366fSVenugopal Iyer 
21390dc2366fSVenugopal Iyer 	IXGBE_DEBUGLOG_3(ixgbe,
21400dc2366fSVenugopal Iyer 	    "IRM CB: interrupts new value: 0x%x(0x%x:0x%x).",
21410dc2366fSVenugopal Iyer 	    ixgbe->intr_cnt, ixgbe->intr_cnt_min, ixgbe->intr_cnt_max);
21420dc2366fSVenugopal Iyer 	return (DDI_SUCCESS);
21430dc2366fSVenugopal Iyer 
21440dc2366fSVenugopal Iyer intr_adjust_fail:
21450dc2366fSVenugopal Iyer 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
21460dc2366fSVenugopal Iyer 	mutex_exit(&ixgbe->gen_lock);
21470dc2366fSVenugopal Iyer 	return (DDI_FAILURE);
21480dc2366fSVenugopal Iyer }
21490dc2366fSVenugopal Iyer 
21500dc2366fSVenugopal Iyer /*
21510dc2366fSVenugopal Iyer  * ixgbe_intr_cb_register - Register interrupt callback function.
21520dc2366fSVenugopal Iyer  */
21530dc2366fSVenugopal Iyer static int
21540dc2366fSVenugopal Iyer ixgbe_intr_cb_register(ixgbe_t *ixgbe)
21550dc2366fSVenugopal Iyer {
21560dc2366fSVenugopal Iyer 	if (ddi_cb_register(ixgbe->dip, DDI_CB_FLAG_INTR, ixgbe_cbfunc,
21570dc2366fSVenugopal Iyer 	    ixgbe, NULL, &ixgbe->cb_hdl) != DDI_SUCCESS) {
21580dc2366fSVenugopal Iyer 		return (IXGBE_FAILURE);
21590dc2366fSVenugopal Iyer 	}
21600dc2366fSVenugopal Iyer 	IXGBE_DEBUGLOG_0(ixgbe, "Interrupt callback function registered.");
21610dc2366fSVenugopal Iyer 	return (IXGBE_SUCCESS);
21620dc2366fSVenugopal Iyer }
21630dc2366fSVenugopal Iyer 
21640dc2366fSVenugopal Iyer /*
21659da57d7bSbt150084  * ixgbe_alloc_rings - Allocate memory space for rx/tx rings.
21669da57d7bSbt150084  */
21679da57d7bSbt150084 static int
21689da57d7bSbt150084 ixgbe_alloc_rings(ixgbe_t *ixgbe)
21699da57d7bSbt150084 {
21709da57d7bSbt150084 	/*
21719da57d7bSbt150084 	 * Allocate memory space for rx rings
21729da57d7bSbt150084 	 */
21739da57d7bSbt150084 	ixgbe->rx_rings = kmem_zalloc(
21749da57d7bSbt150084 	    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings,
21759da57d7bSbt150084 	    KM_NOSLEEP);
21769da57d7bSbt150084 
21779da57d7bSbt150084 	if (ixgbe->rx_rings == NULL) {
21789da57d7bSbt150084 		return (IXGBE_FAILURE);
21799da57d7bSbt150084 	}
21809da57d7bSbt150084 
21819da57d7bSbt150084 	/*
21829da57d7bSbt150084 	 * Allocate memory space for tx rings
21839da57d7bSbt150084 	 */
21849da57d7bSbt150084 	ixgbe->tx_rings = kmem_zalloc(
21859da57d7bSbt150084 	    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings,
21869da57d7bSbt150084 	    KM_NOSLEEP);
21879da57d7bSbt150084 
21889da57d7bSbt150084 	if (ixgbe->tx_rings == NULL) {
21899da57d7bSbt150084 		kmem_free(ixgbe->rx_rings,
21909da57d7bSbt150084 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
21919da57d7bSbt150084 		ixgbe->rx_rings = NULL;
21929da57d7bSbt150084 		return (IXGBE_FAILURE);
21939da57d7bSbt150084 	}
21949da57d7bSbt150084 
2195da14cebeSEric Cheng 	/*
2196da14cebeSEric Cheng 	 * Allocate memory space for rx ring groups
2197da14cebeSEric Cheng 	 */
2198da14cebeSEric Cheng 	ixgbe->rx_groups = kmem_zalloc(
2199da14cebeSEric Cheng 	    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups,
2200da14cebeSEric Cheng 	    KM_NOSLEEP);
2201da14cebeSEric Cheng 
2202da14cebeSEric Cheng 	if (ixgbe->rx_groups == NULL) {
2203da14cebeSEric Cheng 		kmem_free(ixgbe->rx_rings,
2204da14cebeSEric Cheng 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
2205da14cebeSEric Cheng 		kmem_free(ixgbe->tx_rings,
2206da14cebeSEric Cheng 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
2207da14cebeSEric Cheng 		ixgbe->rx_rings = NULL;
2208da14cebeSEric Cheng 		ixgbe->tx_rings = NULL;
2209da14cebeSEric Cheng 		return (IXGBE_FAILURE);
2210da14cebeSEric Cheng 	}
2211da14cebeSEric Cheng 
22129da57d7bSbt150084 	return (IXGBE_SUCCESS);
22139da57d7bSbt150084 }
22149da57d7bSbt150084 
22159da57d7bSbt150084 /*
22169da57d7bSbt150084  * ixgbe_free_rings - Free the memory space of rx/tx rings.
22179da57d7bSbt150084  */
22189da57d7bSbt150084 static void
22199da57d7bSbt150084 ixgbe_free_rings(ixgbe_t *ixgbe)
22209da57d7bSbt150084 {
22219da57d7bSbt150084 	if (ixgbe->rx_rings != NULL) {
22229da57d7bSbt150084 		kmem_free(ixgbe->rx_rings,
22239da57d7bSbt150084 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
22249da57d7bSbt150084 		ixgbe->rx_rings = NULL;
22259da57d7bSbt150084 	}
22269da57d7bSbt150084 
22279da57d7bSbt150084 	if (ixgbe->tx_rings != NULL) {
22289da57d7bSbt150084 		kmem_free(ixgbe->tx_rings,
22299da57d7bSbt150084 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
22309da57d7bSbt150084 		ixgbe->tx_rings = NULL;
22319da57d7bSbt150084 	}
2232da14cebeSEric Cheng 
2233da14cebeSEric Cheng 	if (ixgbe->rx_groups != NULL) {
2234da14cebeSEric Cheng 		kmem_free(ixgbe->rx_groups,
2235da14cebeSEric Cheng 		    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups);
2236da14cebeSEric Cheng 		ixgbe->rx_groups = NULL;
2237da14cebeSEric Cheng 	}
22389da57d7bSbt150084 }
22399da57d7bSbt150084 
2240ea65739eSchenlu chen - Sun Microsystems - Beijing China static int
2241ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_alloc_rx_data(ixgbe_t *ixgbe)
2242ea65739eSchenlu chen - Sun Microsystems - Beijing China {
2243ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_rx_ring_t *rx_ring;
2244ea65739eSchenlu chen - Sun Microsystems - Beijing China 	int i;
2245ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2246ea65739eSchenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
2247ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rx_ring = &ixgbe->rx_rings[i];
2248ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS)
2249ea65739eSchenlu chen - Sun Microsystems - Beijing China 			goto alloc_rx_rings_failure;
2250ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
2251ea65739eSchenlu chen - Sun Microsystems - Beijing China 	return (IXGBE_SUCCESS);
2252ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2253ea65739eSchenlu chen - Sun Microsystems - Beijing China alloc_rx_rings_failure:
2254ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_free_rx_data(ixgbe);
2255ea65739eSchenlu chen - Sun Microsystems - Beijing China 	return (IXGBE_FAILURE);
2256ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2257ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2258ea65739eSchenlu chen - Sun Microsystems - Beijing China static void
2259ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_data(ixgbe_t *ixgbe)
2260ea65739eSchenlu chen - Sun Microsystems - Beijing China {
2261ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_rx_ring_t *rx_ring;
2262ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_rx_data_t *rx_data;
2263ea65739eSchenlu chen - Sun Microsystems - Beijing China 	int i;
2264ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2265ea65739eSchenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
2266ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rx_ring = &ixgbe->rx_rings[i];
2267ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2268ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mutex_enter(&ixgbe->rx_pending_lock);
2269ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rx_data = rx_ring->rx_data;
2270ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2271ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (rx_data != NULL) {
2272ea65739eSchenlu chen - Sun Microsystems - Beijing China 			rx_data->flag |= IXGBE_RX_STOPPED;
2273ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2274ea65739eSchenlu chen - Sun Microsystems - Beijing China 			if (rx_data->rcb_pending == 0) {
2275ea65739eSchenlu chen - Sun Microsystems - Beijing China 				ixgbe_free_rx_ring_data(rx_data);
2276ea65739eSchenlu chen - Sun Microsystems - Beijing China 				rx_ring->rx_data = NULL;
2277ea65739eSchenlu chen - Sun Microsystems - Beijing China 			}
2278ea65739eSchenlu chen - Sun Microsystems - Beijing China 		}
2279ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2280ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&ixgbe->rx_pending_lock);
2281ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
2282ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2283ea65739eSchenlu chen - Sun Microsystems - Beijing China 
22849da57d7bSbt150084 /*
22859da57d7bSbt150084  * ixgbe_setup_rings - Setup rx/tx rings.
22869da57d7bSbt150084  */
22879da57d7bSbt150084 static void
22889da57d7bSbt150084 ixgbe_setup_rings(ixgbe_t *ixgbe)
22899da57d7bSbt150084 {
22909da57d7bSbt150084 	/*
22919da57d7bSbt150084 	 * Setup the rx/tx rings, including the following:
22929da57d7bSbt150084 	 *
22939da57d7bSbt150084 	 * 1. Setup the descriptor ring and the control block buffers;
22949da57d7bSbt150084 	 * 2. Initialize necessary registers for receive/transmit;
22959da57d7bSbt150084 	 * 3. Initialize software pointers/parameters for receive/transmit;
22969da57d7bSbt150084 	 */
22979da57d7bSbt150084 	ixgbe_setup_rx(ixgbe);
22989da57d7bSbt150084 
22999da57d7bSbt150084 	ixgbe_setup_tx(ixgbe);
23009da57d7bSbt150084 }
23019da57d7bSbt150084 
23029da57d7bSbt150084 static void
23039da57d7bSbt150084 ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring)
23049da57d7bSbt150084 {
23059da57d7bSbt150084 	ixgbe_t *ixgbe = rx_ring->ixgbe;
2306ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_rx_data_t *rx_data = rx_ring->rx_data;
23079da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
23089da57d7bSbt150084 	rx_control_block_t *rcb;
23099da57d7bSbt150084 	union ixgbe_adv_rx_desc	*rbd;
23109da57d7bSbt150084 	uint32_t size;
23119da57d7bSbt150084 	uint32_t buf_low;
23129da57d7bSbt150084 	uint32_t buf_high;
23139da57d7bSbt150084 	uint32_t reg_val;
23149da57d7bSbt150084 	int i;
23159da57d7bSbt150084 
23169da57d7bSbt150084 	ASSERT(mutex_owned(&rx_ring->rx_lock));
23179da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
23189da57d7bSbt150084 
23199da57d7bSbt150084 	for (i = 0; i < ixgbe->rx_ring_size; i++) {
2320ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rcb = rx_data->work_list[i];
2321ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rbd = &rx_data->rbd_ring[i];
23229da57d7bSbt150084 
23239da57d7bSbt150084 		rbd->read.pkt_addr = rcb->rx_buf.dma_address;
23249da57d7bSbt150084 		rbd->read.hdr_addr = NULL;
23259da57d7bSbt150084 	}
23269da57d7bSbt150084 
23279da57d7bSbt150084 	/*
23289da57d7bSbt150084 	 * Initialize the length register
23299da57d7bSbt150084 	 */
2330ea65739eSchenlu chen - Sun Microsystems - Beijing China 	size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc);
23310dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->hw_index), size);
23329da57d7bSbt150084 
23339da57d7bSbt150084 	/*
23349da57d7bSbt150084 	 * Initialize the base address registers
23359da57d7bSbt150084 	 */
2336ea65739eSchenlu chen - Sun Microsystems - Beijing China 	buf_low = (uint32_t)rx_data->rbd_area.dma_address;
2337ea65739eSchenlu chen - Sun Microsystems - Beijing China 	buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32);
23380dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->hw_index), buf_high);
23390dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->hw_index), buf_low);
23409da57d7bSbt150084 
23419da57d7bSbt150084 	/*
23429da57d7bSbt150084 	 * Setup head & tail pointers
23439da57d7bSbt150084 	 */
23440dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->hw_index),
23450dc2366fSVenugopal Iyer 	    rx_data->ring_size - 1);
23460dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->hw_index), 0);
23479da57d7bSbt150084 
2348ea65739eSchenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_next = 0;
2349ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	rx_data->lro_first = 0;
23509da57d7bSbt150084 
23519da57d7bSbt150084 	/*
23529da57d7bSbt150084 	 * Setup the Receive Descriptor Control Register (RXDCTL)
23539da57d7bSbt150084 	 * PTHRESH=32 descriptors (half the internal cache)
23549da57d7bSbt150084 	 * HTHRESH=0 descriptors (to minimize latency on fetch)
23559da57d7bSbt150084 	 * WTHRESH defaults to 1 (writeback each descriptor)
23569da57d7bSbt150084 	 */
23570dc2366fSVenugopal Iyer 	reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index));
23589da57d7bSbt150084 	reg_val |= IXGBE_RXDCTL_ENABLE;	/* enable queue */
235973cd555cSBin Tu - Sun Microsystems - Beijing China 
23607e579c30SDale Ghent 	/* Not a valid value for 82599, X540 or X550 */
236169b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82598EB) {
23629da57d7bSbt150084 		reg_val |= 0x0020;	/* pthresh */
236373cd555cSBin Tu - Sun Microsystems - Beijing China 	}
23640dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val);
23659da57d7bSbt150084 
236669b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82599EB ||
23677e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
23687e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
23697e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550EM_x) {
237073cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
237173cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS);
237273cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
237373cd555cSBin Tu - Sun Microsystems - Beijing China 	}
237473cd555cSBin Tu - Sun Microsystems - Beijing China 
23759da57d7bSbt150084 	/*
23769da57d7bSbt150084 	 * Setup the Split and Replication Receive Control Register.
23779da57d7bSbt150084 	 * Set the rx buffer size and the advanced descriptor type.
23789da57d7bSbt150084 	 */
23799da57d7bSbt150084 	reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) |
23809da57d7bSbt150084 	    IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
238173cd555cSBin Tu - Sun Microsystems - Beijing China 	reg_val |= IXGBE_SRRCTL_DROP_EN;
23820dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->hw_index), reg_val);
23839da57d7bSbt150084 }
23849da57d7bSbt150084 
23859da57d7bSbt150084 static void
23869da57d7bSbt150084 ixgbe_setup_rx(ixgbe_t *ixgbe)
23879da57d7bSbt150084 {
23889da57d7bSbt150084 	ixgbe_rx_ring_t *rx_ring;
23899da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
23909da57d7bSbt150084 	uint32_t reg_val;
2391da14cebeSEric Cheng 	uint32_t ring_mapping;
23920dc2366fSVenugopal Iyer 	uint32_t i, index;
23930dc2366fSVenugopal Iyer 	uint32_t psrtype_rss_bit;
23949da57d7bSbt150084 
23957e579c30SDale Ghent 	/*
23967e579c30SDale Ghent 	 * Ensure that Rx is disabled while setting up
23977e579c30SDale Ghent 	 * the Rx unit and Rx descriptor ring(s)
23987e579c30SDale Ghent 	 */
23997e579c30SDale Ghent 	ixgbe_disable_rx(hw);
24007e579c30SDale Ghent 
240173cd555cSBin Tu - Sun Microsystems - Beijing China 	/* PSRTYPE must be configured for 82599 */
24020dc2366fSVenugopal Iyer 	if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ &&
24030dc2366fSVenugopal Iyer 	    ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) {
240473cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
240573cd555cSBin Tu - Sun Microsystems - Beijing China 		    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
24060dc2366fSVenugopal Iyer 		reg_val |= IXGBE_PSRTYPE_L2HDR;
24070dc2366fSVenugopal Iyer 		reg_val |= 0x80000000;
240873cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val);
24090dc2366fSVenugopal Iyer 	} else {
24100dc2366fSVenugopal Iyer 		if (ixgbe->num_rx_groups > 32) {
24110dc2366fSVenugopal Iyer 			psrtype_rss_bit = 0x20000000;
24120dc2366fSVenugopal Iyer 		} else {
24130dc2366fSVenugopal Iyer 			psrtype_rss_bit = 0x40000000;
24140dc2366fSVenugopal Iyer 		}
24150dc2366fSVenugopal Iyer 		for (i = 0; i < ixgbe->capab->max_rx_grp_num; i++) {
24160dc2366fSVenugopal Iyer 			reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
24170dc2366fSVenugopal Iyer 			    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
24180dc2366fSVenugopal Iyer 			reg_val |= IXGBE_PSRTYPE_L2HDR;
24190dc2366fSVenugopal Iyer 			reg_val |= psrtype_rss_bit;
24200dc2366fSVenugopal Iyer 			IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val);
24210dc2366fSVenugopal Iyer 		}
24220dc2366fSVenugopal Iyer 	}
242373cd555cSBin Tu - Sun Microsystems - Beijing China 
24249da57d7bSbt150084 	/*
24257e579c30SDale Ghent 	 * Set filter control in FCTRL to determine types of packets are passed
24267e579c30SDale Ghent 	 * up to the driver.
24277e579c30SDale Ghent 	 * - Pass broadcast packets.
24287e579c30SDale Ghent 	 * - Do not pass flow control pause frames (82598-specific)
24299da57d7bSbt150084 	 */
24309da57d7bSbt150084 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
24317e579c30SDale Ghent 	reg_val |= IXGBE_FCTRL_BAM; /* Broadcast Accept Mode */
24327e579c30SDale Ghent 	if (hw->mac.type == ixgbe_mac_82598EB) {
24337e579c30SDale Ghent 		reg_val |= IXGBE_FCTRL_DPF; /* Discard Pause Frames */
24347e579c30SDale Ghent 	}
24359da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val);
24369da57d7bSbt150084 
24379da57d7bSbt150084 	/*
24380dc2366fSVenugopal Iyer 	 * Hardware checksum settings
24390dc2366fSVenugopal Iyer 	 */
24400dc2366fSVenugopal Iyer 	if (ixgbe->rx_hcksum_enable) {
24417e579c30SDale Ghent 		reg_val = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
24427e579c30SDale Ghent 		reg_val |= IXGBE_RXCSUM_IPPCSE;	/* IP checksum */
24430dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val);
24440dc2366fSVenugopal Iyer 	}
24450dc2366fSVenugopal Iyer 
24460dc2366fSVenugopal Iyer 	/*
24470dc2366fSVenugopal Iyer 	 * Setup VMDq and RSS for multiple receive queues
24480dc2366fSVenugopal Iyer 	 */
24490dc2366fSVenugopal Iyer 	switch (ixgbe->classify_mode) {
24500dc2366fSVenugopal Iyer 	case IXGBE_CLASSIFY_RSS:
24510dc2366fSVenugopal Iyer 		/*
24520dc2366fSVenugopal Iyer 		 * One group, only RSS is needed when more than
24530dc2366fSVenugopal Iyer 		 * one ring enabled.
24540dc2366fSVenugopal Iyer 		 */
24550dc2366fSVenugopal Iyer 		ixgbe_setup_rss(ixgbe);
24560dc2366fSVenugopal Iyer 		break;
24570dc2366fSVenugopal Iyer 
24580dc2366fSVenugopal Iyer 	case IXGBE_CLASSIFY_VMDQ:
24590dc2366fSVenugopal Iyer 		/*
24600dc2366fSVenugopal Iyer 		 * Multiple groups, each group has one ring,
24610dc2366fSVenugopal Iyer 		 * only VMDq is needed.
24620dc2366fSVenugopal Iyer 		 */
24630dc2366fSVenugopal Iyer 		ixgbe_setup_vmdq(ixgbe);
24640dc2366fSVenugopal Iyer 		break;
24650dc2366fSVenugopal Iyer 
24660dc2366fSVenugopal Iyer 	case IXGBE_CLASSIFY_VMDQ_RSS:
24670dc2366fSVenugopal Iyer 		/*
24680dc2366fSVenugopal Iyer 		 * Multiple groups and multiple rings, both
24690dc2366fSVenugopal Iyer 		 * VMDq and RSS are needed.
24700dc2366fSVenugopal Iyer 		 */
24710dc2366fSVenugopal Iyer 		ixgbe_setup_vmdq_rss(ixgbe);
24720dc2366fSVenugopal Iyer 		break;
24730dc2366fSVenugopal Iyer 
24740dc2366fSVenugopal Iyer 	default:
24750dc2366fSVenugopal Iyer 		break;
24760dc2366fSVenugopal Iyer 	}
24770dc2366fSVenugopal Iyer 
24780dc2366fSVenugopal Iyer 	/*
24799da57d7bSbt150084 	 * Enable the receive unit.  This must be done after filter
24807e579c30SDale Ghent 	 * control is set in FCTRL. On 82598, we disable the descriptor monitor.
24817e579c30SDale Ghent 	 * 82598 is the only adapter which defines this RXCTRL option.
24829da57d7bSbt150084 	 */
24837e579c30SDale Ghent 	reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
24847e579c30SDale Ghent 	if (hw->mac.type == ixgbe_mac_82598EB)
24857e579c30SDale Ghent 		reg_val |= IXGBE_RXCTRL_DMBYPS; /* descriptor monitor bypass */
24867e579c30SDale Ghent 	reg_val |= IXGBE_RXCTRL_RXEN;
24877e579c30SDale Ghent 	(void) ixgbe_enable_rx_dma(hw, reg_val);
24889da57d7bSbt150084 
24899da57d7bSbt150084 	/*
24909da57d7bSbt150084 	 * ixgbe_setup_rx_ring must be called after configuring RXCTRL
24919da57d7bSbt150084 	 */
24929da57d7bSbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
24939da57d7bSbt150084 		rx_ring = &ixgbe->rx_rings[i];
24949da57d7bSbt150084 		ixgbe_setup_rx_ring(rx_ring);
24959da57d7bSbt150084 	}
24969da57d7bSbt150084 
24979da57d7bSbt150084 	/*
2498da14cebeSEric Cheng 	 * Setup the per-ring statistics mapping.
2499da14cebeSEric Cheng 	 */
2500da14cebeSEric Cheng 	ring_mapping = 0;
2501da14cebeSEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
25020dc2366fSVenugopal Iyer 		index = ixgbe->rx_rings[i].hw_index;
25030dc2366fSVenugopal Iyer 		ring_mapping = IXGBE_READ_REG(hw, IXGBE_RQSMR(index >> 2));
25040dc2366fSVenugopal Iyer 		ring_mapping |= (i & 0xF) << (8 * (index & 0x3));
25050dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(index >> 2), ring_mapping);
2506da14cebeSEric Cheng 	}
2507da14cebeSEric Cheng 
2508da14cebeSEric Cheng 	/*
250973cd555cSBin Tu - Sun Microsystems - Beijing China 	 * The Max Frame Size in MHADD/MAXFRS will be internally increased
251073cd555cSBin Tu - Sun Microsystems - Beijing China 	 * by four bytes if the packet has a VLAN field, so includes MTU,
251173cd555cSBin Tu - Sun Microsystems - Beijing China 	 * ethernet header and frame check sequence.
251273cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Register is MAXFRS in 82599.
25139da57d7bSbt150084 	 */
25147e579c30SDale Ghent 	reg_val = IXGBE_READ_REG(hw, IXGBE_MHADD);
25157e579c30SDale Ghent 	reg_val &= ~IXGBE_MHADD_MFS_MASK;
25167e579c30SDale Ghent 	reg_val |= (ixgbe->default_mtu + sizeof (struct ether_header)
25179da57d7bSbt150084 	    + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT;
25189da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val);
25199da57d7bSbt150084 
25209da57d7bSbt150084 	/*
25219da57d7bSbt150084 	 * Setup Jumbo Frame enable bit
25229da57d7bSbt150084 	 */
25239da57d7bSbt150084 	reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
25247e579c30SDale Ghent 	if (ixgbe->default_mtu > ETHERMTU)
25259da57d7bSbt150084 		reg_val |= IXGBE_HLREG0_JUMBOEN;
25267e579c30SDale Ghent 	else
25277e579c30SDale Ghent 		reg_val &= ~IXGBE_HLREG0_JUMBOEN;
25289da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
25291878b971SVenugopal Iyer 
25301878b971SVenugopal Iyer 	/*
25311878b971SVenugopal Iyer 	 * Setup RSC for multiple receive queues.
25321878b971SVenugopal Iyer 	 */
25331878b971SVenugopal Iyer 	if (ixgbe->lro_enable) {
25341878b971SVenugopal Iyer 		for (i = 0; i < ixgbe->num_rx_rings; i++) {
25351878b971SVenugopal Iyer 			/*
25361878b971SVenugopal Iyer 			 * Make sure rx_buf_size * MAXDESC not greater
25371878b971SVenugopal Iyer 			 * than 65535.
25381878b971SVenugopal Iyer 			 * Intel recommends 4 for MAXDESC field value.
25391878b971SVenugopal Iyer 			 */
25401878b971SVenugopal Iyer 			reg_val = IXGBE_READ_REG(hw, IXGBE_RSCCTL(i));
25411878b971SVenugopal Iyer 			reg_val |= IXGBE_RSCCTL_RSCEN;
25421878b971SVenugopal Iyer 			if (ixgbe->rx_buf_size == IXGBE_PKG_BUF_16k)
25431878b971SVenugopal Iyer 				reg_val |= IXGBE_RSCCTL_MAXDESC_1;
25441878b971SVenugopal Iyer 			else
25451878b971SVenugopal Iyer 				reg_val |= IXGBE_RSCCTL_MAXDESC_4;
25461878b971SVenugopal Iyer 			IXGBE_WRITE_REG(hw,  IXGBE_RSCCTL(i), reg_val);
25471878b971SVenugopal Iyer 		}
25481878b971SVenugopal Iyer 
25491878b971SVenugopal Iyer 		reg_val = IXGBE_READ_REG(hw, IXGBE_RSCDBU);
25501878b971SVenugopal Iyer 		reg_val |= IXGBE_RSCDBU_RSCACKDIS;
25511878b971SVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, reg_val);
25521878b971SVenugopal Iyer 
25531878b971SVenugopal Iyer 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
25541878b971SVenugopal Iyer 		reg_val |= IXGBE_RDRXCTL_RSCACKC;
255519843f01SPaul Guo 		reg_val |= IXGBE_RDRXCTL_FCOE_WRFIX;
25561878b971SVenugopal Iyer 		reg_val &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
25571878b971SVenugopal Iyer 
25581878b971SVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
25591878b971SVenugopal Iyer 	}
25609da57d7bSbt150084 }
25619da57d7bSbt150084 
25629da57d7bSbt150084 static void
25639da57d7bSbt150084 ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring)
25649da57d7bSbt150084 {
25659da57d7bSbt150084 	ixgbe_t *ixgbe = tx_ring->ixgbe;
25669da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
25679da57d7bSbt150084 	uint32_t size;
25689da57d7bSbt150084 	uint32_t buf_low;
25699da57d7bSbt150084 	uint32_t buf_high;
25709da57d7bSbt150084 	uint32_t reg_val;
25719da57d7bSbt150084 
25729da57d7bSbt150084 	ASSERT(mutex_owned(&tx_ring->tx_lock));
25739da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
25749da57d7bSbt150084 
25759da57d7bSbt150084 	/*
25769da57d7bSbt150084 	 * Initialize the length register
25779da57d7bSbt150084 	 */
25789da57d7bSbt150084 	size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc);
25799da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size);
25809da57d7bSbt150084 
25819da57d7bSbt150084 	/*
25829da57d7bSbt150084 	 * Initialize the base address registers
25839da57d7bSbt150084 	 */
25849da57d7bSbt150084 	buf_low = (uint32_t)tx_ring->tbd_area.dma_address;
25859da57d7bSbt150084 	buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32);
25869da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low);
25879da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high);
25889da57d7bSbt150084 
25899da57d7bSbt150084 	/*
25909da57d7bSbt150084 	 * Setup head & tail pointers
25919da57d7bSbt150084 	 */
25929da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0);
25939da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0);
25949da57d7bSbt150084 
25959da57d7bSbt150084 	/*
25969da57d7bSbt150084 	 * Setup head write-back
25979da57d7bSbt150084 	 */
25989da57d7bSbt150084 	if (ixgbe->tx_head_wb_enable) {
25999da57d7bSbt150084 		/*
26009da57d7bSbt150084 		 * The memory of the head write-back is allocated using
26019da57d7bSbt150084 		 * the extra tbd beyond the tail of the tbd ring.
26029da57d7bSbt150084 		 */
26039da57d7bSbt150084 		tx_ring->tbd_head_wb = (uint32_t *)
26049da57d7bSbt150084 		    ((uintptr_t)tx_ring->tbd_area.address + size);
26059da57d7bSbt150084 		*tx_ring->tbd_head_wb = 0;
26069da57d7bSbt150084 
26079da57d7bSbt150084 		buf_low = (uint32_t)
26089da57d7bSbt150084 		    (tx_ring->tbd_area.dma_address + size);
26099da57d7bSbt150084 		buf_high = (uint32_t)
26109da57d7bSbt150084 		    ((tx_ring->tbd_area.dma_address + size) >> 32);
26119da57d7bSbt150084 
26129da57d7bSbt150084 		/* Set the head write-back enable bit */
26139da57d7bSbt150084 		buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE;
26149da57d7bSbt150084 
26159da57d7bSbt150084 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low);
26169da57d7bSbt150084 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high);
26179da57d7bSbt150084 
26189da57d7bSbt150084 		/*
26199da57d7bSbt150084 		 * Turn off relaxed ordering for head write back or it will
26209da57d7bSbt150084 		 * cause problems with the tx recycling
26219da57d7bSbt150084 		 */
262269b5a878SDan McDonald 
262369b5a878SDan McDonald 		reg_val = (hw->mac.type == ixgbe_mac_82598EB) ?
262469b5a878SDan McDonald 		    IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(tx_ring->index)) :
262569b5a878SDan McDonald 		    IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(tx_ring->index));
262669b5a878SDan McDonald 		reg_val &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
262769b5a878SDan McDonald 		if (hw->mac.type == ixgbe_mac_82598EB) {
26289da57d7bSbt150084 			IXGBE_WRITE_REG(hw,
26299da57d7bSbt150084 			    IXGBE_DCA_TXCTRL(tx_ring->index), reg_val);
26309da57d7bSbt150084 		} else {
263169b5a878SDan McDonald 			IXGBE_WRITE_REG(hw,
263269b5a878SDan McDonald 			    IXGBE_DCA_TXCTRL_82599(tx_ring->index), reg_val);
263369b5a878SDan McDonald 		}
263469b5a878SDan McDonald 	} else {
26359da57d7bSbt150084 		tx_ring->tbd_head_wb = NULL;
26369da57d7bSbt150084 	}
26379da57d7bSbt150084 
26389da57d7bSbt150084 	tx_ring->tbd_head = 0;
26399da57d7bSbt150084 	tx_ring->tbd_tail = 0;
26409da57d7bSbt150084 	tx_ring->tbd_free = tx_ring->ring_size;
26419da57d7bSbt150084 
2642ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->tx_ring_init == B_TRUE) {
26439da57d7bSbt150084 		tx_ring->tcb_head = 0;
26449da57d7bSbt150084 		tx_ring->tcb_tail = 0;
26459da57d7bSbt150084 		tx_ring->tcb_free = tx_ring->free_list_size;
26469da57d7bSbt150084 	}
26479da57d7bSbt150084 
26489da57d7bSbt150084 	/*
2649f27d3025Sgg161487 	 * Initialize the s/w context structure
26509da57d7bSbt150084 	 */
2651f27d3025Sgg161487 	bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t));
26529da57d7bSbt150084 }
26539da57d7bSbt150084 
26549da57d7bSbt150084 static void
26559da57d7bSbt150084 ixgbe_setup_tx(ixgbe_t *ixgbe)
26569da57d7bSbt150084 {
2657c971fb7eSgg161487 	struct ixgbe_hw *hw = &ixgbe->hw;
26589da57d7bSbt150084 	ixgbe_tx_ring_t *tx_ring;
2659c971fb7eSgg161487 	uint32_t reg_val;
2660da14cebeSEric Cheng 	uint32_t ring_mapping;
26619da57d7bSbt150084 	int i;
26629da57d7bSbt150084 
26639da57d7bSbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
26649da57d7bSbt150084 		tx_ring = &ixgbe->tx_rings[i];
26659da57d7bSbt150084 		ixgbe_setup_tx_ring(tx_ring);
26669da57d7bSbt150084 	}
2667c971fb7eSgg161487 
2668c971fb7eSgg161487 	/*
2669da14cebeSEric Cheng 	 * Setup the per-ring statistics mapping.
2670da14cebeSEric Cheng 	 */
2671da14cebeSEric Cheng 	ring_mapping = 0;
2672da14cebeSEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
2673da14cebeSEric Cheng 		ring_mapping |= (i & 0xF) << (8 * (i & 0x3));
2674da14cebeSEric Cheng 		if ((i & 0x3) == 0x3) {
26755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			switch (hw->mac.type) {
26765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82598EB:
267773cd555cSBin Tu - Sun Microsystems - Beijing China 				IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2),
267873cd555cSBin Tu - Sun Microsystems - Beijing China 				    ring_mapping);
26795b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
26805b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
26815b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82599EB:
268269b5a878SDan McDonald 			case ixgbe_mac_X540:
26837e579c30SDale Ghent 			case ixgbe_mac_X550:
26847e579c30SDale Ghent 			case ixgbe_mac_X550EM_x:
26855b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2),
26865b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				    ring_mapping);
26875b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
26885b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
26895b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			default:
26905b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
269173cd555cSBin Tu - Sun Microsystems - Beijing China 			}
26925b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
2693da14cebeSEric Cheng 			ring_mapping = 0;
2694da14cebeSEric Cheng 		}
2695da14cebeSEric Cheng 	}
26965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (i & 0x3) {
26975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		switch (hw->mac.type) {
26985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82598EB:
2699da14cebeSEric Cheng 			IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping);
27005b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
27015b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
27025b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82599EB:
270369b5a878SDan McDonald 		case ixgbe_mac_X540:
27047e579c30SDale Ghent 		case ixgbe_mac_X550:
27057e579c30SDale Ghent 		case ixgbe_mac_X550EM_x:
27065b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping);
27075b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
27085b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
27095b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		default:
27105b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
27115b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
271273cd555cSBin Tu - Sun Microsystems - Beijing China 	}
2713da14cebeSEric Cheng 
2714da14cebeSEric Cheng 	/*
2715c971fb7eSgg161487 	 * Enable CRC appending and TX padding (for short tx frames)
2716c971fb7eSgg161487 	 */
2717c971fb7eSgg161487 	reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2718c971fb7eSgg161487 	reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN;
2719c971fb7eSgg161487 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
272073cd555cSBin Tu - Sun Microsystems - Beijing China 
272173cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
27227e579c30SDale Ghent 	 * enable DMA for 82599, X540 and X550 parts
272373cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
272469b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82599EB ||
27257e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
27267e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
27277e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550EM_x) {
272873cd555cSBin Tu - Sun Microsystems - Beijing China 		/* DMATXCTL.TE must be set after all Tx config is complete */
272973cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
273073cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val |= IXGBE_DMATXCTL_TE;
273173cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val);
273269b5a878SDan McDonald 
273369b5a878SDan McDonald 		/* Disable arbiter to set MTQC */
273469b5a878SDan McDonald 		reg_val = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
273569b5a878SDan McDonald 		reg_val |= IXGBE_RTTDCS_ARBDIS;
273669b5a878SDan McDonald 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg_val);
273769b5a878SDan McDonald 		IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
273869b5a878SDan McDonald 		reg_val &= ~IXGBE_RTTDCS_ARBDIS;
273969b5a878SDan McDonald 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg_val);
274073cd555cSBin Tu - Sun Microsystems - Beijing China 	}
274173cd555cSBin Tu - Sun Microsystems - Beijing China 
274273cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
274373cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Enabling tx queues ..
274473cd555cSBin Tu - Sun Microsystems - Beijing China 	 * For 82599 must be done after DMATXCTL.TE is set
274573cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
274673cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
274773cd555cSBin Tu - Sun Microsystems - Beijing China 		tx_ring = &ixgbe->tx_rings[i];
274873cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index));
274973cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val |= IXGBE_TXDCTL_ENABLE;
275073cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val);
275173cd555cSBin Tu - Sun Microsystems - Beijing China 	}
27529da57d7bSbt150084 }
27539da57d7bSbt150084 
27549da57d7bSbt150084 /*
27559da57d7bSbt150084  * ixgbe_setup_rss - Setup receive-side scaling feature.
27569da57d7bSbt150084  */
27579da57d7bSbt150084 static void
27589da57d7bSbt150084 ixgbe_setup_rss(ixgbe_t *ixgbe)
27599da57d7bSbt150084 {
27609da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
27617e579c30SDale Ghent 	uint32_t mrqc;
27629da57d7bSbt150084 
27639da57d7bSbt150084 	/*
27647e579c30SDale Ghent 	 * Initialize RETA/ERETA table
27659da57d7bSbt150084 	 */
27667e579c30SDale Ghent 	ixgbe_setup_rss_table(ixgbe);
27679da57d7bSbt150084 
27689da57d7bSbt150084 	/*
2769c971fb7eSgg161487 	 * Enable RSS & perform hash on these packet types
27709da57d7bSbt150084 	 */
27719da57d7bSbt150084 	mrqc = IXGBE_MRQC_RSSEN |
27729da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4 |
27739da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
27749da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
27759da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
27769da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
27779da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6 |
27789da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
27799da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
27809da57d7bSbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
27819da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
27829da57d7bSbt150084 }
27839da57d7bSbt150084 
27849da57d7bSbt150084 /*
27850dc2366fSVenugopal Iyer  * ixgbe_setup_vmdq - Setup MAC classification feature
27860dc2366fSVenugopal Iyer  */
27870dc2366fSVenugopal Iyer static void
27880dc2366fSVenugopal Iyer ixgbe_setup_vmdq(ixgbe_t *ixgbe)
27890dc2366fSVenugopal Iyer {
27900dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
27910dc2366fSVenugopal Iyer 	uint32_t vmdctl, i, vtctl;
27920dc2366fSVenugopal Iyer 
27930dc2366fSVenugopal Iyer 	/*
27940dc2366fSVenugopal Iyer 	 * Setup the VMDq Control register, enable VMDq based on
27950dc2366fSVenugopal Iyer 	 * packet destination MAC address:
27960dc2366fSVenugopal Iyer 	 */
27970dc2366fSVenugopal Iyer 	switch (hw->mac.type) {
27980dc2366fSVenugopal Iyer 	case ixgbe_mac_82598EB:
27990dc2366fSVenugopal Iyer 		/*
28000dc2366fSVenugopal Iyer 		 * VMDq Enable = 1;
28010dc2366fSVenugopal Iyer 		 * VMDq Filter = 0; MAC filtering
28020dc2366fSVenugopal Iyer 		 * Default VMDq output index = 0;
28030dc2366fSVenugopal Iyer 		 */
28040dc2366fSVenugopal Iyer 		vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
28050dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
28060dc2366fSVenugopal Iyer 		break;
28070dc2366fSVenugopal Iyer 
28080dc2366fSVenugopal Iyer 	case ixgbe_mac_82599EB:
280969b5a878SDan McDonald 	case ixgbe_mac_X540:
28107e579c30SDale Ghent 	case ixgbe_mac_X550:
28117e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
28120dc2366fSVenugopal Iyer 		/*
28130dc2366fSVenugopal Iyer 		 * Enable VMDq-only.
28140dc2366fSVenugopal Iyer 		 */
28150dc2366fSVenugopal Iyer 		vmdctl = IXGBE_MRQC_VMDQEN;
28160dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl);
28170dc2366fSVenugopal Iyer 
28180dc2366fSVenugopal Iyer 		for (i = 0; i < hw->mac.num_rar_entries; i++) {
28190dc2366fSVenugopal Iyer 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0);
28200dc2366fSVenugopal Iyer 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0);
28210dc2366fSVenugopal Iyer 		}
28220dc2366fSVenugopal Iyer 
28230dc2366fSVenugopal Iyer 		/*
28240dc2366fSVenugopal Iyer 		 * Enable Virtualization and Replication.
28250dc2366fSVenugopal Iyer 		 */
28260dc2366fSVenugopal Iyer 		vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
28270dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
28280dc2366fSVenugopal Iyer 
28290dc2366fSVenugopal Iyer 		/*
28300dc2366fSVenugopal Iyer 		 * Enable receiving packets to all VFs
28310dc2366fSVenugopal Iyer 		 */
28320dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL);
28330dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL);
28340dc2366fSVenugopal Iyer 		break;
28350dc2366fSVenugopal Iyer 
28360dc2366fSVenugopal Iyer 	default:
28370dc2366fSVenugopal Iyer 		break;
28380dc2366fSVenugopal Iyer 	}
28390dc2366fSVenugopal Iyer }
28400dc2366fSVenugopal Iyer 
28410dc2366fSVenugopal Iyer /*
28420dc2366fSVenugopal Iyer  * ixgbe_setup_vmdq_rss - Setup both vmdq feature and rss feature.
28430dc2366fSVenugopal Iyer  */
28440dc2366fSVenugopal Iyer static void
28450dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe)
28460dc2366fSVenugopal Iyer {
28470dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
28487e579c30SDale Ghent 	uint32_t i, mrqc;
28497e579c30SDale Ghent 	uint32_t vtctl, vmdctl;
28500dc2366fSVenugopal Iyer 
28510dc2366fSVenugopal Iyer 	/*
28527e579c30SDale Ghent 	 * Initialize RETA/ERETA table
28530dc2366fSVenugopal Iyer 	 */
28547e579c30SDale Ghent 	ixgbe_setup_rss_table(ixgbe);
28550dc2366fSVenugopal Iyer 
28560dc2366fSVenugopal Iyer 	/*
28570dc2366fSVenugopal Iyer 	 * Enable and setup RSS and VMDq
28580dc2366fSVenugopal Iyer 	 */
28590dc2366fSVenugopal Iyer 	switch (hw->mac.type) {
28600dc2366fSVenugopal Iyer 	case ixgbe_mac_82598EB:
28610dc2366fSVenugopal Iyer 		/*
28620dc2366fSVenugopal Iyer 		 * Enable RSS & Setup RSS Hash functions
28630dc2366fSVenugopal Iyer 		 */
28640dc2366fSVenugopal Iyer 		mrqc = IXGBE_MRQC_RSSEN |
28650dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4 |
28660dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
28670dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
28680dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
28690dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
28700dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6 |
28710dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
28720dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
28730dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
28740dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
28750dc2366fSVenugopal Iyer 
28760dc2366fSVenugopal Iyer 		/*
28770dc2366fSVenugopal Iyer 		 * Enable and Setup VMDq
28780dc2366fSVenugopal Iyer 		 * VMDq Filter = 0; MAC filtering
28790dc2366fSVenugopal Iyer 		 * Default VMDq output index = 0;
28800dc2366fSVenugopal Iyer 		 */
28810dc2366fSVenugopal Iyer 		vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
28820dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
28830dc2366fSVenugopal Iyer 		break;
28840dc2366fSVenugopal Iyer 
28850dc2366fSVenugopal Iyer 	case ixgbe_mac_82599EB:
288669b5a878SDan McDonald 	case ixgbe_mac_X540:
28877e579c30SDale Ghent 	case ixgbe_mac_X550:
28887e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
28890dc2366fSVenugopal Iyer 		/*
28900dc2366fSVenugopal Iyer 		 * Enable RSS & Setup RSS Hash functions
28910dc2366fSVenugopal Iyer 		 */
28920dc2366fSVenugopal Iyer 		mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 |
28930dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
28940dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
28950dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
28960dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
28970dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6 |
28980dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
28990dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
29000dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
29010dc2366fSVenugopal Iyer 
29020dc2366fSVenugopal Iyer 		/*
29030dc2366fSVenugopal Iyer 		 * Enable VMDq+RSS.
29040dc2366fSVenugopal Iyer 		 */
29050dc2366fSVenugopal Iyer 		if (ixgbe->num_rx_groups > 32)  {
29060dc2366fSVenugopal Iyer 			mrqc = mrqc | IXGBE_MRQC_VMDQRSS64EN;
29070dc2366fSVenugopal Iyer 		} else {
29080dc2366fSVenugopal Iyer 			mrqc = mrqc | IXGBE_MRQC_VMDQRSS32EN;
29090dc2366fSVenugopal Iyer 		}
29100dc2366fSVenugopal Iyer 
29110dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
29120dc2366fSVenugopal Iyer 
29130dc2366fSVenugopal Iyer 		for (i = 0; i < hw->mac.num_rar_entries; i++) {
29140dc2366fSVenugopal Iyer 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0);
29150dc2366fSVenugopal Iyer 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0);
29160dc2366fSVenugopal Iyer 		}
29170dc2366fSVenugopal Iyer 		break;
29180dc2366fSVenugopal Iyer 
29190dc2366fSVenugopal Iyer 	default:
29200dc2366fSVenugopal Iyer 		break;
29210dc2366fSVenugopal Iyer 
29220dc2366fSVenugopal Iyer 	}
29230dc2366fSVenugopal Iyer 
292469b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82599EB ||
29257e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
29267e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
29277e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550EM_x) {
29280dc2366fSVenugopal Iyer 		/*
29290dc2366fSVenugopal Iyer 		 * Enable Virtualization and Replication.
29300dc2366fSVenugopal Iyer 		 */
29310dc2366fSVenugopal Iyer 		vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
29320dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
29330dc2366fSVenugopal Iyer 
29340dc2366fSVenugopal Iyer 		/*
29350dc2366fSVenugopal Iyer 		 * Enable receiving packets to all VFs
29360dc2366fSVenugopal Iyer 		 */
29370dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL);
29380dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL);
29390dc2366fSVenugopal Iyer 	}
29400dc2366fSVenugopal Iyer }
29410dc2366fSVenugopal Iyer 
29420dc2366fSVenugopal Iyer /*
29437e579c30SDale Ghent  * ixgbe_setup_rss_table - Setup RSS table
29447e579c30SDale Ghent  */
29457e579c30SDale Ghent static void
29467e579c30SDale Ghent ixgbe_setup_rss_table(ixgbe_t *ixgbe)
29477e579c30SDale Ghent {
29487e579c30SDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
29497e579c30SDale Ghent 	uint32_t i, j;
29507e579c30SDale Ghent 	uint32_t random;
29517e579c30SDale Ghent 	uint32_t reta;
29527e579c30SDale Ghent 	uint32_t ring_per_group;
29537e579c30SDale Ghent 	uint32_t ring;
29547e579c30SDale Ghent 	uint32_t table_size;
29557e579c30SDale Ghent 	uint32_t index_mult;
29567e579c30SDale Ghent 	uint32_t rxcsum;
29577e579c30SDale Ghent 
29587e579c30SDale Ghent 	/*
29597e579c30SDale Ghent 	 * Set multiplier for RETA setup and table size based on MAC type.
29607e579c30SDale Ghent 	 * RETA table sizes vary by model:
29617e579c30SDale Ghent 	 *
29627e579c30SDale Ghent 	 * 82598, 82599, X540: 128 table entries.
29637e579c30SDale Ghent 	 * X550: 512 table entries.
29647e579c30SDale Ghent 	 */
29657e579c30SDale Ghent 	index_mult = 0x1;
29667e579c30SDale Ghent 	table_size = 128;
29677e579c30SDale Ghent 	switch (ixgbe->hw.mac.type) {
29687e579c30SDale Ghent 	case ixgbe_mac_82598EB:
29697e579c30SDale Ghent 		index_mult = 0x11;
29707e579c30SDale Ghent 		break;
29717e579c30SDale Ghent 	case ixgbe_mac_X550:
29727e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
29737e579c30SDale Ghent 		table_size = 512;
29747e579c30SDale Ghent 		break;
29757e579c30SDale Ghent 	default:
29767e579c30SDale Ghent 		break;
29777e579c30SDale Ghent 	}
29787e579c30SDale Ghent 
29797e579c30SDale Ghent 	/*
29807e579c30SDale Ghent 	 * Fill out RSS redirection table. The configuation of the indices is
29817e579c30SDale Ghent 	 * hardware-dependent.
29827e579c30SDale Ghent 	 *
29837e579c30SDale Ghent 	 *  82598: 8 bits wide containing two 4 bit RSS indices
29847e579c30SDale Ghent 	 *  82599, X540: 8 bits wide containing one 4 bit RSS index
29857e579c30SDale Ghent 	 *  X550: 8 bits wide containing one 6 bit RSS index
29867e579c30SDale Ghent 	 */
29877e579c30SDale Ghent 	reta = 0;
29887e579c30SDale Ghent 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
29897e579c30SDale Ghent 
29907e579c30SDale Ghent 	for (i = 0, j = 0; i < table_size; i++, j++) {
29917e579c30SDale Ghent 		if (j == ring_per_group) j = 0;
29927e579c30SDale Ghent 
29937e579c30SDale Ghent 		/*
29947e579c30SDale Ghent 		 * The low 8 bits are for hash value (n+0);
29957e579c30SDale Ghent 		 * The next 8 bits are for hash value (n+1), etc.
29967e579c30SDale Ghent 		 */
29977e579c30SDale Ghent 		ring = (j * index_mult);
29987e579c30SDale Ghent 		reta = reta >> 8;
29997e579c30SDale Ghent 		reta = reta | (((uint32_t)ring) << 24);
30007e579c30SDale Ghent 
300105d069e4SToomas Soome 		if ((i & 3) == 3) {
30027e579c30SDale Ghent 			/*
30037e579c30SDale Ghent 			 * The first 128 table entries are programmed into the
30047e579c30SDale Ghent 			 * RETA register, with any beyond that (eg; on X550)
30057e579c30SDale Ghent 			 * into ERETA.
30067e579c30SDale Ghent 			 */
30077e579c30SDale Ghent 			if (i < 128)
30087e579c30SDale Ghent 				IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
30097e579c30SDale Ghent 			else
30107e579c30SDale Ghent 				IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32),
30117e579c30SDale Ghent 				    reta);
30127e579c30SDale Ghent 			reta = 0;
30137e579c30SDale Ghent 		}
301405d069e4SToomas Soome 	}
30157e579c30SDale Ghent 
30167e579c30SDale Ghent 	/*
30177e579c30SDale Ghent 	 * Fill out hash function seeds with a random constant
30187e579c30SDale Ghent 	 */
30197e579c30SDale Ghent 	for (i = 0; i < 10; i++) {
30207e579c30SDale Ghent 		(void) random_get_pseudo_bytes((uint8_t *)&random,
30217e579c30SDale Ghent 		    sizeof (uint32_t));
30227e579c30SDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random);
30237e579c30SDale Ghent 	}
30247e579c30SDale Ghent 
30257e579c30SDale Ghent 	/*
30267e579c30SDale Ghent 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
30277e579c30SDale Ghent 	 * It is an adapter hardware limitation that Packet Checksum is
30287e579c30SDale Ghent 	 * mutually exclusive with RSS.
30297e579c30SDale Ghent 	 */
30307e579c30SDale Ghent 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
30317e579c30SDale Ghent 	rxcsum |= IXGBE_RXCSUM_PCSD;
30327e579c30SDale Ghent 	rxcsum &= ~IXGBE_RXCSUM_IPPCSE;
30337e579c30SDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
30347e579c30SDale Ghent }
30357e579c30SDale Ghent 
30367e579c30SDale Ghent /*
30379da57d7bSbt150084  * ixgbe_init_unicst - Initialize the unicast addresses.
30389da57d7bSbt150084  */
30399da57d7bSbt150084 static void
30409da57d7bSbt150084 ixgbe_init_unicst(ixgbe_t *ixgbe)
30419da57d7bSbt150084 {
30429da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
3043da14cebeSEric Cheng 	uint8_t *mac_addr;
30449da57d7bSbt150084 	int slot;
30459da57d7bSbt150084 	/*
30469da57d7bSbt150084 	 * Here we should consider two situations:
30479da57d7bSbt150084 	 *
3048da14cebeSEric Cheng 	 * 1. Chipset is initialized at the first time,
3049da14cebeSEric Cheng 	 *    Clear all the multiple unicast addresses.
30509da57d7bSbt150084 	 *
30519da57d7bSbt150084 	 * 2. Chipset is reset
30529da57d7bSbt150084 	 *    Recover the multiple unicast addresses from the
30539da57d7bSbt150084 	 *    software data structure to the RAR registers.
30549da57d7bSbt150084 	 */
30559da57d7bSbt150084 	if (!ixgbe->unicst_init) {
30569da57d7bSbt150084 		/*
30579da57d7bSbt150084 		 * Initialize the multiple unicast addresses
30589da57d7bSbt150084 		 */
30590dc2366fSVenugopal Iyer 		ixgbe->unicst_total = hw->mac.num_rar_entries;
3060da14cebeSEric Cheng 		ixgbe->unicst_avail = ixgbe->unicst_total;
3061da14cebeSEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3062da14cebeSEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
3063da14cebeSEric Cheng 			bzero(mac_addr, ETHERADDRL);
3064da14cebeSEric Cheng 			(void) ixgbe_set_rar(hw, slot, mac_addr, NULL, NULL);
30659da57d7bSbt150084 			ixgbe->unicst_addr[slot].mac.set = 0;
3066da14cebeSEric Cheng 		}
30679da57d7bSbt150084 		ixgbe->unicst_init = B_TRUE;
30689da57d7bSbt150084 	} else {
30699da57d7bSbt150084 		/* Re-configure the RAR registers */
3070da14cebeSEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3071da14cebeSEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
3072da14cebeSEric Cheng 			if (ixgbe->unicst_addr[slot].mac.set == 1) {
3073da14cebeSEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
30740dc2366fSVenugopal Iyer 				    ixgbe->unicst_addr[slot].mac.group_index,
30750dc2366fSVenugopal Iyer 				    IXGBE_RAH_AV);
3076da14cebeSEric Cheng 			} else {
3077da14cebeSEric Cheng 				bzero(mac_addr, ETHERADDRL);
3078da14cebeSEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
3079da14cebeSEric Cheng 				    NULL, NULL);
30809da57d7bSbt150084 			}
30819da57d7bSbt150084 		}
3082da14cebeSEric Cheng 	}
3083da14cebeSEric Cheng }
3084da14cebeSEric Cheng 
30859da57d7bSbt150084 /*
3086da14cebeSEric Cheng  * ixgbe_unicst_find - Find the slot for the specified unicast address
3087da14cebeSEric Cheng  */
3088da14cebeSEric Cheng int
3089da14cebeSEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr)
3090da14cebeSEric Cheng {
3091da14cebeSEric Cheng 	int slot;
3092da14cebeSEric Cheng 
3093da14cebeSEric Cheng 	ASSERT(mutex_owned(&ixgbe->gen_lock));
3094da14cebeSEric Cheng 
3095da14cebeSEric Cheng 	for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3096da14cebeSEric Cheng 		if (bcmp(ixgbe->unicst_addr[slot].mac.addr,
3097da14cebeSEric Cheng 		    mac_addr, ETHERADDRL) == 0)
3098da14cebeSEric Cheng 			return (slot);
3099da14cebeSEric Cheng 	}
3100da14cebeSEric Cheng 
3101da14cebeSEric Cheng 	return (-1);
3102da14cebeSEric Cheng }
3103da14cebeSEric Cheng 
3104da14cebeSEric Cheng /*
31059da57d7bSbt150084  * ixgbe_multicst_add - Add a multicst address.
31069da57d7bSbt150084  */
31079da57d7bSbt150084 int
31089da57d7bSbt150084 ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr)
31099da57d7bSbt150084 {
31109da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
31119da57d7bSbt150084 
31129da57d7bSbt150084 	if ((multiaddr[0] & 01) == 0) {
31139da57d7bSbt150084 		return (EINVAL);
31149da57d7bSbt150084 	}
31159da57d7bSbt150084 
31169da57d7bSbt150084 	if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) {
31179da57d7bSbt150084 		return (ENOENT);
31189da57d7bSbt150084 	}
31199da57d7bSbt150084 
31209da57d7bSbt150084 	bcopy(multiaddr,
31219da57d7bSbt150084 	    &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL);
31229da57d7bSbt150084 	ixgbe->mcast_count++;
31239da57d7bSbt150084 
31249da57d7bSbt150084 	/*
31259da57d7bSbt150084 	 * Update the multicast table in the hardware
31269da57d7bSbt150084 	 */
31279da57d7bSbt150084 	ixgbe_setup_multicst(ixgbe);
31289da57d7bSbt150084 
31299da57d7bSbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
31309da57d7bSbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
31319da57d7bSbt150084 		return (EIO);
31329da57d7bSbt150084 	}
31339da57d7bSbt150084 
31349da57d7bSbt150084 	return (0);
31359da57d7bSbt150084 }
31369da57d7bSbt150084 
31379da57d7bSbt150084 /*
31389da57d7bSbt150084  * ixgbe_multicst_remove - Remove a multicst address.
31399da57d7bSbt150084  */
31409da57d7bSbt150084 int
31419da57d7bSbt150084 ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr)
31429da57d7bSbt150084 {
31439da57d7bSbt150084 	int i;
31449da57d7bSbt150084 
31459da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
31469da57d7bSbt150084 
31479da57d7bSbt150084 	for (i = 0; i < ixgbe->mcast_count; i++) {
31489da57d7bSbt150084 		if (bcmp(multiaddr, &ixgbe->mcast_table[i],
31499da57d7bSbt150084 		    ETHERADDRL) == 0) {
31509da57d7bSbt150084 			for (i++; i < ixgbe->mcast_count; i++) {
31519da57d7bSbt150084 				ixgbe->mcast_table[i - 1] =
31529da57d7bSbt150084 				    ixgbe->mcast_table[i];
31539da57d7bSbt150084 			}
31549da57d7bSbt150084 			ixgbe->mcast_count--;
31559da57d7bSbt150084 			break;
31569da57d7bSbt150084 		}
31579da57d7bSbt150084 	}
31589da57d7bSbt150084 
31599da57d7bSbt150084 	/*
31609da57d7bSbt150084 	 * Update the multicast table in the hardware
31619da57d7bSbt150084 	 */
31629da57d7bSbt150084 	ixgbe_setup_multicst(ixgbe);
31639da57d7bSbt150084 
31649da57d7bSbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
31659da57d7bSbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
31669da57d7bSbt150084 		return (EIO);
31679da57d7bSbt150084 	}
31689da57d7bSbt150084 
31699da57d7bSbt150084 	return (0);
31709da57d7bSbt150084 }
31719da57d7bSbt150084 
31729da57d7bSbt150084 /*
31739da57d7bSbt150084  * ixgbe_setup_multicast - Setup multicast data structures.
31749da57d7bSbt150084  *
31759da57d7bSbt150084  * This routine initializes all of the multicast related structures
31769da57d7bSbt150084  * and save them in the hardware registers.
31779da57d7bSbt150084  */
31789da57d7bSbt150084 static void
31799da57d7bSbt150084 ixgbe_setup_multicst(ixgbe_t *ixgbe)
31809da57d7bSbt150084 {
31819da57d7bSbt150084 	uint8_t *mc_addr_list;
31829da57d7bSbt150084 	uint32_t mc_addr_count;
31839da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
31849da57d7bSbt150084 
31859da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
31869da57d7bSbt150084 
31879da57d7bSbt150084 	ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES);
31889da57d7bSbt150084 
31899da57d7bSbt150084 	mc_addr_list = (uint8_t *)ixgbe->mcast_table;
31909da57d7bSbt150084 	mc_addr_count = ixgbe->mcast_count;
31919da57d7bSbt150084 
31929da57d7bSbt150084 	/*
31939da57d7bSbt150084 	 * Update the multicast addresses to the MTA registers
31949da57d7bSbt150084 	 */
31959da57d7bSbt150084 	(void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
319669b5a878SDan McDonald 	    ixgbe_mc_table_itr, TRUE);
31979da57d7bSbt150084 }
31989da57d7bSbt150084 
31999da57d7bSbt150084 /*
32000dc2366fSVenugopal Iyer  * ixgbe_setup_vmdq_rss_conf - Configure vmdq and rss (number and mode).
32010dc2366fSVenugopal Iyer  *
32020dc2366fSVenugopal Iyer  * Configure the rx classification mode (vmdq & rss) and vmdq & rss numbers.
32030dc2366fSVenugopal Iyer  * Different chipsets may have different allowed configuration of vmdq and rss.
32040dc2366fSVenugopal Iyer  */
32050dc2366fSVenugopal Iyer static void
32060dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe)
32070dc2366fSVenugopal Iyer {
32080dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
32090dc2366fSVenugopal Iyer 	uint32_t ring_per_group;
32100dc2366fSVenugopal Iyer 
32110dc2366fSVenugopal Iyer 	switch (hw->mac.type) {
32120dc2366fSVenugopal Iyer 	case ixgbe_mac_82598EB:
32130dc2366fSVenugopal Iyer 		/*
32140dc2366fSVenugopal Iyer 		 * 82598 supports the following combination:
32150dc2366fSVenugopal Iyer 		 * vmdq no. x rss no.
32160dc2366fSVenugopal Iyer 		 * [5..16]  x 1
32170dc2366fSVenugopal Iyer 		 * [1..4]   x [1..16]
32180dc2366fSVenugopal Iyer 		 * However 8 rss queue per pool (vmdq) is sufficient for
32190dc2366fSVenugopal Iyer 		 * most cases.
32200dc2366fSVenugopal Iyer 		 */
32210dc2366fSVenugopal Iyer 		ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
32220dc2366fSVenugopal Iyer 		if (ixgbe->num_rx_groups > 4) {
32230dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = ixgbe->num_rx_groups;
32240dc2366fSVenugopal Iyer 		} else {
32250dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
32260dc2366fSVenugopal Iyer 			    min(8, ring_per_group);
32270dc2366fSVenugopal Iyer 		}
32280dc2366fSVenugopal Iyer 
32290dc2366fSVenugopal Iyer 		break;
32300dc2366fSVenugopal Iyer 
32310dc2366fSVenugopal Iyer 	case ixgbe_mac_82599EB:
323269b5a878SDan McDonald 	case ixgbe_mac_X540:
32337e579c30SDale Ghent 	case ixgbe_mac_X550:
32347e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
32350dc2366fSVenugopal Iyer 		/*
32360dc2366fSVenugopal Iyer 		 * 82599 supports the following combination:
32370dc2366fSVenugopal Iyer 		 * vmdq no. x rss no.
32380dc2366fSVenugopal Iyer 		 * [33..64] x [1..2]
32390dc2366fSVenugopal Iyer 		 * [2..32]  x [1..4]
32400dc2366fSVenugopal Iyer 		 * 1 x [1..16]
32410dc2366fSVenugopal Iyer 		 * However 8 rss queue per pool (vmdq) is sufficient for
32420dc2366fSVenugopal Iyer 		 * most cases.
324369b5a878SDan McDonald 		 *
32447e579c30SDale Ghent 		 * For now, treat X540 and X550 like the 82599.
32450dc2366fSVenugopal Iyer 		 */
32460dc2366fSVenugopal Iyer 		ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
32470dc2366fSVenugopal Iyer 		if (ixgbe->num_rx_groups == 1) {
32480dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = min(8, ring_per_group);
32490dc2366fSVenugopal Iyer 		} else if (ixgbe->num_rx_groups <= 32) {
32500dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
32510dc2366fSVenugopal Iyer 			    min(4, ring_per_group);
32520dc2366fSVenugopal Iyer 		} else if (ixgbe->num_rx_groups <= 64) {
32530dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
32540dc2366fSVenugopal Iyer 			    min(2, ring_per_group);
32550dc2366fSVenugopal Iyer 		}
32560dc2366fSVenugopal Iyer 		break;
32570dc2366fSVenugopal Iyer 
32580dc2366fSVenugopal Iyer 	default:
32590dc2366fSVenugopal Iyer 		break;
32600dc2366fSVenugopal Iyer 	}
32610dc2366fSVenugopal Iyer 
32620dc2366fSVenugopal Iyer 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
32630dc2366fSVenugopal Iyer 
32640dc2366fSVenugopal Iyer 	if (ixgbe->num_rx_groups == 1 && ring_per_group == 1) {
32650dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
32660dc2366fSVenugopal Iyer 	} else if (ixgbe->num_rx_groups != 1 && ring_per_group == 1) {
32670dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ;
32680dc2366fSVenugopal Iyer 	} else if (ixgbe->num_rx_groups != 1 && ring_per_group != 1) {
32690dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ_RSS;
32700dc2366fSVenugopal Iyer 	} else {
32710dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_RSS;
32720dc2366fSVenugopal Iyer 	}
32730dc2366fSVenugopal Iyer 
327419843f01SPaul Guo 	IXGBE_DEBUGLOG_2(ixgbe, "rx group number:%d, rx ring number:%d",
32750dc2366fSVenugopal Iyer 	    ixgbe->num_rx_groups, ixgbe->num_rx_rings);
32760dc2366fSVenugopal Iyer }
32770dc2366fSVenugopal Iyer 
32780dc2366fSVenugopal Iyer /*
32799da57d7bSbt150084  * ixgbe_get_conf - Get driver configurations set in driver.conf.
32809da57d7bSbt150084  *
32819da57d7bSbt150084  * This routine gets user-configured values out of the configuration
32829da57d7bSbt150084  * file ixgbe.conf.
32839da57d7bSbt150084  *
32849da57d7bSbt150084  * For each configurable value, there is a minimum, a maximum, and a
32859da57d7bSbt150084  * default.
32869da57d7bSbt150084  * If user does not configure a value, use the default.
32879da57d7bSbt150084  * If user configures below the minimum, use the minumum.
32889da57d7bSbt150084  * If user configures above the maximum, use the maxumum.
32899da57d7bSbt150084  */
32909da57d7bSbt150084 static void
32919da57d7bSbt150084 ixgbe_get_conf(ixgbe_t *ixgbe)
32929da57d7bSbt150084 {
32939da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
32949da57d7bSbt150084 	uint32_t flow_control;
32959da57d7bSbt150084 
32969da57d7bSbt150084 	/*
32979da57d7bSbt150084 	 * ixgbe driver supports the following user configurations:
32989da57d7bSbt150084 	 *
32999da57d7bSbt150084 	 * Jumbo frame configuration:
33009da57d7bSbt150084 	 *    default_mtu
33019da57d7bSbt150084 	 *
33029da57d7bSbt150084 	 * Ethernet flow control configuration:
33039da57d7bSbt150084 	 *    flow_control
33049da57d7bSbt150084 	 *
33059da57d7bSbt150084 	 * Multiple rings configurations:
33069da57d7bSbt150084 	 *    tx_queue_number
33079da57d7bSbt150084 	 *    tx_ring_size
33089da57d7bSbt150084 	 *    rx_queue_number
33099da57d7bSbt150084 	 *    rx_ring_size
33109da57d7bSbt150084 	 *
33119da57d7bSbt150084 	 * Call ixgbe_get_prop() to get the value for a specific
33129da57d7bSbt150084 	 * configuration parameter.
33139da57d7bSbt150084 	 */
33149da57d7bSbt150084 
33159da57d7bSbt150084 	/*
33169da57d7bSbt150084 	 * Jumbo frame configuration - max_frame_size controls host buffer
33179da57d7bSbt150084 	 * allocation, so includes MTU, ethernet header, vlan tag and
33189da57d7bSbt150084 	 * frame check sequence.
33199da57d7bSbt150084 	 */
33209da57d7bSbt150084 	ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU,
33211fedc51fSWinson Wang - Sun Microsystems - Beijing China 	    MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU);
33229da57d7bSbt150084 
33239da57d7bSbt150084 	ixgbe->max_frame_size = ixgbe->default_mtu +
33249da57d7bSbt150084 	    sizeof (struct ether_vlan_header) + ETHERFCSL;
33259da57d7bSbt150084 
33269da57d7bSbt150084 	/*
33279da57d7bSbt150084 	 * Ethernet flow control configuration
33289da57d7bSbt150084 	 */
33299da57d7bSbt150084 	flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL,
3330da14cebeSEric Cheng 	    ixgbe_fc_none, 3, ixgbe_fc_none);
33319da57d7bSbt150084 	if (flow_control == 3)
33329da57d7bSbt150084 		flow_control = ixgbe_fc_default;
33339da57d7bSbt150084 
333473cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
333573cd555cSBin Tu - Sun Microsystems - Beijing China 	 * fc.requested mode is what the user requests.  After autoneg,
333673cd555cSBin Tu - Sun Microsystems - Beijing China 	 * fc.current_mode will be the flow_control mode that was negotiated.
333773cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
333873cd555cSBin Tu - Sun Microsystems - Beijing China 	hw->fc.requested_mode = flow_control;
33399da57d7bSbt150084 
33409da57d7bSbt150084 	/*
33419da57d7bSbt150084 	 * Multiple rings configurations
33429da57d7bSbt150084 	 */
33439da57d7bSbt150084 	ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM,
334413740cb2SPaul Guo 	    ixgbe->capab->min_tx_que_num,
334513740cb2SPaul Guo 	    ixgbe->capab->max_tx_que_num,
334613740cb2SPaul Guo 	    ixgbe->capab->def_tx_que_num);
33479da57d7bSbt150084 	ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE,
33489da57d7bSbt150084 	    MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE);
33499da57d7bSbt150084 
33509da57d7bSbt150084 	ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM,
335113740cb2SPaul Guo 	    ixgbe->capab->min_rx_que_num,
335213740cb2SPaul Guo 	    ixgbe->capab->max_rx_que_num,
335313740cb2SPaul Guo 	    ixgbe->capab->def_rx_que_num);
33549da57d7bSbt150084 	ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE,
33559da57d7bSbt150084 	    MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE);
33569da57d7bSbt150084 
33579da57d7bSbt150084 	/*
3358da14cebeSEric Cheng 	 * Multiple groups configuration
3359da14cebeSEric Cheng 	 */
3360da14cebeSEric Cheng 	ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM,
33610dc2366fSVenugopal Iyer 	    ixgbe->capab->min_rx_grp_num, ixgbe->capab->max_rx_grp_num,
33620dc2366fSVenugopal Iyer 	    ixgbe->capab->def_rx_grp_num);
3363da14cebeSEric Cheng 
3364da14cebeSEric Cheng 	ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE,
3365da14cebeSEric Cheng 	    0, 1, DEFAULT_MR_ENABLE);
3366da14cebeSEric Cheng 
3367da14cebeSEric Cheng 	if (ixgbe->mr_enable == B_FALSE) {
3368da14cebeSEric Cheng 		ixgbe->num_tx_rings = 1;
3369da14cebeSEric Cheng 		ixgbe->num_rx_rings = 1;
3370da14cebeSEric Cheng 		ixgbe->num_rx_groups = 1;
33710dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
33720dc2366fSVenugopal Iyer 	} else {
33730dc2366fSVenugopal Iyer 		ixgbe->num_rx_rings = ixgbe->num_rx_groups *
33740dc2366fSVenugopal Iyer 		    max(ixgbe->num_rx_rings / ixgbe->num_rx_groups, 1);
33750dc2366fSVenugopal Iyer 		/*
33760dc2366fSVenugopal Iyer 		 * The combination of num_rx_rings and num_rx_groups
33770dc2366fSVenugopal Iyer 		 * may be not supported by h/w. We need to adjust
33780dc2366fSVenugopal Iyer 		 * them to appropriate values.
33790dc2366fSVenugopal Iyer 		 */
33800dc2366fSVenugopal Iyer 		ixgbe_setup_vmdq_rss_conf(ixgbe);
3381da14cebeSEric Cheng 	}
3382da14cebeSEric Cheng 
3383da14cebeSEric Cheng 	/*
33849da57d7bSbt150084 	 * Tunable used to force an interrupt type. The only use is
33859da57d7bSbt150084 	 * for testing of the lesser interrupt types.
33869da57d7bSbt150084 	 * 0 = don't force interrupt type
3387da14cebeSEric Cheng 	 * 1 = force interrupt type MSI-X
33889da57d7bSbt150084 	 * 2 = force interrupt type MSI
33899da57d7bSbt150084 	 * 3 = force interrupt type Legacy
33909da57d7bSbt150084 	 */
33919da57d7bSbt150084 	ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE,
33929da57d7bSbt150084 	    IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE);
33939da57d7bSbt150084 
33949da57d7bSbt150084 	ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE,
3395c971fb7eSgg161487 	    0, 1, DEFAULT_TX_HCKSUM_ENABLE);
33969da57d7bSbt150084 	ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE,
3397c971fb7eSgg161487 	    0, 1, DEFAULT_RX_HCKSUM_ENABLE);
33989da57d7bSbt150084 	ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE,
3399c971fb7eSgg161487 	    0, 1, DEFAULT_LSO_ENABLE);
3400ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	ixgbe->lro_enable = ixgbe_get_prop(ixgbe, PROP_LRO_ENABLE,
3401ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	    0, 1, DEFAULT_LRO_ENABLE);
34029da57d7bSbt150084 	ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE,
3403c971fb7eSgg161487 	    0, 1, DEFAULT_TX_HEAD_WB_ENABLE);
34045b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->relax_order_enable = ixgbe_get_prop(ixgbe,
34055b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    PROP_RELAX_ORDER_ENABLE, 0, 1, DEFAULT_RELAX_ORDER_ENABLE);
3406c971fb7eSgg161487 
34077e579c30SDale Ghent 	/* Head Write Back not recommended for 82599, X540 and X550 */
340869b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82599EB ||
34097e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
34107e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
34117e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550EM_x) {
341273cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe->tx_head_wb_enable = B_FALSE;
341373cd555cSBin Tu - Sun Microsystems - Beijing China 	}
341473cd555cSBin Tu - Sun Microsystems - Beijing China 
3415c971fb7eSgg161487 	/*
3416c971fb7eSgg161487 	 * ixgbe LSO needs the tx h/w checksum support.
3417c971fb7eSgg161487 	 * LSO will be disabled if tx h/w checksum is not
3418c971fb7eSgg161487 	 * enabled.
3419c971fb7eSgg161487 	 */
3420c971fb7eSgg161487 	if (ixgbe->tx_hcksum_enable == B_FALSE) {
3421c971fb7eSgg161487 		ixgbe->lso_enable = B_FALSE;
3422c971fb7eSgg161487 	}
34239da57d7bSbt150084 
3424ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	/*
3425ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 * ixgbe LRO needs the rx h/w checksum support.
3426ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 * LRO will be disabled if rx h/w checksum is not
3427ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 * enabled.
3428ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 */
3429ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	if (ixgbe->rx_hcksum_enable == B_FALSE) {
3430ffd8e883SWinson Wang - Sun Microsystems - Beijing China 		ixgbe->lro_enable = B_FALSE;
3431ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	}
3432ffd8e883SWinson Wang - Sun Microsystems - Beijing China 
3433ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	/*
34347e579c30SDale Ghent 	 * ixgbe LRO only supported by 82599, X540 and X550
3435ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 */
343669b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82598EB) {
3437ffd8e883SWinson Wang - Sun Microsystems - Beijing China 		ixgbe->lro_enable = B_FALSE;
3438ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	}
34399da57d7bSbt150084 	ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD,
34409da57d7bSbt150084 	    MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD,
34419da57d7bSbt150084 	    DEFAULT_TX_COPY_THRESHOLD);
34429da57d7bSbt150084 	ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe,
34439da57d7bSbt150084 	    PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD,
34449da57d7bSbt150084 	    MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD);
34459da57d7bSbt150084 	ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe,
34469da57d7bSbt150084 	    PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD,
34479da57d7bSbt150084 	    MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD);
34489da57d7bSbt150084 	ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe,
34499da57d7bSbt150084 	    PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD,
34509da57d7bSbt150084 	    MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD);
34519da57d7bSbt150084 
34529da57d7bSbt150084 	ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD,
34539da57d7bSbt150084 	    MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD,
34549da57d7bSbt150084 	    DEFAULT_RX_COPY_THRESHOLD);
34559da57d7bSbt150084 	ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR,
34569da57d7bSbt150084 	    MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR,
34579da57d7bSbt150084 	    DEFAULT_RX_LIMIT_PER_INTR);
34589da57d7bSbt150084 
3459ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING,
3460ea65739eSchenlu chen - Sun Microsystems - Beijing China 	    ixgbe->capab->min_intr_throttle,
3461ea65739eSchenlu chen - Sun Microsystems - Beijing China 	    ixgbe->capab->max_intr_throttle,
3462ea65739eSchenlu chen - Sun Microsystems - Beijing China 	    ixgbe->capab->def_intr_throttle);
3463185c5677SPaul Guo 	/*
34647e579c30SDale Ghent 	 * 82599, X540 and X550 require the interrupt throttling rate is
34657e579c30SDale Ghent 	 * a multiple of 8. This is enforced by the register definiton.
3466185c5677SPaul Guo 	 */
34677e579c30SDale Ghent 	if (hw->mac.type == ixgbe_mac_82599EB ||
34687e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
34697e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
34707e579c30SDale Ghent 	    hw->mac.type == ixgbe_mac_X550EM_x)
3471ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8;
347243fab1a9SSaso Kiselkov 
347343fab1a9SSaso Kiselkov 	hw->allow_unsupported_sfp = ixgbe_get_prop(ixgbe,
347443fab1a9SSaso Kiselkov 	    PROP_ALLOW_UNSUPPORTED_SFP, 0, 1, DEFAULT_ALLOW_UNSUPPORTED_SFP);
347573cd555cSBin Tu - Sun Microsystems - Beijing China }
3476ea65739eSchenlu chen - Sun Microsystems - Beijing China 
3477ea65739eSchenlu chen - Sun Microsystems - Beijing China static void
3478ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_init_params(ixgbe_t *ixgbe)
3479ea65739eSchenlu chen - Sun Microsystems - Beijing China {
34807e579c30SDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
34817e579c30SDale Ghent 	ixgbe_link_speed speeds_supported = 0;
34827e579c30SDale Ghent 	boolean_t negotiate;
34837e579c30SDale Ghent 
34847e579c30SDale Ghent 	/*
34857e579c30SDale Ghent 	 * Get a list of speeds the adapter supports. If the hw struct hasn't
34867e579c30SDale Ghent 	 * been populated with this information yet, retrieve it from the
34877e579c30SDale Ghent 	 * adapter and save it to our own variable.
34887e579c30SDale Ghent 	 *
34897e579c30SDale Ghent 	 * On certain adapters, such as ones which use SFPs, the contents of
34907e579c30SDale Ghent 	 * hw->phy.speeds_supported (and hw->phy.autoneg_advertised) are not
34917e579c30SDale Ghent 	 * updated, so we must rely on calling ixgbe_get_link_capabilities()
34927e579c30SDale Ghent 	 * in order to ascertain the speeds which we are capable of supporting,
34937e579c30SDale Ghent 	 * and in the case of SFP-equipped adapters, which speed we are
34947e579c30SDale Ghent 	 * advertising. If ixgbe_get_link_capabilities() fails for some reason,
34957e579c30SDale Ghent 	 * we'll go with a default list of speeds as a last resort.
34967e579c30SDale Ghent 	 */
34977e579c30SDale Ghent 	speeds_supported = hw->phy.speeds_supported;
34987e579c30SDale Ghent 
34997e579c30SDale Ghent 	if (speeds_supported == 0) {
35007e579c30SDale Ghent 		if (ixgbe_get_link_capabilities(hw, &speeds_supported,
35017e579c30SDale Ghent 		    &negotiate) != IXGBE_SUCCESS) {
35027e579c30SDale Ghent 			if (hw->mac.type == ixgbe_mac_82598EB) {
35037e579c30SDale Ghent 				speeds_supported =
35047e579c30SDale Ghent 				    IXGBE_LINK_SPEED_82598_AUTONEG;
35057e579c30SDale Ghent 			} else {
35067e579c30SDale Ghent 				speeds_supported =
35077e579c30SDale Ghent 				    IXGBE_LINK_SPEED_82599_AUTONEG;
35087e579c30SDale Ghent 			}
35097e579c30SDale Ghent 		}
35107e579c30SDale Ghent 	}
35117e579c30SDale Ghent 	ixgbe->speeds_supported = speeds_supported;
35127e579c30SDale Ghent 
35137e579c30SDale Ghent 	/*
35147e579c30SDale Ghent 	 * By default, all supported speeds are enabled and advertised.
35157e579c30SDale Ghent 	 */
35167e579c30SDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_10GB_FULL) {
3517ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->param_en_10000fdx_cap = 1;
3518ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->param_adv_10000fdx_cap = 1;
35197e579c30SDale Ghent 	} else {
35207e579c30SDale Ghent 		ixgbe->param_en_10000fdx_cap = 0;
35217e579c30SDale Ghent 		ixgbe->param_adv_10000fdx_cap = 0;
35227e579c30SDale Ghent 	}
35237e579c30SDale Ghent 
35247e579c30SDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_5GB_FULL) {
35257e579c30SDale Ghent 		ixgbe->param_en_5000fdx_cap = 1;
35267e579c30SDale Ghent 		ixgbe->param_adv_5000fdx_cap = 1;
35277e579c30SDale Ghent 	} else {
35287e579c30SDale Ghent 		ixgbe->param_en_5000fdx_cap = 0;
35297e579c30SDale Ghent 		ixgbe->param_adv_5000fdx_cap = 0;
35307e579c30SDale Ghent 	}
35317e579c30SDale Ghent 
35327e579c30SDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_2_5GB_FULL) {
35337e579c30SDale Ghent 		ixgbe->param_en_2500fdx_cap = 1;
35347e579c30SDale Ghent 		ixgbe->param_adv_2500fdx_cap = 1;
35357e579c30SDale Ghent 	} else {
35367e579c30SDale Ghent 		ixgbe->param_en_2500fdx_cap = 0;
35377e579c30SDale Ghent 		ixgbe->param_adv_2500fdx_cap = 0;
35387e579c30SDale Ghent 	}
35397e579c30SDale Ghent 
35407e579c30SDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_1GB_FULL) {
35417e579c30SDale Ghent 		ixgbe->param_en_1000fdx_cap = 1;
3542ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->param_adv_1000fdx_cap = 1;
35437e579c30SDale Ghent 	} else {
35447e579c30SDale Ghent 		ixgbe->param_en_1000fdx_cap = 0;
35457e579c30SDale Ghent 		ixgbe->param_adv_1000fdx_cap = 0;
35467e579c30SDale Ghent 	}
35477e579c30SDale Ghent 
35487e579c30SDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_100_FULL) {
35497e579c30SDale Ghent 		ixgbe->param_en_100fdx_cap = 1;
3550ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->param_adv_100fdx_cap = 1;
35517e579c30SDale Ghent 	} else {
35527e579c30SDale Ghent 		ixgbe->param_en_100fdx_cap = 0;
35537e579c30SDale Ghent 		ixgbe->param_adv_100fdx_cap = 0;
35547e579c30SDale Ghent 	}
3555ea65739eSchenlu chen - Sun Microsystems - Beijing China 
3556ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_pause_cap = 1;
3557ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_asym_pause_cap = 1;
3558ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_rem_fault = 0;
3559ea65739eSchenlu chen - Sun Microsystems - Beijing China 
3560ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_adv_autoneg_cap = 1;
3561ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_adv_pause_cap = 1;
3562ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_adv_asym_pause_cap = 1;
3563ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_adv_rem_fault = 0;
3564ea65739eSchenlu chen - Sun Microsystems - Beijing China 
3565ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_10000fdx_cap = 0;
35667e579c30SDale Ghent 	ixgbe->param_lp_5000fdx_cap = 0;
35677e579c30SDale Ghent 	ixgbe->param_lp_2500fdx_cap = 0;
3568ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_1000fdx_cap = 0;
3569ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_100fdx_cap = 0;
3570ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_autoneg_cap = 0;
3571ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_pause_cap = 0;
3572ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_asym_pause_cap = 0;
3573ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_rem_fault = 0;
35749da57d7bSbt150084 }
35759da57d7bSbt150084 
35769da57d7bSbt150084 /*
35779da57d7bSbt150084  * ixgbe_get_prop - Get a property value out of the configuration file
35789da57d7bSbt150084  * ixgbe.conf.
35799da57d7bSbt150084  *
35809da57d7bSbt150084  * Caller provides the name of the property, a default value, a minimum
35819da57d7bSbt150084  * value, and a maximum value.
35829da57d7bSbt150084  *
35839da57d7bSbt150084  * Return configured value of the property, with default, minimum and
35849da57d7bSbt150084  * maximum properly applied.
35859da57d7bSbt150084  */
35869da57d7bSbt150084 static int
35879da57d7bSbt150084 ixgbe_get_prop(ixgbe_t *ixgbe,
35889da57d7bSbt150084     char *propname,	/* name of the property */
35899da57d7bSbt150084     int minval,		/* minimum acceptable value */
35909da57d7bSbt150084     int maxval,		/* maximim acceptable value */
35919da57d7bSbt150084     int defval)		/* default value */
35929da57d7bSbt150084 {
35939da57d7bSbt150084 	int value;
35949da57d7bSbt150084 
35959da57d7bSbt150084 	/*
35969da57d7bSbt150084 	 * Call ddi_prop_get_int() to read the conf settings
35979da57d7bSbt150084 	 */
35989da57d7bSbt150084 	value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip,
35999da57d7bSbt150084 	    DDI_PROP_DONTPASS, propname, defval);
36009da57d7bSbt150084 	if (value > maxval)
36019da57d7bSbt150084 		value = maxval;
36029da57d7bSbt150084 
36039da57d7bSbt150084 	if (value < minval)
36049da57d7bSbt150084 		value = minval;
36059da57d7bSbt150084 
36069da57d7bSbt150084 	return (value);
36079da57d7bSbt150084 }
36089da57d7bSbt150084 
36099da57d7bSbt150084 /*
36109da57d7bSbt150084  * ixgbe_driver_setup_link - Using the link properties to setup the link.
36119da57d7bSbt150084  */
36129da57d7bSbt150084 int
36139da57d7bSbt150084 ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw)
36149da57d7bSbt150084 {
36157e579c30SDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
36167e579c30SDale Ghent 	ixgbe_link_speed advertised = 0;
36179da57d7bSbt150084 
36189da57d7bSbt150084 	/*
36197e579c30SDale Ghent 	 * Assemble a list of enabled speeds to auto-negotiate with.
36209da57d7bSbt150084 	 */
36217e579c30SDale Ghent 	if (ixgbe->param_en_10000fdx_cap == 1)
36227e579c30SDale Ghent 		advertised |= IXGBE_LINK_SPEED_10GB_FULL;
36239da57d7bSbt150084 
36247e579c30SDale Ghent 	if (ixgbe->param_en_5000fdx_cap == 1)
36257e579c30SDale Ghent 		advertised |= IXGBE_LINK_SPEED_5GB_FULL;
36269da57d7bSbt150084 
36277e579c30SDale Ghent 	if (ixgbe->param_en_2500fdx_cap == 1)
36287e579c30SDale Ghent 		advertised |= IXGBE_LINK_SPEED_2_5GB_FULL;
36299da57d7bSbt150084 
36307e579c30SDale Ghent 	if (ixgbe->param_en_1000fdx_cap == 1)
36317e579c30SDale Ghent 		advertised |= IXGBE_LINK_SPEED_1GB_FULL;
36329da57d7bSbt150084 
36337e579c30SDale Ghent 	if (ixgbe->param_en_100fdx_cap == 1)
36347e579c30SDale Ghent 		advertised |= IXGBE_LINK_SPEED_100_FULL;
36357e579c30SDale Ghent 
36367e579c30SDale Ghent 	/*
36377e579c30SDale Ghent 	 * As a last resort, autoneg with a default list of speeds.
36387e579c30SDale Ghent 	 */
36397e579c30SDale Ghent 	if (ixgbe->param_adv_autoneg_cap == 1 && advertised == 0) {
36407e579c30SDale Ghent 		ixgbe_notice(ixgbe, "Invalid link settings. Setting link "
36417e579c30SDale Ghent 		    "to autonegotiate with full capabilities.");
36427e579c30SDale Ghent 
36437e579c30SDale Ghent 		if (hw->mac.type == ixgbe_mac_82598EB)
36447e579c30SDale Ghent 			advertised = IXGBE_LINK_SPEED_82598_AUTONEG;
36457e579c30SDale Ghent 		else
36467e579c30SDale Ghent 			advertised = IXGBE_LINK_SPEED_82599_AUTONEG;
36479da57d7bSbt150084 	}
36489da57d7bSbt150084 
36499da57d7bSbt150084 	if (setup_hw) {
36507e579c30SDale Ghent 		if (ixgbe_setup_link(&ixgbe->hw, advertised,
36517e579c30SDale Ghent 		    ixgbe->param_adv_autoneg_cap) != IXGBE_SUCCESS) {
365273cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe_notice(ixgbe, "Setup link failed on this "
365373cd555cSBin Tu - Sun Microsystems - Beijing China 			    "device.");
36549da57d7bSbt150084 			return (IXGBE_FAILURE);
36559da57d7bSbt150084 		}
365673cd555cSBin Tu - Sun Microsystems - Beijing China 	}
36579da57d7bSbt150084 
36589da57d7bSbt150084 	return (IXGBE_SUCCESS);
36599da57d7bSbt150084 }
36609da57d7bSbt150084 
36619da57d7bSbt150084 /*
366262e6e1adSPaul Guo  * ixgbe_driver_link_check - Link status processing.
366362e6e1adSPaul Guo  *
366462e6e1adSPaul Guo  * This function can be called in both kernel context and interrupt context
36659da57d7bSbt150084  */
366613740cb2SPaul Guo static void
366762e6e1adSPaul Guo ixgbe_driver_link_check(ixgbe_t *ixgbe)
36689da57d7bSbt150084 {
36699da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
36709da57d7bSbt150084 	ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
36719da57d7bSbt150084 	boolean_t link_up = B_FALSE;
36729da57d7bSbt150084 	boolean_t link_changed = B_FALSE;
36739da57d7bSbt150084 
367462e6e1adSPaul Guo 	ASSERT(mutex_owned(&ixgbe->gen_lock));
36759da57d7bSbt150084 
36767e579c30SDale Ghent 	(void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
36779da57d7bSbt150084 	if (link_up) {
367862e6e1adSPaul Guo 		ixgbe->link_check_complete = B_TRUE;
367962e6e1adSPaul Guo 
368073cd555cSBin Tu - Sun Microsystems - Beijing China 		/* Link is up, enable flow control settings */
368169b5a878SDan McDonald 		(void) ixgbe_fc_enable(hw);
368273cd555cSBin Tu - Sun Microsystems - Beijing China 
36839da57d7bSbt150084 		/*
36849da57d7bSbt150084 		 * The Link is up, check whether it was marked as down earlier
36859da57d7bSbt150084 		 */
36869da57d7bSbt150084 		if (ixgbe->link_state != LINK_STATE_UP) {
36879da57d7bSbt150084 			switch (speed) {
36889da57d7bSbt150084 			case IXGBE_LINK_SPEED_10GB_FULL:
36899da57d7bSbt150084 				ixgbe->link_speed = SPEED_10GB;
36909da57d7bSbt150084 				break;
36917e579c30SDale Ghent 			case IXGBE_LINK_SPEED_5GB_FULL:
36927e579c30SDale Ghent 				ixgbe->link_speed = SPEED_5GB;
36937e579c30SDale Ghent 				break;
36947e579c30SDale Ghent 			case IXGBE_LINK_SPEED_2_5GB_FULL:
36957e579c30SDale Ghent 				ixgbe->link_speed = SPEED_2_5GB;
36967e579c30SDale Ghent 				break;
36979da57d7bSbt150084 			case IXGBE_LINK_SPEED_1GB_FULL:
36989da57d7bSbt150084 				ixgbe->link_speed = SPEED_1GB;
36999da57d7bSbt150084 				break;
37009da57d7bSbt150084 			case IXGBE_LINK_SPEED_100_FULL:
37019da57d7bSbt150084 				ixgbe->link_speed = SPEED_100;
37029da57d7bSbt150084 			}
37039da57d7bSbt150084 			ixgbe->link_duplex = LINK_DUPLEX_FULL;
37049da57d7bSbt150084 			ixgbe->link_state = LINK_STATE_UP;
37059da57d7bSbt150084 			link_changed = B_TRUE;
37069da57d7bSbt150084 		}
37079da57d7bSbt150084 	} else {
370862e6e1adSPaul Guo 		if (ixgbe->link_check_complete == B_TRUE ||
370962e6e1adSPaul Guo 		    (ixgbe->link_check_complete == B_FALSE &&
371062e6e1adSPaul Guo 		    gethrtime() >= ixgbe->link_check_hrtime)) {
371162e6e1adSPaul Guo 			/*
371262e6e1adSPaul Guo 			 * The link is really down
371362e6e1adSPaul Guo 			 */
371462e6e1adSPaul Guo 			ixgbe->link_check_complete = B_TRUE;
371562e6e1adSPaul Guo 
37169da57d7bSbt150084 			if (ixgbe->link_state != LINK_STATE_DOWN) {
37179da57d7bSbt150084 				ixgbe->link_speed = 0;
371862e6e1adSPaul Guo 				ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN;
37199da57d7bSbt150084 				ixgbe->link_state = LINK_STATE_DOWN;
37209da57d7bSbt150084 				link_changed = B_TRUE;
37219da57d7bSbt150084 			}
37229da57d7bSbt150084 		}
372362e6e1adSPaul Guo 	}
37249da57d7bSbt150084 
372513740cb2SPaul Guo 	/*
372662e6e1adSPaul Guo 	 * If we are in an interrupt context, need to re-enable the
372762e6e1adSPaul Guo 	 * interrupt, which was automasked
372862e6e1adSPaul Guo 	 */
372962e6e1adSPaul Guo 	if (servicing_interrupt() != 0) {
373013740cb2SPaul Guo 		ixgbe->eims |= IXGBE_EICR_LSC;
373113740cb2SPaul Guo 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
373262e6e1adSPaul Guo 	}
373313740cb2SPaul Guo 
373413740cb2SPaul Guo 	if (link_changed) {
373513740cb2SPaul Guo 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
373613740cb2SPaul Guo 	}
37379da57d7bSbt150084 }
37389da57d7bSbt150084 
37399da57d7bSbt150084 /*
374073cd555cSBin Tu - Sun Microsystems - Beijing China  * ixgbe_sfp_check - sfp module processing done in taskq only for 82599.
374173cd555cSBin Tu - Sun Microsystems - Beijing China  */
374273cd555cSBin Tu - Sun Microsystems - Beijing China static void
374373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_sfp_check(void *arg)
374473cd555cSBin Tu - Sun Microsystems - Beijing China {
374573cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
374673cd555cSBin Tu - Sun Microsystems - Beijing China 	uint32_t eicr = ixgbe->eicr;
374773cd555cSBin Tu - Sun Microsystems - Beijing China 	struct ixgbe_hw *hw = &ixgbe->hw;
374873cd555cSBin Tu - Sun Microsystems - Beijing China 
374962e6e1adSPaul Guo 	mutex_enter(&ixgbe->gen_lock);
3750*59596c01SRobert Mustacchi 	(void) hw->phy.ops.identify_sfp(hw);
37517e579c30SDale Ghent 	if (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) {
375273cd555cSBin Tu - Sun Microsystems - Beijing China 		/* clear the interrupt */
37537e579c30SDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
375473cd555cSBin Tu - Sun Microsystems - Beijing China 
375573cd555cSBin Tu - Sun Microsystems - Beijing China 		/* if link up, do multispeed fiber setup */
37563cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
37577e579c30SDale Ghent 		    B_TRUE);
375873cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_driver_link_check(ixgbe);
37595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_get_hw_state(ixgbe);
37607e579c30SDale Ghent 	} else if (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)) {
376173cd555cSBin Tu - Sun Microsystems - Beijing China 		/* clear the interrupt */
37627e579c30SDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2_BY_MAC(hw));
376373cd555cSBin Tu - Sun Microsystems - Beijing China 
376473cd555cSBin Tu - Sun Microsystems - Beijing China 		/* if link up, do sfp module setup */
376573cd555cSBin Tu - Sun Microsystems - Beijing China 		(void) hw->mac.ops.setup_sfp(hw);
376673cd555cSBin Tu - Sun Microsystems - Beijing China 
376773cd555cSBin Tu - Sun Microsystems - Beijing China 		/* do multispeed fiber setup */
37683cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
37697e579c30SDale Ghent 		    B_TRUE);
377073cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_driver_link_check(ixgbe);
37715b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_get_hw_state(ixgbe);
377273cd555cSBin Tu - Sun Microsystems - Beijing China 	}
377362e6e1adSPaul Guo 	mutex_exit(&ixgbe->gen_lock);
37745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
37755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
37765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * We need to fully re-check the link later.
37775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
37785b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->link_check_complete = B_FALSE;
37795b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->link_check_hrtime = gethrtime() +
37805b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
37815b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
37825b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
37835b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
37845b6dd21fSchenlu chen - Sun Microsystems - Beijing China  * ixgbe_overtemp_check - overtemp module processing done in taskq
37855b6dd21fSchenlu chen - Sun Microsystems - Beijing China  *
37865b6dd21fSchenlu chen - Sun Microsystems - Beijing China  * This routine will only be called on adapters with temperature sensor.
37875b6dd21fSchenlu chen - Sun Microsystems - Beijing China  * The indication of over-temperature can be either SDP0 interrupt or the link
37885b6dd21fSchenlu chen - Sun Microsystems - Beijing China  * status change interrupt.
37895b6dd21fSchenlu chen - Sun Microsystems - Beijing China  */
37905b6dd21fSchenlu chen - Sun Microsystems - Beijing China static void
37915b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_overtemp_check(void *arg)
37925b6dd21fSchenlu chen - Sun Microsystems - Beijing China {
37935b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
37945b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	struct ixgbe_hw *hw = &ixgbe->hw;
37955b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	uint32_t eicr = ixgbe->eicr;
37965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_link_speed speed;
37975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	boolean_t link_up;
37985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
37995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	mutex_enter(&ixgbe->gen_lock);
38005b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
38015b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* make sure we know current state of link */
38027e579c30SDale Ghent 	(void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
38035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
38045b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* check over-temp condition */
38057e579c30SDale Ghent 	if (((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) && (!link_up)) ||
38065b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    (eicr & IXGBE_EICR_LSC)) {
38075b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) {
38085b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
38095b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
38105b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			/*
38115b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			 * Disable the adapter interrupts
38125b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			 */
38135b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_disable_adapter_interrupts(ixgbe);
38145b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
38155b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			/*
38165b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			 * Disable Rx/Tx units
38175b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			 */
38185b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			(void) ixgbe_stop_adapter(hw);
38195b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
38205b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
38215b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_error(ixgbe,
38225b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "Problem: Network adapter has been stopped "
38235b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "because it has overheated");
38245b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_error(ixgbe,
38255b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "Action: Restart the computer. "
38265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "If the problem persists, power off the system "
38275b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "and replace the adapter");
38285b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
38295b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
38305b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
38315b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* write to clear the interrupt */
38325b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
38335b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
38345b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	mutex_exit(&ixgbe->gen_lock);
383562e6e1adSPaul Guo }
383662e6e1adSPaul Guo 
383762e6e1adSPaul Guo /*
38387e579c30SDale Ghent  * ixgbe_phy_check - taskq to process interrupts from an external PHY
38397e579c30SDale Ghent  *
38407e579c30SDale Ghent  * This routine will only be called on adapters with external PHYs
38417e579c30SDale Ghent  * (such as X550) that may be trying to raise our attention to some event.
38427e579c30SDale Ghent  * Currently, this is limited to claiming PHY overtemperature and link status
38437e579c30SDale Ghent  * change (LSC) events, however this may expand to include other things in
38447e579c30SDale Ghent  * future adapters.
38457e579c30SDale Ghent  */
38467e579c30SDale Ghent static void
38477e579c30SDale Ghent ixgbe_phy_check(void *arg)
38487e579c30SDale Ghent {
38497e579c30SDale Ghent 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
38507e579c30SDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
38517e579c30SDale Ghent 	int rv;
38527e579c30SDale Ghent 
38537e579c30SDale Ghent 	mutex_enter(&ixgbe->gen_lock);
38547e579c30SDale Ghent 
38557e579c30SDale Ghent 	/*
38567e579c30SDale Ghent 	 * X550 baseT PHY overtemp and LSC events are handled here.
38577e579c30SDale Ghent 	 *
38587e579c30SDale Ghent 	 * If an overtemp event occurs, it will be reflected in the
38597e579c30SDale Ghent 	 * return value of phy.ops.handle_lasi() and the common code will
38607e579c30SDale Ghent 	 * automatically power off the baseT PHY. This is our cue to trigger
38617e579c30SDale Ghent 	 * an FMA event.
38627e579c30SDale Ghent 	 *
38637e579c30SDale Ghent 	 * If a link status change event occurs, phy.ops.handle_lasi() will
38647e579c30SDale Ghent 	 * automatically initiate a link setup between the integrated KR PHY
38657e579c30SDale Ghent 	 * and the external X557 PHY to ensure that the link speed between
38667e579c30SDale Ghent 	 * them matches the link speed of the baseT link.
38677e579c30SDale Ghent 	 */
38687e579c30SDale Ghent 	rv = ixgbe_handle_lasi(hw);
38697e579c30SDale Ghent 
38707e579c30SDale Ghent 	if (rv == IXGBE_ERR_OVERTEMP) {
38717e579c30SDale Ghent 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
38727e579c30SDale Ghent 
38737e579c30SDale Ghent 		/*
38747e579c30SDale Ghent 		 * Disable the adapter interrupts
38757e579c30SDale Ghent 		 */
38767e579c30SDale Ghent 		ixgbe_disable_adapter_interrupts(ixgbe);
38777e579c30SDale Ghent 
38787e579c30SDale Ghent 		/*
38797e579c30SDale Ghent 		 * Disable Rx/Tx units
38807e579c30SDale Ghent 		 */
38817e579c30SDale Ghent 		(void) ixgbe_stop_adapter(hw);
38827e579c30SDale Ghent 
38837e579c30SDale Ghent 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
38847e579c30SDale Ghent 		ixgbe_error(ixgbe,
38857e579c30SDale Ghent 		    "Problem: Network adapter has been stopped due to a "
38867e579c30SDale Ghent 		    "overtemperature event being detected.");
38877e579c30SDale Ghent 		ixgbe_error(ixgbe,
38887e579c30SDale Ghent 		    "Action: Shut down or restart the computer. If the issue "
38897e579c30SDale Ghent 		    "persists, please take action in accordance with the "
38907e579c30SDale Ghent 		    "recommendations from your system vendor.");
38917e579c30SDale Ghent 	}
38927e579c30SDale Ghent 
38937e579c30SDale Ghent 	mutex_exit(&ixgbe->gen_lock);
38947e579c30SDale Ghent }
38957e579c30SDale Ghent 
38967e579c30SDale Ghent /*
389762e6e1adSPaul Guo  * ixgbe_link_timer - timer for link status detection
389862e6e1adSPaul Guo  */
389962e6e1adSPaul Guo static void
390062e6e1adSPaul Guo ixgbe_link_timer(void *arg)
390162e6e1adSPaul Guo {
390262e6e1adSPaul Guo 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
390362e6e1adSPaul Guo 
390462e6e1adSPaul Guo 	mutex_enter(&ixgbe->gen_lock);
390562e6e1adSPaul Guo 	ixgbe_driver_link_check(ixgbe);
390662e6e1adSPaul Guo 	mutex_exit(&ixgbe->gen_lock);
390773cd555cSBin Tu - Sun Microsystems - Beijing China }
390873cd555cSBin Tu - Sun Microsystems - Beijing China 
390973cd555cSBin Tu - Sun Microsystems - Beijing China /*
39109da57d7bSbt150084  * ixgbe_local_timer - Driver watchdog function.
39119da57d7bSbt150084  *
391262e6e1adSPaul Guo  * This function will handle the transmit stall check and other routines.
39139da57d7bSbt150084  */
39149da57d7bSbt150084 static void
39159da57d7bSbt150084 ixgbe_local_timer(void *arg)
39169da57d7bSbt150084 {
39179da57d7bSbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
39189da57d7bSbt150084 
39195b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->ixgbe_state & IXGBE_OVERTEMP)
39205b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto out;
39215b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
392262e6e1adSPaul Guo 	if (ixgbe->ixgbe_state & IXGBE_ERROR) {
39239da57d7bSbt150084 		ixgbe->reset_count++;
39249da57d7bSbt150084 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
39259da57d7bSbt150084 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
39265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto out;
39279da57d7bSbt150084 	}
39289da57d7bSbt150084 
392962e6e1adSPaul Guo 	if (ixgbe_stall_check(ixgbe)) {
393062e6e1adSPaul Guo 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL);
393162e6e1adSPaul Guo 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
393262e6e1adSPaul Guo 
393362e6e1adSPaul Guo 		ixgbe->reset_count++;
393462e6e1adSPaul Guo 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
393562e6e1adSPaul Guo 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
39369da57d7bSbt150084 	}
3937ffd8e883SWinson Wang - Sun Microsystems - Beijing China 
39385b6dd21fSchenlu chen - Sun Microsystems - Beijing China out:
3939ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	ixgbe_restart_watchdog_timer(ixgbe);
394062e6e1adSPaul Guo }
39419da57d7bSbt150084 
39429da57d7bSbt150084 /*
39439da57d7bSbt150084  * ixgbe_stall_check - Check for transmit stall.
39449da57d7bSbt150084  *
39459da57d7bSbt150084  * This function checks if the adapter is stalled (in transmit).
39469da57d7bSbt150084  *
39479da57d7bSbt150084  * It is called each time the watchdog timeout is invoked.
39489da57d7bSbt150084  * If the transmit descriptor reclaim continuously fails,
39499da57d7bSbt150084  * the watchdog value will increment by 1. If the watchdog
39509da57d7bSbt150084  * value exceeds the threshold, the ixgbe is assumed to
39519da57d7bSbt150084  * have stalled and need to be reset.
39529da57d7bSbt150084  */
39539da57d7bSbt150084 static boolean_t
39549da57d7bSbt150084 ixgbe_stall_check(ixgbe_t *ixgbe)
39559da57d7bSbt150084 {
39569da57d7bSbt150084 	ixgbe_tx_ring_t *tx_ring;
39579da57d7bSbt150084 	boolean_t result;
39589da57d7bSbt150084 	int i;
39599da57d7bSbt150084 
39609da57d7bSbt150084 	if (ixgbe->link_state != LINK_STATE_UP)
39619da57d7bSbt150084 		return (B_FALSE);
39629da57d7bSbt150084 
39639da57d7bSbt150084 	/*
39649da57d7bSbt150084 	 * If any tx ring is stalled, we'll reset the chipset
39659da57d7bSbt150084 	 */
39669da57d7bSbt150084 	result = B_FALSE;
39679da57d7bSbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
39689da57d7bSbt150084 		tx_ring = &ixgbe->tx_rings[i];
3969ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) {
3970da14cebeSEric Cheng 			tx_ring->tx_recycle(tx_ring);
3971185c5677SPaul Guo 		}
39729da57d7bSbt150084 
39739da57d7bSbt150084 		if (tx_ring->recycle_fail > 0)
39749da57d7bSbt150084 			tx_ring->stall_watchdog++;
39759da57d7bSbt150084 		else
39769da57d7bSbt150084 			tx_ring->stall_watchdog = 0;
39779da57d7bSbt150084 
39789da57d7bSbt150084 		if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) {
39799da57d7bSbt150084 			result = B_TRUE;
39809da57d7bSbt150084 			break;
39819da57d7bSbt150084 		}
39829da57d7bSbt150084 	}
39839da57d7bSbt150084 
39849da57d7bSbt150084 	if (result) {
39859da57d7bSbt150084 		tx_ring->stall_watchdog = 0;
39869da57d7bSbt150084 		tx_ring->recycle_fail = 0;
39879da57d7bSbt150084 	}
39889da57d7bSbt150084 
39899da57d7bSbt150084 	return (result);
39909da57d7bSbt150084 }
39919da57d7bSbt150084 
39929da57d7bSbt150084 
39939da57d7bSbt150084 /*
39949da57d7bSbt150084  * is_valid_mac_addr - Check if the mac address is valid.
39959da57d7bSbt150084  */
39969da57d7bSbt150084 static boolean_t
39979da57d7bSbt150084 is_valid_mac_addr(uint8_t *mac_addr)
39989da57d7bSbt150084 {
39999da57d7bSbt150084 	const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 };
40009da57d7bSbt150084 	const uint8_t addr_test2[6] =
40019da57d7bSbt150084 	    { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
40029da57d7bSbt150084 
40039da57d7bSbt150084 	if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) ||
40049da57d7bSbt150084 	    !(bcmp(addr_test2, mac_addr, ETHERADDRL)))
40059da57d7bSbt150084 		return (B_FALSE);
40069da57d7bSbt150084 
40079da57d7bSbt150084 	return (B_TRUE);
40089da57d7bSbt150084 }
40099da57d7bSbt150084 
40109da57d7bSbt150084 static boolean_t
40119da57d7bSbt150084 ixgbe_find_mac_address(ixgbe_t *ixgbe)
40129da57d7bSbt150084 {
40139da57d7bSbt150084 #ifdef __sparc
40149da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
40159da57d7bSbt150084 	uchar_t *bytes;
40169da57d7bSbt150084 	struct ether_addr sysaddr;
40179da57d7bSbt150084 	uint_t nelts;
40189da57d7bSbt150084 	int err;
40199da57d7bSbt150084 	boolean_t found = B_FALSE;
40209da57d7bSbt150084 
40219da57d7bSbt150084 	/*
40229da57d7bSbt150084 	 * The "vendor's factory-set address" may already have
40239da57d7bSbt150084 	 * been extracted from the chip, but if the property
40249da57d7bSbt150084 	 * "local-mac-address" is set we use that instead.
40259da57d7bSbt150084 	 *
40269da57d7bSbt150084 	 * We check whether it looks like an array of 6
40279da57d7bSbt150084 	 * bytes (which it should, if OBP set it).  If we can't
40289da57d7bSbt150084 	 * make sense of it this way, we'll ignore it.
40299da57d7bSbt150084 	 */
40309da57d7bSbt150084 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
40319da57d7bSbt150084 	    DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts);
40329da57d7bSbt150084 	if (err == DDI_PROP_SUCCESS) {
40339da57d7bSbt150084 		if (nelts == ETHERADDRL) {
40349da57d7bSbt150084 			while (nelts--)
40359da57d7bSbt150084 				hw->mac.addr[nelts] = bytes[nelts];
40369da57d7bSbt150084 			found = B_TRUE;
40379da57d7bSbt150084 		}
40389da57d7bSbt150084 		ddi_prop_free(bytes);
40399da57d7bSbt150084 	}
40409da57d7bSbt150084 
40419da57d7bSbt150084 	/*
40429da57d7bSbt150084 	 * Look up the OBP property "local-mac-address?". If the user has set
40439da57d7bSbt150084 	 * 'local-mac-address? = false', use "the system address" instead.
40449da57d7bSbt150084 	 */
40459da57d7bSbt150084 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0,
40469da57d7bSbt150084 	    "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) {
40479da57d7bSbt150084 		if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) {
40489da57d7bSbt150084 			if (localetheraddr(NULL, &sysaddr) != 0) {
40499da57d7bSbt150084 				bcopy(&sysaddr, hw->mac.addr, ETHERADDRL);
40509da57d7bSbt150084 				found = B_TRUE;
40519da57d7bSbt150084 			}
40529da57d7bSbt150084 		}
40539da57d7bSbt150084 		ddi_prop_free(bytes);
40549da57d7bSbt150084 	}
40559da57d7bSbt150084 
40569da57d7bSbt150084 	/*
40579da57d7bSbt150084 	 * Finally(!), if there's a valid "mac-address" property (created
40589da57d7bSbt150084 	 * if we netbooted from this interface), we must use this instead
40599da57d7bSbt150084 	 * of any of the above to ensure that the NFS/install server doesn't
40607e579c30SDale Ghent 	 * get confused by the address changing as illumos takes over!
40619da57d7bSbt150084 	 */
40629da57d7bSbt150084 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
40639da57d7bSbt150084 	    DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts);
40649da57d7bSbt150084 	if (err == DDI_PROP_SUCCESS) {
40659da57d7bSbt150084 		if (nelts == ETHERADDRL) {
40669da57d7bSbt150084 			while (nelts--)
40679da57d7bSbt150084 				hw->mac.addr[nelts] = bytes[nelts];
40689da57d7bSbt150084 			found = B_TRUE;
40699da57d7bSbt150084 		}
40709da57d7bSbt150084 		ddi_prop_free(bytes);
40719da57d7bSbt150084 	}
40729da57d7bSbt150084 
40739da57d7bSbt150084 	if (found) {
40749da57d7bSbt150084 		bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
40759da57d7bSbt150084 		return (B_TRUE);
40769da57d7bSbt150084 	}
40779da57d7bSbt150084 #else
40789da57d7bSbt150084 	_NOTE(ARGUNUSED(ixgbe));
40799da57d7bSbt150084 #endif
40809da57d7bSbt150084 
40819da57d7bSbt150084 	return (B_TRUE);
40829da57d7bSbt150084 }
40839da57d7bSbt150084 
40849da57d7bSbt150084 #pragma inline(ixgbe_arm_watchdog_timer)
40859da57d7bSbt150084 static void
40869da57d7bSbt150084 ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe)
40879da57d7bSbt150084 {
40889da57d7bSbt150084 	/*
40899da57d7bSbt150084 	 * Fire a watchdog timer
40909da57d7bSbt150084 	 */
40919da57d7bSbt150084 	ixgbe->watchdog_tid =
40929da57d7bSbt150084 	    timeout(ixgbe_local_timer,
40939da57d7bSbt150084 	    (void *)ixgbe, 1 * drv_usectohz(1000000));
40949da57d7bSbt150084 
40959da57d7bSbt150084 }
40969da57d7bSbt150084 
40979da57d7bSbt150084 /*
40989da57d7bSbt150084  * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer.
40999da57d7bSbt150084  */
41009da57d7bSbt150084 void
41019da57d7bSbt150084 ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe)
41029da57d7bSbt150084 {
41039da57d7bSbt150084 	mutex_enter(&ixgbe->watchdog_lock);
41049da57d7bSbt150084 
41059da57d7bSbt150084 	if (!ixgbe->watchdog_enable) {
41069da57d7bSbt150084 		ixgbe->watchdog_enable = B_TRUE;
41079da57d7bSbt150084 		ixgbe->watchdog_start = B_TRUE;
41089da57d7bSbt150084 		ixgbe_arm_watchdog_timer(ixgbe);
41099da57d7bSbt150084 	}
41109da57d7bSbt150084 
41119da57d7bSbt150084 	mutex_exit(&ixgbe->watchdog_lock);
41129da57d7bSbt150084 }
41139da57d7bSbt150084 
41149da57d7bSbt150084 /*
41159da57d7bSbt150084  * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer.
41169da57d7bSbt150084  */
41179da57d7bSbt150084 void
41189da57d7bSbt150084 ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe)
41199da57d7bSbt150084 {
41209da57d7bSbt150084 	timeout_id_t tid;
41219da57d7bSbt150084 
41229da57d7bSbt150084 	mutex_enter(&ixgbe->watchdog_lock);
41239da57d7bSbt150084 
41249da57d7bSbt150084 	ixgbe->watchdog_enable = B_FALSE;
41259da57d7bSbt150084 	ixgbe->watchdog_start = B_FALSE;
41269da57d7bSbt150084 	tid = ixgbe->watchdog_tid;
41279da57d7bSbt150084 	ixgbe->watchdog_tid = 0;
41289da57d7bSbt150084 
41299da57d7bSbt150084 	mutex_exit(&ixgbe->watchdog_lock);
41309da57d7bSbt150084 
41319da57d7bSbt150084 	if (tid != 0)
41329da57d7bSbt150084 		(void) untimeout(tid);
41339da57d7bSbt150084 }
41349da57d7bSbt150084 
41359da57d7bSbt150084 /*
41369da57d7bSbt150084  * ixgbe_start_watchdog_timer - Start the driver watchdog timer.
41379da57d7bSbt150084  */
413813740cb2SPaul Guo void
41399da57d7bSbt150084 ixgbe_start_watchdog_timer(ixgbe_t *ixgbe)
41409da57d7bSbt150084 {
41419da57d7bSbt150084 	mutex_enter(&ixgbe->watchdog_lock);
41429da57d7bSbt150084 
41439da57d7bSbt150084 	if (ixgbe->watchdog_enable) {
41449da57d7bSbt150084 		if (!ixgbe->watchdog_start) {
41459da57d7bSbt150084 			ixgbe->watchdog_start = B_TRUE;
41469da57d7bSbt150084 			ixgbe_arm_watchdog_timer(ixgbe);
41479da57d7bSbt150084 		}
41489da57d7bSbt150084 	}
41499da57d7bSbt150084 
41509da57d7bSbt150084 	mutex_exit(&ixgbe->watchdog_lock);
41519da57d7bSbt150084 }
41529da57d7bSbt150084 
41539da57d7bSbt150084 /*
41549da57d7bSbt150084  * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer.
41559da57d7bSbt150084  */
41569da57d7bSbt150084 static void
41579da57d7bSbt150084 ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe)
41589da57d7bSbt150084 {
41599da57d7bSbt150084 	mutex_enter(&ixgbe->watchdog_lock);
41609da57d7bSbt150084 
41619da57d7bSbt150084 	if (ixgbe->watchdog_start)
41629da57d7bSbt150084 		ixgbe_arm_watchdog_timer(ixgbe);
41639da57d7bSbt150084 
41649da57d7bSbt150084 	mutex_exit(&ixgbe->watchdog_lock);
41659da57d7bSbt150084 }
41669da57d7bSbt150084 
41679da57d7bSbt150084 /*
41689da57d7bSbt150084  * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer.
41699da57d7bSbt150084  */
417013740cb2SPaul Guo void
41719da57d7bSbt150084 ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe)
41729da57d7bSbt150084 {
41739da57d7bSbt150084 	timeout_id_t tid;
41749da57d7bSbt150084 
41759da57d7bSbt150084 	mutex_enter(&ixgbe->watchdog_lock);
41769da57d7bSbt150084 
41779da57d7bSbt150084 	ixgbe->watchdog_start = B_FALSE;
41789da57d7bSbt150084 	tid = ixgbe->watchdog_tid;
41799da57d7bSbt150084 	ixgbe->watchdog_tid = 0;
41809da57d7bSbt150084 
41819da57d7bSbt150084 	mutex_exit(&ixgbe->watchdog_lock);
41829da57d7bSbt150084 
41839da57d7bSbt150084 	if (tid != 0)
41849da57d7bSbt150084 		(void) untimeout(tid);
41859da57d7bSbt150084 }
41869da57d7bSbt150084 
41879da57d7bSbt150084 /*
41889da57d7bSbt150084  * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts.
41899da57d7bSbt150084  */
41909da57d7bSbt150084 static void
41919da57d7bSbt150084 ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe)
41929da57d7bSbt150084 {
41939da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
41949da57d7bSbt150084 
41959da57d7bSbt150084 	/*
41969da57d7bSbt150084 	 * mask all interrupts off
41979da57d7bSbt150084 	 */
41989da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff);
41999da57d7bSbt150084 
42009da57d7bSbt150084 	/*
42019da57d7bSbt150084 	 * for MSI-X, also disable autoclear
42029da57d7bSbt150084 	 */
42039da57d7bSbt150084 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
42049da57d7bSbt150084 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0);
42059da57d7bSbt150084 	}
42069da57d7bSbt150084 
42079da57d7bSbt150084 	IXGBE_WRITE_FLUSH(hw);
42089da57d7bSbt150084 }
42099da57d7bSbt150084 
42109da57d7bSbt150084 /*
42119da57d7bSbt150084  * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts.
42129da57d7bSbt150084  */
42139da57d7bSbt150084 static void
42149da57d7bSbt150084 ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe)
42159da57d7bSbt150084 {
42169da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
421713740cb2SPaul Guo 	uint32_t eiac, eiam;
421813740cb2SPaul Guo 	uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
42199da57d7bSbt150084 
422013740cb2SPaul Guo 	/* interrupt types to enable */
422113740cb2SPaul Guo 	ixgbe->eims = IXGBE_EIMS_ENABLE_MASK;	/* shared code default */
422213740cb2SPaul Guo 	ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER;	/* minus tcp timer */
422313740cb2SPaul Guo 	ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */
422413740cb2SPaul Guo 
422513740cb2SPaul Guo 	/* enable automask on "other" causes that this adapter can generate */
422613740cb2SPaul Guo 	eiam = ixgbe->capab->other_intr;
42279da57d7bSbt150084 
42289da57d7bSbt150084 	/*
42299da57d7bSbt150084 	 * msi-x mode
42309da57d7bSbt150084 	 */
42319da57d7bSbt150084 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
42329da57d7bSbt150084 		/* enable autoclear but not on bits 29:20 */
423313740cb2SPaul Guo 		eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR);
42349da57d7bSbt150084 
42359da57d7bSbt150084 		/* general purpose interrupt enable */
423613740cb2SPaul Guo 		gpie |= (IXGBE_GPIE_MSIX_MODE
423713740cb2SPaul Guo 		    | IXGBE_GPIE_PBA_SUPPORT
423813740cb2SPaul Guo 		    | IXGBE_GPIE_OCD
423913740cb2SPaul Guo 		    | IXGBE_GPIE_EIAME);
42409da57d7bSbt150084 	/*
42419da57d7bSbt150084 	 * non-msi-x mode
42429da57d7bSbt150084 	 */
42439da57d7bSbt150084 	} else {
42449da57d7bSbt150084 
42459da57d7bSbt150084 		/* disable autoclear, leave gpie at default */
42469da57d7bSbt150084 		eiac = 0;
424713740cb2SPaul Guo 
424873cd555cSBin Tu - Sun Microsystems - Beijing China 		/*
424973cd555cSBin Tu - Sun Microsystems - Beijing China 		 * General purpose interrupt enable.
42507e579c30SDale Ghent 		 * For 82599, X540 and X550, extended interrupt
42517e579c30SDale Ghent 		 * automask enable only in MSI or MSI-X mode
425273cd555cSBin Tu - Sun Microsystems - Beijing China 		 */
425369b5a878SDan McDonald 		if ((hw->mac.type == ixgbe_mac_82598EB) ||
425473cd555cSBin Tu - Sun Microsystems - Beijing China 		    (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) {
425513740cb2SPaul Guo 			gpie |= IXGBE_GPIE_EIAME;
42569da57d7bSbt150084 		}
425773cd555cSBin Tu - Sun Microsystems - Beijing China 	}
42585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
42595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* Enable specific "other" interrupt types */
42605b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
42615b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
42625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		gpie |= ixgbe->capab->other_gpie;
42635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
42645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
42655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
426669b5a878SDan McDonald 	case ixgbe_mac_X540:
42677e579c30SDale Ghent 	case ixgbe_mac_X550:
42687e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
42695b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		gpie |= ixgbe->capab->other_gpie;
42705b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
42715b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		/* Enable RSC Delay 8us when LRO enabled  */
4272ffd8e883SWinson Wang - Sun Microsystems - Beijing China 		if (ixgbe->lro_enable) {
4273ffd8e883SWinson Wang - Sun Microsystems - Beijing China 			gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT);
4274ffd8e883SWinson Wang - Sun Microsystems - Beijing China 		}
42755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
42765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
42775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	default:
42785b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
42795b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
42805b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
428113740cb2SPaul Guo 	/* write to interrupt control registers */
428213740cb2SPaul Guo 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
42839da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac);
428413740cb2SPaul Guo 	IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam);
42859da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
42869da57d7bSbt150084 	IXGBE_WRITE_FLUSH(hw);
42879da57d7bSbt150084 }
42889da57d7bSbt150084 
42899da57d7bSbt150084 /*
42909da57d7bSbt150084  * ixgbe_loopback_ioctl - Loopback support.
42919da57d7bSbt150084  */
42929da57d7bSbt150084 enum ioc_reply
42939da57d7bSbt150084 ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp)
42949da57d7bSbt150084 {
42959da57d7bSbt150084 	lb_info_sz_t *lbsp;
42969da57d7bSbt150084 	lb_property_t *lbpp;
42979da57d7bSbt150084 	uint32_t *lbmp;
42989da57d7bSbt150084 	uint32_t size;
42999da57d7bSbt150084 	uint32_t value;
43009da57d7bSbt150084 
43019da57d7bSbt150084 	if (mp->b_cont == NULL)
43029da57d7bSbt150084 		return (IOC_INVAL);
43039da57d7bSbt150084 
43049da57d7bSbt150084 	switch (iocp->ioc_cmd) {
43059da57d7bSbt150084 	default:
43069da57d7bSbt150084 		return (IOC_INVAL);
43079da57d7bSbt150084 
43089da57d7bSbt150084 	case LB_GET_INFO_SIZE:
43099da57d7bSbt150084 		size = sizeof (lb_info_sz_t);
43109da57d7bSbt150084 		if (iocp->ioc_count != size)
43119da57d7bSbt150084 			return (IOC_INVAL);
43129da57d7bSbt150084 
43139da57d7bSbt150084 		value = sizeof (lb_normal);
43149da57d7bSbt150084 		value += sizeof (lb_mac);
43151fedc51fSWinson Wang - Sun Microsystems - Beijing China 		value += sizeof (lb_external);
43169da57d7bSbt150084 
43179da57d7bSbt150084 		lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr;
43189da57d7bSbt150084 		*lbsp = value;
43199da57d7bSbt150084 		break;
43209da57d7bSbt150084 
43219da57d7bSbt150084 	case LB_GET_INFO:
43229da57d7bSbt150084 		value = sizeof (lb_normal);
43239da57d7bSbt150084 		value += sizeof (lb_mac);
43241fedc51fSWinson Wang - Sun Microsystems - Beijing China 		value += sizeof (lb_external);
43259da57d7bSbt150084 
43269da57d7bSbt150084 		size = value;
43279da57d7bSbt150084 		if (iocp->ioc_count != size)
43289da57d7bSbt150084 			return (IOC_INVAL);
43299da57d7bSbt150084 
43309da57d7bSbt150084 		value = 0;
43319da57d7bSbt150084 		lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr;
43329da57d7bSbt150084 
43339da57d7bSbt150084 		lbpp[value++] = lb_normal;
43349da57d7bSbt150084 		lbpp[value++] = lb_mac;
43351fedc51fSWinson Wang - Sun Microsystems - Beijing China 		lbpp[value++] = lb_external;
43369da57d7bSbt150084 		break;
43379da57d7bSbt150084 
43389da57d7bSbt150084 	case LB_GET_MODE:
43399da57d7bSbt150084 		size = sizeof (uint32_t);
43409da57d7bSbt150084 		if (iocp->ioc_count != size)
43419da57d7bSbt150084 			return (IOC_INVAL);
43429da57d7bSbt150084 
43439da57d7bSbt150084 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
43449da57d7bSbt150084 		*lbmp = ixgbe->loopback_mode;
43459da57d7bSbt150084 		break;
43469da57d7bSbt150084 
43479da57d7bSbt150084 	case LB_SET_MODE:
43489da57d7bSbt150084 		size = 0;
43499da57d7bSbt150084 		if (iocp->ioc_count != sizeof (uint32_t))
43509da57d7bSbt150084 			return (IOC_INVAL);
43519da57d7bSbt150084 
43529da57d7bSbt150084 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
43539da57d7bSbt150084 		if (!ixgbe_set_loopback_mode(ixgbe, *lbmp))
43549da57d7bSbt150084 			return (IOC_INVAL);
43559da57d7bSbt150084 		break;
43569da57d7bSbt150084 	}
43579da57d7bSbt150084 
43589da57d7bSbt150084 	iocp->ioc_count = size;
43599da57d7bSbt150084 	iocp->ioc_error = 0;
43609da57d7bSbt150084 
43619da57d7bSbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
43629da57d7bSbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
43639da57d7bSbt150084 		return (IOC_INVAL);
43649da57d7bSbt150084 	}
43659da57d7bSbt150084 
43669da57d7bSbt150084 	return (IOC_REPLY);
43679da57d7bSbt150084 }
43689da57d7bSbt150084 
43699da57d7bSbt150084 /*
43709da57d7bSbt150084  * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode.
43719da57d7bSbt150084  */
43729da57d7bSbt150084 static boolean_t
43739da57d7bSbt150084 ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode)
43749da57d7bSbt150084 {
43759da57d7bSbt150084 	if (mode == ixgbe->loopback_mode)
43769da57d7bSbt150084 		return (B_TRUE);
43779da57d7bSbt150084 
43789da57d7bSbt150084 	ixgbe->loopback_mode = mode;
43799da57d7bSbt150084 
43809da57d7bSbt150084 	if (mode == IXGBE_LB_NONE) {
43819da57d7bSbt150084 		/*
43829da57d7bSbt150084 		 * Reset the chip
43839da57d7bSbt150084 		 */
43849da57d7bSbt150084 		(void) ixgbe_reset(ixgbe);
43859da57d7bSbt150084 		return (B_TRUE);
43869da57d7bSbt150084 	}
43879da57d7bSbt150084 
43889da57d7bSbt150084 	mutex_enter(&ixgbe->gen_lock);
43899da57d7bSbt150084 
43909da57d7bSbt150084 	switch (mode) {
43919da57d7bSbt150084 	default:
43929da57d7bSbt150084 		mutex_exit(&ixgbe->gen_lock);
43939da57d7bSbt150084 		return (B_FALSE);
43949da57d7bSbt150084 
43951fedc51fSWinson Wang - Sun Microsystems - Beijing China 	case IXGBE_LB_EXTERNAL:
43961fedc51fSWinson Wang - Sun Microsystems - Beijing China 		break;
43971fedc51fSWinson Wang - Sun Microsystems - Beijing China 
43989da57d7bSbt150084 	case IXGBE_LB_INTERNAL_MAC:
43999da57d7bSbt150084 		ixgbe_set_internal_mac_loopback(ixgbe);
44009da57d7bSbt150084 		break;
44019da57d7bSbt150084 	}
44029da57d7bSbt150084 
44039da57d7bSbt150084 	mutex_exit(&ixgbe->gen_lock);
44049da57d7bSbt150084 
44059da57d7bSbt150084 	return (B_TRUE);
44069da57d7bSbt150084 }
44079da57d7bSbt150084 
44089da57d7bSbt150084 /*
44099da57d7bSbt150084  * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode.
44109da57d7bSbt150084  */
44119da57d7bSbt150084 static void
44129da57d7bSbt150084 ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe)
44139da57d7bSbt150084 {
44149da57d7bSbt150084 	struct ixgbe_hw *hw;
44159da57d7bSbt150084 	uint32_t reg;
44169da57d7bSbt150084 	uint8_t atlas;
44179da57d7bSbt150084 
44189da57d7bSbt150084 	hw = &ixgbe->hw;
44199da57d7bSbt150084 
44209da57d7bSbt150084 	/*
44219da57d7bSbt150084 	 * Setup MAC loopback
44229da57d7bSbt150084 	 */
44239da57d7bSbt150084 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0);
44249da57d7bSbt150084 	reg |= IXGBE_HLREG0_LPBK;
44259da57d7bSbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg);
44269da57d7bSbt150084 
44279da57d7bSbt150084 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
44289da57d7bSbt150084 	reg &= ~IXGBE_AUTOC_LMS_MASK;
44299da57d7bSbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
44309da57d7bSbt150084 
44319da57d7bSbt150084 	/*
44329da57d7bSbt150084 	 * Disable Atlas Tx lanes to keep packets in loopback and not on wire
44339da57d7bSbt150084 	 */
44345b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
44355b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
44369da57d7bSbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
44379da57d7bSbt150084 		    &atlas);
44389da57d7bSbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_REG_EN;
44399da57d7bSbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
44409da57d7bSbt150084 		    atlas);
44419da57d7bSbt150084 
44429da57d7bSbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
44439da57d7bSbt150084 		    &atlas);
44449da57d7bSbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
44459da57d7bSbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
44469da57d7bSbt150084 		    atlas);
44479da57d7bSbt150084 
44489da57d7bSbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
44499da57d7bSbt150084 		    &atlas);
44509da57d7bSbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
44519da57d7bSbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
44529da57d7bSbt150084 		    atlas);
44539da57d7bSbt150084 
44549da57d7bSbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
44559da57d7bSbt150084 		    &atlas);
44569da57d7bSbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
44579da57d7bSbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
44589da57d7bSbt150084 		    atlas);
44595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
44605b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
44615b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
446269b5a878SDan McDonald 	case ixgbe_mac_X540:
44637e579c30SDale Ghent 	case ixgbe_mac_X550:
44647e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
446500f1c25aSchenlu chen - Sun Microsystems - Beijing China 		reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
446600f1c25aSchenlu chen - Sun Microsystems - Beijing China 		reg |= (IXGBE_AUTOC_FLU |
446700f1c25aSchenlu chen - Sun Microsystems - Beijing China 		    IXGBE_AUTOC_10G_KX4);
446800f1c25aSchenlu chen - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
446900f1c25aSchenlu chen - Sun Microsystems - Beijing China 
447000f1c25aSchenlu chen - Sun Microsystems - Beijing China 		(void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL,
44717e579c30SDale Ghent 		    B_FALSE);
44725b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
44735b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
44745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	default:
44755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
44769da57d7bSbt150084 	}
44779da57d7bSbt150084 }
44789da57d7bSbt150084 
44799da57d7bSbt150084 #pragma inline(ixgbe_intr_rx_work)
44809da57d7bSbt150084 /*
44819da57d7bSbt150084  * ixgbe_intr_rx_work - RX processing of ISR.
44829da57d7bSbt150084  */
44839da57d7bSbt150084 static void
44849da57d7bSbt150084 ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring)
44859da57d7bSbt150084 {
44869da57d7bSbt150084 	mblk_t *mp;
44879da57d7bSbt150084 
44889da57d7bSbt150084 	mutex_enter(&rx_ring->rx_lock);
44899da57d7bSbt150084 
4490da14cebeSEric Cheng 	mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
44919da57d7bSbt150084 	mutex_exit(&rx_ring->rx_lock);
44929da57d7bSbt150084 
44939da57d7bSbt150084 	if (mp != NULL)
4494da14cebeSEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
4495da14cebeSEric Cheng 		    rx_ring->ring_gen_num);
44969da57d7bSbt150084 }
44979da57d7bSbt150084 
44989da57d7bSbt150084 #pragma inline(ixgbe_intr_tx_work)
44999da57d7bSbt150084 /*
45009da57d7bSbt150084  * ixgbe_intr_tx_work - TX processing of ISR.
45019da57d7bSbt150084  */
45029da57d7bSbt150084 static void
45039da57d7bSbt150084 ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring)
45049da57d7bSbt150084 {
4505ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_t *ixgbe = tx_ring->ixgbe;
4506ea65739eSchenlu chen - Sun Microsystems - Beijing China 
45079da57d7bSbt150084 	/*
45089da57d7bSbt150084 	 * Recycle the tx descriptors
45099da57d7bSbt150084 	 */
45109da57d7bSbt150084 	tx_ring->tx_recycle(tx_ring);
45119da57d7bSbt150084 
45129da57d7bSbt150084 	/*
45139da57d7bSbt150084 	 * Schedule the re-transmit
45149da57d7bSbt150084 	 */
45159da57d7bSbt150084 	if (tx_ring->reschedule &&
4516ea65739eSchenlu chen - Sun Microsystems - Beijing China 	    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) {
45179da57d7bSbt150084 		tx_ring->reschedule = B_FALSE;
4518da14cebeSEric Cheng 		mac_tx_ring_update(tx_ring->ixgbe->mac_hdl,
4519da14cebeSEric Cheng 		    tx_ring->ring_handle);
4520abcd9e32SRyan Zezeski 		tx_ring->stat_reschedule++;
45219da57d7bSbt150084 	}
45229da57d7bSbt150084 }
45239da57d7bSbt150084 
45249da57d7bSbt150084 #pragma inline(ixgbe_intr_other_work)
45259da57d7bSbt150084 /*
452613740cb2SPaul Guo  * ixgbe_intr_other_work - Process interrupt types other than tx/rx
45279da57d7bSbt150084  */
45289da57d7bSbt150084 static void
452913740cb2SPaul Guo ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr)
45309da57d7bSbt150084 {
45317e579c30SDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
45327e579c30SDale Ghent 
453362e6e1adSPaul Guo 	ASSERT(mutex_owned(&ixgbe->gen_lock));
453462e6e1adSPaul Guo 
453513740cb2SPaul Guo 	/*
453662e6e1adSPaul Guo 	 * handle link status change
453713740cb2SPaul Guo 	 */
453813740cb2SPaul Guo 	if (eicr & IXGBE_EICR_LSC) {
453962e6e1adSPaul Guo 		ixgbe_driver_link_check(ixgbe);
45405b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_get_hw_state(ixgbe);
454113740cb2SPaul Guo 	}
45429da57d7bSbt150084 
45439da57d7bSbt150084 	/*
454413740cb2SPaul Guo 	 * check for fan failure on adapters with fans
45459da57d7bSbt150084 	 */
454613740cb2SPaul Guo 	if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
454713740cb2SPaul Guo 	    (eicr & IXGBE_EICR_GPI_SDP1)) {
45485b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
45495b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
45505b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		/*
45515b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 * Disable the adapter interrupts
45525b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 */
45535b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_disable_adapter_interrupts(ixgbe);
45545b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
45555b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		/*
45565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 * Disable Rx/Tx units
45575b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 */
45585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		(void) ixgbe_stop_adapter(&ixgbe->hw);
45595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
45605b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
45615b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe,
45625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    "Problem: Network adapter has been stopped "
45635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    "because the fan has stopped.\n");
45645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe,
45655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    "Action: Replace the adapter.\n");
45669da57d7bSbt150084 
456713740cb2SPaul Guo 		/* re-enable the interrupt, which was automasked */
456813740cb2SPaul Guo 		ixgbe->eims |= IXGBE_EICR_GPI_SDP1;
456913740cb2SPaul Guo 	}
45709da57d7bSbt150084 
45719da57d7bSbt150084 	/*
45725b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Do SFP check for adapters with hot-plug capability
457373cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
45745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if ((ixgbe->capab->flags & IXGBE_FLAG_SFP_PLUG_CAPABLE) &&
45757e579c30SDale Ghent 	    ((eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) ||
45767e579c30SDale Ghent 	    (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)))) {
45775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->eicr = eicr;
457862e6e1adSPaul Guo 		if ((ddi_taskq_dispatch(ixgbe->sfp_taskq,
457973cd555cSBin Tu - Sun Microsystems - Beijing China 		    ixgbe_sfp_check, (void *)ixgbe,
458073cd555cSBin Tu - Sun Microsystems - Beijing China 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
4581185c5677SPaul Guo 			ixgbe_log(ixgbe, "No memory available to dispatch "
4582185c5677SPaul Guo 			    "taskq for SFP check");
458373cd555cSBin Tu - Sun Microsystems - Beijing China 		}
45845b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
458562e6e1adSPaul Guo 
458662e6e1adSPaul Guo 	/*
45875b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Do over-temperature check for adapters with temp sensor
458862e6e1adSPaul Guo 	 */
45895b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if ((ixgbe->capab->flags & IXGBE_FLAG_TEMP_SENSOR_CAPABLE) &&
45907e579c30SDale Ghent 	    ((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) ||
45917e579c30SDale Ghent 	    (eicr & IXGBE_EICR_LSC))) {
45925b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->eicr = eicr;
45935b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		if ((ddi_taskq_dispatch(ixgbe->overtemp_taskq,
45945b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    ixgbe_overtemp_check, (void *)ixgbe,
45955b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
45965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_log(ixgbe, "No memory available to dispatch "
45975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "taskq for overtemp check");
45985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
459973cd555cSBin Tu - Sun Microsystems - Beijing China 	}
46007e579c30SDale Ghent 
46017e579c30SDale Ghent 	/*
46027e579c30SDale Ghent 	 * Process an external PHY interrupt
46037e579c30SDale Ghent 	 */
46047e579c30SDale Ghent 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
46057e579c30SDale Ghent 	    (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
46067e579c30SDale Ghent 		ixgbe->eicr = eicr;
46077e579c30SDale Ghent 		if ((ddi_taskq_dispatch(ixgbe->phy_taskq,
46087e579c30SDale Ghent 		    ixgbe_phy_check, (void *)ixgbe,
46097e579c30SDale Ghent 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
46107e579c30SDale Ghent 			ixgbe_log(ixgbe, "No memory available to dispatch "
46117e579c30SDale Ghent 			    "taskq for PHY check");
46127e579c30SDale Ghent 		}
46137e579c30SDale Ghent 	}
461473cd555cSBin Tu - Sun Microsystems - Beijing China }
461573cd555cSBin Tu - Sun Microsystems - Beijing China 
461673cd555cSBin Tu - Sun Microsystems - Beijing China /*
46179da57d7bSbt150084  * ixgbe_intr_legacy - Interrupt handler for legacy interrupts.
46189da57d7bSbt150084  */
46199da57d7bSbt150084 static uint_t
46209da57d7bSbt150084 ixgbe_intr_legacy(void *arg1, void *arg2)
46219da57d7bSbt150084 {
46229da57d7bSbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
46239da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
46249da57d7bSbt150084 	ixgbe_tx_ring_t *tx_ring;
4625da14cebeSEric Cheng 	ixgbe_rx_ring_t *rx_ring;
46269da57d7bSbt150084 	uint32_t eicr;
46279da57d7bSbt150084 	mblk_t *mp;
46289da57d7bSbt150084 	boolean_t tx_reschedule;
46299da57d7bSbt150084 	uint_t result;
46309da57d7bSbt150084 
463113740cb2SPaul Guo 	_NOTE(ARGUNUSED(arg2));
46329da57d7bSbt150084 
46339da57d7bSbt150084 	mutex_enter(&ixgbe->gen_lock);
46349da57d7bSbt150084 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
46359da57d7bSbt150084 		mutex_exit(&ixgbe->gen_lock);
46369da57d7bSbt150084 		return (DDI_INTR_UNCLAIMED);
46379da57d7bSbt150084 	}
46389da57d7bSbt150084 
46399da57d7bSbt150084 	mp = NULL;
46409da57d7bSbt150084 	tx_reschedule = B_FALSE;
46419da57d7bSbt150084 
46429da57d7bSbt150084 	/*
46439da57d7bSbt150084 	 * Any bit set in eicr: claim this interrupt
46449da57d7bSbt150084 	 */
46459da57d7bSbt150084 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
464662e6e1adSPaul Guo 
464762e6e1adSPaul Guo 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
464819843f01SPaul Guo 		mutex_exit(&ixgbe->gen_lock);
464962e6e1adSPaul Guo 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
465062e6e1adSPaul Guo 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
465162e6e1adSPaul Guo 		return (DDI_INTR_CLAIMED);
465262e6e1adSPaul Guo 	}
465362e6e1adSPaul Guo 
46549da57d7bSbt150084 	if (eicr) {
46559da57d7bSbt150084 		/*
46569da57d7bSbt150084 		 * For legacy interrupt, we have only one interrupt,
46579da57d7bSbt150084 		 * so we have only one rx ring and one tx ring enabled.
46589da57d7bSbt150084 		 */
46599da57d7bSbt150084 		ASSERT(ixgbe->num_rx_rings == 1);
46609da57d7bSbt150084 		ASSERT(ixgbe->num_tx_rings == 1);
46619da57d7bSbt150084 
46629da57d7bSbt150084 		/*
4663da14cebeSEric Cheng 		 * For legacy interrupt, rx rings[0] will use RTxQ[0].
46649da57d7bSbt150084 		 */
4665da14cebeSEric Cheng 		if (eicr & 0x1) {
466673cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE;
466773cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
466873cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
46699da57d7bSbt150084 			/*
46709da57d7bSbt150084 			 * Clean the rx descriptors
46719da57d7bSbt150084 			 */
4672da14cebeSEric Cheng 			rx_ring = &ixgbe->rx_rings[0];
4673da14cebeSEric Cheng 			mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
4674da14cebeSEric Cheng 		}
46759da57d7bSbt150084 
46769da57d7bSbt150084 		/*
4677da14cebeSEric Cheng 		 * For legacy interrupt, tx rings[0] will use RTxQ[1].
4678da14cebeSEric Cheng 		 */
4679da14cebeSEric Cheng 		if (eicr & 0x2) {
4680da14cebeSEric Cheng 			/*
46819da57d7bSbt150084 			 * Recycle the tx descriptors
46829da57d7bSbt150084 			 */
46839da57d7bSbt150084 			tx_ring = &ixgbe->tx_rings[0];
46849da57d7bSbt150084 			tx_ring->tx_recycle(tx_ring);
46859da57d7bSbt150084 
46869da57d7bSbt150084 			/*
46879da57d7bSbt150084 			 * Schedule the re-transmit
46889da57d7bSbt150084 			 */
46899da57d7bSbt150084 			tx_reschedule = (tx_ring->reschedule &&
4690ea65739eSchenlu chen - Sun Microsystems - Beijing China 			    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh));
46919da57d7bSbt150084 		}
46929da57d7bSbt150084 
469313740cb2SPaul Guo 		/* any interrupt type other than tx/rx */
469413740cb2SPaul Guo 		if (eicr & ixgbe->capab->other_intr) {
46955b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			switch (hw->mac.type) {
46965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82598EB:
469713740cb2SPaul Guo 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
46985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
46995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
47005b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82599EB:
470169b5a878SDan McDonald 			case ixgbe_mac_X540:
47027e579c30SDale Ghent 			case ixgbe_mac_X550:
47037e579c30SDale Ghent 			case ixgbe_mac_X550EM_x:
470473cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe->eimc = IXGBE_82599_OTHER_INTR;
470573cd555cSBin Tu - Sun Microsystems - Beijing China 				IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
47065b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
47075b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
47085b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			default:
47095b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
471073cd555cSBin Tu - Sun Microsystems - Beijing China 			}
471113740cb2SPaul Guo 			ixgbe_intr_other_work(ixgbe, eicr);
471273cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
47139da57d7bSbt150084 		}
47149da57d7bSbt150084 
471513740cb2SPaul Guo 		mutex_exit(&ixgbe->gen_lock);
471613740cb2SPaul Guo 
47179da57d7bSbt150084 		result = DDI_INTR_CLAIMED;
47189da57d7bSbt150084 	} else {
471913740cb2SPaul Guo 		mutex_exit(&ixgbe->gen_lock);
472013740cb2SPaul Guo 
47219da57d7bSbt150084 		/*
47229da57d7bSbt150084 		 * No interrupt cause bits set: don't claim this interrupt.
47239da57d7bSbt150084 		 */
47249da57d7bSbt150084 		result = DDI_INTR_UNCLAIMED;
47259da57d7bSbt150084 	}
47269da57d7bSbt150084 
472713740cb2SPaul Guo 	/* re-enable the interrupts which were automasked */
472813740cb2SPaul Guo 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
47299da57d7bSbt150084 
47309da57d7bSbt150084 	/*
47319da57d7bSbt150084 	 * Do the following work outside of the gen_lock
47329da57d7bSbt150084 	 */
473373cd555cSBin Tu - Sun Microsystems - Beijing China 	if (mp != NULL) {
4734da14cebeSEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
4735da14cebeSEric Cheng 		    rx_ring->ring_gen_num);
473673cd555cSBin Tu - Sun Microsystems - Beijing China 	}
47379da57d7bSbt150084 
47389da57d7bSbt150084 	if (tx_reschedule)  {
47399da57d7bSbt150084 		tx_ring->reschedule = B_FALSE;
4740da14cebeSEric Cheng 		mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle);
4741abcd9e32SRyan Zezeski 		tx_ring->stat_reschedule++;
47429da57d7bSbt150084 	}
47439da57d7bSbt150084 
47449da57d7bSbt150084 	return (result);
47459da57d7bSbt150084 }
47469da57d7bSbt150084 
47479da57d7bSbt150084 /*
47489da57d7bSbt150084  * ixgbe_intr_msi - Interrupt handler for MSI.
47499da57d7bSbt150084  */
47509da57d7bSbt150084 static uint_t
47519da57d7bSbt150084 ixgbe_intr_msi(void *arg1, void *arg2)
47529da57d7bSbt150084 {
47539da57d7bSbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
47549da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
47559da57d7bSbt150084 	uint32_t eicr;
47569da57d7bSbt150084 
475713740cb2SPaul Guo 	_NOTE(ARGUNUSED(arg2));
475813740cb2SPaul Guo 
47599da57d7bSbt150084 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
47609da57d7bSbt150084 
476162e6e1adSPaul Guo 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
476262e6e1adSPaul Guo 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
476362e6e1adSPaul Guo 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
476462e6e1adSPaul Guo 		return (DDI_INTR_CLAIMED);
476562e6e1adSPaul Guo 	}
476662e6e1adSPaul Guo 
47679da57d7bSbt150084 	/*
47689da57d7bSbt150084 	 * For MSI interrupt, we have only one vector,
47699da57d7bSbt150084 	 * so we have only one rx ring and one tx ring enabled.
47709da57d7bSbt150084 	 */
47719da57d7bSbt150084 	ASSERT(ixgbe->num_rx_rings == 1);
47729da57d7bSbt150084 	ASSERT(ixgbe->num_tx_rings == 1);
47739da57d7bSbt150084 
47749da57d7bSbt150084 	/*
4775da14cebeSEric Cheng 	 * For MSI interrupt, rx rings[0] will use RTxQ[0].
47769da57d7bSbt150084 	 */
4777da14cebeSEric Cheng 	if (eicr & 0x1) {
47789da57d7bSbt150084 		ixgbe_intr_rx_work(&ixgbe->rx_rings[0]);
4779da14cebeSEric Cheng 	}
4780da14cebeSEric Cheng 
4781da14cebeSEric Cheng 	/*
4782da14cebeSEric Cheng 	 * For MSI interrupt, tx rings[0] will use RTxQ[1].
4783da14cebeSEric Cheng 	 */
4784da14cebeSEric Cheng 	if (eicr & 0x2) {
47859da57d7bSbt150084 		ixgbe_intr_tx_work(&ixgbe->tx_rings[0]);
47869da57d7bSbt150084 	}
47879da57d7bSbt150084 
478813740cb2SPaul Guo 	/* any interrupt type other than tx/rx */
478913740cb2SPaul Guo 	if (eicr & ixgbe->capab->other_intr) {
479013740cb2SPaul Guo 		mutex_enter(&ixgbe->gen_lock);
47915b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		switch (hw->mac.type) {
47925b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82598EB:
479313740cb2SPaul Guo 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
47945b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
47955b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
47965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82599EB:
479769b5a878SDan McDonald 		case ixgbe_mac_X540:
47987e579c30SDale Ghent 		case ixgbe_mac_X550:
47997e579c30SDale Ghent 		case ixgbe_mac_X550EM_x:
480073cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eimc = IXGBE_82599_OTHER_INTR;
480173cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
48025b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
48035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
48045b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		default:
48055b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
480673cd555cSBin Tu - Sun Microsystems - Beijing China 		}
480713740cb2SPaul Guo 		ixgbe_intr_other_work(ixgbe, eicr);
480873cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
480913740cb2SPaul Guo 		mutex_exit(&ixgbe->gen_lock);
48109da57d7bSbt150084 	}
48119da57d7bSbt150084 
481213740cb2SPaul Guo 	/* re-enable the interrupts which were automasked */
481313740cb2SPaul Guo 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
481413740cb2SPaul Guo 
48159da57d7bSbt150084 	return (DDI_INTR_CLAIMED);
48169da57d7bSbt150084 }
48179da57d7bSbt150084 
48189da57d7bSbt150084 /*
481973cd555cSBin Tu - Sun Microsystems - Beijing China  * ixgbe_intr_msix - Interrupt handler for MSI-X.
48209da57d7bSbt150084  */
48219da57d7bSbt150084 static uint_t
482273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_msix(void *arg1, void *arg2)
48239da57d7bSbt150084 {
482473cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1;
48259da57d7bSbt150084 	ixgbe_t *ixgbe = vect->ixgbe;
482673cd555cSBin Tu - Sun Microsystems - Beijing China 	struct ixgbe_hw *hw = &ixgbe->hw;
482773cd555cSBin Tu - Sun Microsystems - Beijing China 	uint32_t eicr;
4828da14cebeSEric Cheng 	int r_idx = 0;
48299da57d7bSbt150084 
483013740cb2SPaul Guo 	_NOTE(ARGUNUSED(arg2));
483113740cb2SPaul Guo 
48329da57d7bSbt150084 	/*
4833da14cebeSEric Cheng 	 * Clean each rx ring that has its bit set in the map
48349da57d7bSbt150084 	 */
48359da57d7bSbt150084 	r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1));
48369da57d7bSbt150084 	while (r_idx >= 0) {
48379da57d7bSbt150084 		ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]);
48389da57d7bSbt150084 		r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
48399da57d7bSbt150084 		    (ixgbe->num_rx_rings - 1));
48409da57d7bSbt150084 	}
48419da57d7bSbt150084 
4842da14cebeSEric Cheng 	/*
4843da14cebeSEric Cheng 	 * Clean each tx ring that has its bit set in the map
4844da14cebeSEric Cheng 	 */
4845da14cebeSEric Cheng 	r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1));
4846da14cebeSEric Cheng 	while (r_idx >= 0) {
4847da14cebeSEric Cheng 		ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]);
4848da14cebeSEric Cheng 		r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
4849da14cebeSEric Cheng 		    (ixgbe->num_tx_rings - 1));
4850da14cebeSEric Cheng 	}
4851da14cebeSEric Cheng 
48529da57d7bSbt150084 
48539da57d7bSbt150084 	/*
485473cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Clean other interrupt (link change) that has its bit set in the map
48559da57d7bSbt150084 	 */
485673cd555cSBin Tu - Sun Microsystems - Beijing China 	if (BT_TEST(vect->other_map, 0) == 1) {
48579da57d7bSbt150084 		eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
48589da57d7bSbt150084 
485962e6e1adSPaul Guo 		if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) !=
486062e6e1adSPaul Guo 		    DDI_FM_OK) {
486162e6e1adSPaul Guo 			ddi_fm_service_impact(ixgbe->dip,
486262e6e1adSPaul Guo 			    DDI_SERVICE_DEGRADED);
486362e6e1adSPaul Guo 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
486462e6e1adSPaul Guo 			return (DDI_INTR_CLAIMED);
486562e6e1adSPaul Guo 		}
486662e6e1adSPaul Guo 
48679da57d7bSbt150084 		/*
48685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 * Check "other" cause bits: any interrupt type other than tx/rx
48699da57d7bSbt150084 		 */
487013740cb2SPaul Guo 		if (eicr & ixgbe->capab->other_intr) {
487113740cb2SPaul Guo 			mutex_enter(&ixgbe->gen_lock);
48725b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			switch (hw->mac.type) {
48735b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82598EB:
487413740cb2SPaul Guo 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
487513740cb2SPaul Guo 				ixgbe_intr_other_work(ixgbe, eicr);
48765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
48775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
48785b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82599EB:
487969b5a878SDan McDonald 			case ixgbe_mac_X540:
48807e579c30SDale Ghent 			case ixgbe_mac_X550:
48817e579c30SDale Ghent 			case ixgbe_mac_X550EM_x:
488273cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
488373cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe_intr_other_work(ixgbe, eicr);
48845b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
48855b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
48865b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			default:
48875b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
48885b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			}
488973cd555cSBin Tu - Sun Microsystems - Beijing China 			mutex_exit(&ixgbe->gen_lock);
489073cd555cSBin Tu - Sun Microsystems - Beijing China 		}
48919da57d7bSbt150084 
489213740cb2SPaul Guo 		/* re-enable the interrupts which were automasked */
489313740cb2SPaul Guo 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
489473cd555cSBin Tu - Sun Microsystems - Beijing China 	}
489513740cb2SPaul Guo 
48969da57d7bSbt150084 	return (DDI_INTR_CLAIMED);
48979da57d7bSbt150084 }
48989da57d7bSbt150084 
48999da57d7bSbt150084 /*
49009da57d7bSbt150084  * ixgbe_alloc_intrs - Allocate interrupts for the driver.
49019da57d7bSbt150084  *
49029da57d7bSbt150084  * Normal sequence is to try MSI-X; if not sucessful, try MSI;
49039da57d7bSbt150084  * if not successful, try Legacy.
49049da57d7bSbt150084  * ixgbe->intr_force can be used to force sequence to start with
49059da57d7bSbt150084  * any of the 3 types.
49069da57d7bSbt150084  * If MSI-X is not used, number of tx/rx rings is forced to 1.
49079da57d7bSbt150084  */
49089da57d7bSbt150084 static int
49099da57d7bSbt150084 ixgbe_alloc_intrs(ixgbe_t *ixgbe)
49109da57d7bSbt150084 {
49119da57d7bSbt150084 	dev_info_t *devinfo;
49129da57d7bSbt150084 	int intr_types;
49139da57d7bSbt150084 	int rc;
49149da57d7bSbt150084 
49159da57d7bSbt150084 	devinfo = ixgbe->dip;
49169da57d7bSbt150084 
49179da57d7bSbt150084 	/*
49189da57d7bSbt150084 	 * Get supported interrupt types
49199da57d7bSbt150084 	 */
49209da57d7bSbt150084 	rc = ddi_intr_get_supported_types(devinfo, &intr_types);
49219da57d7bSbt150084 
49229da57d7bSbt150084 	if (rc != DDI_SUCCESS) {
49239da57d7bSbt150084 		ixgbe_log(ixgbe,
49249da57d7bSbt150084 		    "Get supported interrupt types failed: %d", rc);
49259da57d7bSbt150084 		return (IXGBE_FAILURE);
49269da57d7bSbt150084 	}
49279da57d7bSbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types);
49289da57d7bSbt150084 
49299da57d7bSbt150084 	ixgbe->intr_type = 0;
49309da57d7bSbt150084 
49319da57d7bSbt150084 	/*
49329da57d7bSbt150084 	 * Install MSI-X interrupts
49339da57d7bSbt150084 	 */
49349da57d7bSbt150084 	if ((intr_types & DDI_INTR_TYPE_MSIX) &&
49359da57d7bSbt150084 	    (ixgbe->intr_force <= IXGBE_INTR_MSIX)) {
49369da57d7bSbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX);
49379da57d7bSbt150084 		if (rc == IXGBE_SUCCESS)
49389da57d7bSbt150084 			return (IXGBE_SUCCESS);
49399da57d7bSbt150084 
49409da57d7bSbt150084 		ixgbe_log(ixgbe,
49419da57d7bSbt150084 		    "Allocate MSI-X failed, trying MSI interrupts...");
49429da57d7bSbt150084 	}
49439da57d7bSbt150084 
49449da57d7bSbt150084 	/*
4945da14cebeSEric Cheng 	 * MSI-X not used, force rings and groups to 1
49469da57d7bSbt150084 	 */
49479da57d7bSbt150084 	ixgbe->num_rx_rings = 1;
4948da14cebeSEric Cheng 	ixgbe->num_rx_groups = 1;
49499da57d7bSbt150084 	ixgbe->num_tx_rings = 1;
49500dc2366fSVenugopal Iyer 	ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
49519da57d7bSbt150084 	ixgbe_log(ixgbe,
4952da14cebeSEric Cheng 	    "MSI-X not used, force rings and groups number to 1");
49539da57d7bSbt150084 
49549da57d7bSbt150084 	/*
49559da57d7bSbt150084 	 * Install MSI interrupts
49569da57d7bSbt150084 	 */
49579da57d7bSbt150084 	if ((intr_types & DDI_INTR_TYPE_MSI) &&
49589da57d7bSbt150084 	    (ixgbe->intr_force <= IXGBE_INTR_MSI)) {
49599da57d7bSbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI);
49609da57d7bSbt150084 		if (rc == IXGBE_SUCCESS)
49619da57d7bSbt150084 			return (IXGBE_SUCCESS);
49629da57d7bSbt150084 
49639da57d7bSbt150084 		ixgbe_log(ixgbe,
49649da57d7bSbt150084 		    "Allocate MSI failed, trying Legacy interrupts...");
49659da57d7bSbt150084 	}
49669da57d7bSbt150084 
49679da57d7bSbt150084 	/*
49689da57d7bSbt150084 	 * Install legacy interrupts
49699da57d7bSbt150084 	 */
49709da57d7bSbt150084 	if (intr_types & DDI_INTR_TYPE_FIXED) {
49717e579c30SDale Ghent 		/*
49727e579c30SDale Ghent 		 * Disallow legacy interrupts for X550. X550 has a silicon
49737e579c30SDale Ghent 		 * bug which prevents Shared Legacy interrupts from working.
49747e579c30SDale Ghent 		 * For details, please reference:
49757e579c30SDale Ghent 		 *
49767e579c30SDale Ghent 		 * Intel Ethernet Controller X550 Specification Update rev. 2.1
49777e579c30SDale Ghent 		 * May 2016, erratum 22: PCIe Interrupt Status Bit
49787e579c30SDale Ghent 		 */
49797e579c30SDale Ghent 		if (ixgbe->hw.mac.type == ixgbe_mac_X550 ||
49807e579c30SDale Ghent 		    ixgbe->hw.mac.type == ixgbe_mac_X550EM_x ||
49817e579c30SDale Ghent 		    ixgbe->hw.mac.type == ixgbe_mac_X550_vf ||
49827e579c30SDale Ghent 		    ixgbe->hw.mac.type == ixgbe_mac_X550EM_x_vf) {
49837e579c30SDale Ghent 			ixgbe_log(ixgbe,
49847e579c30SDale Ghent 			    "Legacy interrupts are not supported on this "
49857e579c30SDale Ghent 			    "adapter. Please use MSI or MSI-X instead.");
49867e579c30SDale Ghent 			return (IXGBE_FAILURE);
49877e579c30SDale Ghent 		}
49889da57d7bSbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED);
49899da57d7bSbt150084 		if (rc == IXGBE_SUCCESS)
49909da57d7bSbt150084 			return (IXGBE_SUCCESS);
49919da57d7bSbt150084 
49929da57d7bSbt150084 		ixgbe_log(ixgbe,
49939da57d7bSbt150084 		    "Allocate Legacy interrupts failed");
49949da57d7bSbt150084 	}
49959da57d7bSbt150084 
49969da57d7bSbt150084 	/*
49979da57d7bSbt150084 	 * If none of the 3 types succeeded, return failure
49989da57d7bSbt150084 	 */
49999da57d7bSbt150084 	return (IXGBE_FAILURE);
50009da57d7bSbt150084 }
50019da57d7bSbt150084 
50029da57d7bSbt150084 /*
50039da57d7bSbt150084  * ixgbe_alloc_intr_handles - Allocate interrupt handles.
50049da57d7bSbt150084  *
50059da57d7bSbt150084  * For legacy and MSI, only 1 handle is needed.  For MSI-X,
50069da57d7bSbt150084  * if fewer than 2 handles are available, return failure.
5007da14cebeSEric Cheng  * Upon success, this maps the vectors to rx and tx rings for
5008da14cebeSEric Cheng  * interrupts.
50099da57d7bSbt150084  */
50109da57d7bSbt150084 static int
50119da57d7bSbt150084 ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type)
50129da57d7bSbt150084 {
50139da57d7bSbt150084 	dev_info_t *devinfo;
50140dc2366fSVenugopal Iyer 	int request, count, actual;
5015da14cebeSEric Cheng 	int minimum;
50169da57d7bSbt150084 	int rc;
50170dc2366fSVenugopal Iyer 	uint32_t ring_per_group;
50189da57d7bSbt150084 
50199da57d7bSbt150084 	devinfo = ixgbe->dip;
50209da57d7bSbt150084 
50219da57d7bSbt150084 	switch (intr_type) {
50229da57d7bSbt150084 	case DDI_INTR_TYPE_FIXED:
50239da57d7bSbt150084 		request = 1;	/* Request 1 legacy interrupt handle */
50249da57d7bSbt150084 		minimum = 1;
50259da57d7bSbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy");
50269da57d7bSbt150084 		break;
50279da57d7bSbt150084 
50289da57d7bSbt150084 	case DDI_INTR_TYPE_MSI:
50299da57d7bSbt150084 		request = 1;	/* Request 1 MSI interrupt handle */
50309da57d7bSbt150084 		minimum = 1;
50319da57d7bSbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI");
50329da57d7bSbt150084 		break;
50339da57d7bSbt150084 
50349da57d7bSbt150084 	case DDI_INTR_TYPE_MSIX:
50359da57d7bSbt150084 		/*
50369da57d7bSbt150084 		 * Best number of vectors for the adapter is
50370dc2366fSVenugopal Iyer 		 * (# rx rings + # tx rings), however we will
50380dc2366fSVenugopal Iyer 		 * limit the request number.
50399da57d7bSbt150084 		 */
50400dc2366fSVenugopal Iyer 		request = min(16, ixgbe->num_rx_rings + ixgbe->num_tx_rings);
504173cd555cSBin Tu - Sun Microsystems - Beijing China 		if (request > ixgbe->capab->max_ring_vect)
504273cd555cSBin Tu - Sun Microsystems - Beijing China 			request = ixgbe->capab->max_ring_vect;
50430dc2366fSVenugopal Iyer 		minimum = 1;
50449da57d7bSbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X");
50459da57d7bSbt150084 		break;
50469da57d7bSbt150084 
50479da57d7bSbt150084 	default:
50489da57d7bSbt150084 		ixgbe_log(ixgbe,
50499da57d7bSbt150084 		    "invalid call to ixgbe_alloc_intr_handles(): %d\n",
50509da57d7bSbt150084 		    intr_type);
50519da57d7bSbt150084 		return (IXGBE_FAILURE);
50529da57d7bSbt150084 	}
50539da57d7bSbt150084 	IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d  minimum: %d",
50549da57d7bSbt150084 	    request, minimum);
50559da57d7bSbt150084 
50569da57d7bSbt150084 	/*
50579da57d7bSbt150084 	 * Get number of supported interrupts
50589da57d7bSbt150084 	 */
50599da57d7bSbt150084 	rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
50609da57d7bSbt150084 	if ((rc != DDI_SUCCESS) || (count < minimum)) {
50619da57d7bSbt150084 		ixgbe_log(ixgbe,
50629da57d7bSbt150084 		    "Get interrupt number failed. Return: %d, count: %d",
50639da57d7bSbt150084 		    rc, count);
50649da57d7bSbt150084 		return (IXGBE_FAILURE);
50659da57d7bSbt150084 	}
50669da57d7bSbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count);
50679da57d7bSbt150084 
50689da57d7bSbt150084 	actual = 0;
50699da57d7bSbt150084 	ixgbe->intr_cnt = 0;
50700dc2366fSVenugopal Iyer 	ixgbe->intr_cnt_max = 0;
50710dc2366fSVenugopal Iyer 	ixgbe->intr_cnt_min = 0;
50729da57d7bSbt150084 
50739da57d7bSbt150084 	/*
50749da57d7bSbt150084 	 * Allocate an array of interrupt handles
50759da57d7bSbt150084 	 */
50769da57d7bSbt150084 	ixgbe->intr_size = request * sizeof (ddi_intr_handle_t);
50779da57d7bSbt150084 	ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP);
50789da57d7bSbt150084 
50799da57d7bSbt150084 	rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0,
50809da57d7bSbt150084 	    request, &actual, DDI_INTR_ALLOC_NORMAL);
50819da57d7bSbt150084 	if (rc != DDI_SUCCESS) {
50829da57d7bSbt150084 		ixgbe_log(ixgbe, "Allocate interrupts failed. "
50839da57d7bSbt150084 		    "return: %d, request: %d, actual: %d",
50849da57d7bSbt150084 		    rc, request, actual);
50859da57d7bSbt150084 		goto alloc_handle_fail;
50869da57d7bSbt150084 	}
50879da57d7bSbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual);
50889da57d7bSbt150084 
50890dc2366fSVenugopal Iyer 	/*
50900dc2366fSVenugopal Iyer 	 * upper/lower limit of interrupts
50910dc2366fSVenugopal Iyer 	 */
50929da57d7bSbt150084 	ixgbe->intr_cnt = actual;
50930dc2366fSVenugopal Iyer 	ixgbe->intr_cnt_max = request;
50940dc2366fSVenugopal Iyer 	ixgbe->intr_cnt_min = minimum;
50950dc2366fSVenugopal Iyer 
50960dc2366fSVenugopal Iyer 	/*
50970dc2366fSVenugopal Iyer 	 * rss number per group should not exceed the rx interrupt number,
50980dc2366fSVenugopal Iyer 	 * else need to adjust rx ring number.
50990dc2366fSVenugopal Iyer 	 */
51000dc2366fSVenugopal Iyer 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
51010dc2366fSVenugopal Iyer 	ASSERT((ixgbe->num_rx_rings % ixgbe->num_rx_groups) == 0);
51025b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (actual < ring_per_group) {
51035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->num_rx_rings = ixgbe->num_rx_groups * actual;
51040dc2366fSVenugopal Iyer 		ixgbe_setup_vmdq_rss_conf(ixgbe);
51050dc2366fSVenugopal Iyer 	}
51069da57d7bSbt150084 
51079da57d7bSbt150084 	/*
5108da14cebeSEric Cheng 	 * Now we know the actual number of vectors.  Here we map the vector
5109da14cebeSEric Cheng 	 * to other, rx rings and tx ring.
51109da57d7bSbt150084 	 */
51119da57d7bSbt150084 	if (actual < minimum) {
51129da57d7bSbt150084 		ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d",
51139da57d7bSbt150084 		    actual);
51149da57d7bSbt150084 		goto alloc_handle_fail;
51159da57d7bSbt150084 	}
51169da57d7bSbt150084 
51179da57d7bSbt150084 	/*
51189da57d7bSbt150084 	 * Get priority for first vector, assume remaining are all the same
51199da57d7bSbt150084 	 */
51209da57d7bSbt150084 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
51219da57d7bSbt150084 	if (rc != DDI_SUCCESS) {
51229da57d7bSbt150084 		ixgbe_log(ixgbe,
51239da57d7bSbt150084 		    "Get interrupt priority failed: %d", rc);
51249da57d7bSbt150084 		goto alloc_handle_fail;
51259da57d7bSbt150084 	}
51269da57d7bSbt150084 
51279da57d7bSbt150084 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
51289da57d7bSbt150084 	if (rc != DDI_SUCCESS) {
51299da57d7bSbt150084 		ixgbe_log(ixgbe,
51309da57d7bSbt150084 		    "Get interrupt cap failed: %d", rc);
51319da57d7bSbt150084 		goto alloc_handle_fail;
51329da57d7bSbt150084 	}
51339da57d7bSbt150084 
51349da57d7bSbt150084 	ixgbe->intr_type = intr_type;
51359da57d7bSbt150084 
51369da57d7bSbt150084 	return (IXGBE_SUCCESS);
51379da57d7bSbt150084 
51389da57d7bSbt150084 alloc_handle_fail:
51399da57d7bSbt150084 	ixgbe_rem_intrs(ixgbe);
51409da57d7bSbt150084 
51419da57d7bSbt150084 	return (IXGBE_FAILURE);
51429da57d7bSbt150084 }
51439da57d7bSbt150084 
51449da57d7bSbt150084 /*
51459da57d7bSbt150084  * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type.
51469da57d7bSbt150084  *
51479da57d7bSbt150084  * Before adding the interrupt handlers, the interrupt vectors have
51489da57d7bSbt150084  * been allocated, and the rx/tx rings have also been allocated.
51499da57d7bSbt150084  */
51509da57d7bSbt150084 static int
51519da57d7bSbt150084 ixgbe_add_intr_handlers(ixgbe_t *ixgbe)
51529da57d7bSbt150084 {
5153da14cebeSEric Cheng 	int vector = 0;
51549da57d7bSbt150084 	int rc;
51559da57d7bSbt150084 
51569da57d7bSbt150084 	switch (ixgbe->intr_type) {
51579da57d7bSbt150084 	case DDI_INTR_TYPE_MSIX:
51589da57d7bSbt150084 		/*
515973cd555cSBin Tu - Sun Microsystems - Beijing China 		 * Add interrupt handler for all vectors
51609da57d7bSbt150084 		 */
516173cd555cSBin Tu - Sun Microsystems - Beijing China 		for (vector = 0; vector < ixgbe->intr_cnt; vector++) {
51629da57d7bSbt150084 			/*
51639da57d7bSbt150084 			 * install pointer to vect_map[vector]
51649da57d7bSbt150084 			 */
51659da57d7bSbt150084 			rc = ddi_intr_add_handler(ixgbe->htable[vector],
516673cd555cSBin Tu - Sun Microsystems - Beijing China 			    (ddi_intr_handler_t *)ixgbe_intr_msix,
51679da57d7bSbt150084 			    (void *)&ixgbe->vect_map[vector], NULL);
51689da57d7bSbt150084 
51699da57d7bSbt150084 			if (rc != DDI_SUCCESS) {
51709da57d7bSbt150084 				ixgbe_log(ixgbe,
517119843f01SPaul Guo 				    "Add interrupt handler failed. "
5172da14cebeSEric Cheng 				    "return: %d, vector: %d", rc, vector);
51739da57d7bSbt150084 				for (vector--; vector >= 0; vector--) {
51749da57d7bSbt150084 					(void) ddi_intr_remove_handler(
51759da57d7bSbt150084 					    ixgbe->htable[vector]);
51769da57d7bSbt150084 				}
51779da57d7bSbt150084 				return (IXGBE_FAILURE);
51789da57d7bSbt150084 			}
51799da57d7bSbt150084 		}
5180da14cebeSEric Cheng 
51819da57d7bSbt150084 		break;
51829da57d7bSbt150084 
51839da57d7bSbt150084 	case DDI_INTR_TYPE_MSI:
51849da57d7bSbt150084 		/*
51859da57d7bSbt150084 		 * Add interrupt handlers for the only vector
51869da57d7bSbt150084 		 */
51879da57d7bSbt150084 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
51889da57d7bSbt150084 		    (ddi_intr_handler_t *)ixgbe_intr_msi,
51899da57d7bSbt150084 		    (void *)ixgbe, NULL);
51909da57d7bSbt150084 
51919da57d7bSbt150084 		if (rc != DDI_SUCCESS) {
51929da57d7bSbt150084 			ixgbe_log(ixgbe,
51939da57d7bSbt150084 			    "Add MSI interrupt handler failed: %d", rc);
51949da57d7bSbt150084 			return (IXGBE_FAILURE);
51959da57d7bSbt150084 		}
51969da57d7bSbt150084 
51979da57d7bSbt150084 		break;
51989da57d7bSbt150084 
51999da57d7bSbt150084 	case DDI_INTR_TYPE_FIXED:
52009da57d7bSbt150084 		/*
52019da57d7bSbt150084 		 * Add interrupt handlers for the only vector
52029da57d7bSbt150084 		 */
52039da57d7bSbt150084 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
52049da57d7bSbt150084 		    (ddi_intr_handler_t *)ixgbe_intr_legacy,
52059da57d7bSbt150084 		    (void *)ixgbe, NULL);
52069da57d7bSbt150084 
52079da57d7bSbt150084 		if (rc != DDI_SUCCESS) {
52089da57d7bSbt150084 			ixgbe_log(ixgbe,
52099da57d7bSbt150084 			    "Add legacy interrupt handler failed: %d", rc);
52109da57d7bSbt150084 			return (IXGBE_FAILURE);
52119da57d7bSbt150084 		}
52129da57d7bSbt150084 
52139da57d7bSbt150084 		break;
52149da57d7bSbt150084 
52159da57d7bSbt150084 	default:
52169da57d7bSbt150084 		return (IXGBE_FAILURE);
52179da57d7bSbt150084 	}
52189da57d7bSbt150084 
52199da57d7bSbt150084 	return (IXGBE_SUCCESS);
52209da57d7bSbt150084 }
52219da57d7bSbt150084 
52229da57d7bSbt150084 #pragma inline(ixgbe_map_rxring_to_vector)
52239da57d7bSbt150084 /*
52249da57d7bSbt150084  * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector.
52259da57d7bSbt150084  */
52269da57d7bSbt150084 static void
52279da57d7bSbt150084 ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx)
52289da57d7bSbt150084 {
52299da57d7bSbt150084 	/*
52309da57d7bSbt150084 	 * Set bit in map
52319da57d7bSbt150084 	 */
52329da57d7bSbt150084 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
52339da57d7bSbt150084 
52349da57d7bSbt150084 	/*
52359da57d7bSbt150084 	 * Count bits set
52369da57d7bSbt150084 	 */
52379da57d7bSbt150084 	ixgbe->vect_map[v_idx].rxr_cnt++;
52389da57d7bSbt150084 
52399da57d7bSbt150084 	/*
52409da57d7bSbt150084 	 * Remember bit position
52419da57d7bSbt150084 	 */
5242da14cebeSEric Cheng 	ixgbe->rx_rings[r_idx].intr_vector = v_idx;
52439da57d7bSbt150084 	ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx;
52449da57d7bSbt150084 }
52459da57d7bSbt150084 
52469da57d7bSbt150084 #pragma inline(ixgbe_map_txring_to_vector)
52479da57d7bSbt150084 /*
52489da57d7bSbt150084  * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector.
52499da57d7bSbt150084  */
52509da57d7bSbt150084 static void
52519da57d7bSbt150084 ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx)
52529da57d7bSbt150084 {
52539da57d7bSbt150084 	/*
52549da57d7bSbt150084 	 * Set bit in map
52559da57d7bSbt150084 	 */
52569da57d7bSbt150084 	BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx);
52579da57d7bSbt150084 
52589da57d7bSbt150084 	/*
52599da57d7bSbt150084 	 * Count bits set
52609da57d7bSbt150084 	 */
52619da57d7bSbt150084 	ixgbe->vect_map[v_idx].txr_cnt++;
52629da57d7bSbt150084 
52639da57d7bSbt150084 	/*
52649da57d7bSbt150084 	 * Remember bit position
52659da57d7bSbt150084 	 */
5266da14cebeSEric Cheng 	ixgbe->tx_rings[t_idx].intr_vector = v_idx;
52679da57d7bSbt150084 	ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx;
52689da57d7bSbt150084 }
52699da57d7bSbt150084 
52709da57d7bSbt150084 /*
5271da14cebeSEric Cheng  * ixgbe_setup_ivar - Set the given entry in the given interrupt vector
52729da57d7bSbt150084  * allocation register (IVAR).
527373cd555cSBin Tu - Sun Microsystems - Beijing China  * cause:
527473cd555cSBin Tu - Sun Microsystems - Beijing China  *   -1 : other cause
527573cd555cSBin Tu - Sun Microsystems - Beijing China  *    0 : rx
527673cd555cSBin Tu - Sun Microsystems - Beijing China  *    1 : tx
52779da57d7bSbt150084  */
52789da57d7bSbt150084 static void
527973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector,
528073cd555cSBin Tu - Sun Microsystems - Beijing China     int8_t cause)
52819da57d7bSbt150084 {
52829da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
52839da57d7bSbt150084 	u32 ivar, index;
52849da57d7bSbt150084 
528573cd555cSBin Tu - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
528673cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
52879da57d7bSbt150084 		msix_vector |= IXGBE_IVAR_ALLOC_VAL;
528873cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
528973cd555cSBin Tu - Sun Microsystems - Beijing China 			cause = 0;
529073cd555cSBin Tu - Sun Microsystems - Beijing China 		}
529173cd555cSBin Tu - Sun Microsystems - Beijing China 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
52929da57d7bSbt150084 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
5293da14cebeSEric Cheng 		ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3)));
5294da14cebeSEric Cheng 		ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3)));
5295da14cebeSEric Cheng 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
529673cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
52975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
529873cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
529969b5a878SDan McDonald 	case ixgbe_mac_X540:
53007e579c30SDale Ghent 	case ixgbe_mac_X550:
53017e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
530273cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
530373cd555cSBin Tu - Sun Microsystems - Beijing China 			/* other causes */
530473cd555cSBin Tu - Sun Microsystems - Beijing China 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
530573cd555cSBin Tu - Sun Microsystems - Beijing China 			index = (intr_alloc_entry & 1) * 8;
530673cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
530773cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar &= ~(0xFF << index);
530873cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar |= (msix_vector << index);
530973cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
531073cd555cSBin Tu - Sun Microsystems - Beijing China 		} else {
531173cd555cSBin Tu - Sun Microsystems - Beijing China 			/* tx or rx causes */
531273cd555cSBin Tu - Sun Microsystems - Beijing China 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
531373cd555cSBin Tu - Sun Microsystems - Beijing China 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
531473cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw,
531573cd555cSBin Tu - Sun Microsystems - Beijing China 			    IXGBE_IVAR(intr_alloc_entry >> 1));
531673cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar &= ~(0xFF << index);
531773cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar |= (msix_vector << index);
531873cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
531973cd555cSBin Tu - Sun Microsystems - Beijing China 			    ivar);
532073cd555cSBin Tu - Sun Microsystems - Beijing China 		}
532173cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
53225b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
532373cd555cSBin Tu - Sun Microsystems - Beijing China 	default:
532473cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
532573cd555cSBin Tu - Sun Microsystems - Beijing China 	}
5326da14cebeSEric Cheng }
5327da14cebeSEric Cheng 
5328da14cebeSEric Cheng /*
5329da14cebeSEric Cheng  * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of
5330da14cebeSEric Cheng  * given interrupt vector allocation register (IVAR).
533173cd555cSBin Tu - Sun Microsystems - Beijing China  * cause:
533273cd555cSBin Tu - Sun Microsystems - Beijing China  *   -1 : other cause
533373cd555cSBin Tu - Sun Microsystems - Beijing China  *    0 : rx
533473cd555cSBin Tu - Sun Microsystems - Beijing China  *    1 : tx
5335da14cebeSEric Cheng  */
5336da14cebeSEric Cheng static void
533773cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
5338da14cebeSEric Cheng {
5339da14cebeSEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
5340da14cebeSEric Cheng 	u32 ivar, index;
5341da14cebeSEric Cheng 
534273cd555cSBin Tu - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
534373cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
534473cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
534573cd555cSBin Tu - Sun Microsystems - Beijing China 			cause = 0;
534673cd555cSBin Tu - Sun Microsystems - Beijing China 		}
534773cd555cSBin Tu - Sun Microsystems - Beijing China 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
5348da14cebeSEric Cheng 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
534973cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 *
535073cd555cSBin Tu - Sun Microsystems - Beijing China 		    (intr_alloc_entry & 0x3)));
5351da14cebeSEric Cheng 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
535273cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
53535b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
535473cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
535569b5a878SDan McDonald 	case ixgbe_mac_X540:
53567e579c30SDale Ghent 	case ixgbe_mac_X550:
53577e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
535873cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
535973cd555cSBin Tu - Sun Microsystems - Beijing China 			/* other causes */
536073cd555cSBin Tu - Sun Microsystems - Beijing China 			index = (intr_alloc_entry & 1) * 8;
536173cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
536273cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
536373cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
536473cd555cSBin Tu - Sun Microsystems - Beijing China 		} else {
536573cd555cSBin Tu - Sun Microsystems - Beijing China 			/* tx or rx causes */
536673cd555cSBin Tu - Sun Microsystems - Beijing China 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
536773cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw,
536873cd555cSBin Tu - Sun Microsystems - Beijing China 			    IXGBE_IVAR(intr_alloc_entry >> 1));
536973cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
537073cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
537173cd555cSBin Tu - Sun Microsystems - Beijing China 			    ivar);
537273cd555cSBin Tu - Sun Microsystems - Beijing China 		}
537373cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
53745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
537573cd555cSBin Tu - Sun Microsystems - Beijing China 	default:
537673cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
537773cd555cSBin Tu - Sun Microsystems - Beijing China 	}
5378da14cebeSEric Cheng }
5379da14cebeSEric Cheng 
5380da14cebeSEric Cheng /*
538173cd555cSBin Tu - Sun Microsystems - Beijing China  * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of
5382da14cebeSEric Cheng  * given interrupt vector allocation register (IVAR).
538373cd555cSBin Tu - Sun Microsystems - Beijing China  * cause:
538473cd555cSBin Tu - Sun Microsystems - Beijing China  *   -1 : other cause
538573cd555cSBin Tu - Sun Microsystems - Beijing China  *    0 : rx
538673cd555cSBin Tu - Sun Microsystems - Beijing China  *    1 : tx
5387da14cebeSEric Cheng  */
5388da14cebeSEric Cheng static void
538973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
5390da14cebeSEric Cheng {
5391da14cebeSEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
5392da14cebeSEric Cheng 	u32 ivar, index;
5393da14cebeSEric Cheng 
539473cd555cSBin Tu - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
539573cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
539673cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
539773cd555cSBin Tu - Sun Microsystems - Beijing China 			cause = 0;
539873cd555cSBin Tu - Sun Microsystems - Beijing China 		}
539973cd555cSBin Tu - Sun Microsystems - Beijing China 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
5400da14cebeSEric Cheng 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
540173cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 *
540273cd555cSBin Tu - Sun Microsystems - Beijing China 		    (intr_alloc_entry & 0x3)));
54039da57d7bSbt150084 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
540473cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
54055b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
540673cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
540769b5a878SDan McDonald 	case ixgbe_mac_X540:
54087e579c30SDale Ghent 	case ixgbe_mac_X550:
54097e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
541073cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
541173cd555cSBin Tu - Sun Microsystems - Beijing China 			/* other causes */
541273cd555cSBin Tu - Sun Microsystems - Beijing China 			index = (intr_alloc_entry & 1) * 8;
541373cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
541473cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
541573cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
541673cd555cSBin Tu - Sun Microsystems - Beijing China 		} else {
541773cd555cSBin Tu - Sun Microsystems - Beijing China 			/* tx or rx causes */
541873cd555cSBin Tu - Sun Microsystems - Beijing China 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
541973cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw,
542073cd555cSBin Tu - Sun Microsystems - Beijing China 			    IXGBE_IVAR(intr_alloc_entry >> 1));
542173cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
542273cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
542373cd555cSBin Tu - Sun Microsystems - Beijing China 			    ivar);
542473cd555cSBin Tu - Sun Microsystems - Beijing China 		}
542573cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
54265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
542773cd555cSBin Tu - Sun Microsystems - Beijing China 	default:
542873cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
542973cd555cSBin Tu - Sun Microsystems - Beijing China 	}
54309da57d7bSbt150084 }
54319da57d7bSbt150084 
54329da57d7bSbt150084 /*
54330dc2366fSVenugopal Iyer  * Convert the rx ring index driver maintained to the rx ring index
54340dc2366fSVenugopal Iyer  * in h/w.
54350dc2366fSVenugopal Iyer  */
54360dc2366fSVenugopal Iyer static uint32_t
54370dc2366fSVenugopal Iyer ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index)
54380dc2366fSVenugopal Iyer {
54390dc2366fSVenugopal Iyer 
54400dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
54410dc2366fSVenugopal Iyer 	uint32_t rx_ring_per_group, hw_rx_index;
54420dc2366fSVenugopal Iyer 
54430dc2366fSVenugopal Iyer 	if (ixgbe->classify_mode == IXGBE_CLASSIFY_RSS ||
54440dc2366fSVenugopal Iyer 	    ixgbe->classify_mode == IXGBE_CLASSIFY_NONE) {
54450dc2366fSVenugopal Iyer 		return (sw_rx_index);
54460dc2366fSVenugopal Iyer 	} else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ) {
54475b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		switch (hw->mac.type) {
54485b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82598EB:
54490dc2366fSVenugopal Iyer 			return (sw_rx_index);
54505b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
54515b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82599EB:
545269b5a878SDan McDonald 		case ixgbe_mac_X540:
54537e579c30SDale Ghent 		case ixgbe_mac_X550:
54547e579c30SDale Ghent 		case ixgbe_mac_X550EM_x:
54550dc2366fSVenugopal Iyer 			return (sw_rx_index * 2);
54565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
54575b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		default:
54585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
54590dc2366fSVenugopal Iyer 		}
54600dc2366fSVenugopal Iyer 	} else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) {
54610dc2366fSVenugopal Iyer 		rx_ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
54620dc2366fSVenugopal Iyer 
54635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		switch (hw->mac.type) {
54645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82598EB:
54650dc2366fSVenugopal Iyer 			hw_rx_index = (sw_rx_index / rx_ring_per_group) *
54660dc2366fSVenugopal Iyer 			    16 + (sw_rx_index % rx_ring_per_group);
54670dc2366fSVenugopal Iyer 			return (hw_rx_index);
54685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
54695b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82599EB:
547069b5a878SDan McDonald 		case ixgbe_mac_X540:
54717e579c30SDale Ghent 		case ixgbe_mac_X550:
54727e579c30SDale Ghent 		case ixgbe_mac_X550EM_x:
54730dc2366fSVenugopal Iyer 			if (ixgbe->num_rx_groups > 32) {
54740dc2366fSVenugopal Iyer 				hw_rx_index = (sw_rx_index /
54750dc2366fSVenugopal Iyer 				    rx_ring_per_group) * 2 +
54760dc2366fSVenugopal Iyer 				    (sw_rx_index % rx_ring_per_group);
54770dc2366fSVenugopal Iyer 			} else {
54780dc2366fSVenugopal Iyer 				hw_rx_index = (sw_rx_index /
54790dc2366fSVenugopal Iyer 				    rx_ring_per_group) * 4 +
54800dc2366fSVenugopal Iyer 				    (sw_rx_index % rx_ring_per_group);
54810dc2366fSVenugopal Iyer 			}
54820dc2366fSVenugopal Iyer 			return (hw_rx_index);
54835b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
54845b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		default:
54855b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
54860dc2366fSVenugopal Iyer 		}
54870dc2366fSVenugopal Iyer 	}
54880dc2366fSVenugopal Iyer 
54890dc2366fSVenugopal Iyer 	/*
54900dc2366fSVenugopal Iyer 	 * Should never reach. Just to make compiler happy.
54910dc2366fSVenugopal Iyer 	 */
54920dc2366fSVenugopal Iyer 	return (sw_rx_index);
54930dc2366fSVenugopal Iyer }
54940dc2366fSVenugopal Iyer 
54950dc2366fSVenugopal Iyer /*
549673cd555cSBin Tu - Sun Microsystems - Beijing China  * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors.
54979da57d7bSbt150084  *
549873cd555cSBin Tu - Sun Microsystems - Beijing China  * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt
549973cd555cSBin Tu - Sun Microsystems - Beijing China  * to vector[0 - (intr_cnt -1)].
55009da57d7bSbt150084  */
55019da57d7bSbt150084 static int
550273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe)
55039da57d7bSbt150084 {
55049da57d7bSbt150084 	int i, vector = 0;
55059da57d7bSbt150084 
55069da57d7bSbt150084 	/* initialize vector map */
55079da57d7bSbt150084 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
550873cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->intr_cnt; i++) {
550973cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe->vect_map[i].ixgbe = ixgbe;
551073cd555cSBin Tu - Sun Microsystems - Beijing China 	}
55119da57d7bSbt150084 
55129da57d7bSbt150084 	/*
5513da14cebeSEric Cheng 	 * non-MSI-X case is very simple: rx rings[0] on RTxQ[0],
5514da14cebeSEric Cheng 	 * tx rings[0] on RTxQ[1].
55159da57d7bSbt150084 	 */
55169da57d7bSbt150084 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
55179da57d7bSbt150084 		ixgbe_map_rxring_to_vector(ixgbe, 0, 0);
5518da14cebeSEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, 0, 1);
55199da57d7bSbt150084 		return (IXGBE_SUCCESS);
55209da57d7bSbt150084 	}
55219da57d7bSbt150084 
55229da57d7bSbt150084 	/*
552373cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Interrupts/vectors mapping for MSI-X
55249da57d7bSbt150084 	 */
55259da57d7bSbt150084 
55269da57d7bSbt150084 	/*
552773cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Map other interrupt to vector 0,
552873cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Set bit in map and count the bits set.
552973cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
553073cd555cSBin Tu - Sun Microsystems - Beijing China 	BT_SET(ixgbe->vect_map[vector].other_map, 0);
553173cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe->vect_map[vector].other_cnt++;
553273cd555cSBin Tu - Sun Microsystems - Beijing China 
553373cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
553473cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Map rx ring interrupts to vectors
55359da57d7bSbt150084 	 */
5536da14cebeSEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
5537da14cebeSEric Cheng 		ixgbe_map_rxring_to_vector(ixgbe, i, vector);
553873cd555cSBin Tu - Sun Microsystems - Beijing China 		vector = (vector +1) % ixgbe->intr_cnt;
5539da14cebeSEric Cheng 	}
55409da57d7bSbt150084 
55419da57d7bSbt150084 	/*
554273cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Map tx ring interrupts to vectors
55439da57d7bSbt150084 	 */
5544da14cebeSEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
5545da14cebeSEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, i, vector);
554673cd555cSBin Tu - Sun Microsystems - Beijing China 		vector = (vector +1) % ixgbe->intr_cnt;
55479da57d7bSbt150084 	}
55489da57d7bSbt150084 
55499da57d7bSbt150084 	return (IXGBE_SUCCESS);
55509da57d7bSbt150084 }
55519da57d7bSbt150084 
55529da57d7bSbt150084 /*
55539da57d7bSbt150084  * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s).
55549da57d7bSbt150084  *
5555da14cebeSEric Cheng  * This relies on ring/vector mapping already set up in the
55569da57d7bSbt150084  * vect_map[] structures
55579da57d7bSbt150084  */
55589da57d7bSbt150084 static void
55599da57d7bSbt150084 ixgbe_setup_adapter_vector(ixgbe_t *ixgbe)
55609da57d7bSbt150084 {
55619da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
556273cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_intr_vector_t *vect;	/* vector bitmap */
55639da57d7bSbt150084 	int r_idx;	/* ring index */
55649da57d7bSbt150084 	int v_idx;	/* vector index */
55650dc2366fSVenugopal Iyer 	uint32_t hw_index;
55669da57d7bSbt150084 
55679da57d7bSbt150084 	/*
55689da57d7bSbt150084 	 * Clear any previous entries
55699da57d7bSbt150084 	 */
557073cd555cSBin Tu - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
557173cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
557273cd555cSBin Tu - Sun Microsystems - Beijing China 		for (v_idx = 0; v_idx < 25; v_idx++)
55739da57d7bSbt150084 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
557473cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
55755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
557673cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
557769b5a878SDan McDonald 	case ixgbe_mac_X540:
55787e579c30SDale Ghent 	case ixgbe_mac_X550:
55797e579c30SDale Ghent 	case ixgbe_mac_X550EM_x:
558073cd555cSBin Tu - Sun Microsystems - Beijing China 		for (v_idx = 0; v_idx < 64; v_idx++)
558173cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
558273cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0);
558373cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
55845b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
558573cd555cSBin Tu - Sun Microsystems - Beijing China 	default:
558673cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
558773cd555cSBin Tu - Sun Microsystems - Beijing China 	}
558873cd555cSBin Tu - Sun Microsystems - Beijing China 
55899da57d7bSbt150084 	/*
5590da14cebeSEric Cheng 	 * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and
5591da14cebeSEric Cheng 	 * tx rings[0] will use RTxQ[1].
55929da57d7bSbt150084 	 */
5593da14cebeSEric Cheng 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
559473cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_setup_ivar(ixgbe, 0, 0, 0);
559573cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_setup_ivar(ixgbe, 0, 1, 1);
5596da14cebeSEric Cheng 		return;
5597da14cebeSEric Cheng 	}
5598da14cebeSEric Cheng 
5599da14cebeSEric Cheng 	/*
560073cd555cSBin Tu - Sun Microsystems - Beijing China 	 * For MSI-X interrupt, "Other" is always on vector[0].
5601da14cebeSEric Cheng 	 */
560273cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1);
56039da57d7bSbt150084 
56049da57d7bSbt150084 	/*
56059da57d7bSbt150084 	 * For each interrupt vector, populate the IVAR table
56069da57d7bSbt150084 	 */
56079da57d7bSbt150084 	for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) {
56089da57d7bSbt150084 		vect = &ixgbe->vect_map[v_idx];
56099da57d7bSbt150084 
56109da57d7bSbt150084 		/*
56119da57d7bSbt150084 		 * For each rx ring bit set
56129da57d7bSbt150084 		 */
56139da57d7bSbt150084 		r_idx = bt_getlowbit(vect->rx_map, 0,
56149da57d7bSbt150084 		    (ixgbe->num_rx_rings - 1));
56159da57d7bSbt150084 
56169da57d7bSbt150084 		while (r_idx >= 0) {
56170dc2366fSVenugopal Iyer 			hw_index = ixgbe->rx_rings[r_idx].hw_index;
56180dc2366fSVenugopal Iyer 			ixgbe_setup_ivar(ixgbe, hw_index, v_idx, 0);
56199da57d7bSbt150084 			r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
56209da57d7bSbt150084 			    (ixgbe->num_rx_rings - 1));
56219da57d7bSbt150084 		}
56229da57d7bSbt150084 
56239da57d7bSbt150084 		/*
56249da57d7bSbt150084 		 * For each tx ring bit set
56259da57d7bSbt150084 		 */
56269da57d7bSbt150084 		r_idx = bt_getlowbit(vect->tx_map, 0,
56279da57d7bSbt150084 		    (ixgbe->num_tx_rings - 1));
56289da57d7bSbt150084 
56299da57d7bSbt150084 		while (r_idx >= 0) {
563073cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1);
56319da57d7bSbt150084 			r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
56329da57d7bSbt150084 			    (ixgbe->num_tx_rings - 1));
56339da57d7bSbt150084 		}
56349da57d7bSbt150084 	}
56359da57d7bSbt150084 }
56369da57d7bSbt150084 
56379da57d7bSbt150084 /*
56389da57d7bSbt150084  * ixgbe_rem_intr_handlers - Remove the interrupt handlers.
56399da57d7bSbt150084  */
56409da57d7bSbt150084 static void
56419da57d7bSbt150084 ixgbe_rem_intr_handlers(ixgbe_t *ixgbe)
56429da57d7bSbt150084 {
56439da57d7bSbt150084 	int i;
56449da57d7bSbt150084 	int rc;
56459da57d7bSbt150084 
56469da57d7bSbt150084 	for (i = 0; i < ixgbe->intr_cnt; i++) {
56479da57d7bSbt150084 		rc = ddi_intr_remove_handler(ixgbe->htable[i]);
56489da57d7bSbt150084 		if (rc != DDI_SUCCESS) {
56499da57d7bSbt150084 			IXGBE_DEBUGLOG_1(ixgbe,
56509da57d7bSbt150084 			    "Remove intr handler failed: %d", rc);
56519da57d7bSbt150084 		}
56529da57d7bSbt150084 	}
56539da57d7bSbt150084 }
56549da57d7bSbt150084 
56559da57d7bSbt150084 /*
56569da57d7bSbt150084  * ixgbe_rem_intrs - Remove the allocated interrupts.
56579da57d7bSbt150084  */
56589da57d7bSbt150084 static void
56599da57d7bSbt150084 ixgbe_rem_intrs(ixgbe_t *ixgbe)
56609da57d7bSbt150084 {
56619da57d7bSbt150084 	int i;
56629da57d7bSbt150084 	int rc;
56639da57d7bSbt150084 
56649da57d7bSbt150084 	for (i = 0; i < ixgbe->intr_cnt; i++) {
56659da57d7bSbt150084 		rc = ddi_intr_free(ixgbe->htable[i]);
56669da57d7bSbt150084 		if (rc != DDI_SUCCESS) {
56679da57d7bSbt150084 			IXGBE_DEBUGLOG_1(ixgbe,
56689da57d7bSbt150084 			    "Free intr failed: %d", rc);
56699da57d7bSbt150084 		}
56709da57d7bSbt150084 	}
56719da57d7bSbt150084 
56729da57d7bSbt150084 	kmem_free(ixgbe->htable, ixgbe->intr_size);
56739da57d7bSbt150084 	ixgbe->htable = NULL;
56749da57d7bSbt150084 }
56759da57d7bSbt150084 
56769da57d7bSbt150084 /*
56779da57d7bSbt150084  * ixgbe_enable_intrs - Enable all the ddi interrupts.
56789da57d7bSbt150084  */
56799da57d7bSbt150084 static int
56809da57d7bSbt150084 ixgbe_enable_intrs(ixgbe_t *ixgbe)
56819da57d7bSbt150084 {
56829da57d7bSbt150084 	int i;
56839da57d7bSbt150084 	int rc;
56849da57d7bSbt150084 
56859da57d7bSbt150084 	/*
56869da57d7bSbt150084 	 * Enable interrupts
56879da57d7bSbt150084 	 */
56889da57d7bSbt150084 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
56899da57d7bSbt150084 		/*
56909da57d7bSbt150084 		 * Call ddi_intr_block_enable() for MSI
56919da57d7bSbt150084 		 */
56929da57d7bSbt150084 		rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt);
56939da57d7bSbt150084 		if (rc != DDI_SUCCESS) {
56949da57d7bSbt150084 			ixgbe_log(ixgbe,
56959da57d7bSbt150084 			    "Enable block intr failed: %d", rc);
56969da57d7bSbt150084 			return (IXGBE_FAILURE);
56979da57d7bSbt150084 		}
56989da57d7bSbt150084 	} else {
56999da57d7bSbt150084 		/*
57009da57d7bSbt150084 		 * Call ddi_intr_enable() for Legacy/MSI non block enable
57019da57d7bSbt150084 		 */
57029da57d7bSbt150084 		for (i = 0; i < ixgbe->intr_cnt; i++) {
57039da57d7bSbt150084 			rc = ddi_intr_enable(ixgbe->htable[i]);
57049da57d7bSbt150084 			if (rc != DDI_SUCCESS) {
57059da57d7bSbt150084 				ixgbe_log(ixgbe,
57069da57d7bSbt150084 				    "Enable intr failed: %d", rc);
57079da57d7bSbt150084 				return (IXGBE_FAILURE);
57089da57d7bSbt150084 			}
57099da57d7bSbt150084 		}
57109da57d7bSbt150084 	}
57119da57d7bSbt150084 
57129da57d7bSbt150084 	return (IXGBE_SUCCESS);
57139da57d7bSbt150084 }
57149da57d7bSbt150084 
57159da57d7bSbt150084 /*
57169da57d7bSbt150084  * ixgbe_disable_intrs - Disable all the interrupts.
57179da57d7bSbt150084  */
57189da57d7bSbt150084 static int
57199da57d7bSbt150084 ixgbe_disable_intrs(ixgbe_t *ixgbe)
57209da57d7bSbt150084 {
57219da57d7bSbt150084 	int i;
57229da57d7bSbt150084 	int rc;
57239da57d7bSbt150084 
57249da57d7bSbt150084 	/*
57259da57d7bSbt150084 	 * Disable all interrupts
57269da57d7bSbt150084 	 */
57279da57d7bSbt150084 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
57289da57d7bSbt150084 		rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt);
57299da57d7bSbt150084 		if (rc != DDI_SUCCESS) {
57309da57d7bSbt150084 			ixgbe_log(ixgbe,
57319da57d7bSbt150084 			    "Disable block intr failed: %d", rc);
57329da57d7bSbt150084 			return (IXGBE_FAILURE);
57339da57d7bSbt150084 		}
57349da57d7bSbt150084 	} else {
57359da57d7bSbt150084 		for (i = 0; i < ixgbe->intr_cnt; i++) {
57369da57d7bSbt150084 			rc = ddi_intr_disable(ixgbe->htable[i]);
57379da57d7bSbt150084 			if (rc != DDI_SUCCESS) {
57389da57d7bSbt150084 				ixgbe_log(ixgbe,
57399da57d7bSbt150084 				    "Disable intr failed: %d", rc);
57409da57d7bSbt150084 				return (IXGBE_FAILURE);
57419da57d7bSbt150084 			}
57429da57d7bSbt150084 		}
57439da57d7bSbt150084 	}
57449da57d7bSbt150084 
57459da57d7bSbt150084 	return (IXGBE_SUCCESS);
57469da57d7bSbt150084 }
57479da57d7bSbt150084 
57489da57d7bSbt150084 /*
57499da57d7bSbt150084  * ixgbe_get_hw_state - Get and save parameters related to adapter hardware.
57509da57d7bSbt150084  */
57519da57d7bSbt150084 static void
57529da57d7bSbt150084 ixgbe_get_hw_state(ixgbe_t *ixgbe)
57539da57d7bSbt150084 {
57549da57d7bSbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
57557e579c30SDale Ghent 	ixgbe_link_speed speed = 0;
575613740cb2SPaul Guo 	boolean_t link_up = B_FALSE;
57579da57d7bSbt150084 	uint32_t pcs1g_anlp = 0;
57589da57d7bSbt150084 
57599da57d7bSbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
57609da57d7bSbt150084 	ixgbe->param_lp_1000fdx_cap = 0;
57619da57d7bSbt150084 	ixgbe->param_lp_100fdx_cap  = 0;
57629da57d7bSbt150084 
576313740cb2SPaul Guo 	/* check for link, don't wait */
57647e579c30SDale Ghent 	(void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
57655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
57667e579c30SDale Ghent 	/*
57677e579c30SDale Ghent 	 * Update the observed Link Partner's capabilities. Not all adapters
57687e579c30SDale Ghent 	 * can provide full information on the LP's capable speeds, so we
57697e579c30SDale Ghent 	 * provide what we can.
57707e579c30SDale Ghent 	 */
577113740cb2SPaul Guo 	if (link_up) {
57729da57d7bSbt150084 		pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
57739da57d7bSbt150084 
57749da57d7bSbt150084 		ixgbe->param_lp_1000fdx_cap =
57759da57d7bSbt150084 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
57769da57d7bSbt150084 		ixgbe->param_lp_100fdx_cap =
57779da57d7bSbt150084 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
57789da57d7bSbt150084 	}
57799da57d7bSbt150084 
57807e579c30SDale Ghent 	/*
57817e579c30SDale Ghent 	 * Update GLD's notion of the adapter's currently advertised speeds.
57827e579c30SDale Ghent 	 * Since the common code doesn't always record the current autonegotiate
57837e579c30SDale Ghent 	 * settings in the phy struct for all parts (specifically, adapters with
57847e579c30SDale Ghent 	 * SFPs) we first test to see if it is 0, and if so, we fall back to
57857e579c30SDale Ghent 	 * using the adapter's speed capabilities which we saved during instance
57867e579c30SDale Ghent 	 * init in ixgbe_init_params().
57877e579c30SDale Ghent 	 *
57887e579c30SDale Ghent 	 * Adapters with SFPs will always be shown as advertising all of their
57897e579c30SDale Ghent 	 * supported speeds, and adapters with baseT PHYs (where the phy struct
57907e579c30SDale Ghent 	 * is maintained by the common code) will always have a factual view of
57917e579c30SDale Ghent 	 * their currently-advertised speeds. In the case of SFPs, this is
57927e579c30SDale Ghent 	 * acceptable as we default to advertising all speeds that the adapter
57937e579c30SDale Ghent 	 * claims to support, and those properties are immutable; unlike on
57947e579c30SDale Ghent 	 * baseT (copper) PHYs, where speeds can be enabled or disabled at will.
57957e579c30SDale Ghent 	 */
57967e579c30SDale Ghent 	speed = hw->phy.autoneg_advertised;
57977e579c30SDale Ghent 	if (speed == 0)
57987e579c30SDale Ghent 		speed = ixgbe->speeds_supported;
57995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
58007e579c30SDale Ghent 	ixgbe->param_adv_10000fdx_cap =
58017e579c30SDale Ghent 	    (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 1 : 0;
58027e579c30SDale Ghent 	ixgbe->param_adv_5000fdx_cap =
58037e579c30SDale Ghent 	    (speed & IXGBE_LINK_SPEED_5GB_FULL) ? 1 : 0;
58047e579c30SDale Ghent 	ixgbe->param_adv_2500fdx_cap =
58057e579c30SDale Ghent 	    (speed & IXGBE_LINK_SPEED_2_5GB_FULL) ? 1 : 0;
58067e579c30SDale Ghent 	ixgbe->param_adv_1000fdx_cap =
58077e579c30SDale Ghent 	    (speed & IXGBE_LINK_SPEED_1GB_FULL) ? 1 : 0;
58087e579c30SDale Ghent 	ixgbe->param_adv_100fdx_cap =
58097e579c30SDale Ghent 	    (speed & IXGBE_LINK_SPEED_100_FULL) ? 1 : 0;
58109da57d7bSbt150084 }
58119da57d7bSbt150084 
58129da57d7bSbt150084 /*
58139da57d7bSbt150084  * ixgbe_get_driver_control - Notify that driver is in control of device.
58149da57d7bSbt150084  */
58159da57d7bSbt150084 static void
58169da57d7bSbt150084 ixgbe_get_driver_control(struct ixgbe_hw *hw)
58179da57d7bSbt150084 {
58189da57d7bSbt150084 	uint32_t ctrl_ext;
58199da57d7bSbt150084 
58209da57d7bSbt150084 	/*
58219da57d7bSbt150084 	 * Notify firmware that driver is in control of device
58229da57d7bSbt150084 	 */
58239da57d7bSbt150084 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
58249da57d7bSbt150084 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
58259da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
58269da57d7bSbt150084 }
58279da57d7bSbt150084 
58289da57d7bSbt150084 /*
58299da57d7bSbt150084  * ixgbe_release_driver_control - Notify that driver is no longer in control
58309da57d7bSbt150084  * of device.
58319da57d7bSbt150084  */
58329da57d7bSbt150084 static void
58339da57d7bSbt150084 ixgbe_release_driver_control(struct ixgbe_hw *hw)
58349da57d7bSbt150084 {
58359da57d7bSbt150084 	uint32_t ctrl_ext;
58369da57d7bSbt150084 
58379da57d7bSbt150084 	/*
58389da57d7bSbt150084 	 * Notify firmware that driver is no longer in control of device
58399da57d7bSbt150084 	 */
58409da57d7bSbt150084 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
58419da57d7bSbt150084 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
58429da57d7bSbt150084 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
58439da57d7bSbt150084 }
58449da57d7bSbt150084 
58459da57d7bSbt150084 /*
58469da57d7bSbt150084  * ixgbe_atomic_reserve - Atomic decrease operation.
58479da57d7bSbt150084  */
58489da57d7bSbt150084 int
58499da57d7bSbt150084 ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n)
58509da57d7bSbt150084 {
58519da57d7bSbt150084 	uint32_t oldval;
58529da57d7bSbt150084 	uint32_t newval;
58539da57d7bSbt150084 
58549da57d7bSbt150084 	/*
58559da57d7bSbt150084 	 * ATOMICALLY
58569da57d7bSbt150084 	 */
58579da57d7bSbt150084 	do {
58589da57d7bSbt150084 		oldval = *count_p;
58599da57d7bSbt150084 		if (oldval < n)
58609da57d7bSbt150084 			return (-1);
58619da57d7bSbt150084 		newval = oldval - n;
58629da57d7bSbt150084 	} while (atomic_cas_32(count_p, oldval, newval) != oldval);
58639da57d7bSbt150084 
58649da57d7bSbt150084 	return (newval);
58659da57d7bSbt150084 }
58669da57d7bSbt150084 
58679da57d7bSbt150084 /*
58689da57d7bSbt150084  * ixgbe_mc_table_itr - Traverse the entries in the multicast table.
58699da57d7bSbt150084  */
58709da57d7bSbt150084 static uint8_t *
58719da57d7bSbt150084 ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq)
58729da57d7bSbt150084 {
58739da57d7bSbt150084 	uint8_t *addr = *upd_ptr;
58749da57d7bSbt150084 	uint8_t *new_ptr;
58759da57d7bSbt150084 
587613740cb2SPaul Guo 	_NOTE(ARGUNUSED(hw));
587713740cb2SPaul Guo 	_NOTE(ARGUNUSED(vmdq));
587813740cb2SPaul Guo 
58799da57d7bSbt150084 	new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS;
58809da57d7bSbt150084 	*upd_ptr = new_ptr;
58819da57d7bSbt150084 	return (addr);
58829da57d7bSbt150084 }
58839da57d7bSbt150084 
58849da57d7bSbt150084 /*
58859da57d7bSbt150084  * FMA support
58869da57d7bSbt150084  */
58879da57d7bSbt150084 int
58889da57d7bSbt150084 ixgbe_check_acc_handle(ddi_acc_handle_t handle)
58899da57d7bSbt150084 {
58909da57d7bSbt150084 	ddi_fm_error_t de;
58919da57d7bSbt150084 
58929da57d7bSbt150084 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
58939da57d7bSbt150084 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
58949da57d7bSbt150084 	return (de.fme_status);
58959da57d7bSbt150084 }
58969da57d7bSbt150084 
58979da57d7bSbt150084 int
58989da57d7bSbt150084 ixgbe_check_dma_handle(ddi_dma_handle_t handle)
58999da57d7bSbt150084 {
59009da57d7bSbt150084 	ddi_fm_error_t de;
59019da57d7bSbt150084 
59029da57d7bSbt150084 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
59039da57d7bSbt150084 	return (de.fme_status);
59049da57d7bSbt150084 }
59059da57d7bSbt150084 
59069da57d7bSbt150084 /*
59079da57d7bSbt150084  * ixgbe_fm_error_cb - The IO fault service error handling callback function.
59089da57d7bSbt150084  */
59099da57d7bSbt150084 static int
59109da57d7bSbt150084 ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
59119da57d7bSbt150084 {
59129da57d7bSbt150084 	_NOTE(ARGUNUSED(impl_data));
59139da57d7bSbt150084 	/*
59149da57d7bSbt150084 	 * as the driver can always deal with an error in any dma or
59159da57d7bSbt150084 	 * access handle, we can just return the fme_status value.
59169da57d7bSbt150084 	 */
59179da57d7bSbt150084 	pci_ereport_post(dip, err, NULL);
59189da57d7bSbt150084 	return (err->fme_status);
59199da57d7bSbt150084 }
59209da57d7bSbt150084 
59219da57d7bSbt150084 static void
59229da57d7bSbt150084 ixgbe_fm_init(ixgbe_t *ixgbe)
59239da57d7bSbt150084 {
59249da57d7bSbt150084 	ddi_iblock_cookie_t iblk;
5925837c1ac4SStephen Hanson 	int fma_dma_flag;
59269da57d7bSbt150084 
59279da57d7bSbt150084 	/*
59289da57d7bSbt150084 	 * Only register with IO Fault Services if we have some capability
59299da57d7bSbt150084 	 */
59309da57d7bSbt150084 	if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
59319da57d7bSbt150084 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
59329da57d7bSbt150084 	} else {
59339da57d7bSbt150084 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
59349da57d7bSbt150084 	}
59359da57d7bSbt150084 
59369da57d7bSbt150084 	if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
59379da57d7bSbt150084 		fma_dma_flag = 1;
59389da57d7bSbt150084 	} else {
59399da57d7bSbt150084 		fma_dma_flag = 0;
59409da57d7bSbt150084 	}
59419da57d7bSbt150084 
5942837c1ac4SStephen Hanson 	ixgbe_set_fma_flags(fma_dma_flag);
59439da57d7bSbt150084 
59449da57d7bSbt150084 	if (ixgbe->fm_capabilities) {
59459da57d7bSbt150084 
59469da57d7bSbt150084 		/*
59479da57d7bSbt150084 		 * Register capabilities with IO Fault Services
59489da57d7bSbt150084 		 */
59499da57d7bSbt150084 		ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk);
59509da57d7bSbt150084 
59519da57d7bSbt150084 		/*
59529da57d7bSbt150084 		 * Initialize pci ereport capabilities if ereport capable
59539da57d7bSbt150084 		 */
59549da57d7bSbt150084 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
59559da57d7bSbt150084 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
59569da57d7bSbt150084 			pci_ereport_setup(ixgbe->dip);
59579da57d7bSbt150084 
59589da57d7bSbt150084 		/*
59599da57d7bSbt150084 		 * Register error callback if error callback capable
59609da57d7bSbt150084 		 */
59619da57d7bSbt150084 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
59629da57d7bSbt150084 			ddi_fm_handler_register(ixgbe->dip,
59639da57d7bSbt150084 			    ixgbe_fm_error_cb, (void*) ixgbe);
59649da57d7bSbt150084 	}
59659da57d7bSbt150084 }
59669da57d7bSbt150084 
59679da57d7bSbt150084 static void
59689da57d7bSbt150084 ixgbe_fm_fini(ixgbe_t *ixgbe)
59699da57d7bSbt150084 {
59709da57d7bSbt150084 	/*
59719da57d7bSbt150084 	 * Only unregister FMA capabilities if they are registered
59729da57d7bSbt150084 	 */
59739da57d7bSbt150084 	if (ixgbe->fm_capabilities) {
59749da57d7bSbt150084 
59759da57d7bSbt150084 		/*
59769da57d7bSbt150084 		 * Release any resources allocated by pci_ereport_setup()
59779da57d7bSbt150084 		 */
59789da57d7bSbt150084 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
59799da57d7bSbt150084 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
59809da57d7bSbt150084 			pci_ereport_teardown(ixgbe->dip);
59819da57d7bSbt150084 
59829da57d7bSbt150084 		/*
59839da57d7bSbt150084 		 * Un-register error callback if error callback capable
59849da57d7bSbt150084 		 */
59859da57d7bSbt150084 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
59869da57d7bSbt150084 			ddi_fm_handler_unregister(ixgbe->dip);
59879da57d7bSbt150084 
59889da57d7bSbt150084 		/*
59899da57d7bSbt150084 		 * Unregister from IO Fault Service
59909da57d7bSbt150084 		 */
59919da57d7bSbt150084 		ddi_fm_fini(ixgbe->dip);
59929da57d7bSbt150084 	}
59939da57d7bSbt150084 }
59949da57d7bSbt150084 
59959da57d7bSbt150084 void
59969da57d7bSbt150084 ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail)
59979da57d7bSbt150084 {
59989da57d7bSbt150084 	uint64_t ena;
59999da57d7bSbt150084 	char buf[FM_MAX_CLASS];
60009da57d7bSbt150084 
60019da57d7bSbt150084 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
60029da57d7bSbt150084 	ena = fm_ena_generate(0, FM_ENA_FMT1);
60039da57d7bSbt150084 	if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) {
60049da57d7bSbt150084 		ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP,
60059da57d7bSbt150084 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
60069da57d7bSbt150084 	}
60079da57d7bSbt150084 }
6008da14cebeSEric Cheng 
6009da14cebeSEric Cheng static int
6010da14cebeSEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
6011da14cebeSEric Cheng {
6012da14cebeSEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh;
6013da14cebeSEric Cheng 
6014da14cebeSEric Cheng 	mutex_enter(&rx_ring->rx_lock);
6015da14cebeSEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
6016da14cebeSEric Cheng 	mutex_exit(&rx_ring->rx_lock);
6017da14cebeSEric Cheng 	return (0);
6018da14cebeSEric Cheng }
6019da14cebeSEric Cheng 
6020da14cebeSEric Cheng /*
60210dc2366fSVenugopal Iyer  * Get the global ring index by a ring index within a group.
60220dc2366fSVenugopal Iyer  */
60230dc2366fSVenugopal Iyer static int
60240dc2366fSVenugopal Iyer ixgbe_get_rx_ring_index(ixgbe_t *ixgbe, int gindex, int rindex)
60250dc2366fSVenugopal Iyer {
60260dc2366fSVenugopal Iyer 	ixgbe_rx_ring_t *rx_ring;
60270dc2366fSVenugopal Iyer 	int i;
60280dc2366fSVenugopal Iyer 
60290dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
60300dc2366fSVenugopal Iyer 		rx_ring = &ixgbe->rx_rings[i];
60310dc2366fSVenugopal Iyer 		if (rx_ring->group_index == gindex)
60320dc2366fSVenugopal Iyer 			rindex--;
60330dc2366fSVenugopal Iyer 		if (rindex < 0)
60340dc2366fSVenugopal Iyer 			return (i);
60350dc2366fSVenugopal Iyer 	}
60360dc2366fSVenugopal Iyer 
60370dc2366fSVenugopal Iyer 	return (-1);
60380dc2366fSVenugopal Iyer }
60390dc2366fSVenugopal Iyer 
60400dc2366fSVenugopal Iyer /*
6041da14cebeSEric Cheng  * Callback funtion for MAC layer to register all rings.
6042da14cebeSEric Cheng  */
6043da14cebeSEric Cheng /* ARGSUSED */
6044da14cebeSEric Cheng void
60450dc2366fSVenugopal Iyer ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index,
6046da14cebeSEric Cheng     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
6047da14cebeSEric Cheng {
6048da14cebeSEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
6049da14cebeSEric Cheng 	mac_intr_t *mintr = &infop->mri_intr;
6050da14cebeSEric Cheng 
6051da14cebeSEric Cheng 	switch (rtype) {
6052da14cebeSEric Cheng 	case MAC_RING_TYPE_RX: {
60530dc2366fSVenugopal Iyer 		/*
60540dc2366fSVenugopal Iyer 		 * 'index' is the ring index within the group.
60550dc2366fSVenugopal Iyer 		 * Need to get the global ring index by searching in groups.
60560dc2366fSVenugopal Iyer 		 */
60570dc2366fSVenugopal Iyer 		int global_ring_index = ixgbe_get_rx_ring_index(
60580dc2366fSVenugopal Iyer 		    ixgbe, group_index, ring_index);
6059da14cebeSEric Cheng 
60600dc2366fSVenugopal Iyer 		ASSERT(global_ring_index >= 0);
60610dc2366fSVenugopal Iyer 
60620dc2366fSVenugopal Iyer 		ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[global_ring_index];
6063da14cebeSEric Cheng 		rx_ring->ring_handle = rh;
6064da14cebeSEric Cheng 
6065da14cebeSEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
6066da14cebeSEric Cheng 		infop->mri_start = ixgbe_ring_start;
6067da14cebeSEric Cheng 		infop->mri_stop = NULL;
6068da14cebeSEric Cheng 		infop->mri_poll = ixgbe_ring_rx_poll;
60690dc2366fSVenugopal Iyer 		infop->mri_stat = ixgbe_rx_ring_stat;
6070da14cebeSEric Cheng 
6071da14cebeSEric Cheng 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
6072da14cebeSEric Cheng 		mintr->mi_enable = ixgbe_rx_ring_intr_enable;
6073da14cebeSEric Cheng 		mintr->mi_disable = ixgbe_rx_ring_intr_disable;
60740dc2366fSVenugopal Iyer 		if (ixgbe->intr_type &
60750dc2366fSVenugopal Iyer 		    (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
60760dc2366fSVenugopal Iyer 			mintr->mi_ddi_handle =
60770dc2366fSVenugopal Iyer 			    ixgbe->htable[rx_ring->intr_vector];
60780dc2366fSVenugopal Iyer 		}
6079da14cebeSEric Cheng 
6080da14cebeSEric Cheng 		break;
6081da14cebeSEric Cheng 	}
6082da14cebeSEric Cheng 	case MAC_RING_TYPE_TX: {
60830dc2366fSVenugopal Iyer 		ASSERT(group_index == -1);
6084da14cebeSEric Cheng 		ASSERT(ring_index < ixgbe->num_tx_rings);
6085da14cebeSEric Cheng 
6086da14cebeSEric Cheng 		ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index];
6087da14cebeSEric Cheng 		tx_ring->ring_handle = rh;
6088da14cebeSEric Cheng 
6089da14cebeSEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
6090da14cebeSEric Cheng 		infop->mri_start = NULL;
6091da14cebeSEric Cheng 		infop->mri_stop = NULL;
6092da14cebeSEric Cheng 		infop->mri_tx = ixgbe_ring_tx;
60930dc2366fSVenugopal Iyer 		infop->mri_stat = ixgbe_tx_ring_stat;
60940dc2366fSVenugopal Iyer 		if (ixgbe->intr_type &
60950dc2366fSVenugopal Iyer 		    (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
60960dc2366fSVenugopal Iyer 			mintr->mi_ddi_handle =
60970dc2366fSVenugopal Iyer 			    ixgbe->htable[tx_ring->intr_vector];
60980dc2366fSVenugopal Iyer 		}
6099da14cebeSEric Cheng 		break;
6100da14cebeSEric Cheng 	}
6101da14cebeSEric Cheng 	default:
6102da14cebeSEric Cheng 		break;
6103da14cebeSEric Cheng 	}
6104da14cebeSEric Cheng }
6105da14cebeSEric Cheng 
6106da14cebeSEric Cheng /*
6107da14cebeSEric Cheng  * Callback funtion for MAC layer to register all groups.
6108da14cebeSEric Cheng  */
6109da14cebeSEric Cheng void
6110da14cebeSEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index,
6111da14cebeSEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
6112da14cebeSEric Cheng {
6113da14cebeSEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
6114da14cebeSEric Cheng 
6115da14cebeSEric Cheng 	switch (rtype) {
6116da14cebeSEric Cheng 	case MAC_RING_TYPE_RX: {
6117da14cebeSEric Cheng 		ixgbe_rx_group_t *rx_group;
6118da14cebeSEric Cheng 
6119da14cebeSEric Cheng 		rx_group = &ixgbe->rx_groups[index];
6120da14cebeSEric Cheng 		rx_group->group_handle = gh;
6121da14cebeSEric Cheng 
6122da14cebeSEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_group;
6123da14cebeSEric Cheng 		infop->mgi_start = NULL;
6124da14cebeSEric Cheng 		infop->mgi_stop = NULL;
6125da14cebeSEric Cheng 		infop->mgi_addmac = ixgbe_addmac;
6126da14cebeSEric Cheng 		infop->mgi_remmac = ixgbe_remmac;
6127da14cebeSEric Cheng 		infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups);
6128da14cebeSEric Cheng 
6129da14cebeSEric Cheng 		break;
6130da14cebeSEric Cheng 	}
6131da14cebeSEric Cheng 	case MAC_RING_TYPE_TX:
6132da14cebeSEric Cheng 		break;
6133da14cebeSEric Cheng 	default:
6134da14cebeSEric Cheng 		break;
6135da14cebeSEric Cheng 	}
6136da14cebeSEric Cheng }
6137da14cebeSEric Cheng 
6138da14cebeSEric Cheng /*
6139da14cebeSEric Cheng  * Enable interrupt on the specificed rx ring.
6140da14cebeSEric Cheng  */
6141da14cebeSEric Cheng int
6142da14cebeSEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)
6143da14cebeSEric Cheng {
6144da14cebeSEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
6145da14cebeSEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
6146da14cebeSEric Cheng 	int r_idx = rx_ring->index;
61470dc2366fSVenugopal Iyer 	int hw_r_idx = rx_ring->hw_index;
6148da14cebeSEric Cheng 	int v_idx = rx_ring->intr_vector;
6149da14cebeSEric Cheng 
6150da14cebeSEric Cheng 	mutex_enter(&ixgbe->gen_lock);
61510dc2366fSVenugopal Iyer 	if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
61520dc2366fSVenugopal Iyer 		mutex_exit(&ixgbe->gen_lock);
61530dc2366fSVenugopal Iyer 		/*
61540dc2366fSVenugopal Iyer 		 * Simply return 0.
61550dc2366fSVenugopal Iyer 		 * Interrupts are being adjusted. ixgbe_intr_adjust()
61560dc2366fSVenugopal Iyer 		 * will eventually re-enable the interrupt when it's
61570dc2366fSVenugopal Iyer 		 * done with the adjustment.
61580dc2366fSVenugopal Iyer 		 */
61590dc2366fSVenugopal Iyer 		return (0);
61600dc2366fSVenugopal Iyer 	}
6161da14cebeSEric Cheng 
6162da14cebeSEric Cheng 	/*
6163da14cebeSEric Cheng 	 * To enable interrupt by setting the VAL bit of given interrupt
6164da14cebeSEric Cheng 	 * vector allocation register (IVAR).
6165da14cebeSEric Cheng 	 */
61660dc2366fSVenugopal Iyer 	ixgbe_enable_ivar(ixgbe, hw_r_idx, 0);
6167da14cebeSEric Cheng 
6168da14cebeSEric Cheng 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
6169185c5677SPaul Guo 
6170185c5677SPaul Guo 	/*
617119843f01SPaul Guo 	 * Trigger a Rx interrupt on this ring
6172185c5677SPaul Guo 	 */
6173185c5677SPaul Guo 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx));
6174185c5677SPaul Guo 	IXGBE_WRITE_FLUSH(&ixgbe->hw);
6175185c5677SPaul Guo 
6176da14cebeSEric Cheng 	mutex_exit(&ixgbe->gen_lock);
6177da14cebeSEric Cheng 
6178da14cebeSEric Cheng 	return (0);
6179da14cebeSEric Cheng }
6180da14cebeSEric Cheng 
6181da14cebeSEric Cheng /*
6182da14cebeSEric Cheng  * Disable interrupt on the specificed rx ring.
6183da14cebeSEric Cheng  */
6184da14cebeSEric Cheng int
6185da14cebeSEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)
6186da14cebeSEric Cheng {
6187da14cebeSEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
6188da14cebeSEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
6189da14cebeSEric Cheng 	int r_idx = rx_ring->index;
61900dc2366fSVenugopal Iyer 	int hw_r_idx = rx_ring->hw_index;
6191da14cebeSEric Cheng 	int v_idx = rx_ring->intr_vector;
6192da14cebeSEric Cheng 
6193da14cebeSEric Cheng 	mutex_enter(&ixgbe->gen_lock);
61940dc2366fSVenugopal Iyer 	if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
61950dc2366fSVenugopal Iyer 		mutex_exit(&ixgbe->gen_lock);
61960dc2366fSVenugopal Iyer 		/*
61970dc2366fSVenugopal Iyer 		 * Simply return 0.
61980dc2366fSVenugopal Iyer 		 * In the rare case where an interrupt is being
61990dc2366fSVenugopal Iyer 		 * disabled while interrupts are being adjusted,
62000dc2366fSVenugopal Iyer 		 * we don't fail the operation. No interrupts will
62010dc2366fSVenugopal Iyer 		 * be generated while they are adjusted, and
62020dc2366fSVenugopal Iyer 		 * ixgbe_intr_adjust() will cause the interrupts
62030dc2366fSVenugopal Iyer 		 * to be re-enabled once it completes. Note that
62040dc2366fSVenugopal Iyer 		 * in this case, packets may be delivered to the
62050dc2366fSVenugopal Iyer 		 * stack via interrupts before xgbe_rx_ring_intr_enable()
62060dc2366fSVenugopal Iyer 		 * is called again. This is acceptable since interrupt
62070dc2366fSVenugopal Iyer 		 * adjustment is infrequent, and the stack will be
62080dc2366fSVenugopal Iyer 		 * able to handle these packets.
62090dc2366fSVenugopal Iyer 		 */
62100dc2366fSVenugopal Iyer 		return (0);
62110dc2366fSVenugopal Iyer 	}
6212da14cebeSEric Cheng 
6213da14cebeSEric Cheng 	/*
6214da14cebeSEric Cheng 	 * To disable interrupt by clearing the VAL bit of given interrupt
6215da14cebeSEric Cheng 	 * vector allocation register (IVAR).
6216da14cebeSEric Cheng 	 */
62170dc2366fSVenugopal Iyer 	ixgbe_disable_ivar(ixgbe, hw_r_idx, 0);
6218da14cebeSEric Cheng 
6219da14cebeSEric Cheng 	BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx);
6220da14cebeSEric Cheng 
6221da14cebeSEric Cheng 	mutex_exit(&ixgbe->gen_lock);
6222da14cebeSEric Cheng 
6223da14cebeSEric Cheng 	return (0);
6224da14cebeSEric Cheng }
6225da14cebeSEric Cheng 
6226da14cebeSEric Cheng /*
6227da14cebeSEric Cheng  * Add a mac address.
6228da14cebeSEric Cheng  */
6229da14cebeSEric Cheng static int
6230da14cebeSEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr)
6231da14cebeSEric Cheng {
6232da14cebeSEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
6233da14cebeSEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
62340dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
62350dc2366fSVenugopal Iyer 	int slot, i;
6236da14cebeSEric Cheng 
6237da14cebeSEric Cheng 	mutex_enter(&ixgbe->gen_lock);
6238da14cebeSEric Cheng 
6239da14cebeSEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
6240da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6241da14cebeSEric Cheng 		return (ECANCELED);
6242da14cebeSEric Cheng 	}
6243da14cebeSEric Cheng 
6244da14cebeSEric Cheng 	if (ixgbe->unicst_avail == 0) {
6245da14cebeSEric Cheng 		/* no slots available */
6246da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6247da14cebeSEric Cheng 		return (ENOSPC);
6248da14cebeSEric Cheng 	}
6249da14cebeSEric Cheng 
62500dc2366fSVenugopal Iyer 	/*
62510dc2366fSVenugopal Iyer 	 * The first ixgbe->num_rx_groups slots are reserved for each respective
62520dc2366fSVenugopal Iyer 	 * group. The rest slots are shared by all groups. While adding a
62530dc2366fSVenugopal Iyer 	 * MAC address, reserved slots are firstly checked then the shared
62540dc2366fSVenugopal Iyer 	 * slots are searched.
62550dc2366fSVenugopal Iyer 	 */
62560dc2366fSVenugopal Iyer 	slot = -1;
62570dc2366fSVenugopal Iyer 	if (ixgbe->unicst_addr[rx_group->index].mac.set == 1) {
62580dc2366fSVenugopal Iyer 		for (i = ixgbe->num_rx_groups; i < ixgbe->unicst_total; i++) {
62590dc2366fSVenugopal Iyer 			if (ixgbe->unicst_addr[i].mac.set == 0) {
62600dc2366fSVenugopal Iyer 				slot = i;
6261da14cebeSEric Cheng 				break;
6262da14cebeSEric Cheng 			}
6263da14cebeSEric Cheng 		}
62640dc2366fSVenugopal Iyer 	} else {
62650dc2366fSVenugopal Iyer 		slot = rx_group->index;
62660dc2366fSVenugopal Iyer 	}
62670dc2366fSVenugopal Iyer 
62680dc2366fSVenugopal Iyer 	if (slot == -1) {
62690dc2366fSVenugopal Iyer 		/* no slots available */
62700dc2366fSVenugopal Iyer 		mutex_exit(&ixgbe->gen_lock);
62710dc2366fSVenugopal Iyer 		return (ENOSPC);
62720dc2366fSVenugopal Iyer 	}
62730dc2366fSVenugopal Iyer 
62740dc2366fSVenugopal Iyer 	bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
62750dc2366fSVenugopal Iyer 	(void) ixgbe_set_rar(hw, slot, ixgbe->unicst_addr[slot].mac.addr,
62760dc2366fSVenugopal Iyer 	    rx_group->index, IXGBE_RAH_AV);
62770dc2366fSVenugopal Iyer 	ixgbe->unicst_addr[slot].mac.set = 1;
62780dc2366fSVenugopal Iyer 	ixgbe->unicst_addr[slot].mac.group_index = rx_group->index;
62790dc2366fSVenugopal Iyer 	ixgbe->unicst_avail--;
6280da14cebeSEric Cheng 
6281da14cebeSEric Cheng 	mutex_exit(&ixgbe->gen_lock);
6282da14cebeSEric Cheng 
62830dc2366fSVenugopal Iyer 	return (0);
6284da14cebeSEric Cheng }
6285da14cebeSEric Cheng 
6286da14cebeSEric Cheng /*
6287da14cebeSEric Cheng  * Remove a mac address.
6288da14cebeSEric Cheng  */
6289da14cebeSEric Cheng static int
6290da14cebeSEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr)
6291da14cebeSEric Cheng {
6292da14cebeSEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
6293da14cebeSEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
62940dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
6295da14cebeSEric Cheng 	int slot;
6296da14cebeSEric Cheng 
6297da14cebeSEric Cheng 	mutex_enter(&ixgbe->gen_lock);
6298da14cebeSEric Cheng 
6299da14cebeSEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
6300da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6301da14cebeSEric Cheng 		return (ECANCELED);
6302da14cebeSEric Cheng 	}
6303da14cebeSEric Cheng 
6304da14cebeSEric Cheng 	slot = ixgbe_unicst_find(ixgbe, mac_addr);
6305da14cebeSEric Cheng 	if (slot == -1) {
6306da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6307da14cebeSEric Cheng 		return (EINVAL);
6308da14cebeSEric Cheng 	}
6309da14cebeSEric Cheng 
6310da14cebeSEric Cheng 	if (ixgbe->unicst_addr[slot].mac.set == 0) {
6311da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6312da14cebeSEric Cheng 		return (EINVAL);
6313da14cebeSEric Cheng 	}
6314da14cebeSEric Cheng 
6315da14cebeSEric Cheng 	bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
63160dc2366fSVenugopal Iyer 	(void) ixgbe_clear_rar(hw, slot);
6317da14cebeSEric Cheng 	ixgbe->unicst_addr[slot].mac.set = 0;
6318da14cebeSEric Cheng 	ixgbe->unicst_avail++;
6319da14cebeSEric Cheng 
6320da14cebeSEric Cheng 	mutex_exit(&ixgbe->gen_lock);
6321da14cebeSEric Cheng 
63220dc2366fSVenugopal Iyer 	return (0);
6323da14cebeSEric Cheng }
6324