19da57d7bSbt /*
29da57d7bSbt  * CDDL HEADER START
39da57d7bSbt  *
49da57d7bSbt  * The contents of this file are subject to the terms of the
59da57d7bSbt  * Common Development and Distribution License (the "License").
69da57d7bSbt  * You may not use this file except in compliance with the License.
79da57d7bSbt  *
819397407SSherry Moore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
919397407SSherry Moore  * or http://www.opensolaris.org/os/licensing.
109da57d7bSbt  * See the License for the specific language governing permissions
119da57d7bSbt  * and limitations under the License.
129da57d7bSbt  *
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.
159da57d7bSbt  * If applicable, add the following below this CDDL HEADER, with the
169da57d7bSbt  * fields enclosed by brackets "[]" replaced with your own identifying
179da57d7bSbt  * information: Portions Copyright [yyyy] [name of copyright owner]
189da57d7bSbt  *
199da57d7bSbt  * CDDL HEADER END
209da57d7bSbt  */
219da57d7bSbt 
229da57d7bSbt /*
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.
2884de666eSRyan Zezeski  * Copyright 2020 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.
32dc0cb1cdSDale Ghent  * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
33f2fe7acaSRobert Mustacchi  * Copyright 2020 Oxide Computer Company
349da57d7bSbt  */
359da57d7bSbt 
369da57d7bSbt #include "ixgbe_sw.h"
379da57d7bSbt 
38ffd8e883SWinson Wang - Sun Microsystems - Beijing China static char ixgbe_ident[] = "Intel 10Gb Ethernet";
399da57d7bSbt 
409da57d7bSbt /*
419da57d7bSbt  * Local function protoypes
429da57d7bSbt  */
439da57d7bSbt static int ixgbe_register_mac(ixgbe_t *);
449da57d7bSbt static int ixgbe_identify_hardware(ixgbe_t *);
459da57d7bSbt static int ixgbe_regs_map(ixgbe_t *);
469da57d7bSbt static void ixgbe_init_properties(ixgbe_t *);
479da57d7bSbt static int ixgbe_init_driver_settings(ixgbe_t *);
489da57d7bSbt static void ixgbe_init_locks(ixgbe_t *);
499da57d7bSbt static void ixgbe_destroy_locks(ixgbe_t *);
509da57d7bSbt static int ixgbe_init(ixgbe_t *);
519da57d7bSbt static int ixgbe_chip_start(ixgbe_t *);
529da57d7bSbt static void ixgbe_chip_stop(ixgbe_t *);
539da57d7bSbt static int ixgbe_reset(ixgbe_t *);
549da57d7bSbt static void ixgbe_tx_clean(ixgbe_t *);
559da57d7bSbt static boolean_t ixgbe_tx_drain(ixgbe_t *);
569da57d7bSbt static boolean_t ixgbe_rx_drain(ixgbe_t *);
579da57d7bSbt static int ixgbe_alloc_rings(ixgbe_t *);
589da57d7bSbt static void ixgbe_free_rings(ixgbe_t *);
59ea65739eSchenlu chen - Sun Microsystems - Beijing China static int ixgbe_alloc_rx_data(ixgbe_t *);
60ea65739eSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_free_rx_data(ixgbe_t *);
6184de666eSRyan Zezeski static int ixgbe_setup_rings(ixgbe_t *);
6284de666eSRyan Zezeski static int ixgbe_setup_rx(ixgbe_t *);
639da57d7bSbt static void ixgbe_setup_tx(ixgbe_t *);
649da57d7bSbt static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *);
659da57d7bSbt static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *);
669da57d7bSbt static void ixgbe_setup_rss(ixgbe_t *);
670dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq(ixgbe_t *);
680dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq_rss(ixgbe_t *);
69dc0cb1cdSDale Ghent static void ixgbe_setup_rss_table(ixgbe_t *);
709da57d7bSbt static void ixgbe_init_unicst(ixgbe_t *);
7184de666eSRyan Zezeski static int ixgbe_init_vlan(ixgbe_t *);
72da14cebeSEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *);
739da57d7bSbt static void ixgbe_setup_multicst(ixgbe_t *);
749da57d7bSbt static void ixgbe_get_hw_state(ixgbe_t *);
750dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe);
769da57d7bSbt static void ixgbe_get_conf(ixgbe_t *);
77ea65739eSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_init_params(ixgbe_t *);
789da57d7bSbt static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int);
7962e6e1adSPaul Guo static void ixgbe_driver_link_check(ixgbe_t *);
8073cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_sfp_check(void *);
815b6dd21fSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_overtemp_check(void *);
82dc0cb1cdSDale Ghent static void ixgbe_phy_check(void *);
8362e6e1adSPaul Guo static void ixgbe_link_timer(void *);
849da57d7bSbt static void ixgbe_local_timer(void *);
859da57d7bSbt static void ixgbe_arm_watchdog_timer(ixgbe_t *);
869da57d7bSbt static void ixgbe_restart_watchdog_timer(ixgbe_t *);
879da57d7bSbt static void ixgbe_disable_adapter_interrupts(ixgbe_t *);
889da57d7bSbt static void ixgbe_enable_adapter_interrupts(ixgbe_t *);
899da57d7bSbt static boolean_t is_valid_mac_addr(uint8_t *);
909da57d7bSbt static boolean_t ixgbe_stall_check(ixgbe_t *);
919da57d7bSbt static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t);
929da57d7bSbt static void ixgbe_set_internal_mac_loopback(ixgbe_t *);
939da57d7bSbt static boolean_t ixgbe_find_mac_address(ixgbe_t *);
949da57d7bSbt static int ixgbe_alloc_intrs(ixgbe_t *);
959da57d7bSbt static int ixgbe_alloc_intr_handles(ixgbe_t *, int);
969da57d7bSbt static int ixgbe_add_intr_handlers(ixgbe_t *);
979da57d7bSbt static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int);
989da57d7bSbt static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int);
9973cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t);
10073cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t);
10173cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t);
1020dc2366fSVenugopal Iyer static uint32_t ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index);
10373cd555cSBin Tu - Sun Microsystems - Beijing China static int ixgbe_map_intrs_to_vectors(ixgbe_t *);
1049da57d7bSbt static void ixgbe_setup_adapter_vector(ixgbe_t *);
1059da57d7bSbt static void ixgbe_rem_intr_handlers(ixgbe_t *);
1069da57d7bSbt static void ixgbe_rem_intrs(ixgbe_t *);
1079da57d7bSbt static int ixgbe_enable_intrs(ixgbe_t *);
1089da57d7bSbt static int ixgbe_disable_intrs(ixgbe_t *);
1099da57d7bSbt static uint_t ixgbe_intr_legacy(void *, void *);
1109da57d7bSbt static uint_t ixgbe_intr_msi(void *, void *);
11173cd555cSBin Tu - Sun Microsystems - Beijing China static uint_t ixgbe_intr_msix(void *, void *);
1129da57d7bSbt static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *);
1139da57d7bSbt static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *);
11413740cb2SPaul Guo static void ixgbe_intr_other_work(ixgbe_t *, uint32_t);
1159da57d7bSbt static void ixgbe_get_driver_control(struct ixgbe_hw *);
116da14cebeSEric Cheng static int ixgbe_addmac(void *, const uint8_t *);
117da14cebeSEric Cheng static int ixgbe_remmac(void *, const uint8_t *);
11884de666eSRyan Zezeski static int ixgbe_addvlan(mac_group_driver_t, uint16_t);
11984de666eSRyan Zezeski static int ixgbe_remvlan(mac_group_driver_t, uint16_t);
1209da57d7bSbt static void ixgbe_release_driver_control(struct ixgbe_hw *);
1219da57d7bSbt 
1229da57d7bSbt static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t);
1239da57d7bSbt static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t);
1249da57d7bSbt static int ixgbe_resume(dev_info_t *);
1259da57d7bSbt static int ixgbe_suspend(dev_info_t *);
1268c430e59SSaso Kiselkov static int ixgbe_quiesce(dev_info_t *);
1279da57d7bSbt static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *);
1289da57d7bSbt static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *);
1290dc2366fSVenugopal Iyer static int ixgbe_cbfunc(dev_info_t *, ddi_cb_action_t, void *, void *, void *);
1300dc2366fSVenugopal Iyer static int ixgbe_intr_cb_register(ixgbe_t *);
1310dc2366fSVenugopal Iyer static int ixgbe_intr_adjust(ixgbe_t *, ddi_cb_action_t, int);
1329da57d7bSbt 
1339da57d7bSbt static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
1349da57d7bSbt     const void *impl_data);
1359da57d7bSbt static void ixgbe_fm_init(ixgbe_t *);
1369da57d7bSbt static void ixgbe_fm_fini(ixgbe_t *);
137f2fe7acaSRobert Mustacchi static int ixgbe_ufm_fill_image(ddi_ufm_handle_t *, void *arg, uint_t,
138f2fe7acaSRobert Mustacchi     ddi_ufm_image_t *);
139f2fe7acaSRobert Mustacchi static int ixgbe_ufm_fill_slot(ddi_ufm_handle_t *, void *, uint_t, uint_t,
140f2fe7acaSRobert Mustacchi     ddi_ufm_slot_t *);
141f2fe7acaSRobert Mustacchi static int ixgbe_ufm_getcaps(ddi_ufm_handle_t *, void *, ddi_ufm_cap_t *);
142f2fe7acaSRobert Mustacchi static int ixgbe_ufm_readimg(ddi_ufm_handle_t *, void *, uint_t, uint_t,
143f2fe7acaSRobert Mustacchi     uint64_t, uint64_t, void *, uint64_t *);
1449da57d7bSbt 
1450dc2366fSVenugopal Iyer char *ixgbe_priv_props[] = {
1460dc2366fSVenugopal Iyer 	"_tx_copy_thresh",
1470dc2366fSVenugopal Iyer 	"_tx_recycle_thresh",
1480dc2366fSVenugopal Iyer 	"_tx_overload_thresh",
1490dc2366fSVenugopal Iyer 	"_tx_resched_thresh",
1500dc2366fSVenugopal Iyer 	"_rx_copy_thresh",
1510dc2366fSVenugopal Iyer 	"_rx_limit_per_intr",
1520dc2366fSVenugopal Iyer 	"_intr_throttling",
1530dc2366fSVenugopal Iyer 	"_adv_pause_cap",
1540dc2366fSVenugopal Iyer 	"_adv_asym_pause_cap",
1550dc2366fSVenugopal Iyer 	NULL
156ea65739eSchenlu chen - Sun Microsystems - Beijing China };
157ea65739eSchenlu chen - Sun Microsystems - Beijing China 
158ea65739eSchenlu chen - Sun Microsystems - Beijing China #define	IXGBE_MAX_PRIV_PROPS \
159ea65739eSchenlu chen - Sun Microsystems - Beijing China 	(sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t))
160ea65739eSchenlu chen - Sun Microsystems - Beijing China 
1619da57d7bSbt static struct cb_ops ixgbe_cb_ops = {
1629da57d7bSbt 	nulldev,		/* cb_open */
1639da57d7bSbt 	nulldev,		/* cb_close */
1649da57d7bSbt 	nodev,			/* cb_strategy */
1659da57d7bSbt 	nodev,			/* cb_print */
1669da57d7bSbt 	nodev,			/* cb_dump */
1679da57d7bSbt 	nodev,			/* cb_read */
1689da57d7bSbt 	nodev,			/* cb_write */
1699da57d7bSbt 	nodev,			/* cb_ioctl */
1709da57d7bSbt 	nodev,			/* cb_devmap */
1719da57d7bSbt 	nodev,			/* cb_mmap */
1729da57d7bSbt 	nodev,			/* cb_segmap */
1739da57d7bSbt 	nochpoll,		/* cb_chpoll */
1749da57d7bSbt 	ddi_prop_op,		/* cb_prop_op */
1759da57d7bSbt 	NULL,			/* cb_stream */
1769da57d7bSbt 	D_MP | D_HOTPLUG,	/* cb_flag */
1779da57d7bSbt 	CB_REV,			/* cb_rev */
1789da57d7bSbt 	nodev,			/* cb_aread */
1799da57d7bSbt 	nodev			/* cb_awrite */
1809da57d7bSbt };
1819da57d7bSbt 
1829da57d7bSbt static struct dev_ops ixgbe_dev_ops = {
1839da57d7bSbt 	DEVO_REV,		/* devo_rev */
1849da57d7bSbt 	0,			/* devo_refcnt */
1859da57d7bSbt 	NULL,			/* devo_getinfo */
1869da57d7bSbt 	nulldev,		/* devo_identify */
1879da57d7bSbt 	nulldev,		/* devo_probe */
1889da57d7bSbt 	ixgbe_attach,		/* devo_attach */
1899da57d7bSbt 	ixgbe_detach,		/* devo_detach */
1909da57d7bSbt 	nodev,			/* devo_reset */
1919da57d7bSbt 	&ixgbe_cb_ops,		/* devo_cb_ops */
1929da57d7bSbt 	NULL,			/* devo_bus_ops */
19319397407SSherry Moore 	ddi_power,		/* devo_power */
1948c430e59SSaso Kiselkov 	ixgbe_quiesce,		/* devo_quiesce */
1959da57d7bSbt };
1969da57d7bSbt 
1979da57d7bSbt static struct modldrv ixgbe_modldrv = {
1989da57d7bSbt 	&mod_driverops,		/* Type of module.  This one is a driver */
199ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	ixgbe_ident,		/* Discription string */
2009da57d7bSbt 	&ixgbe_dev_ops		/* driver ops */
2019da57d7bSbt };
2029da57d7bSbt 
2039da57d7bSbt static struct modlinkage ixgbe_modlinkage = {
2049da57d7bSbt 	MODREV_1, &ixgbe_modldrv, NULL
2059da57d7bSbt };
2069da57d7bSbt 
2079da57d7bSbt /*
2089da57d7bSbt  * Access attributes for register mapping
2099da57d7bSbt  */
2109da57d7bSbt ddi_device_acc_attr_t ixgbe_regs_acc_attr = {
211837c1ac4SStephen Hanson 	DDI_DEVICE_ATTR_V1,
2129da57d7bSbt 	DDI_STRUCTURE_LE_ACC,
2139da57d7bSbt 	DDI_STRICTORDER_ACC,
2149da57d7bSbt 	DDI_FLAGERR_ACC
2159da57d7bSbt };
2169da57d7bSbt 
2179da57d7bSbt /*
2189da57d7bSbt  * Loopback property
2199da57d7bSbt  */
2209da57d7bSbt static lb_property_t lb_normal = {
2219da57d7bSbt 	normal,	"normal", IXGBE_LB_NONE
2229da57d7bSbt };
2239da57d7bSbt 
2249da57d7bSbt static lb_property_t lb_mac = {
2259da57d7bSbt 	internal, "MAC", IXGBE_LB_INTERNAL_MAC
2269da57d7bSbt };
2279da57d7bSbt 
2281fedc51fSWinson Wang - Sun Microsystems - Beijing China static lb_property_t lb_external = {
2291fedc51fSWinson Wang - Sun Microsystems - Beijing China 	external, "External", IXGBE_LB_EXTERNAL
2301fedc51fSWinson Wang - Sun Microsystems - Beijing China };
2311fedc51fSWinson Wang - Sun Microsystems - Beijing China 
232ea65739eSchenlu chen - Sun Microsystems - Beijing China #define	IXGBE_M_CALLBACK_FLAGS \
2330dc2366fSVenugopal Iyer 	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
2349da57d7bSbt 
2359da57d7bSbt static mac_callbacks_t ixgbe_m_callbacks = {
2369da57d7bSbt 	IXGBE_M_CALLBACK_FLAGS,
2379da57d7bSbt 	ixgbe_m_stat,
2389da57d7bSbt 	ixgbe_m_start,
2399da57d7bSbt 	ixgbe_m_stop,
2409da57d7bSbt 	ixgbe_m_promisc,
2419da57d7bSbt 	ixgbe_m_multicst,
242da14cebeSEric Cheng 	NULL,
2439da57d7bSbt 	NULL,
2440dc2366fSVenugopal Iyer 	NULL,
2459da57d7bSbt 	ixgbe_m_ioctl,
246ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_m_getcapab,
247ea65739eSchenlu chen - Sun Microsystems - Beijing China 	NULL,
248ea65739eSchenlu chen - Sun Microsystems - Beijing China 	NULL,
249ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_m_setprop,
2500dc2366fSVenugopal Iyer 	ixgbe_m_getprop,
2510dc2366fSVenugopal Iyer 	ixgbe_m_propinfo
2529da57d7bSbt };
2539da57d7bSbt 
25413740cb2SPaul Guo /*
25513740cb2SPaul Guo  * Initialize capabilities of each supported adapter type
25613740cb2SPaul Guo  */
25713740cb2SPaul Guo static adapter_info_t ixgbe_82598eb_cap = {
25813740cb2SPaul Guo 	64,		/* maximum number of rx queues */
25913740cb2SPaul Guo 	1,		/* minimum number of rx queues */
2600dc2366fSVenugopal Iyer 	64,		/* default number of rx queues */
2610dc2366fSVenugopal Iyer 	16,		/* maximum number of rx groups */
2620dc2366fSVenugopal Iyer 	1,		/* minimum number of rx groups */
2630dc2366fSVenugopal Iyer 	1,		/* default number of rx groups */
26413740cb2SPaul Guo 	32,		/* maximum number of tx queues */
26513740cb2SPaul Guo 	1,		/* minimum number of tx queues */
26613740cb2SPaul Guo 	8,		/* default number of tx queues */
2671fedc51fSWinson Wang - Sun Microsystems - Beijing China 	16366,		/* maximum MTU size */
268ea65739eSchenlu chen - Sun Microsystems - Beijing China 	0xFFFF,		/* maximum interrupt throttle rate */
269ea65739eSchenlu chen - Sun Microsystems - Beijing China 	0,		/* minimum interrupt throttle rate */
270ea65739eSchenlu chen - Sun Microsystems - Beijing China 	200,		/* default interrupt throttle rate */
27113740cb2SPaul Guo 	18,		/* maximum total msix vectors */
27213740cb2SPaul Guo 	16,		/* maximum number of ring vectors */
27313740cb2SPaul Guo 	2,		/* maximum number of other vectors */
27413740cb2SPaul Guo 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
2755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	0,		/* "other" interrupt types enable mask */
27613740cb2SPaul Guo 	(IXGBE_FLAG_DCA_CAPABLE	/* capability flags */
27713740cb2SPaul Guo 	| IXGBE_FLAG_RSS_CAPABLE
27813740cb2SPaul Guo 	| IXGBE_FLAG_VMDQ_CAPABLE)
27913740cb2SPaul Guo };
28013740cb2SPaul Guo 
28173cd555cSBin Tu - Sun Microsystems - Beijing China static adapter_info_t ixgbe_82599eb_cap = {
28273cd555cSBin Tu - Sun Microsystems - Beijing China 	128,		/* maximum number of rx queues */
28373cd555cSBin Tu - Sun Microsystems - Beijing China 	1,		/* minimum number of rx queues */
2840dc2366fSVenugopal Iyer 	128,		/* default number of rx queues */
2850dc2366fSVenugopal Iyer 	64,		/* maximum number of rx groups */
2860dc2366fSVenugopal Iyer 	1,		/* minimum number of rx groups */
2870dc2366fSVenugopal Iyer 	1,		/* default number of rx groups */
28873cd555cSBin Tu - Sun Microsystems - Beijing China 	128,		/* maximum number of tx queues */
28973cd555cSBin Tu - Sun Microsystems - Beijing China 	1,		/* minimum number of tx queues */
29073cd555cSBin Tu - Sun Microsystems - Beijing China 	8,		/* default number of tx queues */
2911fedc51fSWinson Wang - Sun Microsystems - Beijing China 	15500,		/* maximum MTU size */
292ea65739eSchenlu chen - Sun Microsystems - Beijing China 	0xFF8,		/* maximum interrupt throttle rate */
293ea65739eSchenlu chen - Sun Microsystems - Beijing China 	0,		/* minimum interrupt throttle rate */
294ea65739eSchenlu chen - Sun Microsystems - Beijing China 	200,		/* default interrupt throttle rate */
29573cd555cSBin Tu - Sun Microsystems - Beijing China 	64,		/* maximum total msix vectors */
29673cd555cSBin Tu - Sun Microsystems - Beijing China 	16,		/* maximum number of ring vectors */
29773cd555cSBin Tu - Sun Microsystems - Beijing China 	2,		/* maximum number of other vectors */
2985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(IXGBE_EICR_LSC
2995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_EICR_GPI_SDP1
3005b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_EICR_GPI_SDP2), /* "other" interrupt types handled */
3015b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
3025b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(IXGBE_SDP1_GPIEN
3035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_SDP2_GPIEN), /* "other" interrupt types enable mask */
3045b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
3055b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(IXGBE_FLAG_DCA_CAPABLE
30673cd555cSBin Tu - Sun Microsystems - Beijing China 	| IXGBE_FLAG_RSS_CAPABLE
307ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	| IXGBE_FLAG_VMDQ_CAPABLE
3085b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_FLAG_RSC_CAPABLE
3095b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	| IXGBE_FLAG_SFP_PLUG_CAPABLE) /* capability flags */
31073cd555cSBin Tu - Sun Microsystems - Beijing China };
31173cd555cSBin Tu - Sun Microsystems - Beijing China 
31269b5a878SDan McDonald static adapter_info_t ixgbe_X540_cap = {
31369b5a878SDan McDonald 	128,		/* maximum number of rx queues */
31469b5a878SDan McDonald 	1,		/* minimum number of rx queues */
31569b5a878SDan McDonald 	128,		/* default number of rx queues */
31669b5a878SDan McDonald 	64,		/* maximum number of rx groups */
31769b5a878SDan McDonald 	1,		/* minimum number of rx groups */
31869b5a878SDan McDonald 	1,		/* default number of rx groups */
31969b5a878SDan McDonald 	128,		/* maximum number of tx queues */
32069b5a878SDan McDonald 	1,		/* minimum number of tx queues */
32169b5a878SDan McDonald 	8,		/* default number of tx queues */
32269b5a878SDan McDonald 	15500,		/* maximum MTU size */
32369b5a878SDan McDonald 	0xFF8,		/* maximum interrupt throttle rate */
32469b5a878SDan McDonald 	0,		/* minimum interrupt throttle rate */
32569b5a878SDan McDonald 	200,		/* default interrupt throttle rate */
32669b5a878SDan McDonald 	64,		/* maximum total msix vectors */
32769b5a878SDan McDonald 	16,		/* maximum number of ring vectors */
32869b5a878SDan McDonald 	2,		/* maximum number of other vectors */
32969b5a878SDan McDonald 	(IXGBE_EICR_LSC
330dc0cb1cdSDale Ghent 	| IXGBE_EICR_GPI_SDP1_X540
331dc0cb1cdSDale Ghent 	| IXGBE_EICR_GPI_SDP2_X540), /* "other" interrupt types handled */
33269b5a878SDan McDonald 
333dc0cb1cdSDale Ghent 	(IXGBE_SDP1_GPIEN_X540
334dc0cb1cdSDale Ghent 	| IXGBE_SDP2_GPIEN_X540), /* "other" interrupt types enable mask */
33569b5a878SDan McDonald 
33669b5a878SDan McDonald 	(IXGBE_FLAG_DCA_CAPABLE
33769b5a878SDan McDonald 	| IXGBE_FLAG_RSS_CAPABLE
33869b5a878SDan McDonald 	| IXGBE_FLAG_VMDQ_CAPABLE
33969b5a878SDan McDonald 	| IXGBE_FLAG_RSC_CAPABLE) /* capability flags */
34069b5a878SDan McDonald };
34169b5a878SDan McDonald 
342dc0cb1cdSDale Ghent static adapter_info_t ixgbe_X550_cap = {
343dc0cb1cdSDale Ghent 	128,		/* maximum number of rx queues */
344dc0cb1cdSDale Ghent 	1,		/* minimum number of rx queues */
345dc0cb1cdSDale Ghent 	128,		/* default number of rx queues */
346dc0cb1cdSDale Ghent 	64,		/* maximum number of rx groups */
347dc0cb1cdSDale Ghent 	1,		/* minimum number of rx groups */
348dc0cb1cdSDale Ghent 	1,		/* default number of rx groups */
349dc0cb1cdSDale Ghent 	128,		/* maximum number of tx queues */
350dc0cb1cdSDale Ghent 	1,		/* minimum number of tx queues */
351dc0cb1cdSDale Ghent 	8,		/* default number of tx queues */
352dc0cb1cdSDale Ghent 	15500,		/* maximum MTU size */
353dc0cb1cdSDale Ghent 	0xFF8,		/* maximum interrupt throttle rate */
354dc0cb1cdSDale Ghent 	0,		/* minimum interrupt throttle rate */
355dc0cb1cdSDale Ghent 	0x200,		/* default interrupt throttle rate */
356dc0cb1cdSDale Ghent 	64,		/* maximum total msix vectors */
357dc0cb1cdSDale Ghent 	16,		/* maximum number of ring vectors */
358dc0cb1cdSDale Ghent 	2,		/* maximum number of other vectors */
359dc0cb1cdSDale Ghent 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
360dc0cb1cdSDale Ghent 	0,		/* "other" interrupt types enable mask */
361dc0cb1cdSDale Ghent 	(IXGBE_FLAG_RSS_CAPABLE
362dc0cb1cdSDale Ghent 	| IXGBE_FLAG_VMDQ_CAPABLE
363dc0cb1cdSDale Ghent 	| IXGBE_FLAG_RSC_CAPABLE) /* capability flags */
364dc0cb1cdSDale Ghent };
365dc0cb1cdSDale Ghent 
366f2fe7acaSRobert Mustacchi static ddi_ufm_ops_t ixgbe_ufm_ops = {
367f2fe7acaSRobert Mustacchi 	.ddi_ufm_op_fill_image = ixgbe_ufm_fill_image,
368f2fe7acaSRobert Mustacchi 	.ddi_ufm_op_fill_slot = ixgbe_ufm_fill_slot,
369f2fe7acaSRobert Mustacchi 	.ddi_ufm_op_getcaps = ixgbe_ufm_getcaps,
370f2fe7acaSRobert Mustacchi 	.ddi_ufm_op_readimg = ixgbe_ufm_readimg
371f2fe7acaSRobert Mustacchi };
372f2fe7acaSRobert Mustacchi 
373f2fe7acaSRobert Mustacchi 
3749da57d7bSbt /*
3759da57d7bSbt  * Module Initialization Functions.
3769da57d7bSbt  */
3779da57d7bSbt 
3789da57d7bSbt int
_init(void)3799da57d7bSbt _init(void)
3809da57d7bSbt {
3819da57d7bSbt 	int status;
3829da57d7bSbt 
3839da57d7bSbt 	mac_init_ops(&ixgbe_dev_ops, MODULE_NAME);
3849da57d7bSbt 
3859da57d7bSbt 	status = mod_install(&ixgbe_modlinkage);
3869da57d7bSbt 
3879da57d7bSbt 	if (status != DDI_SUCCESS) {
3889da57d7bSbt 		mac_fini_ops(&ixgbe_dev_ops);
3899da57d7bSbt 	}
3909da57d7bSbt 
3919da57d7bSbt 	return (status);
3929da57d7bSbt }
3939da57d7bSbt 
3949da57d7bSbt int
_fini(void)3959da57d7bSbt _fini(void)
3969da57d7bSbt {
3979da57d7bSbt 	int status;
3989da57d7bSbt 
3999da57d7bSbt 	status = mod_remove(&ixgbe_modlinkage);
4009da57d7bSbt 
4019da57d7bSbt 	if (status == DDI_SUCCESS) {
4029da57d7bSbt 		mac_fini_ops(&ixgbe_dev_ops);
4039da57d7bSbt 	}
4049da57d7bSbt 
4059da57d7bSbt 	return (status);
4069da57d7bSbt }
4079da57d7bSbt 
4089da57d7bSbt int
_info(struct modinfo * modinfop)4099da57d7bSbt _info(struct modinfo *modinfop)
4109da57d7bSbt {
4119da57d7bSbt 	int status;
4129da57d7bSbt 
4139da57d7bSbt 	status = mod_info(&ixgbe_modlinkage, modinfop);
4149da57d7bSbt 
4159da57d7bSbt 	return (status);
4169da57d7bSbt }
4179da57d7bSbt 
4189da57d7bSbt /*
4199da57d7bSbt  * ixgbe_attach - Driver attach.
4209da57d7bSbt  *
4219da57d7bSbt  * This function is the device specific initialization entry
4229da57d7bSbt  * point. This entry point is required and must be written.
4239da57d7bSbt  * The DDI_ATTACH command must be provided in the attach entry
4249da57d7bSbt  * point. When attach() is called with cmd set to DDI_ATTACH,
4259da57d7bSbt  * all normal kernel services (such as kmem_alloc(9F)) are
4269da57d7bSbt  * available for use by the driver.
4279da57d7bSbt  *
4289da57d7bSbt  * The attach() function will be called once for each instance
4299da57d7bSbt  * of  the  device  on  the  system with cmd set to DDI_ATTACH.
4309da57d7bSbt  * Until attach() succeeds, the only driver entry points which
4319da57d7bSbt  * may be called are open(9E) and getinfo(9E).
4329da57d7bSbt  */
4339da57d7bSbt static int
ixgbe_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)4349da57d7bSbt ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
4359da57d7bSbt {
4369da57d7bSbt 	ixgbe_t *ixgbe;
4379da57d7bSbt 	struct ixgbe_osdep *osdep;
4389da57d7bSbt 	struct ixgbe_hw *hw;
4399da57d7bSbt 	int instance;
44013740cb2SPaul Guo 	char taskqname[32];
4419da57d7bSbt 
4429da57d7bSbt 	/*
4439da57d7bSbt 	 * Check the command and perform corresponding operations
4449da57d7bSbt 	 */
4459da57d7bSbt 	switch (cmd) {
4469da57d7bSbt 	default:
4479da57d7bSbt 		return (DDI_FAILURE);
4489da57d7bSbt 
4499da57d7bSbt 	case DDI_RESUME:
4509da57d7bSbt 		return (ixgbe_resume(devinfo));
4519da57d7bSbt 
4529da57d7bSbt 	case DDI_ATTACH:
4539da57d7bSbt 		break;
4549da57d7bSbt 	}
4559da57d7bSbt 
4569da57d7bSbt 	/* Get the device instance */
4579da57d7bSbt 	instance = ddi_get_instance(devinfo);
4589da57d7bSbt 
4599da57d7bSbt 	/* Allocate memory for the instance data structure */
4609da57d7bSbt 	ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP);
4619da57d7bSbt 
4629da57d7bSbt 	ixgbe->dip = devinfo;
4639da57d7bSbt 	ixgbe->instance = instance;
4649da57d7bSbt 
4659da57d7bSbt 	hw = &ixgbe->hw;
4669da57d7bSbt 	osdep = &ixgbe->osdep;
4679da57d7bSbt 	hw->back = osdep;
4689da57d7bSbt 	osdep->ixgbe = ixgbe;
4699da57d7bSbt 
4709da57d7bSbt 	/* Attach the instance pointer to the dev_info data structure */
4719da57d7bSbt 	ddi_set_driver_private(devinfo, ixgbe);
4729da57d7bSbt 
4739da57d7bSbt 	/*
474dc0cb1cdSDale Ghent 	 * Initialize for FMA support
4759da57d7bSbt 	 */
476c971fb7eSgg 	ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE,
4779da57d7bSbt 	    0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
4789da57d7bSbt 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
4799da57d7bSbt 	ixgbe_fm_init(ixgbe);
4809da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT;
4819da57d7bSbt 
4829da57d7bSbt 	/*
4839da57d7bSbt 	 * Map PCI config space registers
4849da57d7bSbt 	 */
4859da57d7bSbt 	if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
4869da57d7bSbt 		ixgbe_error(ixgbe, "Failed to map PCI configurations");
4879da57d7bSbt 		goto attach_fail;
4889da57d7bSbt 	}
4899da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
4909da57d7bSbt 
4919da57d7bSbt 	/*
4929da57d7bSbt 	 * Identify the chipset family
4939da57d7bSbt 	 */
4949da57d7bSbt 	if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) {
4959da57d7bSbt 		ixgbe_error(ixgbe, "Failed to identify hardware");
4969da57d7bSbt 		goto attach_fail;
4979da57d7bSbt 	}
4989da57d7bSbt 
4999da57d7bSbt 	/*
5009da57d7bSbt 	 * Map device registers
5019da57d7bSbt 	 */
5029da57d7bSbt 	if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) {
5039da57d7bSbt 		ixgbe_error(ixgbe, "Failed to map device registers");
5049da57d7bSbt 		goto attach_fail;
5059da57d7bSbt 	}
5069da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP;
5079da57d7bSbt 
5089da57d7bSbt 	/*
5099da57d7bSbt 	 * Initialize driver parameters
5109da57d7bSbt 	 */
5119da57d7bSbt 	ixgbe_init_properties(ixgbe);
5129da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS;
5139da57d7bSbt 
5140dc2366fSVenugopal Iyer 	/*
5150dc2366fSVenugopal Iyer 	 * Register interrupt callback
5160dc2366fSVenugopal Iyer 	 */
5170dc2366fSVenugopal Iyer 	if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) {
5180dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe, "Failed to register interrupt callback");
5190dc2366fSVenugopal Iyer 		goto attach_fail;
5200dc2366fSVenugopal Iyer 	}
5210dc2366fSVenugopal Iyer 
5229da57d7bSbt 	/*
5239da57d7bSbt 	 * Allocate interrupts
5249da57d7bSbt 	 */
5259da57d7bSbt 	if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) {
5269da57d7bSbt 		ixgbe_error(ixgbe, "Failed to allocate interrupts");
5279da57d7bSbt 		goto attach_fail;
5289da57d7bSbt 	}
5299da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
5309da57d7bSbt 
5319da57d7bSbt 	/*
5329da57d7bSbt 	 * Allocate rx/tx rings based on the ring numbers.
5339da57d7bSbt 	 * The actual numbers of rx/tx rings are decided by the number of
5349da57d7bSbt 	 * allocated interrupt vectors, so we should allocate the rings after
5359da57d7bSbt 	 * interrupts are allocated.
5369da57d7bSbt 	 */
5379da57d7bSbt 	if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) {
5389da57d7bSbt 		ixgbe_error(ixgbe, "Failed to allocate rx and tx rings");
5399da57d7bSbt 		goto attach_fail;
5409da57d7bSbt 	}
5419da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS;
5429da57d7bSbt 
5439da57d7bSbt 	/*
5449da57d7bSbt 	 * Map rings to interrupt vectors
5459da57d7bSbt 	 */
54673cd555cSBin Tu - Sun Microsystems - Beijing China 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
54773cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe, "Failed to map interrupts to vectors");
5489da57d7bSbt 		goto attach_fail;
5499da57d7bSbt 	}
5509da57d7bSbt 
5519da57d7bSbt 	/*
5529da57d7bSbt 	 * Add interrupt handlers
5539da57d7bSbt 	 */
5549da57d7bSbt 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
5559da57d7bSbt 		ixgbe_error(ixgbe, "Failed to add interrupt handlers");
5569da57d7bSbt 		goto attach_fail;
5579da57d7bSbt 	}
5589da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
5599da57d7bSbt 
56013740cb2SPaul Guo 	/*
56162e6e1adSPaul Guo 	 * Create a taskq for sfp-change
56213740cb2SPaul Guo 	 */
5635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(void) sprintf(taskqname, "ixgbe%d_sfp_taskq", instance);
56462e6e1adSPaul Guo 	if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname,
56513740cb2SPaul Guo 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
5665b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe, "sfp_taskq create failed");
56713740cb2SPaul Guo 		goto attach_fail;
56813740cb2SPaul Guo 	}
56962e6e1adSPaul Guo 	ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ;
57013740cb2SPaul Guo 
5715b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
5725b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Create a taskq for over-temp
5735b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
5745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	(void) sprintf(taskqname, "ixgbe%d_overtemp_taskq", instance);
5755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if ((ixgbe->overtemp_taskq = ddi_taskq_create(devinfo, taskqname,
5765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
5775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe, "overtemp_taskq create failed");
5785b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto attach_fail;
5795b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
5805b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->attach_progress |= ATTACH_PROGRESS_OVERTEMP_TASKQ;
5815b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
582dc0cb1cdSDale Ghent 	/*
583dc0cb1cdSDale Ghent 	 * Create a taskq for processing external PHY interrupts
584dc0cb1cdSDale Ghent 	 */
585dc0cb1cdSDale Ghent 	(void) sprintf(taskqname, "ixgbe%d_phy_taskq", instance);
586dc0cb1cdSDale Ghent 	if ((ixgbe->phy_taskq = ddi_taskq_create(devinfo, taskqname,
587dc0cb1cdSDale Ghent 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
588dc0cb1cdSDale Ghent 		ixgbe_error(ixgbe, "phy_taskq create failed");
589dc0cb1cdSDale Ghent 		goto attach_fail;
590dc0cb1cdSDale Ghent 	}
591dc0cb1cdSDale Ghent 	ixgbe->attach_progress |= ATTACH_PROGRESS_PHY_TASKQ;
592dc0cb1cdSDale Ghent 
5939da57d7bSbt 	/*
5949da57d7bSbt 	 * Initialize driver parameters
5959da57d7bSbt 	 */
5969da57d7bSbt 	if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) {
5979da57d7bSbt 		ixgbe_error(ixgbe, "Failed to initialize driver settings");
5989da57d7bSbt 		goto attach_fail;
5999da57d7bSbt 	}
6009da57d7bSbt 
6019da57d7bSbt 	/*
6029da57d7bSbt 	 * Initialize mutexes for this device.
6039da57d7bSbt 	 * Do this before enabling the interrupt handler and
6049da57d7bSbt 	 * register the softint to avoid the condition where
6059da57d7bSbt 	 * interrupt handler can try using uninitialized mutex.
6069da57d7bSbt 	 */
6079da57d7bSbt 	ixgbe_init_locks(ixgbe);
6089da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS;
6099da57d7bSbt 
6109da57d7bSbt 	/*
6119da57d7bSbt 	 * Initialize chipset hardware
6129da57d7bSbt 	 */
6139da57d7bSbt 	if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) {
6149da57d7bSbt 		ixgbe_error(ixgbe, "Failed to initialize adapter");
6159da57d7bSbt 		goto attach_fail;
6169da57d7bSbt 	}
61762e6e1adSPaul Guo 	ixgbe->link_check_complete = B_FALSE;
61862e6e1adSPaul Guo 	ixgbe->link_check_hrtime = gethrtime() +
61962e6e1adSPaul Guo 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
6209da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_INIT;
6219da57d7bSbt 
6229da57d7bSbt 	if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) {
6239da57d7bSbt 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
6249da57d7bSbt 		goto attach_fail;
6259da57d7bSbt 	}
6269da57d7bSbt 
627dc0cb1cdSDale Ghent 	/*
628dc0cb1cdSDale Ghent 	 * Initialize adapter capabilities
629dc0cb1cdSDale Ghent 	 */
630dc0cb1cdSDale Ghent 	ixgbe_init_params(ixgbe);
631dc0cb1cdSDale Ghent 
6329da57d7bSbt 	/*
6339da57d7bSbt 	 * Initialize statistics
6349da57d7bSbt 	 */
6359da57d7bSbt 	if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) {
6369da57d7bSbt 		ixgbe_error(ixgbe, "Failed to initialize statistics");
6379da57d7bSbt 		goto attach_fail;
6389da57d7bSbt 	}
6399da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_STATS;
6409da57d7bSbt 
6419da57d7bSbt 	/*
6429da57d7bSbt 	 * Register the driver to the MAC
6439da57d7bSbt 	 */
6449da57d7bSbt 	if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) {
6459da57d7bSbt 		ixgbe_error(ixgbe, "Failed to register MAC");
6469da57d7bSbt 		goto attach_fail;
6479da57d7bSbt 	}
64813740cb2SPaul Guo 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
6499da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_MAC;
6509da57d7bSbt 
65162e6e1adSPaul Guo 	ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe,
65262e6e1adSPaul Guo 	    IXGBE_CYCLIC_PERIOD, DDI_IPL_0);
65362e6e1adSPaul Guo 	if (ixgbe->periodic_id == 0) {
65462e6e1adSPaul Guo 		ixgbe_error(ixgbe, "Failed to add the link check timer");
65562e6e1adSPaul Guo 		goto attach_fail;
65662e6e1adSPaul Guo 	}
65762e6e1adSPaul Guo 	ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER;
65862e6e1adSPaul Guo 
6599da57d7bSbt 	/*
6609da57d7bSbt 	 * Now that mutex locks are initialized, and the chip is also
6619da57d7bSbt 	 * initialized, enable interrupts.
6629da57d7bSbt 	 */
6639da57d7bSbt 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
6649da57d7bSbt 		ixgbe_error(ixgbe, "Failed to enable DDI interrupts");
6659da57d7bSbt 		goto attach_fail;
6669da57d7bSbt 	}
6679da57d7bSbt 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
6689da57d7bSbt 
669f2fe7acaSRobert Mustacchi 	if (ixgbe->hw.bus.func == 0) {
670f2fe7acaSRobert Mustacchi 		if (ddi_ufm_init(devinfo, DDI_UFM_CURRENT_VERSION,
671f2fe7acaSRobert Mustacchi 		    &ixgbe_ufm_ops, &ixgbe->ixgbe_ufmh, ixgbe) != 0) {
672f2fe7acaSRobert Mustacchi 			ixgbe_error(ixgbe, "Failed to enable DDI UFM support");
673f2fe7acaSRobert Mustacchi 			goto attach_fail;
674f2fe7acaSRobert Mustacchi 		}
675f2fe7acaSRobert Mustacchi 		ixgbe->attach_progress |= ATTACH_PROGRESS_UFM;
676f2fe7acaSRobert Mustacchi 		ddi_ufm_update(ixgbe->ixgbe_ufmh);
677f2fe7acaSRobert Mustacchi 	}
678f2fe7acaSRobert Mustacchi 
679dc0cb1cdSDale Ghent 	ixgbe_log(ixgbe, "%s", ixgbe_ident);
68062e6e1adSPaul Guo 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED);
6819da57d7bSbt 
6829da57d7bSbt 	return (DDI_SUCCESS);
6839da57d7bSbt 
6849da57d7bSbt attach_fail:
6859da57d7bSbt 	ixgbe_unconfigure(devinfo, ixgbe);
6869da57d7bSbt 	return (DDI_FAILURE);
6879da57d7bSbt }
6889da57d7bSbt 
6899da57d7bSbt /*
6909da57d7bSbt  * ixgbe_detach - Driver detach.
6919da57d7bSbt  *
6929da57d7bSbt  * The detach() function is the complement of the attach routine.
6939da57d7bSbt  * If cmd is set to DDI_DETACH, detach() is used to remove  the
6949da57d7bSbt  * state  associated  with  a  given  instance of a device node
6959da57d7bSbt  * prior to the removal of that instance from the system.
6969da57d7bSbt  *
6979da57d7bSbt  * The detach() function will be called once for each  instance
6989da57d7bSbt  * of the device for which there has been a successful attach()
6999da57d7bSbt  * once there are no longer  any  opens  on  the  device.
7009da57d7bSbt  *
7019da57d7bSbt  * Interrupts routine are disabled, All memory allocated by this
7029da57d7bSbt  * driver are freed.
7039da57d7bSbt  */
7049da57d7bSbt static int
ixgbe_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)7059da57d7bSbt ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
7069da57d7bSbt {
7079da57d7bSbt 	ixgbe_t *ixgbe;
7089da57d7bSbt 
7099da57d7bSbt 	/*
7109da57d7bSbt 	 * Check detach command
7119da57d7bSbt 	 */
7129da57d7bSbt 	switch (cmd) {
7139da57d7bSbt 	default:
7149da57d7bSbt 		return (DDI_FAILURE);
7159da57d7bSbt 
7169da57d7bSbt 	case DDI_SUSPEND:
7179da57d7bSbt 		return (ixgbe_suspend(devinfo));
7189da57d7bSbt 
7199da57d7bSbt 	case DDI_DETACH:
7209da57d7bSbt 		break;
7219da57d7bSbt 	}
7229da57d7bSbt 
7239da57d7bSbt 	/*
7249da57d7bSbt 	 * Get the pointer to the driver private data structure
7259da57d7bSbt 	 */
7269da57d7bSbt 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
7279da57d7bSbt 	if (ixgbe == NULL)
7289da57d7bSbt 		return (DDI_FAILURE);
7299da57d7bSbt 
7309da57d7bSbt 	/*
7319da57d7bSbt 	 * If the device is still running, it needs to be stopped first.
7329da57d7bSbt 	 * This check is necessary because under some specific circumstances,
7339da57d7bSbt 	 * the detach routine can be called without stopping the interface
7349da57d7bSbt 	 * first.
7359da57d7bSbt 	 */
7369da57d7bSbt 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
73762e6e1adSPaul Guo 		atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
73862e6e1adSPaul Guo 		mutex_enter(&ixgbe->gen_lock);
739ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_stop(ixgbe, B_TRUE);
7409da57d7bSbt 		mutex_exit(&ixgbe->gen_lock);
7419da57d7bSbt 		/* Disable and stop the watchdog timer */
7429da57d7bSbt 		ixgbe_disable_watchdog_timer(ixgbe);
74362e6e1adSPaul Guo 	}
7449da57d7bSbt 
7459da57d7bSbt 	/*
7469da57d7bSbt 	 * Check if there are still rx buffers held by the upper layer.
7479da57d7bSbt 	 * If so, fail the detach.
7489da57d7bSbt 	 */
7499da57d7bSbt 	if (!ixgbe_rx_drain(ixgbe))
7509da57d7bSbt 		return (DDI_FAILURE);
7519da57d7bSbt 
7529da57d7bSbt 	/*
7539da57d7bSbt 	 * Do the remaining unconfigure routines
7549da57d7bSbt 	 */
7559da57d7bSbt 	ixgbe_unconfigure(devinfo, ixgbe);
7569da57d7bSbt 
7579da57d7bSbt 	return (DDI_SUCCESS);
7589da57d7bSbt }
7599da57d7bSbt 
7608c430e59SSaso Kiselkov /*
7618c430e59SSaso Kiselkov  * quiesce(9E) entry point.
7628c430e59SSaso Kiselkov  *
7638c430e59SSaso Kiselkov  * This function is called when the system is single-threaded at high
7648c430e59SSaso Kiselkov  * PIL with preemption disabled. Therefore, this function must not be
7658c430e59SSaso Kiselkov  * blocked.
7668c430e59SSaso Kiselkov  *
7678c430e59SSaso Kiselkov  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
7688c430e59SSaso Kiselkov  * DDI_FAILURE indicates an error condition and should almost never happen.
7698c430e59SSaso Kiselkov  */
7708c430e59SSaso Kiselkov static int
ixgbe_quiesce(dev_info_t * devinfo)7718c430e59SSaso Kiselkov ixgbe_quiesce(dev_info_t *devinfo)
7728c430e59SSaso Kiselkov {
7738c430e59SSaso Kiselkov 	ixgbe_t *ixgbe;
7748c430e59SSaso Kiselkov 	struct ixgbe_hw *hw;
7758c430e59SSaso Kiselkov 
7768c430e59SSaso Kiselkov 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
7778c430e59SSaso Kiselkov 
7788c430e59SSaso Kiselkov 	if (ixgbe == NULL)
7798c430e59SSaso Kiselkov 		return (DDI_FAILURE);
7808c430e59SSaso Kiselkov 
7818c430e59SSaso Kiselkov 	hw = &ixgbe->hw;
7828c430e59SSaso Kiselkov 
7838c430e59SSaso Kiselkov 	/*
7848c430e59SSaso Kiselkov 	 * Disable the adapter interrupts
7858c430e59SSaso Kiselkov 	 */
7868c430e59SSaso Kiselkov 	ixgbe_disable_adapter_interrupts(ixgbe);
7878c430e59SSaso Kiselkov 
7888c430e59SSaso Kiselkov 	/*
7898c430e59SSaso Kiselkov 	 * Tell firmware driver is no longer in control
7908c430e59SSaso Kiselkov 	 */
7918c430e59SSaso Kiselkov 	ixgbe_release_driver_control(hw);
7928c430e59SSaso Kiselkov 
7938c430e59SSaso Kiselkov 	/*
7948c430e59SSaso Kiselkov 	 * Reset the chipset
7958c430e59SSaso Kiselkov 	 */
7968c430e59SSaso Kiselkov 	(void) ixgbe_reset_hw(hw);
7978c430e59SSaso Kiselkov 
7988c430e59SSaso Kiselkov 	/*
7998c430e59SSaso Kiselkov 	 * Reset PHY
8008c430e59SSaso Kiselkov 	 */
8018c430e59SSaso Kiselkov 	(void) ixgbe_reset_phy(hw);
8028c430e59SSaso Kiselkov 
8038c430e59SSaso Kiselkov 	return (DDI_SUCCESS);
8048c430e59SSaso Kiselkov }
8058c430e59SSaso Kiselkov 
8069da57d7bSbt static void
ixgbe_unconfigure(dev_info_t * devinfo,ixgbe_t * ixgbe)8079da57d7bSbt ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe)
8089da57d7bSbt {
8099da57d7bSbt 	/*
8109da57d7bSbt 	 * Disable interrupt
8119da57d7bSbt 	 */
8129da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
8139da57d7bSbt 		(void) ixgbe_disable_intrs(ixgbe);
8149da57d7bSbt 	}
8159da57d7bSbt 
81662e6e1adSPaul Guo 	/*
81762e6e1adSPaul Guo 	 * remove the link check timer
81862e6e1adSPaul Guo 	 */
81962e6e1adSPaul Guo 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) {
82062e6e1adSPaul Guo 		if (ixgbe->periodic_id != NULL) {
82162e6e1adSPaul Guo 			ddi_periodic_delete(ixgbe->periodic_id);
82262e6e1adSPaul Guo 			ixgbe->periodic_id = NULL;
82362e6e1adSPaul Guo 		}
82462e6e1adSPaul Guo 	}
82562e6e1adSPaul Guo 
826f2fe7acaSRobert Mustacchi 	/*
827f2fe7acaSRobert Mustacchi 	 * Clean up the UFM subsystem. Note this only is set on function 0.
828f2fe7acaSRobert Mustacchi 	 */
829f2fe7acaSRobert Mustacchi 	if (ixgbe->attach_progress & ATTACH_PROGRESS_UFM) {
830f2fe7acaSRobert Mustacchi 		ddi_ufm_fini(ixgbe->ixgbe_ufmh);
831f2fe7acaSRobert Mustacchi 	}
832f2fe7acaSRobert Mustacchi 
8339da57d7bSbt 	/*
8349da57d7bSbt 	 * Unregister MAC
8359da57d7bSbt 	 */
8369da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) {
8379da57d7bSbt 		(void) mac_unregister(ixgbe->mac_hdl);
8389da57d7bSbt 	}
8399da57d7bSbt 
8409da57d7bSbt 	/*
8419da57d7bSbt 	 * Free statistics
8429da57d7bSbt 	 */
8439da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) {
8449da57d7bSbt 		kstat_delete((kstat_t *)ixgbe->ixgbe_ks);
8459da57d7bSbt 	}
8469da57d7bSbt 
8479da57d7bSbt 	/*
8489da57d7bSbt 	 * Remove interrupt handlers
8499da57d7bSbt 	 */
8509da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
8519da57d7bSbt 		ixgbe_rem_intr_handlers(ixgbe);
8529da57d7bSbt 	}
8539da57d7bSbt 
85413740cb2SPaul Guo 	/*
85562e6e1adSPaul Guo 	 * Remove taskq for sfp-status-change
85613740cb2SPaul Guo 	 */
85762e6e1adSPaul Guo 	if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) {
85862e6e1adSPaul Guo 		ddi_taskq_destroy(ixgbe->sfp_taskq);
85913740cb2SPaul Guo 	}
86013740cb2SPaul Guo 
8615b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
8625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Remove taskq for over-temp
8635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
8645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->attach_progress & ATTACH_PROGRESS_OVERTEMP_TASKQ) {
8655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ddi_taskq_destroy(ixgbe->overtemp_taskq);
8665b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
8675b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
868dc0cb1cdSDale Ghent 	/*
869dc0cb1cdSDale Ghent 	 * Remove taskq for external PHYs
870dc0cb1cdSDale Ghent 	 */
871dc0cb1cdSDale Ghent 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PHY_TASKQ) {
872dc0cb1cdSDale Ghent 		ddi_taskq_destroy(ixgbe->phy_taskq);
873dc0cb1cdSDale Ghent 	}
874dc0cb1cdSDale Ghent 
8759da57d7bSbt 	/*
8769da57d7bSbt 	 * Remove interrupts
8779da57d7bSbt 	 */
8789da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) {
8799da57d7bSbt 		ixgbe_rem_intrs(ixgbe);
8809da57d7bSbt 	}
8819da57d7bSbt 
8820dc2366fSVenugopal Iyer 	/*
8830dc2366fSVenugopal Iyer 	 * Unregister interrupt callback handler
8840dc2366fSVenugopal Iyer 	 */
885895d6e02SRobert Mustacchi 	if (ixgbe->cb_hdl != NULL) {
886895d6e02SRobert Mustacchi 		(void) ddi_cb_unregister(ixgbe->cb_hdl);
887895d6e02SRobert Mustacchi 	}
8880dc2366fSVenugopal Iyer 
8899da57d7bSbt 	/*
8909da57d7bSbt 	 * Remove driver properties
8919da57d7bSbt 	 */
8929da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) {
8939da57d7bSbt 		(void) ddi_prop_remove_all(devinfo);
8949da57d7bSbt 	}
8959da57d7bSbt 
8969da57d7bSbt 	/*
8979da57d7bSbt 	 * Stop the chipset
8989da57d7bSbt 	 */
8999da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) {
9009da57d7bSbt 		mutex_enter(&ixgbe->gen_lock);
9019da57d7bSbt 		ixgbe_chip_stop(ixgbe);
9029da57d7bSbt 		mutex_exit(&ixgbe->gen_lock);
9039da57d7bSbt 	}
9049da57d7bSbt 
9059da57d7bSbt 	/*
9069da57d7bSbt 	 * Free register handle
9079da57d7bSbt 	 */
9089da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
9099da57d7bSbt 		if (ixgbe->osdep.reg_handle != NULL)
9109da57d7bSbt 			ddi_regs_map_free(&ixgbe->osdep.reg_handle);
9119da57d7bSbt 	}
9129da57d7bSbt 
9139da57d7bSbt 	/*
9149da57d7bSbt 	 * Free PCI config handle
9159da57d7bSbt 	 */
9169da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) {
9179da57d7bSbt 		if (ixgbe->osdep.cfg_handle != NULL)
9189da57d7bSbt 			pci_config_teardown(&ixgbe->osdep.cfg_handle);
9199da57d7bSbt 	}
9209da57d7bSbt 
9219da57d7bSbt 	/*
9229da57d7bSbt 	 * Free locks
9239da57d7bSbt 	 */
9249da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) {
9259da57d7bSbt 		ixgbe_destroy_locks(ixgbe);
9269da57d7bSbt 	}
9279da57d7bSbt 
9289da57d7bSbt 	/*
9299da57d7bSbt 	 * Free the rx/tx rings
9309da57d7bSbt 	 */
9319da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) {
9329da57d7bSbt 		ixgbe_free_rings(ixgbe);
9339da57d7bSbt 	}
9349da57d7bSbt 
9359da57d7bSbt 	/*
9369da57d7bSbt 	 * Unregister FMA capabilities
9379da57d7bSbt 	 */
9389da57d7bSbt 	if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) {
9399da57d7bSbt 		ixgbe_fm_fini(ixgbe);
9409da57d7bSbt 	}
9419da57d7bSbt 
9429da57d7bSbt 	/*
9439da57d7bSbt 	 * Free the driver data structure
9449da57d7bSbt 	 */
9459da57d7bSbt 	kmem_free(ixgbe, sizeof (ixgbe_t));
9469da57d7bSbt 
9479da57d7bSbt 	ddi_set_driver_private(devinfo, NULL);
9489da57d7bSbt }
9499da57d7bSbt 
9509da57d7bSbt /*
9519da57d7bSbt  * ixgbe_register_mac - Register the driver and its function pointers with
9529da57d7bSbt  * the GLD interface.
9539da57d7bSbt  */
9549da57d7bSbt static int
ixgbe_register_mac(ixgbe_t * ixgbe)9559da57d7bSbt ixgbe_register_mac(ixgbe_t *ixgbe)
9569da57d7bSbt {
9579da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
9589da57d7bSbt 	mac_register_t *mac;
9599da57d7bSbt 	int status;
9609da57d7bSbt 
9619da57d7bSbt 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
9629da57d7bSbt 		return (IXGBE_FAILURE);
9639da57d7bSbt 
9649da57d7bSbt 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
9659da57d7bSbt 	mac->m_driver = ixgbe;
9669da57d7bSbt 	mac->m_dip = ixgbe->dip;
9679da57d7bSbt 	mac->m_src_addr = hw->mac.addr;
9689da57d7bSbt 	mac->m_callbacks = &ixgbe_m_callbacks;
9699da57d7bSbt 	mac->m_min_sdu = 0;
9709da57d7bSbt 	mac->m_max_sdu = ixgbe->default_mtu;
9719da57d7bSbt 	mac->m_margin = VLAN_TAGSZ;
972ea65739eSchenlu chen - Sun Microsystems - Beijing China 	mac->m_priv_props = ixgbe_priv_props;
973da14cebeSEric Cheng 	mac->m_v12n = MAC_VIRT_LEVEL1;
9749da57d7bSbt 
9759da57d7bSbt 	status = mac_register(mac, &ixgbe->mac_hdl);
9769da57d7bSbt 
9779da57d7bSbt 	mac_free(mac);
9789da57d7bSbt 
9799da57d7bSbt 	return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE);
9809da57d7bSbt }
9819da57d7bSbt 
9829da57d7bSbt /*
9839da57d7bSbt  * ixgbe_identify_hardware - Identify the type of the chipset.
9849da57d7bSbt  */
9859da57d7bSbt static int
ixgbe_identify_hardware(ixgbe_t * ixgbe)9869da57d7bSbt ixgbe_identify_hardware(ixgbe_t *ixgbe)
9879da57d7bSbt {
9889da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
9899da57d7bSbt 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
9909da57d7bSbt 
9919da57d7bSbt 	/*
9929da57d7bSbt 	 * Get the device id
9939da57d7bSbt 	 */
9949da57d7bSbt 	hw->vendor_id =
9959da57d7bSbt 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
9969da57d7bSbt 	hw->device_id =
9979da57d7bSbt 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
9989da57d7bSbt 	hw->revision_id =
9999da57d7bSbt 	    pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
10009da57d7bSbt 	hw->subsystem_device_id =
10019da57d7bSbt 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
10029da57d7bSbt 	hw->subsystem_vendor_id =
10039da57d7bSbt 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
10049da57d7bSbt 
100513740cb2SPaul Guo 	/*
100613740cb2SPaul Guo 	 * Set the mac type of the adapter based on the device id
100713740cb2SPaul Guo 	 */
100813740cb2SPaul Guo 	if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) {
100913740cb2SPaul Guo 		return (IXGBE_FAILURE);
101013740cb2SPaul Guo 	}
101113740cb2SPaul Guo 
101213740cb2SPaul Guo 	/*
101313740cb2SPaul Guo 	 * Install adapter capabilities
101413740cb2SPaul Guo 	 */
101513740cb2SPaul Guo 	switch (hw->mac.type) {
101613740cb2SPaul Guo 	case ixgbe_mac_82598EB:
101719843f01SPaul Guo 		IXGBE_DEBUGLOG_0(ixgbe, "identify 82598 adapter\n");
101813740cb2SPaul Guo 		ixgbe->capab = &ixgbe_82598eb_cap;
101913740cb2SPaul Guo 
102013740cb2SPaul Guo 		if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) {
102113740cb2SPaul Guo 			ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
102213740cb2SPaul Guo 			ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1;
10235b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe->capab->other_gpie |= IXGBE_SDP1_GPIEN;
102413740cb2SPaul Guo 		}
102573cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
10265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
102773cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
102819843f01SPaul Guo 		IXGBE_DEBUGLOG_0(ixgbe, "identify 82599 adapter\n");
102973cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe->capab = &ixgbe_82599eb_cap;
103073cd555cSBin Tu - Sun Microsystems - Beijing China 
10315b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM) {
10325b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe->capab->flags |= IXGBE_FLAG_TEMP_SENSOR_CAPABLE;
10335b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP0;
10345b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN;
10355b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
103613740cb2SPaul Guo 		break;
10375b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
103869b5a878SDan McDonald 	case ixgbe_mac_X540:
103969b5a878SDan McDonald 		IXGBE_DEBUGLOG_0(ixgbe, "identify X540 adapter\n");
104069b5a878SDan McDonald 		ixgbe->capab = &ixgbe_X540_cap;
104169b5a878SDan McDonald 		/*
104269b5a878SDan McDonald 		 * For now, X540 is all set in its capab structure.
104369b5a878SDan McDonald 		 * As other X540 variants show up, things can change here.
104469b5a878SDan McDonald 		 */
104569b5a878SDan McDonald 		break;
104669b5a878SDan McDonald 
1047dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
1048dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
104948ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
1050dc0cb1cdSDale Ghent 		IXGBE_DEBUGLOG_0(ixgbe, "identify X550 adapter\n");
1051dc0cb1cdSDale Ghent 		ixgbe->capab = &ixgbe_X550_cap;
1052dc0cb1cdSDale Ghent 
105348ed61a7SRobert Mustacchi 		if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
105448ed61a7SRobert Mustacchi 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP ||
105548ed61a7SRobert Mustacchi 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N ||
105648ed61a7SRobert Mustacchi 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_QSFP ||
105748ed61a7SRobert Mustacchi 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_QSFP_N) {
1058dc0cb1cdSDale Ghent 			ixgbe->capab->flags |= IXGBE_FLAG_SFP_PLUG_CAPABLE;
105948ed61a7SRobert Mustacchi 		}
1060dc0cb1cdSDale Ghent 
1061dc0cb1cdSDale Ghent 		/*
1062dc0cb1cdSDale Ghent 		 * Link detection on X552 SFP+ and X552/X557-AT
1063dc0cb1cdSDale Ghent 		 */
1064dc0cb1cdSDale Ghent 		if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
106548ed61a7SRobert Mustacchi 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP ||
106648ed61a7SRobert Mustacchi 		    hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N ||
1067dc0cb1cdSDale Ghent 		    hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
1068dc0cb1cdSDale Ghent 			ixgbe->capab->other_intr |=
1069dc0cb1cdSDale Ghent 			    IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
107048ed61a7SRobert Mustacchi 		}
107148ed61a7SRobert Mustacchi 		if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
1072dc0cb1cdSDale Ghent 			ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN_X540;
1073dc0cb1cdSDale Ghent 		}
1074dc0cb1cdSDale Ghent 		break;
1075dc0cb1cdSDale Ghent 
107613740cb2SPaul Guo 	default:
107719843f01SPaul Guo 		IXGBE_DEBUGLOG_1(ixgbe,
107813740cb2SPaul Guo 		    "adapter not supported in ixgbe_identify_hardware(): %d\n",
107913740cb2SPaul Guo 		    hw->mac.type);
108013740cb2SPaul Guo 		return (IXGBE_FAILURE);
108113740cb2SPaul Guo 	}
108213740cb2SPaul Guo 
10839da57d7bSbt 	return (IXGBE_SUCCESS);
10849da57d7bSbt }
10859da57d7bSbt 
10869da57d7bSbt /*
10879da57d7bSbt  * ixgbe_regs_map - Map the device registers.
10889da57d7bSbt  *
10899da57d7bSbt  */
10909da57d7bSbt static int
ixgbe_regs_map(ixgbe_t * ixgbe)10919da57d7bSbt ixgbe_regs_map(ixgbe_t *ixgbe)
10929da57d7bSbt {
10939da57d7bSbt 	dev_info_t *devinfo = ixgbe->dip;
10949da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
10959da57d7bSbt 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
10969da57d7bSbt 	off_t mem_size;
10979da57d7bSbt 
10989da57d7bSbt 	/*
10999da57d7bSbt 	 * First get the size of device registers to be mapped.
11009da57d7bSbt 	 */
110173cd555cSBin Tu - Sun Microsystems - Beijing China 	if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size)
110273cd555cSBin Tu - Sun Microsystems - Beijing China 	    != DDI_SUCCESS) {
11039da57d7bSbt 		return (IXGBE_FAILURE);
11049da57d7bSbt 	}
11059da57d7bSbt 
11069da57d7bSbt 	/*
11079da57d7bSbt 	 * Call ddi_regs_map_setup() to map registers
11089da57d7bSbt 	 */
110973cd555cSBin Tu - Sun Microsystems - Beijing China 	if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET,
11109da57d7bSbt 	    (caddr_t *)&hw->hw_addr, 0,
11119da57d7bSbt 	    mem_size, &ixgbe_regs_acc_attr,
11129da57d7bSbt 	    &osdep->reg_handle)) != DDI_SUCCESS) {
11139da57d7bSbt 		return (IXGBE_FAILURE);
11149da57d7bSbt 	}
11159da57d7bSbt 
11169da57d7bSbt 	return (IXGBE_SUCCESS);
11179da57d7bSbt }
11189da57d7bSbt 
11199da57d7bSbt /*
11209da57d7bSbt  * ixgbe_init_properties - Initialize driver properties.
11219da57d7bSbt  */
11229da57d7bSbt static void
ixgbe_init_properties(ixgbe_t * ixgbe)11239da57d7bSbt ixgbe_init_properties(ixgbe_t *ixgbe)
11249da57d7bSbt {
11259da57d7bSbt 	/*
11269da57d7bSbt 	 * Get conf file properties, including link settings
11279da57d7bSbt 	 * jumbo frames, ring number, descriptor number, etc.
11289da57d7bSbt 	 */
11299da57d7bSbt 	ixgbe_get_conf(ixgbe);
11309da57d7bSbt }
11319da57d7bSbt 
11329da57d7bSbt /*
11339da57d7bSbt  * ixgbe_init_driver_settings - Initialize driver settings.
11349da57d7bSbt  *
11359da57d7bSbt  * The settings include hardware function pointers, bus information,
11369da57d7bSbt  * rx/tx rings settings, link state, and any other parameters that
11379da57d7bSbt  * need to be setup during driver initialization.
11389da57d7bSbt  */
11399da57d7bSbt static int
ixgbe_init_driver_settings(ixgbe_t * ixgbe)11409da57d7bSbt ixgbe_init_driver_settings(ixgbe_t *ixgbe)
11419da57d7bSbt {
11429da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
1143da14cebeSEric Cheng 	dev_info_t *devinfo = ixgbe->dip;
11449da57d7bSbt 	ixgbe_rx_ring_t *rx_ring;
11450dc2366fSVenugopal Iyer 	ixgbe_rx_group_t *rx_group;
11469da57d7bSbt 	ixgbe_tx_ring_t *tx_ring;
11479da57d7bSbt 	uint32_t rx_size;
11489da57d7bSbt 	uint32_t tx_size;
11490dc2366fSVenugopal Iyer 	uint32_t ring_per_group;
11509da57d7bSbt 	int i;
11519da57d7bSbt 
11529da57d7bSbt 	/*
11539da57d7bSbt 	 * Initialize chipset specific hardware function pointers
11549da57d7bSbt 	 */
11559da57d7bSbt 	if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) {
11569da57d7bSbt 		return (IXGBE_FAILURE);
11579da57d7bSbt 	}
11589da57d7bSbt 
1159da14cebeSEric Cheng 	/*
1160da14cebeSEric Cheng 	 * Get the system page size
1161da14cebeSEric Cheng 	 */
1162da14cebeSEric Cheng 	ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1);
1163da14cebeSEric Cheng 
11649da57d7bSbt 	/*
11659da57d7bSbt 	 * Set rx buffer size
11669da57d7bSbt 	 *
11679da57d7bSbt 	 * The IP header alignment room is counted in the calculation.
11689da57d7bSbt 	 * The rx buffer size is in unit of 1K that is required by the
11699da57d7bSbt 	 * chipset hardware.
11709da57d7bSbt 	 */
11719da57d7bSbt 	rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
11729da57d7bSbt 	ixgbe->rx_buf_size = ((rx_size >> 10) +
11739da57d7bSbt 	    ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
11749da57d7bSbt 
11759da57d7bSbt 	/*
11769da57d7bSbt 	 * Set tx buffer size
11779da57d7bSbt 	 */
11789da57d7bSbt 	tx_size = ixgbe->max_frame_size;
11799da57d7bSbt 	ixgbe->tx_buf_size = ((tx_size >> 10) +
11809da57d7bSbt 	    ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
11819da57d7bSbt 
11829da57d7bSbt 	/*
11830dc2366fSVenugopal Iyer 	 * Initialize rx/tx rings/groups parameters
11849da57d7bSbt 	 */
11850dc2366fSVenugopal Iyer 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
11869da57d7bSbt 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
11879da57d7bSbt 		rx_ring = &ixgbe->rx_rings[i];
11889da57d7bSbt 		rx_ring->index = i;
11899da57d7bSbt 		rx_ring->ixgbe = ixgbe;
11900dc2366fSVenugopal Iyer 		rx_ring->group_index = i / ring_per_group;
11910dc2366fSVenugopal Iyer 		rx_ring->hw_index = ixgbe_get_hw_rx_index(ixgbe, i);
11920dc2366fSVenugopal Iyer 	}
11930dc2366fSVenugopal Iyer 
11940dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_rx_groups; i++) {
11950dc2366fSVenugopal Iyer 		rx_group = &ixgbe->rx_groups[i];
11960dc2366fSVenugopal Iyer 		rx_group->index = i;
11970dc2366fSVenugopal Iyer 		rx_group->ixgbe = ixgbe;
119884de666eSRyan Zezeski 		list_create(&rx_group->vlans, sizeof (ixgbe_vlan_t),
119984de666eSRyan Zezeski 		    offsetof(ixgbe_vlan_t, ixvl_link));
12009da57d7bSbt 	}
12019da57d7bSbt 
12029da57d7bSbt 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
12039da57d7bSbt 		tx_ring = &ixgbe->tx_rings[i];
12049da57d7bSbt 		tx_ring->index = i;
12059da57d7bSbt 		tx_ring->ixgbe = ixgbe;
12069da57d7bSbt 		if (ixgbe->tx_head_wb_enable)
12079da57d7bSbt 			tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb;
12089da57d7bSbt 		else
12099da57d7bSbt 			tx_ring->tx_recycle = ixgbe_tx_recycle_legacy;
12109da57d7bSbt 
12119da57d7bSbt 		tx_ring->ring_size = ixgbe->tx_ring_size;
12129da57d7bSbt 		tx_ring->free_list_size = ixgbe->tx_ring_size +
12139da57d7bSbt 		    (ixgbe->tx_ring_size >> 1);
12149da57d7bSbt 	}
12159da57d7bSbt 
12169da57d7bSbt 	/*
12179da57d7bSbt 	 * Initialize values of interrupt throttling rate
12189da57d7bSbt 	 */
121973cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 1; i < MAX_INTR_VECTOR; i++)
12209da57d7bSbt 		ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0];
12219da57d7bSbt 
12229da57d7bSbt 	/*
12239da57d7bSbt 	 * The initial link state should be "unknown"
12249da57d7bSbt 	 */
12259da57d7bSbt 	ixgbe->link_state = LINK_STATE_UNKNOWN;
122673cd555cSBin Tu - Sun Microsystems - Beijing China 
12279da57d7bSbt 	return (IXGBE_SUCCESS);
12289da57d7bSbt }
12299da57d7bSbt 
12309da57d7bSbt /*
12319da57d7bSbt  * ixgbe_init_locks - Initialize locks.
12329da57d7bSbt  */
12339da57d7bSbt static void
ixgbe_init_locks(ixgbe_t * ixgbe)12349da57d7bSbt ixgbe_init_locks(ixgbe_t *ixgbe)
12359da57d7bSbt {
12369da57d7bSbt 	ixgbe_rx_ring_t *rx_ring;
12379da57d7bSbt 	ixgbe_tx_ring_t *tx_ring;
12389da57d7bSbt 	int i;
12399da57d7bSbt 
12409da57d7bSbt 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
12419da57d7bSbt 		rx_ring = &ixgbe->rx_rings[i];
12429da57d7bSbt 		mutex_init(&rx_ring->rx_lock, NULL,
12439da57d7bSbt 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12449da57d7bSbt 	}
12459da57d7bSbt 
12469da57d7bSbt 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
12479da57d7bSbt 		tx_ring = &ixgbe->tx_rings[i];
12489da57d7bSbt 		mutex_init(&tx_ring->tx_lock, NULL,
12499da57d7bSbt 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12509da57d7bSbt 		mutex_init(&tx_ring->recycle_lock, NULL,
12519da57d7bSbt 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12529da57d7bSbt 		mutex_init(&tx_ring->tcb_head_lock, NULL,
12539da57d7bSbt 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12549da57d7bSbt 		mutex_init(&tx_ring->tcb_tail_lock, NULL,
12559da57d7bSbt 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12569da57d7bSbt 	}
12579da57d7bSbt 
12589da57d7bSbt 	mutex_init(&ixgbe->gen_lock, NULL,
12599da57d7bSbt 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12609da57d7bSbt 
12619da57d7bSbt 	mutex_init(&ixgbe->watchdog_lock, NULL,
12629da57d7bSbt 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12639da57d7bSbt }
12649da57d7bSbt 
12659da57d7bSbt /*
12669da57d7bSbt  * ixgbe_destroy_locks - Destroy locks.
12679da57d7bSbt  */
12689da57d7bSbt static void
ixgbe_destroy_locks(ixgbe_t * ixgbe)12699da57d7bSbt ixgbe_destroy_locks(ixgbe_t *ixgbe)
12709da57d7bSbt {
12719da57d7bSbt 	ixgbe_rx_ring_t *rx_ring;
12729da57d7bSbt 	ixgbe_tx_ring_t *tx_ring;
12739da57d7bSbt 	int i;
12749da57d7bSbt 
12759da57d7bSbt 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
12769da57d7bSbt 		rx_ring = &ixgbe->rx_rings[i];
12779da57d7bSbt 		mutex_destroy(&rx_ring->rx_lock);
12789da57d7bSbt 	}
12799da57d7bSbt 
12809da57d7bSbt 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
12819da57d7bSbt 		tx_ring = &ixgbe->tx_rings[i];
12829da57d7bSbt 		mutex_destroy(&tx_ring->tx_lock);
12839da57d7bSbt 		mutex_destroy(&tx_ring->recycle_lock);
12849da57d7bSbt 		mutex_destroy(&tx_ring->tcb_head_lock);
12859da57d7bSbt 		mutex_destroy(&tx_ring->tcb_tail_lock);
12869da57d7bSbt 	}
12879da57d7bSbt 
12889da57d7bSbt 	mutex_destroy(&ixgbe->gen_lock);
12899da57d7bSbt 	mutex_destroy(&ixgbe->watchdog_lock);
12909da57d7bSbt }
12919da57d7bSbt 
129237367bbaSRobert Mustacchi /*
129337367bbaSRobert Mustacchi  * We need to try and determine which LED index in hardware corresponds to the
129437367bbaSRobert Mustacchi  * link/activity LED. This is the one that'll be overwritten when we perform
129537367bbaSRobert Mustacchi  * GLDv3 LED activity.
129637367bbaSRobert Mustacchi  */
129737367bbaSRobert Mustacchi static void
ixgbe_led_init(ixgbe_t * ixgbe)129837367bbaSRobert Mustacchi ixgbe_led_init(ixgbe_t *ixgbe)
129937367bbaSRobert Mustacchi {
130037367bbaSRobert Mustacchi 	uint32_t reg, i;
130137367bbaSRobert Mustacchi 	struct ixgbe_hw *hw = &ixgbe->hw;
130237367bbaSRobert Mustacchi 
130337367bbaSRobert Mustacchi 	reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
130437367bbaSRobert Mustacchi 	for (i = 0; i < 4; i++) {
130537367bbaSRobert Mustacchi 		if (((reg >> IXGBE_LED_MODE_SHIFT(i)) &
130637367bbaSRobert Mustacchi 		    IXGBE_LED_MODE_MASK_BASE) == IXGBE_LED_LINK_ACTIVE) {
130737367bbaSRobert Mustacchi 			ixgbe->ixgbe_led_index = i;
130837367bbaSRobert Mustacchi 			return;
130937367bbaSRobert Mustacchi 		}
131037367bbaSRobert Mustacchi 	}
131137367bbaSRobert Mustacchi 
131237367bbaSRobert Mustacchi 	/*
131337367bbaSRobert Mustacchi 	 * If we couldn't determine this, we use the default for various MACs
131437367bbaSRobert Mustacchi 	 * based on information Intel has inserted into other drivers over the
131548ed61a7SRobert Mustacchi 	 * years.
131637367bbaSRobert Mustacchi 	 */
131737367bbaSRobert Mustacchi 	switch (hw->mac.type) {
131848ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
131948ed61a7SRobert Mustacchi 		ixgbe->ixgbe_led_index = 0;
132048ed61a7SRobert Mustacchi 		break;
132137367bbaSRobert Mustacchi 	case ixgbe_mac_X550EM_x:
132237367bbaSRobert Mustacchi 		ixgbe->ixgbe_led_index = 1;
132337367bbaSRobert Mustacchi 		break;
132437367bbaSRobert Mustacchi 	default:
132537367bbaSRobert Mustacchi 		ixgbe->ixgbe_led_index = 2;
132637367bbaSRobert Mustacchi 		break;
132737367bbaSRobert Mustacchi 	}
132837367bbaSRobert Mustacchi }
132937367bbaSRobert Mustacchi 
13309da57d7bSbt static int
ixgbe_resume(dev_info_t * devinfo)13319da57d7bSbt ixgbe_resume(dev_info_t *devinfo)
13329da57d7bSbt {
13339da57d7bSbt 	ixgbe_t *ixgbe;
133462e6e1adSPaul Guo 	int i;
13359da57d7bSbt 
13369da57d7bSbt 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
13379da57d7bSbt 	if (ixgbe == NULL)
13389da57d7bSbt 		return (DDI_FAILURE);
13399da57d7bSbt 
13409da57d7bSbt 	mutex_enter(&ixgbe->gen_lock);
13419da57d7bSbt 
13429da57d7bSbt 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
1343ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
13449da57d7bSbt 			mutex_exit(&ixgbe->gen_lock);
13459da57d7bSbt 			return (DDI_FAILURE);
13469da57d7bSbt 		}
13479da57d7bSbt 
13489da57d7bSbt 		/*
13499da57d7bSbt 		 * Enable and start the watchdog timer
13509da57d7bSbt 		 */
13519da57d7bSbt 		ixgbe_enable_watchdog_timer(ixgbe);
13529da57d7bSbt 	}
13539da57d7bSbt 
135462e6e1adSPaul Guo 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED);
135562e6e1adSPaul Guo 
135662e6e1adSPaul Guo 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
135762e6e1adSPaul Guo 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
135862e6e1adSPaul Guo 			mac_tx_ring_update(ixgbe->mac_hdl,
135962e6e1adSPaul Guo 			    ixgbe->tx_rings[i].ring_handle);
136062e6e1adSPaul Guo 		}
136162e6e1adSPaul Guo 	}
13629da57d7bSbt 
13639da57d7bSbt 	mutex_exit(&ixgbe->gen_lock);
13649da57d7bSbt 
13659da57d7bSbt 	return (DDI_SUCCESS);
13669da57d7bSbt }
13679da57d7bSbt 
13689da57d7bSbt static int
ixgbe_suspend(dev_info_t * devinfo)13699da57d7bSbt ixgbe_suspend(dev_info_t *devinfo)
13709da57d7bSbt {
13719da57d7bSbt 	ixgbe_t *ixgbe;
13729da57d7bSbt 
13739da57d7bSbt 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
13749da57d7bSbt 	if (ixgbe == NULL)
13759da57d7bSbt 		return (DDI_FAILURE);
13769da57d7bSbt 
13779da57d7bSbt 	mutex_enter(&ixgbe->gen_lock);
13789da57d7bSbt 
137962e6e1adSPaul Guo 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED);
1380ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
1381ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&ixgbe->gen_lock);
1382ea65739eSchenlu chen - Sun Microsystems - Beijing China 		return (DDI_SUCCESS);
1383ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
1384ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_stop(ixgbe, B_FALSE);
13859da57d7bSbt 
13869da57d7bSbt 	mutex_exit(&ixgbe->gen_lock);
13879da57d7bSbt 
13889da57d7bSbt 	/*
13899da57d7bSbt 	 * Disable and stop the watchdog timer
13909da57d7bSbt 	 */
13919da57d7bSbt 	ixgbe_disable_watchdog_timer(ixgbe);
13929da57d7bSbt 
13939da57d7bSbt 	return (DDI_SUCCESS);
13949da57d7bSbt }
13959da57d7bSbt 
13969da57d7bSbt /*
13979da57d7bSbt  * ixgbe_init - Initialize the device.
13989da57d7bSbt  */
13999da57d7bSbt static int
ixgbe_init(ixgbe_t * ixgbe)14009da57d7bSbt ixgbe_init(ixgbe_t *ixgbe)
14019da57d7bSbt {
14029da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
140369c76190SKeith M Wesolowski 	u8 pbanum[IXGBE_PBANUM_LENGTH];
1404dc0cb1cdSDale Ghent 	int rv;
14059da57d7bSbt 
14069da57d7bSbt 	mutex_enter(&ixgbe->gen_lock);
14079da57d7bSbt 
14089da57d7bSbt 	/*
1409dc0cb1cdSDale Ghent 	 * Configure/Initialize hardware
14109da57d7bSbt 	 */
1411dc0cb1cdSDale Ghent 	rv = ixgbe_init_hw(hw);
1412dc0cb1cdSDale Ghent 	if (rv != IXGBE_SUCCESS) {
1413dc0cb1cdSDale Ghent 		switch (rv) {
1414dc0cb1cdSDale Ghent 
1415dc0cb1cdSDale Ghent 		/*
1416dc0cb1cdSDale Ghent 		 * The first three errors are not prohibitive to us progressing
1417dc0cb1cdSDale Ghent 		 * further, and are maily advisory in nature. In the case of a
1418dc0cb1cdSDale Ghent 		 * SFP module not being present or not deemed supported by the
1419dc0cb1cdSDale Ghent 		 * common code, we adivse the operator of this fact but carry on
1420dc0cb1cdSDale Ghent 		 * instead of failing hard, as SFPs can be inserted or replaced
1421dc0cb1cdSDale Ghent 		 * while the driver is running. In the case of a unknown error,
1422dc0cb1cdSDale Ghent 		 * we fail-hard, logging the reason and emitting a FMA event.
1423dc0cb1cdSDale Ghent 		 */
1424dc0cb1cdSDale Ghent 		case IXGBE_ERR_EEPROM_VERSION:
1425dc0cb1cdSDale Ghent 			ixgbe_error(ixgbe,
1426dc0cb1cdSDale Ghent 			    "This Intel 10Gb Ethernet device is pre-release and"
1427dc0cb1cdSDale Ghent 			    " contains outdated firmware. Please contact your"
1428dc0cb1cdSDale Ghent 			    " hardware vendor for a replacement.");
1429dc0cb1cdSDale Ghent 			break;
1430dc0cb1cdSDale Ghent 		case IXGBE_ERR_SFP_NOT_PRESENT:
1431dc0cb1cdSDale Ghent 			ixgbe_error(ixgbe,
1432dc0cb1cdSDale Ghent 			    "No SFP+ module detected on this interface. Please "
1433dc0cb1cdSDale Ghent 			    "install a supported SFP+ module for this "
1434dc0cb1cdSDale Ghent 			    "interface to become operational.");
1435dc0cb1cdSDale Ghent 			break;
1436dc0cb1cdSDale Ghent 		case IXGBE_ERR_SFP_NOT_SUPPORTED:
1437dc0cb1cdSDale Ghent 			ixgbe_error(ixgbe,
1438dc0cb1cdSDale Ghent 			    "Unsupported SFP+ module detected. Please replace "
1439dc0cb1cdSDale Ghent 			    "it with a supported SFP+ module per Intel "
1440dc0cb1cdSDale Ghent 			    "documentation, or bypass this check with "
1441dc0cb1cdSDale Ghent 			    "allow_unsupported_sfp=1 in ixgbe.conf.");
1442dc0cb1cdSDale Ghent 			break;
1443dc0cb1cdSDale Ghent 		default:
1444dc0cb1cdSDale Ghent 			ixgbe_error(ixgbe,
1445dc0cb1cdSDale Ghent 			    "Failed to initialize hardware. ixgbe_init_hw "
1446dc0cb1cdSDale Ghent 			    "returned %d", rv);
1447dc0cb1cdSDale Ghent 			ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
1448dc0cb1cdSDale Ghent 			goto init_fail;
1449dc0cb1cdSDale Ghent 		}
14509da57d7bSbt 	}
14519da57d7bSbt 
14529da57d7bSbt 	/*
14539da57d7bSbt 	 * Need to init eeprom before validating the checksum.
14549da57d7bSbt 	 */
14559da57d7bSbt 	if (ixgbe_init_eeprom_params(hw) < 0) {
14569da57d7bSbt 		ixgbe_error(ixgbe,
14579da57d7bSbt 		    "Unable to intitialize the eeprom interface.");
14589da57d7bSbt 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
14599da57d7bSbt 		goto init_fail;
14609da57d7bSbt 	}
14619da57d7bSbt 
14629da57d7bSbt 	/*
14639da57d7bSbt 	 * NVM validation
14649da57d7bSbt 	 */
14659da57d7bSbt 	if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
14669da57d7bSbt 		/*
14679da57d7bSbt 		 * Some PCI-E parts fail the first check due to
14689da57d7bSbt 		 * the link being in sleep state.  Call it again,
14699da57d7bSbt 		 * if it fails a second time it's a real issue.
14709da57d7bSbt 		 */
14719da57d7bSbt 		if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
14729da57d7bSbt 			ixgbe_error(ixgbe,
14739da57d7bSbt 			    "Invalid NVM checksum. Please contact "
14749da57d7bSbt 			    "the vendor to update the NVM.");
14759da57d7bSbt 			ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
14769da57d7bSbt 			goto init_fail;
14779da57d7bSbt 		}
14789da57d7bSbt 	}
14799da57d7bSbt 
14809da57d7bSbt 	/*
14819da57d7bSbt 	 * Setup default flow control thresholds - enable/disable
14829da57d7bSbt 	 * & flow control type is controlled by ixgbe.conf
14839da57d7bSbt 	 */
148469b5a878SDan McDonald 	hw->fc.high_water[0] = DEFAULT_FCRTH;
148569b5a878SDan McDonald 	hw->fc.low_water[0] = DEFAULT_FCRTL;
14869da57d7bSbt 	hw->fc.pause_time = DEFAULT_FCPAUSE;
14879da57d7bSbt 	hw->fc.send_xon = B_TRUE;
14889da57d7bSbt 
1489dc0cb1cdSDale Ghent 	/*
1490dc0cb1cdSDale Ghent 	 * Initialize flow control
1491dc0cb1cdSDale Ghent 	 */
1492dc0cb1cdSDale Ghent 	(void) ixgbe_start_hw(hw);
1493dc0cb1cdSDale Ghent 
14949da57d7bSbt 	/*
14959da57d7bSbt 	 * Initialize link settings
14969da57d7bSbt 	 */
14979da57d7bSbt 	(void) ixgbe_driver_setup_link(ixgbe, B_FALSE);
14989da57d7bSbt 
14999da57d7bSbt 	/*
15009da57d7bSbt 	 * Initialize the chipset hardware
15019da57d7bSbt 	 */
15029da57d7bSbt 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
15039da57d7bSbt 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
15049da57d7bSbt 		goto init_fail;
15059da57d7bSbt 	}
15069da57d7bSbt 
150769c76190SKeith M Wesolowski 	/*
150869c76190SKeith M Wesolowski 	 * Read identifying information and place in devinfo.
150969c76190SKeith M Wesolowski 	 */
151069c76190SKeith M Wesolowski 	pbanum[0] = '\0';
151169c76190SKeith M Wesolowski 	(void) ixgbe_read_pba_string(hw, pbanum, sizeof (pbanum));
151269c76190SKeith M Wesolowski 	if (*pbanum != '\0') {
151369c76190SKeith M Wesolowski 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, ixgbe->dip,
151469c76190SKeith M Wesolowski 		    "printed-board-assembly", (char *)pbanum);
151569c76190SKeith M Wesolowski 	}
151669c76190SKeith M Wesolowski 
151737367bbaSRobert Mustacchi 	/*
151837367bbaSRobert Mustacchi 	 * Determine LED index.
151937367bbaSRobert Mustacchi 	 */
152037367bbaSRobert Mustacchi 	ixgbe_led_init(ixgbe);
152137367bbaSRobert Mustacchi 
15229da57d7bSbt 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
15239da57d7bSbt 		goto init_fail;
15249da57d7bSbt 	}
15259da57d7bSbt 
15269da57d7bSbt 	mutex_exit(&ixgbe->gen_lock);
15279da57d7bSbt 	return (IXGBE_SUCCESS);
15289da57d7bSbt 
15299da57d7bSbt init_fail:
15309da57d7bSbt 	/*
15319da57d7bSbt 	 * Reset PHY
15329da57d7bSbt 	 */
15339da57d7bSbt 	(void) ixgbe_reset_phy(hw);
15349da57d7bSbt 
15359da57d7bSbt 	mutex_exit(&ixgbe->gen_lock);
15369da57d7bSbt 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
15379da57d7bSbt 	return (IXGBE_FAILURE);
15389da57d7bSbt }
15399da57d7bSbt 
15409da57d7bSbt /*
15419da57d7bSbt  * ixgbe_chip_start - Initialize and start the chipset hardware.
15429da57d7bSbt  */
15439da57d7bSbt static int
ixgbe_chip_start(ixgbe_t * ixgbe)15449da57d7bSbt ixgbe_chip_start(ixgbe_t *ixgbe)
15459da57d7bSbt {
15469da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
1547dc0cb1cdSDale Ghent 	int i;
15489da57d7bSbt 
15499da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
15509da57d7bSbt 
15519da57d7bSbt 	/*
15529da57d7bSbt 	 * Get the mac address
15539da57d7bSbt 	 * This function should handle SPARC case correctly.
15549da57d7bSbt 	 */
15559da57d7bSbt 	if (!ixgbe_find_mac_address(ixgbe)) {
15569da57d7bSbt 		ixgbe_error(ixgbe, "Failed to get the mac address");
15579da57d7bSbt 		return (IXGBE_FAILURE);
15589da57d7bSbt 	}
15599da57d7bSbt 
15609da57d7bSbt 	/*
15619da57d7bSbt 	 * Validate the mac address
15629da57d7bSbt 	 */
15639da57d7bSbt 	(void) ixgbe_init_rx_addrs(hw);
15649da57d7bSbt 	if (!is_valid_mac_addr(hw->mac.addr)) {
15659da57d7bSbt 		ixgbe_error(ixgbe, "Invalid mac address");
15669da57d7bSbt 		return (IXGBE_FAILURE);
15679da57d7bSbt 	}
15689da57d7bSbt 
156919843f01SPaul Guo 	/*
157019843f01SPaul Guo 	 * Re-enable relaxed ordering for performance.  It is disabled
157119843f01SPaul Guo 	 * by default in the hardware init.
157219843f01SPaul Guo 	 */
15735b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->relax_order_enable == B_TRUE)
15745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_enable_relaxed_ordering(hw);
157519843f01SPaul Guo 
15769da57d7bSbt 	/*
15779da57d7bSbt 	 * Setup adapter interrupt vectors
15789da57d7bSbt 	 */
15799da57d7bSbt 	ixgbe_setup_adapter_vector(ixgbe);
15809da57d7bSbt 
15819da57d7bSbt 	/*
15829da57d7bSbt 	 * Initialize unicast addresses.
15839da57d7bSbt 	 */
15849da57d7bSbt 	ixgbe_init_unicst(ixgbe);
15859da57d7bSbt 
15869da57d7bSbt 	/*
15879da57d7bSbt 	 * Setup and initialize the mctable structures.
15889da57d7bSbt 	 */
15899da57d7bSbt 	ixgbe_setup_multicst(ixgbe);
15909da57d7bSbt 
15919da57d7bSbt 	/*
15929da57d7bSbt 	 * Set interrupt throttling rate
15939da57d7bSbt 	 */
159473cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->intr_cnt; i++) {
15959da57d7bSbt 		IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]);
159673cd555cSBin Tu - Sun Microsystems - Beijing China 	}
15979da57d7bSbt 
15989da57d7bSbt 	/*
1599dc0cb1cdSDale Ghent 	 * Disable Wake-on-LAN
1600dc0cb1cdSDale Ghent 	 */
1601dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_WUC, 0);
1602dc0cb1cdSDale Ghent 
1603dc0cb1cdSDale Ghent 	/*
1604dc0cb1cdSDale Ghent 	 * Some adapters offer Energy Efficient Ethernet (EEE) support.
1605dc0cb1cdSDale Ghent 	 * Due to issues with EEE in e1000g/igb, we disable this by default
1606dc0cb1cdSDale Ghent 	 * as a precautionary measure.
1607dc0cb1cdSDale Ghent 	 *
160848ed61a7SRobert Mustacchi 	 * Currently, this is present on a number of the X550 family parts.
1609dc0cb1cdSDale Ghent 	 */
1610dc0cb1cdSDale Ghent 	(void) ixgbe_setup_eee(hw, B_FALSE);
1611dc0cb1cdSDale Ghent 
1612dc0cb1cdSDale Ghent 	/*
1613dc0cb1cdSDale Ghent 	 * Turn on any present SFP Tx laser
1614dc0cb1cdSDale Ghent 	 */
1615dc0cb1cdSDale Ghent 	ixgbe_enable_tx_laser(hw);
1616dc0cb1cdSDale Ghent 
1617dc0cb1cdSDale Ghent 	/*
1618dc0cb1cdSDale Ghent 	 * Power on the PHY
1619dc0cb1cdSDale Ghent 	 */
1620dc0cb1cdSDale Ghent 	(void) ixgbe_set_phy_power(hw, B_TRUE);
1621dc0cb1cdSDale Ghent 
1622dc0cb1cdSDale Ghent 	/*
1623dc0cb1cdSDale Ghent 	 * Save the state of the PHY
16249da57d7bSbt 	 */
16259da57d7bSbt 	ixgbe_get_hw_state(ixgbe);
16269da57d7bSbt 
16279da57d7bSbt 	/*
16289da57d7bSbt 	 * Make sure driver has control
16299da57d7bSbt 	 */
16309da57d7bSbt 	ixgbe_get_driver_control(hw);
16319da57d7bSbt 
16329da57d7bSbt 	return (IXGBE_SUCCESS);
16339da57d7bSbt }
16349da57d7bSbt 
16359da57d7bSbt /*
16369da57d7bSbt  * ixgbe_chip_stop - Stop the chipset hardware
16379da57d7bSbt  */
16389da57d7bSbt static void
ixgbe_chip_stop(ixgbe_t * ixgbe)16399da57d7bSbt ixgbe_chip_stop(ixgbe_t *ixgbe)
16409da57d7bSbt {
16419da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
1642dc0cb1cdSDale Ghent 	int rv;
16439da57d7bSbt 
16449da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
16459da57d7bSbt 
16469da57d7bSbt 	/*
1647dc0cb1cdSDale Ghent 	 * Stop interupt generation and disable Tx unit
16489da57d7bSbt 	 */
1649dc0cb1cdSDale Ghent 	hw->adapter_stopped = B_FALSE;
1650dc0cb1cdSDale Ghent 	(void) ixgbe_stop_adapter(hw);
16519da57d7bSbt 
16529da57d7bSbt 	/*
16539da57d7bSbt 	 * Reset the chipset
16549da57d7bSbt 	 */
16559da57d7bSbt 	(void) ixgbe_reset_hw(hw);
16569da57d7bSbt 
16579da57d7bSbt 	/*
16589da57d7bSbt 	 * Reset PHY
16599da57d7bSbt 	 */
16609da57d7bSbt 	(void) ixgbe_reset_phy(hw);
1661dc0cb1cdSDale Ghent 
1662dc0cb1cdSDale Ghent 	/*
1663dc0cb1cdSDale Ghent 	 * Enter LPLU (Low Power, Link Up) mode, if available. Avoid resetting
1664dc0cb1cdSDale Ghent 	 * the PHY while doing so. Else, just power down the PHY.
1665dc0cb1cdSDale Ghent 	 */
1666dc0cb1cdSDale Ghent 	if (hw->phy.ops.enter_lplu != NULL) {
1667dc0cb1cdSDale Ghent 		hw->phy.reset_disable = B_TRUE;
1668dc0cb1cdSDale Ghent 		rv = hw->phy.ops.enter_lplu(hw);
1669dc0cb1cdSDale Ghent 		if (rv != IXGBE_SUCCESS)
1670dc0cb1cdSDale Ghent 			ixgbe_error(ixgbe, "Error while entering LPLU: %d", rv);
1671dc0cb1cdSDale Ghent 		hw->phy.reset_disable = B_FALSE;
1672dc0cb1cdSDale Ghent 	} else {
1673dc0cb1cdSDale Ghent 		(void) ixgbe_set_phy_power(hw, B_FALSE);
1674dc0cb1cdSDale Ghent 	}
1675dc0cb1cdSDale Ghent 
1676dc0cb1cdSDale Ghent 	/*
1677dc0cb1cdSDale Ghent 	 * Turn off any present SFP Tx laser
1678dc0cb1cdSDale Ghent 	 * Expected for health and safety reasons
1679dc0cb1cdSDale Ghent 	 */
1680dc0cb1cdSDale Ghent 	ixgbe_disable_tx_laser(hw);
1681dc0cb1cdSDale Ghent 
1682dc0cb1cdSDale Ghent 	/*
1683dc0cb1cdSDale Ghent 	 * Tell firmware driver is no longer in control
1684dc0cb1cdSDale Ghent 	 */
1685dc0cb1cdSDale Ghent 	ixgbe_release_driver_control(hw);
1686dc0cb1cdSDale Ghent 
16879da57d7bSbt }
16889da57d7bSbt 
16899da57d7bSbt /*
16909da57d7bSbt  * ixgbe_reset - Reset the chipset and re-start the driver.
16919da57d7bSbt  *
16929da57d7bSbt  * It involves stopping and re-starting the chipset,
16939da57d7bSbt  * and re-configuring the rx/tx rings.
16949da57d7bSbt  */
16959da57d7bSbt static int
ixgbe_reset(ixgbe_t * ixgbe)16969da57d7bSbt ixgbe_reset(ixgbe_t *ixgbe)
16979da57d7bSbt {
169862e6e1adSPaul Guo 	int i;
169962e6e1adSPaul Guo 
1700ea65739eSchenlu chen - Sun Microsystems - Beijing China 	/*
1701ea65739eSchenlu chen - Sun Microsystems - Beijing China 	 * Disable and stop the watchdog timer
1702ea65739eSchenlu chen - Sun Microsystems - Beijing China 	 */
1703ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_disable_watchdog_timer(ixgbe);
17049da57d7bSbt 
17059da57d7bSbt 	mutex_enter(&ixgbe->gen_lock);
17069da57d7bSbt 
17079da57d7bSbt 	ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED);
170862e6e1adSPaul Guo 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
17099da57d7bSbt 
1710ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_stop(ixgbe, B_FALSE);
17119da57d7bSbt 
1712ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
1713ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&ixgbe->gen_lock);
1714ea65739eSchenlu chen - Sun Microsystems - Beijing China 		return (IXGBE_FAILURE);
17159da57d7bSbt 	}
17169da57d7bSbt 
171762e6e1adSPaul Guo 	/*
171862e6e1adSPaul Guo 	 * After resetting, need to recheck the link status.
171962e6e1adSPaul Guo 	 */
172062e6e1adSPaul Guo 	ixgbe->link_check_complete = B_FALSE;
172162e6e1adSPaul Guo 	ixgbe->link_check_hrtime = gethrtime() +
172262e6e1adSPaul Guo 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
172362e6e1adSPaul Guo 
172462e6e1adSPaul Guo 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED);
172562e6e1adSPaul Guo 
172662e6e1adSPaul Guo 	if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) {
172762e6e1adSPaul Guo 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
172862e6e1adSPaul Guo 			mac_tx_ring_update(ixgbe->mac_hdl,
172962e6e1adSPaul Guo 			    ixgbe->tx_rings[i].ring_handle);
173062e6e1adSPaul Guo 		}
173162e6e1adSPaul Guo 	}
173262e6e1adSPaul Guo 
1733ea65739eSchenlu chen - Sun Microsystems - Beijing China 	mutex_exit(&ixgbe->gen_lock);
17349da57d7bSbt 
17359da57d7bSbt 	/*
1736ea65739eSchenlu chen - Sun Microsystems - Beijing China 	 * Enable and start the watchdog timer
17379da57d7bSbt 	 */
1738ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_enable_watchdog_timer(ixgbe);
17399da57d7bSbt 
17409da57d7bSbt 	return (IXGBE_SUCCESS);
17419da57d7bSbt }
17429da57d7bSbt 
17439da57d7bSbt /*
17449da57d7bSbt  * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources.
17459da57d7bSbt  */
17469da57d7bSbt static void
ixgbe_tx_clean(ixgbe_t * ixgbe)17479da57d7bSbt ixgbe_tx_clean(ixgbe_t *ixgbe)
17489da57d7bSbt {
17499da57d7bSbt 	ixgbe_tx_ring_t *tx_ring;
17509da57d7bSbt 	tx_control_block_t *tcb;
17519da57d7bSbt 	link_list_t pending_list;
17529da57d7bSbt 	uint32_t desc_num;
17539da57d7bSbt 	int i, j;
17549da57d7bSbt 
17559da57d7bSbt 	LINK_LIST_INIT(&pending_list);
17569da57d7bSbt 
17579da57d7bSbt 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
17589da57d7bSbt 		tx_ring = &ixgbe->tx_rings[i];
17599da57d7bSbt 
17609da57d7bSbt 		mutex_enter(&tx_ring->recycle_lock);
17619da57d7bSbt 
17629da57d7bSbt 		/*
17639da57d7bSbt 		 * Clean the pending tx data - the pending packets in the
17649da57d7bSbt 		 * work_list that have no chances to be transmitted again.
17659da57d7bSbt 		 *
17669da57d7bSbt 		 * We must ensure the chipset is stopped or the link is down
17679da57d7bSbt 		 * before cleaning the transmit packets.
17689da57d7bSbt 		 */
17699da57d7bSbt 		desc_num = 0;
17709da57d7bSbt 		for (j = 0; j < tx_ring->ring_size; j++) {
17719da57d7bSbt 			tcb = tx_ring->work_list[j];
17729da57d7bSbt 			if (tcb != NULL) {
17739da57d7bSbt 				desc_num += tcb->desc_num;
17749da57d7bSbt 
17759da57d7bSbt 				tx_ring->work_list[j] = NULL;
17769da57d7bSbt 
17779da57d7bSbt 				ixgbe_free_tcb(tcb);
17789da57d7bSbt 
17799da57d7bSbt 				LIST_PUSH_TAIL(&pending_list, &tcb->link);
17809da57d7bSbt 			}
17819da57d7bSbt 		}
17829da57d7bSbt 
17839da57d7bSbt 		if (desc_num > 0) {
17849da57d7bSbt 			atomic_add_32(&tx_ring->tbd_free, desc_num);
17859da57d7bSbt 			ASSERT(tx_ring->tbd_free == tx_ring->ring_size);
17869da57d7bSbt 
17879da57d7bSbt 			/*
17889da57d7bSbt 			 * Reset the head and tail pointers of the tbd ring;
17899da57d7bSbt 			 * Reset the writeback head if it's enable.
17909da57d7bSbt 			 */
17919da57d7bSbt 			tx_ring->tbd_head = 0;
17929da57d7bSbt 			tx_ring->tbd_tail = 0;
17939da57d7bSbt 			if (ixgbe->tx_head_wb_enable)
17949da57d7bSbt 				*tx_ring->tbd_head_wb = 0;
17959da57d7bSbt 
17969da57d7bSbt 			IXGBE_WRITE_REG(&ixgbe->hw,
17979da57d7bSbt 			    IXGBE_TDH(tx_ring->index), 0);
17989da57d7bSbt 			IXGBE_WRITE_REG(&ixgbe->hw,
17999da57d7bSbt 			    IXGBE_TDT(tx_ring->index), 0);
18009da57d7bSbt 		}
18019da57d7bSbt 
18029da57d7bSbt 		mutex_exit(&tx_ring->recycle_lock);
18039da57d7bSbt 
18049da57d7bSbt 		/*
18059da57d7bSbt 		 * Add the tx control blocks in the pending list to
18069da57d7bSbt 		 * the free list.
18079da57d7bSbt 		 */
18089da57d7bSbt 		ixgbe_put_free_list(tx_ring, &pending_list);
18099da57d7bSbt 	}
18109da57d7bSbt }
18119da57d7bSbt 
18129da57d7bSbt /*
18139da57d7bSbt  * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be
18149da57d7bSbt  * transmitted.
18159da57d7bSbt  */
18169da57d7bSbt static boolean_t
ixgbe_tx_drain(ixgbe_t * ixgbe)18179da57d7bSbt ixgbe_tx_drain(ixgbe_t *ixgbe)
18189da57d7bSbt {
18199da57d7bSbt 	ixgbe_tx_ring_t *tx_ring;
18209da57d7bSbt 	boolean_t done;
18219da57d7bSbt 	int i, j;
18229da57d7bSbt 
18239da57d7bSbt 	/*
18249da57d7bSbt 	 * Wait for a specific time to allow pending tx packets
18259da57d7bSbt 	 * to be transmitted.
18269da57d7bSbt 	 *
18279da57d7bSbt 	 * Check the counter tbd_free to see if transmission is done.
18289da57d7bSbt 	 * No lock protection is needed here.
18299da57d7bSbt 	 *
18309da57d7bSbt 	 * Return B_TRUE if all pending packets have been transmitted;
18319da57d7bSbt 	 * Otherwise return B_FALSE;
18329da57d7bSbt 	 */
18339da57d7bSbt 	for (i = 0; i < TX_DRAIN_TIME; i++) {
18349da57d7bSbt 
18359da57d7bSbt 		done = B_TRUE;
18369da57d7bSbt 		for (j = 0; j < ixgbe->num_tx_rings; j++) {
18379da57d7bSbt 			tx_ring = &ixgbe->tx_rings[j];
18389da57d7bSbt 			done = done &&
18399da57d7bSbt 			    (tx_ring->tbd_free == tx_ring->ring_size);
18409da57d7bSbt 		}
18419da57d7bSbt 
18429da57d7bSbt 		if (done)
18439da57d7bSbt 			break;
18449da57d7bSbt 
18459da57d7bSbt 		msec_delay(1);
18469da57d7bSbt 	}
18479da57d7bSbt 
18489da57d7bSbt 	return (done);
18499da57d7bSbt }
18509da57d7bSbt 
18519da57d7bSbt /*
18529da57d7bSbt  * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer.
18539da57d7bSbt  */
18549da57d7bSbt static boolean_t
ixgbe_rx_drain(ixgbe_t * ixgbe)18559da57d7bSbt ixgbe_rx_drain(ixgbe_t *ixgbe)
18569da57d7bSbt {
1857ea65739eSchenlu chen - Sun Microsystems - Beijing China 	boolean_t done = B_TRUE;
1858ea65739eSchenlu chen - Sun Microsystems - Beijing China 	int i;
18599da57d7bSbt 
18609da57d7bSbt 	/*
18619da57d7bSbt 	 * Polling the rx free list to check if those rx buffers held by
18629da57d7bSbt 	 * the upper layer are released.
18639da57d7bSbt 	 *
18649da57d7bSbt 	 * Check the counter rcb_free to see if all pending buffers are
18659da57d7bSbt 	 * released. No lock protection is needed here.
18669da57d7bSbt 	 *
18679da57d7bSbt 	 * Return B_TRUE if all pending buffers have been released;
18689da57d7bSbt 	 * Otherwise return B_FALSE;
18699da57d7bSbt 	 */
18709da57d7bSbt 	for (i = 0; i < RX_DRAIN_TIME; i++) {
1871ea65739eSchenlu chen - Sun Microsystems - Beijing China 		done = (ixgbe->rcb_pending == 0);
18729da57d7bSbt 
18739da57d7bSbt 		if (done)
18749da57d7bSbt 			break;
18759da57d7bSbt 
18769da57d7bSbt 		msec_delay(1);
18779da57d7bSbt 	}
18789da57d7bSbt 
18799da57d7bSbt 	return (done);
18809da57d7bSbt }
18819da57d7bSbt 
18829da57d7bSbt /*
18839da57d7bSbt  * ixgbe_start - Start the driver/chipset.
18849da57d7bSbt  */
18859da57d7bSbt int
ixgbe_start(ixgbe_t * ixgbe,boolean_t alloc_buffer)1886ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer)
18879da57d7bSbt {
1888dc0cb1cdSDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
18899da57d7bSbt 	int i;
18909da57d7bSbt 
18919da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
18929da57d7bSbt 
1893ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (alloc_buffer) {
1894ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) {
1895ea65739eSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_error(ixgbe,
1896ea65739eSchenlu chen - Sun Microsystems - Beijing China 			    "Failed to allocate software receive rings");
1897ea65739eSchenlu chen - Sun Microsystems - Beijing China 			return (IXGBE_FAILURE);
1898ea65739eSchenlu chen - Sun Microsystems - Beijing China 		}
1899ea65739eSchenlu chen - Sun Microsystems - Beijing China 
1900ea65739eSchenlu chen - Sun Microsystems - Beijing China 		/* Allocate buffers for all the rx/tx rings */
1901ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) {
1902ea65739eSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_error(ixgbe, "Failed to allocate DMA resource");
1903ea65739eSchenlu chen - Sun Microsystems - Beijing China 			return (IXGBE_FAILURE);
1904ea65739eSchenlu chen - Sun Microsystems - Beijing China 		}
1905ea65739eSchenlu chen - Sun Microsystems - Beijing China 
1906ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->tx_ring_init = B_TRUE;
1907ea65739eSchenlu chen - Sun Microsystems - Beijing China 	} else {
1908ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->tx_ring_init = B_FALSE;
1909ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
1910ea65739eSchenlu chen - Sun Microsystems - Beijing China 
19119da57d7bSbt 	for (i = 0; i < ixgbe->num_rx_rings; i++)
19129da57d7bSbt 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
19139da57d7bSbt 	for (i = 0; i < ixgbe->num_tx_rings; i++)
19149da57d7bSbt 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
19159da57d7bSbt 
19169da57d7bSbt 	/*
19179da57d7bSbt 	 * Start the chipset hardware
19189da57d7bSbt 	 */
19199da57d7bSbt 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
19209da57d7bSbt 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
19219da57d7bSbt 		goto start_failure;
19229da57d7bSbt 	}
19239da57d7bSbt 
1924dc0cb1cdSDale Ghent 	/*
1925dc0cb1cdSDale Ghent 	 * Configure link now for X550
1926dc0cb1cdSDale Ghent 	 *
1927dc0cb1cdSDale Ghent 	 * X550 possesses a LPLU (Low-Power Link Up) mode which keeps the
1928dc0cb1cdSDale Ghent 	 * resting state of the adapter at a 1Gb FDX speed. Prior to the X550,
1929dc0cb1cdSDale Ghent 	 * the resting state of the link would be the maximum speed that
1930dc0cb1cdSDale Ghent 	 * autonegotiation will allow (usually 10Gb, infrastructure allowing)
1931dc0cb1cdSDale Ghent 	 * so we never bothered with explicitly setting the link to 10Gb as it
1932dc0cb1cdSDale Ghent 	 * would already be at that state on driver attach. With X550, we must
1933dc0cb1cdSDale Ghent 	 * trigger a re-negotiation of the link in order to switch from a LPLU
1934dc0cb1cdSDale Ghent 	 * 1Gb link to 10Gb (cable and link partner permitting.)
1935dc0cb1cdSDale Ghent 	 */
1936dc0cb1cdSDale Ghent 	if (hw->mac.type == ixgbe_mac_X550 ||
193748ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_a ||
1938dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X550EM_x) {
1939dc0cb1cdSDale Ghent 		(void) ixgbe_driver_setup_link(ixgbe, B_TRUE);
1940dc0cb1cdSDale Ghent 		ixgbe_get_hw_state(ixgbe);
1941dc0cb1cdSDale Ghent 	}
1942dc0cb1cdSDale Ghent 
19439da57d7bSbt 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
19449da57d7bSbt 		goto start_failure;
19459da57d7bSbt 	}
19469da57d7bSbt 
19479da57d7bSbt 	/*
19489da57d7bSbt 	 * Setup the rx/tx rings
19499da57d7bSbt 	 */
195084de666eSRyan Zezeski 	if (ixgbe_setup_rings(ixgbe) != IXGBE_SUCCESS)
195184de666eSRyan Zezeski 		goto start_failure;
19529da57d7bSbt 
195362e6e1adSPaul Guo 	/*
195462e6e1adSPaul Guo 	 * ixgbe_start() will be called when resetting, however if reset
19555b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * happens, we need to clear the ERROR, STALL and OVERTEMP flags
19565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * before enabling the interrupts.
195762e6e1adSPaul Guo 	 */
19585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR
19595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    | IXGBE_STALL| IXGBE_OVERTEMP));
196062e6e1adSPaul Guo 
19619da57d7bSbt 	/*
19629da57d7bSbt 	 * Enable adapter interrupts
19639da57d7bSbt 	 * The interrupts must be enabled after the driver state is START
19649da57d7bSbt 	 */
19659da57d7bSbt 	ixgbe_enable_adapter_interrupts(ixgbe);
19669da57d7bSbt 
19679da57d7bSbt 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
19689da57d7bSbt 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
19699da57d7bSbt 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
19709da57d7bSbt 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
19719da57d7bSbt 
19729da57d7bSbt 	return (IXGBE_SUCCESS);
19739da57d7bSbt 
19749da57d7bSbt start_failure:
19759da57d7bSbt 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
19769da57d7bSbt 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
19779da57d7bSbt 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
19789da57d7bSbt 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
19799da57d7bSbt 
19809da57d7bSbt 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
19819da57d7bSbt 
19829da57d7bSbt 	return (IXGBE_FAILURE);
19839da57d7bSbt }
19849da57d7bSbt 
19859da57d7bSbt /*
19869da57d7bSbt  * ixgbe_stop - Stop the driver/chipset.
19879da57d7bSbt  */
19889da57d7bSbt void
ixgbe_stop(ixgbe_t * ixgbe,boolean_t free_buffer)1989ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer)
19909da57d7bSbt {
19919da57d7bSbt 	int i;
19929da57d7bSbt 
19939da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
19949da57d7bSbt 
19959da57d7bSbt 	/*
19969da57d7bSbt 	 * Disable the adapter interrupts
19979da57d7bSbt 	 */
19989da57d7bSbt 	ixgbe_disable_adapter_interrupts(ixgbe);
19999da57d7bSbt 
20009da57d7bSbt 	/*
20019da57d7bSbt 	 * Drain the pending tx packets
20029da57d7bSbt 	 */
20039da57d7bSbt 	(void) ixgbe_tx_drain(ixgbe);
20049da57d7bSbt 
20059da57d7bSbt 	for (i = 0; i < ixgbe->num_rx_rings; i++)
20069da57d7bSbt 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
20079da57d7bSbt 	for (i = 0; i < ixgbe->num_tx_rings; i++)
20089da57d7bSbt 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
20099da57d7bSbt 
20109da57d7bSbt 	/*
20119da57d7bSbt 	 * Stop the chipset hardware
20129da57d7bSbt 	 */
20139da57d7bSbt 	ixgbe_chip_stop(ixgbe);
20149da57d7bSbt 
20159da57d7bSbt 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
20169da57d7bSbt 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
20179da57d7bSbt 	}
20189da57d7bSbt 
20199da57d7bSbt 	/*
20209da57d7bSbt 	 * Clean the pending tx data/resources
20219da57d7bSbt 	 */
20229da57d7bSbt 	ixgbe_tx_clean(ixgbe);
20239da57d7bSbt 
20249da57d7bSbt 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
20259da57d7bSbt 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
20269da57d7bSbt 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
20279da57d7bSbt 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
2028ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2029ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->link_state == LINK_STATE_UP) {
2030ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->link_state = LINK_STATE_UNKNOWN;
2031ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
2032ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
2033ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2034ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (free_buffer) {
2035ea65739eSchenlu chen - Sun Microsystems - Beijing China 		/*
2036ea65739eSchenlu chen - Sun Microsystems - Beijing China 		 * Release the DMA/memory resources of rx/tx rings
2037ea65739eSchenlu chen - Sun Microsystems - Beijing China 		 */
2038ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_free_dma(ixgbe);
2039ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_free_rx_data(ixgbe);
2040ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
20419da57d7bSbt }
20429da57d7bSbt 
20430dc2366fSVenugopal Iyer /*
20440dc2366fSVenugopal Iyer  * ixgbe_cbfunc - Driver interface for generic DDI callbacks
20450dc2366fSVenugopal Iyer  */
20460dc2366fSVenugopal Iyer /* ARGSUSED */
20470dc2366fSVenugopal Iyer static int
ixgbe_cbfunc(dev_info_t * dip,ddi_cb_action_t cbaction,void * cbarg,void * arg1,void * arg2)20480dc2366fSVenugopal Iyer ixgbe_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
20490dc2366fSVenugopal Iyer     void *arg1, void *arg2)
20500dc2366fSVenugopal Iyer {
20510dc2366fSVenugopal Iyer 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
20520dc2366fSVenugopal Iyer 
20530dc2366fSVenugopal Iyer 	switch (cbaction) {
20540dc2366fSVenugopal Iyer 	/* IRM callback */
20550dc2366fSVenugopal Iyer 	int count;
20560dc2366fSVenugopal Iyer 	case DDI_CB_INTR_ADD:
20570dc2366fSVenugopal Iyer 	case DDI_CB_INTR_REMOVE:
20580dc2366fSVenugopal Iyer 		count = (int)(uintptr_t)cbarg;
20590dc2366fSVenugopal Iyer 		ASSERT(ixgbe->intr_type == DDI_INTR_TYPE_MSIX);
20600dc2366fSVenugopal Iyer 		DTRACE_PROBE2(ixgbe__irm__callback, int, count,
20610dc2366fSVenugopal Iyer 		    int, ixgbe->intr_cnt);
20620dc2366fSVenugopal Iyer 		if (ixgbe_intr_adjust(ixgbe, cbaction, count) !=
20630dc2366fSVenugopal Iyer 		    DDI_SUCCESS) {
20640dc2366fSVenugopal Iyer 			ixgbe_error(ixgbe,
20650dc2366fSVenugopal Iyer 			    "IRM CB: Failed to adjust interrupts");
20660dc2366fSVenugopal Iyer 			goto cb_fail;
20670dc2366fSVenugopal Iyer 		}
20680dc2366fSVenugopal Iyer 		break;
20690dc2366fSVenugopal Iyer 	default:
20700dc2366fSVenugopal Iyer 		IXGBE_DEBUGLOG_1(ixgbe, "DDI CB: action 0x%x NOT supported",
20710dc2366fSVenugopal Iyer 		    cbaction);
20720dc2366fSVenugopal Iyer 		return (DDI_ENOTSUP);
20730dc2366fSVenugopal Iyer 	}
20740dc2366fSVenugopal Iyer 	return (DDI_SUCCESS);
20750dc2366fSVenugopal Iyer cb_fail:
20760dc2366fSVenugopal Iyer 	return (DDI_FAILURE);
20770dc2366fSVenugopal Iyer }
20780dc2366fSVenugopal Iyer 
20790dc2366fSVenugopal Iyer /*
20800dc2366fSVenugopal Iyer  * ixgbe_intr_adjust - Adjust interrupt to respond to IRM request.
20810dc2366fSVenugopal Iyer  */
20820dc2366fSVenugopal Iyer static int
ixgbe_intr_adjust(ixgbe_t * ixgbe,ddi_cb_action_t cbaction,int count)20830dc2366fSVenugopal Iyer ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count)
20840dc2366fSVenugopal Iyer {
20850dc2366fSVenugopal Iyer 	int i, rc, actual;
20860dc2366fSVenugopal Iyer 
20870dc2366fSVenugopal Iyer 	if (count == 0)
20880dc2366fSVenugopal Iyer 		return (DDI_SUCCESS);
20890dc2366fSVenugopal Iyer 
20900dc2366fSVenugopal Iyer 	if ((cbaction == DDI_CB_INTR_ADD &&
20910dc2366fSVenugopal Iyer 	    ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) ||
20920dc2366fSVenugopal Iyer 	    (cbaction == DDI_CB_INTR_REMOVE &&
20930dc2366fSVenugopal Iyer 	    ixgbe->intr_cnt - count < ixgbe->intr_cnt_min))
20940dc2366fSVenugopal Iyer 		return (DDI_FAILURE);
20950dc2366fSVenugopal Iyer 
20960dc2366fSVenugopal Iyer 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
20970dc2366fSVenugopal Iyer 		return (DDI_FAILURE);
20980dc2366fSVenugopal Iyer 	}
20990dc2366fSVenugopal Iyer 
21000dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_rx_rings; i++)
21010dc2366fSVenugopal Iyer 		mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL);
21020dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_tx_rings; i++)
21030dc2366fSVenugopal Iyer 		mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL);
21040dc2366fSVenugopal Iyer 
21050dc2366fSVenugopal Iyer 	mutex_enter(&ixgbe->gen_lock);
21060dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state &= ~IXGBE_STARTED;
21070dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST;
21080dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state |= IXGBE_SUSPENDED;
21090dc2366fSVenugopal Iyer 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
21100dc2366fSVenugopal Iyer 
21110dc2366fSVenugopal Iyer 	ixgbe_stop(ixgbe, B_FALSE);
21120dc2366fSVenugopal Iyer 	/*
21130dc2366fSVenugopal Iyer 	 * Disable interrupts
21140dc2366fSVenugopal Iyer 	 */
21150dc2366fSVenugopal Iyer 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
21160dc2366fSVenugopal Iyer 		rc = ixgbe_disable_intrs(ixgbe);
21170dc2366fSVenugopal Iyer 		ASSERT(rc == IXGBE_SUCCESS);
21180dc2366fSVenugopal Iyer 	}
21190dc2366fSVenugopal Iyer 	ixgbe->attach_progress &= ~ATTACH_PROGRESS_ENABLE_INTR;
21200dc2366fSVenugopal Iyer 
21210dc2366fSVenugopal Iyer 	/*
21220dc2366fSVenugopal Iyer 	 * Remove interrupt handlers
21230dc2366fSVenugopal Iyer 	 */
21240dc2366fSVenugopal Iyer 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
21250dc2366fSVenugopal Iyer 		ixgbe_rem_intr_handlers(ixgbe);
21260dc2366fSVenugopal Iyer 	}
21270dc2366fSVenugopal Iyer 	ixgbe->attach_progress &= ~ATTACH_PROGRESS_ADD_INTR;
21280dc2366fSVenugopal Iyer 
21290dc2366fSVenugopal Iyer 	/*
21300dc2366fSVenugopal Iyer 	 * Clear vect_map
21310dc2366fSVenugopal Iyer 	 */
21320dc2366fSVenugopal Iyer 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
21330dc2366fSVenugopal Iyer 	switch (cbaction) {
21340dc2366fSVenugopal Iyer 	case DDI_CB_INTR_ADD:
21350dc2366fSVenugopal Iyer 		rc = ddi_intr_alloc(ixgbe->dip, ixgbe->htable,
21360dc2366fSVenugopal Iyer 		    DDI_INTR_TYPE_MSIX, ixgbe->intr_cnt, count, &actual,
21370dc2366fSVenugopal Iyer 		    DDI_INTR_ALLOC_NORMAL);
21380dc2366fSVenugopal Iyer 		if (rc != DDI_SUCCESS || actual != count) {
21390dc2366fSVenugopal Iyer 			ixgbe_log(ixgbe, "Adjust interrupts failed."
21400dc2366fSVenugopal Iyer 			    "return: %d, irm cb size: %d, actual: %d",
21410dc2366fSVenugopal Iyer 			    rc, count, actual);
21420dc2366fSVenugopal Iyer 			goto intr_adjust_fail;
21430dc2366fSVenugopal Iyer 		}
21440dc2366fSVenugopal Iyer 		ixgbe->intr_cnt += count;
21450dc2366fSVenugopal Iyer 		break;
21460dc2366fSVenugopal Iyer 
21470dc2366fSVenugopal Iyer 	case DDI_CB_INTR_REMOVE:
21480dc2366fSVenugopal Iyer 		for (i = ixgbe->intr_cnt - count;
21490dc2366fSVenugopal Iyer 		    i < ixgbe->intr_cnt; i ++) {
21500dc2366fSVenugopal Iyer 			rc = ddi_intr_free(ixgbe->htable[i]);
21510dc2366fSVenugopal Iyer 			ixgbe->htable[i] = NULL;
21520dc2366fSVenugopal Iyer 			if (rc != DDI_SUCCESS) {
21530dc2366fSVenugopal Iyer 				ixgbe_log(ixgbe, "Adjust interrupts failed."
21540dc2366fSVenugopal Iyer 				    "return: %d, irm cb size: %d, actual: %d",
21550dc2366fSVenugopal Iyer 				    rc, count, actual);
21560dc2366fSVenugopal Iyer 				goto intr_adjust_fail;
21570dc2366fSVenugopal Iyer 			}
21580dc2366fSVenugopal Iyer 		}
21590dc2366fSVenugopal Iyer 		ixgbe->intr_cnt -= count;
21600dc2366fSVenugopal Iyer 		break;
21610dc2366fSVenugopal Iyer 	}
21620dc2366fSVenugopal Iyer 
21630dc2366fSVenugopal Iyer 	/*
21640dc2366fSVenugopal Iyer 	 * Get priority for first vector, assume remaining are all the same
21650dc2366fSVenugopal Iyer 	 */
21660dc2366fSVenugopal Iyer 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
21670dc2366fSVenugopal Iyer 	if (rc != DDI_SUCCESS) {
21680dc2366fSVenugopal Iyer 		ixgbe_log(ixgbe,
21690dc2366fSVenugopal Iyer 		    "Get interrupt priority failed: %d", rc);
21700dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
21710dc2366fSVenugopal Iyer 	}
21720dc2366fSVenugopal Iyer 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
21730dc2366fSVenugopal Iyer 	if (rc != DDI_SUCCESS) {
21740dc2366fSVenugopal Iyer 		ixgbe_log(ixgbe, "Get interrupt cap failed: %d", rc);
21750dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
21760dc2366fSVenugopal Iyer 	}
21770dc2366fSVenugopal Iyer 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
21780dc2366fSVenugopal Iyer 
21790dc2366fSVenugopal Iyer 	/*
21800dc2366fSVenugopal Iyer 	 * Map rings to interrupt vectors
21810dc2366fSVenugopal Iyer 	 */
21820dc2366fSVenugopal Iyer 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
21830dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe,
21840dc2366fSVenugopal Iyer 		    "IRM CB: Failed to map interrupts to vectors");
21850dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
21860dc2366fSVenugopal Iyer 	}
21870dc2366fSVenugopal Iyer 
21880dc2366fSVenugopal Iyer 	/*
21890dc2366fSVenugopal Iyer 	 * Add interrupt handlers
21900dc2366fSVenugopal Iyer 	 */
21910dc2366fSVenugopal Iyer 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
21920dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe, "IRM CB: Failed to add interrupt handlers");
21930dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
21940dc2366fSVenugopal Iyer 	}
21950dc2366fSVenugopal Iyer 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
21960dc2366fSVenugopal Iyer 
21970dc2366fSVenugopal Iyer 	/*
21980dc2366fSVenugopal Iyer 	 * Now that mutex locks are initialized, and the chip is also
21990dc2366fSVenugopal Iyer 	 * initialized, enable interrupts.
22000dc2366fSVenugopal Iyer 	 */
22010dc2366fSVenugopal Iyer 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
22020dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts");
22030dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
22040dc2366fSVenugopal Iyer 	}
22050dc2366fSVenugopal Iyer 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
22060dc2366fSVenugopal Iyer 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
22070dc2366fSVenugopal Iyer 		ixgbe_error(ixgbe, "IRM CB: Failed to start");
22080dc2366fSVenugopal Iyer 		goto intr_adjust_fail;
22090dc2366fSVenugopal Iyer 	}
22100dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST;
22110dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED;
22120dc2366fSVenugopal Iyer 	ixgbe->ixgbe_state |= IXGBE_STARTED;
22130dc2366fSVenugopal Iyer 	mutex_exit(&ixgbe->gen_lock);
22140dc2366fSVenugopal Iyer 
22150dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
22160dc2366fSVenugopal Iyer 		mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle,
22170dc2366fSVenugopal Iyer 		    ixgbe->htable[ixgbe->rx_rings[i].intr_vector]);
22180dc2366fSVenugopal Iyer 	}
22190dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
22200dc2366fSVenugopal Iyer 		mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle,
22210dc2366fSVenugopal Iyer 		    ixgbe->htable[ixgbe->tx_rings[i].intr_vector]);
22220dc2366fSVenugopal Iyer 	}
22230dc2366fSVenugopal Iyer 
22240dc2366fSVenugopal Iyer 	/* Wakeup all Tx rings */
22250dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
22260dc2366fSVenugopal Iyer 		mac_tx_ring_update(ixgbe->mac_hdl,
22270dc2366fSVenugopal Iyer 		    ixgbe->tx_rings[i].ring_handle);
22280dc2366fSVenugopal Iyer 	}
22290dc2366fSVenugopal Iyer 
22300dc2366fSVenugopal Iyer 	IXGBE_DEBUGLOG_3(ixgbe,
22310dc2366fSVenugopal Iyer 	    "IRM CB: interrupts new value: 0x%x(0x%x:0x%x).",
22320dc2366fSVenugopal Iyer 	    ixgbe->intr_cnt, ixgbe->intr_cnt_min, ixgbe->intr_cnt_max);
22330dc2366fSVenugopal Iyer 	return (DDI_SUCCESS);
22340dc2366fSVenugopal Iyer 
22350dc2366fSVenugopal Iyer intr_adjust_fail:
22360dc2366fSVenugopal Iyer 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
22370dc2366fSVenugopal Iyer 	mutex_exit(&ixgbe->gen_lock);
22380dc2366fSVenugopal Iyer 	return (DDI_FAILURE);
22390dc2366fSVenugopal Iyer }
22400dc2366fSVenugopal Iyer 
22410dc2366fSVenugopal Iyer /*
22420dc2366fSVenugopal Iyer  * ixgbe_intr_cb_register - Register interrupt callback function.
22430dc2366fSVenugopal Iyer  */
22440dc2366fSVenugopal Iyer static int
ixgbe_intr_cb_register(ixgbe_t * ixgbe)22450dc2366fSVenugopal Iyer ixgbe_intr_cb_register(ixgbe_t *ixgbe)
22460dc2366fSVenugopal Iyer {
22470dc2366fSVenugopal Iyer 	if (ddi_cb_register(ixgbe->dip, DDI_CB_FLAG_INTR, ixgbe_cbfunc,
22480dc2366fSVenugopal Iyer 	    ixgbe, NULL, &ixgbe->cb_hdl) != DDI_SUCCESS) {
22490dc2366fSVenugopal Iyer 		return (IXGBE_FAILURE);
22500dc2366fSVenugopal Iyer 	}
22510dc2366fSVenugopal Iyer 	IXGBE_DEBUGLOG_0(ixgbe, "Interrupt callback function registered.");
22520dc2366fSVenugopal Iyer 	return (IXGBE_SUCCESS);
22530dc2366fSVenugopal Iyer }
22540dc2366fSVenugopal Iyer 
22559da57d7bSbt /*
22569da57d7bSbt  * ixgbe_alloc_rings - Allocate memory space for rx/tx rings.
22579da57d7bSbt  */
22589da57d7bSbt static int
ixgbe_alloc_rings(ixgbe_t * ixgbe)22599da57d7bSbt ixgbe_alloc_rings(ixgbe_t *ixgbe)
22609da57d7bSbt {
22619da57d7bSbt 	/*
22629da57d7bSbt 	 * Allocate memory space for rx rings
22639da57d7bSbt 	 */
22649da57d7bSbt 	ixgbe->rx_rings = kmem_zalloc(
22659da57d7bSbt 	    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings,
22669da57d7bSbt 	    KM_NOSLEEP);
22679da57d7bSbt 
22689da57d7bSbt 	if (ixgbe->rx_rings == NULL) {
22699da57d7bSbt 		return (IXGBE_FAILURE);
22709da57d7bSbt 	}
22719da57d7bSbt 
22729da57d7bSbt 	/*
22739da57d7bSbt 	 * Allocate memory space for tx rings
22749da57d7bSbt 	 */
22759da57d7bSbt 	ixgbe->tx_rings = kmem_zalloc(
22769da57d7bSbt 	    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings,
22779da57d7bSbt 	    KM_NOSLEEP);
22789da57d7bSbt 
22799da57d7bSbt 	if (ixgbe->tx_rings == NULL) {
22809da57d7bSbt 		kmem_free(ixgbe->rx_rings,
22819da57d7bSbt 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
22829da57d7bSbt 		ixgbe->rx_rings = NULL;
22839da57d7bSbt 		return (IXGBE_FAILURE);
22849da57d7bSbt 	}
22859da57d7bSbt 
2286da14cebeSEric Cheng 	/*
2287da14cebeSEric Cheng 	 * Allocate memory space for rx ring groups
2288da14cebeSEric Cheng 	 */
2289da14cebeSEric Cheng 	ixgbe->rx_groups = kmem_zalloc(
2290da14cebeSEric Cheng 	    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups,
2291da14cebeSEric Cheng 	    KM_NOSLEEP);
2292da14cebeSEric Cheng 
2293da14cebeSEric Cheng 	if (ixgbe->rx_groups == NULL) {
2294da14cebeSEric Cheng 		kmem_free(ixgbe->rx_rings,
2295da14cebeSEric Cheng 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
2296da14cebeSEric Cheng 		kmem_free(ixgbe->tx_rings,
2297da14cebeSEric Cheng 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
2298da14cebeSEric Cheng 		ixgbe->rx_rings = NULL;
2299da14cebeSEric Cheng 		ixgbe->tx_rings = NULL;
2300da14cebeSEric Cheng 		return (IXGBE_FAILURE);
2301da14cebeSEric Cheng 	}
2302da14cebeSEric Cheng 
23039da57d7bSbt 	return (IXGBE_SUCCESS);
23049da57d7bSbt }
23059da57d7bSbt 
23069da57d7bSbt /*
23079da57d7bSbt  * ixgbe_free_rings - Free the memory space of rx/tx rings.
23089da57d7bSbt  */
23099da57d7bSbt static void
ixgbe_free_rings(ixgbe_t * ixgbe)23109da57d7bSbt ixgbe_free_rings(ixgbe_t *ixgbe)
23119da57d7bSbt {
23129da57d7bSbt 	if (ixgbe->rx_rings != NULL) {
23139da57d7bSbt 		kmem_free(ixgbe->rx_rings,
23149da57d7bSbt 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
23159da57d7bSbt 		ixgbe->rx_rings = NULL;
23169da57d7bSbt 	}
23179da57d7bSbt 
23189da57d7bSbt 	if (ixgbe->tx_rings != NULL) {
23199da57d7bSbt 		kmem_free(ixgbe->tx_rings,
23209da57d7bSbt 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
23219da57d7bSbt 		ixgbe->tx_rings = NULL;
23229da57d7bSbt 	}
2323da14cebeSEric Cheng 
232484de666eSRyan Zezeski 	for (uint_t i = 0; i < ixgbe->num_rx_groups; i++) {
232584de666eSRyan Zezeski 		ixgbe_vlan_t *vlp;
232684de666eSRyan Zezeski 		ixgbe_rx_group_t *rx_group = &ixgbe->rx_groups[i];
232784de666eSRyan Zezeski 
232884de666eSRyan Zezeski 		while ((vlp = list_remove_head(&rx_group->vlans)) != NULL)
232984de666eSRyan Zezeski 			kmem_free(vlp, sizeof (ixgbe_vlan_t));
233084de666eSRyan Zezeski 
233184de666eSRyan Zezeski 		list_destroy(&rx_group->vlans);
233284de666eSRyan Zezeski 	}
233384de666eSRyan Zezeski 
2334da14cebeSEric Cheng 	if (ixgbe->rx_groups != NULL) {
2335da14cebeSEric Cheng 		kmem_free(ixgbe->rx_groups,
2336da14cebeSEric Cheng 		    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups);
2337da14cebeSEric Cheng 		ixgbe->rx_groups = NULL;
2338da14cebeSEric Cheng 	}
23399da57d7bSbt }
23409da57d7bSbt 
2341ea65739eSchenlu chen - Sun Microsystems - Beijing China static int
ixgbe_alloc_rx_data(ixgbe_t * ixgbe)2342ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_alloc_rx_data(ixgbe_t *ixgbe)
2343ea65739eSchenlu chen - Sun Microsystems - Beijing China {
2344ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_rx_ring_t *rx_ring;
2345ea65739eSchenlu chen - Sun Microsystems - Beijing China 	int i;
2346ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2347ea65739eSchenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
2348ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rx_ring = &ixgbe->rx_rings[i];
2349ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS)
2350ea65739eSchenlu chen - Sun Microsystems - Beijing China 			goto alloc_rx_rings_failure;
2351ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
2352ea65739eSchenlu chen - Sun Microsystems - Beijing China 	return (IXGBE_SUCCESS);
2353ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2354ea65739eSchenlu chen - Sun Microsystems - Beijing China alloc_rx_rings_failure:
2355ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_free_rx_data(ixgbe);
2356ea65739eSchenlu chen - Sun Microsystems - Beijing China 	return (IXGBE_FAILURE);
2357ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2358ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2359ea65739eSchenlu chen - Sun Microsystems - Beijing China static void
ixgbe_free_rx_data(ixgbe_t * ixgbe)2360ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_data(ixgbe_t *ixgbe)
2361ea65739eSchenlu chen - Sun Microsystems - Beijing China {
2362ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_rx_ring_t *rx_ring;
2363ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_rx_data_t *rx_data;
2364ea65739eSchenlu chen - Sun Microsystems - Beijing China 	int i;
2365ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2366ea65739eSchenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
2367ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rx_ring = &ixgbe->rx_rings[i];
2368ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2369ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mutex_enter(&ixgbe->rx_pending_lock);
2370ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rx_data = rx_ring->rx_data;
2371ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2372ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (rx_data != NULL) {
2373ea65739eSchenlu chen - Sun Microsystems - Beijing China 			rx_data->flag |= IXGBE_RX_STOPPED;
2374ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2375ea65739eSchenlu chen - Sun Microsystems - Beijing China 			if (rx_data->rcb_pending == 0) {
2376ea65739eSchenlu chen - Sun Microsystems - Beijing China 				ixgbe_free_rx_ring_data(rx_data);
2377ea65739eSchenlu chen - Sun Microsystems - Beijing China 				rx_ring->rx_data = NULL;
2378ea65739eSchenlu chen - Sun Microsystems - Beijing China 			}
2379ea65739eSchenlu chen - Sun Microsystems - Beijing China 		}
2380ea65739eSchenlu chen - Sun Microsystems - Beijing China 
2381ea65739eSchenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&ixgbe->rx_pending_lock);
2382ea65739eSchenlu chen - Sun Microsystems - Beijing China 	}
2383ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2384ea65739eSchenlu chen - Sun Microsystems - Beijing China 
23859da57d7bSbt /*
23869da57d7bSbt  * ixgbe_setup_rings - Setup rx/tx rings.
23879da57d7bSbt  */
238884de666eSRyan Zezeski static int
ixgbe_setup_rings(ixgbe_t * ixgbe)23899da57d7bSbt ixgbe_setup_rings(ixgbe_t *ixgbe)
23909da57d7bSbt {
23919da57d7bSbt 	/*
23929da57d7bSbt 	 * Setup the rx/tx rings, including the following:
23939da57d7bSbt 	 *
23949da57d7bSbt 	 * 1. Setup the descriptor ring and the control block buffers;
23959da57d7bSbt 	 * 2. Initialize necessary registers for receive/transmit;
23969da57d7bSbt 	 * 3. Initialize software pointers/parameters for receive/transmit;
23979da57d7bSbt 	 */
239884de666eSRyan Zezeski 	if (ixgbe_setup_rx(ixgbe) != IXGBE_SUCCESS)
239984de666eSRyan Zezeski 		return (IXGBE_FAILURE);
24009da57d7bSbt 
24019da57d7bSbt 	ixgbe_setup_tx(ixgbe);
240284de666eSRyan Zezeski 
240384de666eSRyan Zezeski 	return (IXGBE_SUCCESS);
24049da57d7bSbt }
24059da57d7bSbt 
24069da57d7bSbt static void
ixgbe_setup_rx_ring(ixgbe_rx_ring_t * rx_ring)24079da57d7bSbt ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring)
24089da57d7bSbt {
24099da57d7bSbt 	ixgbe_t *ixgbe = rx_ring->ixgbe;
2410ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_rx_data_t *rx_data = rx_ring->rx_data;
24119da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
24129da57d7bSbt 	rx_control_block_t *rcb;
24139da57d7bSbt 	union ixgbe_adv_rx_desc	*rbd;
24149da57d7bSbt 	uint32_t size;
24159da57d7bSbt 	uint32_t buf_low;
24169da57d7bSbt 	uint32_t buf_high;
24179da57d7bSbt 	uint32_t reg_val;
24189da57d7bSbt 	int i;
24199da57d7bSbt 
24209da57d7bSbt 	ASSERT(mutex_owned(&rx_ring->rx_lock));
24219da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
24229da57d7bSbt 
24239da57d7bSbt 	for (i = 0; i < ixgbe->rx_ring_size; i++) {
2424ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rcb = rx_data->work_list[i];
2425ea65739eSchenlu chen - Sun Microsystems - Beijing China 		rbd = &rx_data->rbd_ring[i];
24269da57d7bSbt 
24279da57d7bSbt 		rbd->read.pkt_addr = rcb->rx_buf.dma_address;
2428afac708dSToomas Soome 		rbd->read.hdr_addr = 0;
24299da57d7bSbt 	}
24309da57d7bSbt 
24319da57d7bSbt 	/*
24329da57d7bSbt 	 * Initialize the length register
24339da57d7bSbt 	 */
2434ea65739eSchenlu chen - Sun Microsystems - Beijing China 	size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc);
24350dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->hw_index), size);
24369da57d7bSbt 
24379da57d7bSbt 	/*
24389da57d7bSbt 	 * Initialize the base address registers
24399da57d7bSbt 	 */
2440ea65739eSchenlu chen - Sun Microsystems - Beijing China 	buf_low = (uint32_t)rx_data->rbd_area.dma_address;
2441ea65739eSchenlu chen - Sun Microsystems - Beijing China 	buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32);
24420dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->hw_index), buf_high);
24430dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->hw_index), buf_low);
24449da57d7bSbt 
24459da57d7bSbt 	/*
24469da57d7bSbt 	 * Setup head & tail pointers
24479da57d7bSbt 	 */
24480dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->hw_index),
24490dc2366fSVenugopal Iyer 	    rx_data->ring_size - 1);
24500dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->hw_index), 0);
24519da57d7bSbt 
2452ea65739eSchenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_next = 0;
2453ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	rx_data->lro_first = 0;
24549da57d7bSbt 
24559da57d7bSbt 	/*
24569da57d7bSbt 	 * Setup the Receive Descriptor Control Register (RXDCTL)
24579da57d7bSbt 	 * PTHRESH=32 descriptors (half the internal cache)
24589da57d7bSbt 	 * HTHRESH=0 descriptors (to minimize latency on fetch)
24599da57d7bSbt 	 * WTHRESH defaults to 1 (writeback each descriptor)
24609da57d7bSbt 	 */
24610dc2366fSVenugopal Iyer 	reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index));
24629da57d7bSbt 	reg_val |= IXGBE_RXDCTL_ENABLE;	/* enable queue */
246373cd555cSBin Tu - Sun Microsystems - Beijing China 
2464dc0cb1cdSDale Ghent 	/* Not a valid value for 82599, X540 or X550 */
246569b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82598EB) {
246673cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val |= 0x0020;	/* pthresh */
246773cd555cSBin Tu - Sun Microsystems - Beijing China 	}
24680dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val);
24699da57d7bSbt 
247069b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82599EB ||
2471dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
2472dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
247348ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_x ||
247448ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_a) {
247573cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
247673cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS);
247773cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
247873cd555cSBin Tu - Sun Microsystems - Beijing China 	}
247973cd555cSBin Tu - Sun Microsystems - Beijing China 
24809da57d7bSbt 	/*
24819da57d7bSbt 	 * Setup the Split and Replication Receive Control Register.
24829da57d7bSbt 	 * Set the rx buffer size and the advanced descriptor type.
24839da57d7bSbt 	 */
24849da57d7bSbt 	reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) |
24859da57d7bSbt 	    IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
248673cd555cSBin Tu - Sun Microsystems - Beijing China 	reg_val |= IXGBE_SRRCTL_DROP_EN;
24870dc2366fSVenugopal Iyer 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->hw_index), reg_val);
24889da57d7bSbt }
24899da57d7bSbt 
249084de666eSRyan Zezeski static int
ixgbe_setup_rx(ixgbe_t * ixgbe)24919da57d7bSbt ixgbe_setup_rx(ixgbe_t *ixgbe)
24929da57d7bSbt {
24939da57d7bSbt 	ixgbe_rx_ring_t *rx_ring;
24949da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
24959da57d7bSbt 	uint32_t reg_val;
2496168e1ed4SRyan Zezeski 	uint32_t i;
24970dc2366fSVenugopal Iyer 	uint32_t psrtype_rss_bit;
24989da57d7bSbt 
2499dc0cb1cdSDale Ghent 	/*
2500dc0cb1cdSDale Ghent 	 * Ensure that Rx is disabled while setting up
2501dc0cb1cdSDale Ghent 	 * the Rx unit and Rx descriptor ring(s)
2502dc0cb1cdSDale Ghent 	 */
2503dc0cb1cdSDale Ghent 	ixgbe_disable_rx(hw);
2504dc0cb1cdSDale Ghent 
250573cd555cSBin Tu - Sun Microsystems - Beijing China 	/* PSRTYPE must be configured for 82599 */
25060dc2366fSVenugopal Iyer 	if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ &&
25070dc2366fSVenugopal Iyer 	    ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) {
25080dc2366fSVenugopal Iyer 		reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
25090dc2366fSVenugopal Iyer 		    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
25100dc2366fSVenugopal Iyer 		reg_val |= IXGBE_PSRTYPE_L2HDR;
25110dc2366fSVenugopal Iyer 		reg_val |= 0x80000000;
25120dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val);
25130dc2366fSVenugopal Iyer 	} else {
25140dc2366fSVenugopal Iyer 		if (ixgbe->num_rx_groups > 32) {
25150dc2366fSVenugopal Iyer 			psrtype_rss_bit = 0x20000000;
25160dc2366fSVenugopal Iyer 		} else {
25170dc2366fSVenugopal Iyer 			psrtype_rss_bit = 0x40000000;
25180dc2366fSVenugopal Iyer 		}
25190dc2366fSVenugopal Iyer 		for (i = 0; i < ixgbe->capab->max_rx_grp_num; i++) {
25200dc2366fSVenugopal Iyer 			reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
25210dc2366fSVenugopal Iyer 			    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
25220dc2366fSVenugopal Iyer 			reg_val |= IXGBE_PSRTYPE_L2HDR;
25230dc2366fSVenugopal Iyer 			reg_val |= psrtype_rss_bit;
25240dc2366fSVenugopal Iyer 			IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val);
25250dc2366fSVenugopal Iyer 		}
25260dc2366fSVenugopal Iyer 	}
252773cd555cSBin Tu - Sun Microsystems - Beijing China 
25289da57d7bSbt 	/*
2529dc0cb1cdSDale Ghent 	 * Set filter control in FCTRL to determine types of packets are passed
2530dc0cb1cdSDale Ghent 	 * up to the driver.
2531dc0cb1cdSDale Ghent 	 * - Pass broadcast packets.
2532dc0cb1cdSDale Ghent 	 * - Do not pass flow control pause frames (82598-specific)
25339da57d7bSbt 	 */
25349da57d7bSbt 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
2535dc0cb1cdSDale Ghent 	reg_val |= IXGBE_FCTRL_BAM; /* Broadcast Accept Mode */
2536dc0cb1cdSDale Ghent 	if (hw->mac.type == ixgbe_mac_82598EB) {
2537dc0cb1cdSDale Ghent 		reg_val |= IXGBE_FCTRL_DPF; /* Discard Pause Frames */
2538dc0cb1cdSDale Ghent 	}
25399da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val);
25409da57d7bSbt 
25410dc2366fSVenugopal Iyer 	/*
25420dc2366fSVenugopal Iyer 	 * Hardware checksum settings
25430dc2366fSVenugopal Iyer 	 */
25440dc2366fSVenugopal Iyer 	if (ixgbe->rx_hcksum_enable) {
2545dc0cb1cdSDale Ghent 		reg_val = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
2546dc0cb1cdSDale Ghent 		reg_val |= IXGBE_RXCSUM_IPPCSE;	/* IP checksum */
25470dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val);
25480dc2366fSVenugopal Iyer 	}
25490dc2366fSVenugopal Iyer 
25500dc2366fSVenugopal Iyer 	/*
25510dc2366fSVenugopal Iyer 	 * Setup VMDq and RSS for multiple receive queues
25520dc2366fSVenugopal Iyer 	 */
25530dc2366fSVenugopal Iyer 	switch (ixgbe->classify_mode) {
25540dc2366fSVenugopal Iyer 	case IXGBE_CLASSIFY_RSS:
25550dc2366fSVenugopal Iyer 		/*
25560dc2366fSVenugopal Iyer 		 * One group, only RSS is needed when more than
25570dc2366fSVenugopal Iyer 		 * one ring enabled.
25580dc2366fSVenugopal Iyer 		 */
25590dc2366fSVenugopal Iyer 		ixgbe_setup_rss(ixgbe);
25600dc2366fSVenugopal Iyer 		break;
25610dc2366fSVenugopal Iyer 
25620dc2366fSVenugopal Iyer 	case IXGBE_CLASSIFY_VMDQ:
25630dc2366fSVenugopal Iyer 		/*
25640dc2366fSVenugopal Iyer 		 * Multiple groups, each group has one ring,
25650dc2366fSVenugopal Iyer 		 * only VMDq is needed.
25660dc2366fSVenugopal Iyer 		 */
25670dc2366fSVenugopal Iyer 		ixgbe_setup_vmdq(ixgbe);
25680dc2366fSVenugopal Iyer 		break;
25690dc2366fSVenugopal Iyer 
25700dc2366fSVenugopal Iyer 	case IXGBE_CLASSIFY_VMDQ_RSS:
25710dc2366fSVenugopal Iyer 		/*
25720dc2366fSVenugopal Iyer 		 * Multiple groups and multiple rings, both
25730dc2366fSVenugopal Iyer 		 * VMDq and RSS are needed.
25740dc2366fSVenugopal Iyer 		 */
25750dc2366fSVenugopal Iyer 		ixgbe_setup_vmdq_rss(ixgbe);
25760dc2366fSVenugopal Iyer 		break;
25770dc2366fSVenugopal Iyer 
25780dc2366fSVenugopal Iyer 	default:
25790dc2366fSVenugopal Iyer 		break;
25800dc2366fSVenugopal Iyer 	}
25810dc2366fSVenugopal Iyer 
258284de666eSRyan Zezeski 	/*
258384de666eSRyan Zezeski 	 * Initialize VLAN SW and HW state if VLAN filtering is
258484de666eSRyan Zezeski 	 * enabled.
258584de666eSRyan Zezeski 	 */
258684de666eSRyan Zezeski 	if (ixgbe->vlft_enabled) {
258784de666eSRyan Zezeski 		if (ixgbe_init_vlan(ixgbe) != IXGBE_SUCCESS)
258884de666eSRyan Zezeski 			return (IXGBE_FAILURE);
258984de666eSRyan Zezeski 	}
259084de666eSRyan Zezeski 
25919da57d7bSbt 	/*
25929da57d7bSbt 	 * Enable the receive unit.  This must be done after filter
2593dc0cb1cdSDale Ghent 	 * control is set in FCTRL. On 82598, we disable the descriptor monitor.
2594dc0cb1cdSDale Ghent 	 * 82598 is the only adapter which defines this RXCTRL option.
25959da57d7bSbt 	 */
2596dc0cb1cdSDale Ghent 	reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
2597dc0cb1cdSDale Ghent 	if (hw->mac.type == ixgbe_mac_82598EB)
2598dc0cb1cdSDale Ghent 		reg_val |= IXGBE_RXCTRL_DMBYPS; /* descriptor monitor bypass */
2599dc0cb1cdSDale Ghent 	reg_val |= IXGBE_RXCTRL_RXEN;
2600dc0cb1cdSDale Ghent 	(void) ixgbe_enable_rx_dma(hw, reg_val);
26019da57d7bSbt 
26029da57d7bSbt 	/*
26039da57d7bSbt 	 * ixgbe_setup_rx_ring must be called after configuring RXCTRL
26049da57d7bSbt 	 */
26059da57d7bSbt 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
26069da57d7bSbt 		rx_ring = &ixgbe->rx_rings[i];
26079da57d7bSbt 		ixgbe_setup_rx_ring(rx_ring);
26089da57d7bSbt 	}
26099da57d7bSbt 
2610da14cebeSEric Cheng 	/*
2611168e1ed4SRyan Zezeski 	 * The 82598 controller gives us the RNBC (Receive No Buffer
2612168e1ed4SRyan Zezeski 	 * Count) register to determine the number of frames dropped
2613168e1ed4SRyan Zezeski 	 * due to no available descriptors on the destination queue.
2614168e1ed4SRyan Zezeski 	 * However, this register was removed starting with 82599 and
2615168e1ed4SRyan Zezeski 	 * it was replaced with the RQSMR/QPRDC registers. The nice
2616168e1ed4SRyan Zezeski 	 * thing about the new registers is that they allow you to map
2617168e1ed4SRyan Zezeski 	 * groups of queues to specific stat registers. The bad thing
2618168e1ed4SRyan Zezeski 	 * is there are only 16 slots in the stat registers, so this
2619168e1ed4SRyan Zezeski 	 * won't work when we have 32 Rx groups. Instead, we map all
2620168e1ed4SRyan Zezeski 	 * queues to the zero slot of the stat registers, giving us a
2621168e1ed4SRyan Zezeski 	 * global counter at QPRDC[0] (with the equivalent semantics
2622168e1ed4SRyan Zezeski 	 * of RNBC). Perhaps future controllers will have more slots
2623168e1ed4SRyan Zezeski 	 * and we can implement per-group counters.
2624da14cebeSEric Cheng 	 */
2625da14cebeSEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
2626168e1ed4SRyan Zezeski 		uint32_t index = ixgbe->rx_rings[i].hw_index;
2627168e1ed4SRyan Zezeski 		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(index >> 2), 0);
2628da14cebeSEric Cheng 	}
2629da14cebeSEric Cheng 
26309da57d7bSbt 	/*
263173cd555cSBin Tu - Sun Microsystems - Beijing China 	 * The Max Frame Size in MHADD/MAXFRS will be internally increased
263273cd555cSBin Tu - Sun Microsystems - Beijing China 	 * by four bytes if the packet has a VLAN field, so includes MTU,
263373cd555cSBin Tu - Sun Microsystems - Beijing China 	 * ethernet header and frame check sequence.
263473cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Register is MAXFRS in 82599.
26359da57d7bSbt 	 */
2636dc0cb1cdSDale Ghent 	reg_val = IXGBE_READ_REG(hw, IXGBE_MHADD);
2637dc0cb1cdSDale Ghent 	reg_val &= ~IXGBE_MHADD_MFS_MASK;
2638dc0cb1cdSDale Ghent 	reg_val |= (ixgbe->default_mtu + sizeof (struct ether_header)
26399da57d7bSbt 	    + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT;
26409da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val);
26419da57d7bSbt 
26429da57d7bSbt 	/*
26439da57d7bSbt 	 * Setup Jumbo Frame enable bit
26449da57d7bSbt 	 */
2645dc0cb1cdSDale Ghent 	reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2646dc0cb1cdSDale Ghent 	if (ixgbe->default_mtu > ETHERMTU)
26479da57d7bSbt 		reg_val |= IXGBE_HLREG0_JUMBOEN;
2648dc0cb1cdSDale Ghent 	else
2649dc0cb1cdSDale Ghent 		reg_val &= ~IXGBE_HLREG0_JUMBOEN;
2650dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
26511878b971SVenugopal Iyer 
26521878b971SVenugopal Iyer 	/*
26531878b971SVenugopal Iyer 	 * Setup RSC for multiple receive queues.
26541878b971SVenugopal Iyer 	 */
26551878b971SVenugopal Iyer 	if (ixgbe->lro_enable) {
26561878b971SVenugopal Iyer 		for (i = 0; i < ixgbe->num_rx_rings; i++) {
26571878b971SVenugopal Iyer 			/*
26581878b971SVenugopal Iyer 			 * Make sure rx_buf_size * MAXDESC not greater
26591878b971SVenugopal Iyer 			 * than 65535.
26601878b971SVenugopal Iyer 			 * Intel recommends 4 for MAXDESC field value.
26611878b971SVenugopal Iyer 			 */
26621878b971SVenugopal Iyer 			reg_val = IXGBE_READ_REG(hw, IXGBE_RSCCTL(i));
26631878b971SVenugopal Iyer 			reg_val |= IXGBE_RSCCTL_RSCEN;
26641878b971SVenugopal Iyer 			if (ixgbe->rx_buf_size == IXGBE_PKG_BUF_16k)
26651878b971SVenugopal Iyer 				reg_val |= IXGBE_RSCCTL_MAXDESC_1;
26661878b971SVenugopal Iyer 			else
26671878b971SVenugopal Iyer 				reg_val |= IXGBE_RSCCTL_MAXDESC_4;
26681878b971SVenugopal Iyer 			IXGBE_WRITE_REG(hw,  IXGBE_RSCCTL(i), reg_val);
26691878b971SVenugopal Iyer 		}
26701878b971SVenugopal Iyer 
26711878b971SVenugopal Iyer 		reg_val = IXGBE_READ_REG(hw, IXGBE_RSCDBU);
26721878b971SVenugopal Iyer 		reg_val |= IXGBE_RSCDBU_RSCACKDIS;
26731878b971SVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, reg_val);
26741878b971SVenugopal Iyer 
26751878b971SVenugopal Iyer 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
26761878b971SVenugopal Iyer 		reg_val |= IXGBE_RDRXCTL_RSCACKC;
267719843f01SPaul Guo 		reg_val |= IXGBE_RDRXCTL_FCOE_WRFIX;
26781878b971SVenugopal Iyer 		reg_val &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
26791878b971SVenugopal Iyer 
26801878b971SVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
26811878b971SVenugopal Iyer 	}
268284de666eSRyan Zezeski 
268384de666eSRyan Zezeski 	return (IXGBE_SUCCESS);
26849da57d7bSbt }
26859da57d7bSbt 
26869da57d7bSbt static void
ixgbe_setup_tx_ring(ixgbe_tx_ring_t * tx_ring)26879da57d7bSbt ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring)
26889da57d7bSbt {
26899da57d7bSbt 	ixgbe_t *ixgbe = tx_ring->ixgbe;
26909da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
26919da57d7bSbt 	uint32_t size;
26929da57d7bSbt 	uint32_t buf_low;
26939da57d7bSbt 	uint32_t buf_high;
26949da57d7bSbt 	uint32_t reg_val;
26959da57d7bSbt 
26969da57d7bSbt 	ASSERT(mutex_owned(&tx_ring->tx_lock));
26979da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
26989da57d7bSbt 
26999da57d7bSbt 	/*
27009da57d7bSbt 	 * Initialize the length register
27019da57d7bSbt 	 */
27029da57d7bSbt 	size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc);
27039da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size);
27049da57d7bSbt 
27059da57d7bSbt 	/*
27069da57d7bSbt 	 * Initialize the base address registers
27079da57d7bSbt 	 */
27089da57d7bSbt 	buf_low = (uint32_t)tx_ring->tbd_area.dma_address;
27099da57d7bSbt 	buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32);
27109da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low);
27119da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high);
27129da57d7bSbt 
27139da57d7bSbt 	/*
27149da57d7bSbt 	 * Setup head & tail pointers
27159da57d7bSbt 	 */
27169da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0);
27179da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0);
27189da57d7bSbt 
27199da57d7bSbt 	/*
27209da57d7bSbt 	 * Setup head write-back
27219da57d7bSbt 	 */
27229da57d7bSbt 	if (ixgbe->tx_head_wb_enable) {
27239da57d7bSbt 		/*
27249da57d7bSbt 		 * The memory of the head write-back is allocated using
27259da57d7bSbt 		 * the extra tbd beyond the tail of the tbd ring.
27269da57d7bSbt 		 */
27279da57d7bSbt 		tx_ring->tbd_head_wb = (uint32_t *)
27289da57d7bSbt 		    ((uintptr_t)tx_ring->tbd_area.address + size);
27299da57d7bSbt 		*tx_ring->tbd_head_wb = 0;
27309da57d7bSbt 
27319da57d7bSbt 		buf_low = (uint32_t)
27329da57d7bSbt 		    (tx_ring->tbd_area.dma_address + size);
27339da57d7bSbt 		buf_high = (uint32_t)
27349da57d7bSbt 		    ((tx_ring->tbd_area.dma_address + size) >> 32);
27359da57d7bSbt 
27369da57d7bSbt 		/* Set the head write-back enable bit */
27379da57d7bSbt 		buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE;
27389da57d7bSbt 
27399da57d7bSbt 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low);
27409da57d7bSbt 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high);
27419da57d7bSbt 
27429da57d7bSbt 		/*
27439da57d7bSbt 		 * Turn off relaxed ordering for head write back or it will
27449da57d7bSbt 		 * cause problems with the tx recycling
27459da57d7bSbt 		 */
274669b5a878SDan McDonald 
274769b5a878SDan McDonald 		reg_val = (hw->mac.type == ixgbe_mac_82598EB) ?
274869b5a878SDan McDonald 		    IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(tx_ring->index)) :
274969b5a878SDan McDonald 		    IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(tx_ring->index));
275069b5a878SDan McDonald 		reg_val &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
275169b5a878SDan McDonald 		if (hw->mac.type == ixgbe_mac_82598EB) {
275269b5a878SDan McDonald 			IXGBE_WRITE_REG(hw,
275369b5a878SDan McDonald 			    IXGBE_DCA_TXCTRL(tx_ring->index), reg_val);
275469b5a878SDan McDonald 		} else {
275569b5a878SDan McDonald 			IXGBE_WRITE_REG(hw,
275669b5a878SDan McDonald 			    IXGBE_DCA_TXCTRL_82599(tx_ring->index), reg_val);
275769b5a878SDan McDonald 		}
27589da57d7bSbt 	} else {
27599da57d7bSbt 		tx_ring->tbd_head_wb = NULL;
27609da57d7bSbt 	}
27619da57d7bSbt 
27629da57d7bSbt 	tx_ring->tbd_head = 0;
27639da57d7bSbt 	tx_ring->tbd_tail = 0;
27649da57d7bSbt 	tx_ring->tbd_free = tx_ring->ring_size;
27659da57d7bSbt 
2766ea65739eSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->tx_ring_init == B_TRUE) {
27679da57d7bSbt 		tx_ring->tcb_head = 0;
27689da57d7bSbt 		tx_ring->tcb_tail = 0;
27699da57d7bSbt 		tx_ring->tcb_free = tx_ring->free_list_size;
27709da57d7bSbt 	}
27719da57d7bSbt 
27729da57d7bSbt 	/*
2773f27d3025Sgg 	 * Initialize the s/w context structure
27749da57d7bSbt 	 */
2775f27d3025Sgg 	bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t));
27769da57d7bSbt }
27779da57d7bSbt 
27789da57d7bSbt static void
ixgbe_setup_tx(ixgbe_t * ixgbe)27799da57d7bSbt ixgbe_setup_tx(ixgbe_t *ixgbe)
27809da57d7bSbt {
2781c971fb7eSgg 	struct ixgbe_hw *hw = &ixgbe->hw;
27829da57d7bSbt 	ixgbe_tx_ring_t *tx_ring;
2783c971fb7eSgg 	uint32_t reg_val;
27849da57d7bSbt 	int i;
27859da57d7bSbt 
27869da57d7bSbt 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
27879da57d7bSbt 		tx_ring = &ixgbe->tx_rings[i];
27889da57d7bSbt 		ixgbe_setup_tx_ring(tx_ring);
27899da57d7bSbt 	}
2790c971fb7eSgg 
2791da14cebeSEric Cheng 	/*
2792168e1ed4SRyan Zezeski 	 * Setup the per-ring statistics mapping. We map all Tx queues
2793168e1ed4SRyan Zezeski 	 * to slot 0 to stay consistent with Rx.
2794da14cebeSEric Cheng 	 */
2795da14cebeSEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
27965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		switch (hw->mac.type) {
27975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82598EB:
2798168e1ed4SRyan Zezeski 			IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), 0);
27995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
28005b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
28015b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		default:
2802168e1ed4SRyan Zezeski 			IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), 0);
28035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
280473cd555cSBin Tu - Sun Microsystems - Beijing China 		}
28055b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
2806da14cebeSEric Cheng 
2807c971fb7eSgg 	/*
2808c971fb7eSgg 	 * Enable CRC appending and TX padding (for short tx frames)
2809c971fb7eSgg 	 */
2810c971fb7eSgg 	reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2811c971fb7eSgg 	reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN;
2812c971fb7eSgg 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
281373cd555cSBin Tu - Sun Microsystems - Beijing China 
281473cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
2815dc0cb1cdSDale Ghent 	 * enable DMA for 82599, X540 and X550 parts
281673cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
281769b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82599EB ||
2818dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
2819dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
282048ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_x ||
282148ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_a) {
282269b5a878SDan McDonald 		/* DMATXCTL.TE must be set after all Tx config is complete */
282373cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
282473cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val |= IXGBE_DMATXCTL_TE;
282573cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val);
282669b5a878SDan McDonald 
282769b5a878SDan McDonald 		/* Disable arbiter to set MTQC */
282869b5a878SDan McDonald 		reg_val = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
282969b5a878SDan McDonald 		reg_val |= IXGBE_RTTDCS_ARBDIS;
283069b5a878SDan McDonald 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg_val);
283169b5a878SDan McDonald 		IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
283269b5a878SDan McDonald 		reg_val &= ~IXGBE_RTTDCS_ARBDIS;
283369b5a878SDan McDonald 		IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg_val);
283473cd555cSBin Tu - Sun Microsystems - Beijing China 	}
283573cd555cSBin Tu - Sun Microsystems - Beijing China 
283673cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
283773cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Enabling tx queues ..
283873cd555cSBin Tu - Sun Microsystems - Beijing China 	 * For 82599 must be done after DMATXCTL.TE is set
283973cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
284073cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
284173cd555cSBin Tu - Sun Microsystems - Beijing China 		tx_ring = &ixgbe->tx_rings[i];
284273cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index));
284373cd555cSBin Tu - Sun Microsystems - Beijing China 		reg_val |= IXGBE_TXDCTL_ENABLE;
284473cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val);
284573cd555cSBin Tu - Sun Microsystems - Beijing China 	}
28469da57d7bSbt }
28479da57d7bSbt 
28489da57d7bSbt /*
28499da57d7bSbt  * ixgbe_setup_rss - Setup receive-side scaling feature.
28509da57d7bSbt  */
28519da57d7bSbt static void
ixgbe_setup_rss(ixgbe_t * ixgbe)28529da57d7bSbt ixgbe_setup_rss(ixgbe_t *ixgbe)
28539da57d7bSbt {
28549da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
2855dc0cb1cdSDale Ghent 	uint32_t mrqc;
28569da57d7bSbt 
28579da57d7bSbt 	/*
2858dc0cb1cdSDale Ghent 	 * Initialize RETA/ERETA table
28599da57d7bSbt 	 */
2860dc0cb1cdSDale Ghent 	ixgbe_setup_rss_table(ixgbe);
28619da57d7bSbt 
28629da57d7bSbt 	/*
2863c971fb7eSgg 	 * Enable RSS & perform hash on these packet types
28649da57d7bSbt 	 */
28659da57d7bSbt 	mrqc = IXGBE_MRQC_RSSEN |
28669da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV4 |
28679da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
28689da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
28699da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
28709da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
28719da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV6 |
28729da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
28739da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
28749da57d7bSbt 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
28759da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
28769da57d7bSbt }
28779da57d7bSbt 
28780dc2366fSVenugopal Iyer /*
28790dc2366fSVenugopal Iyer  * ixgbe_setup_vmdq - Setup MAC classification feature
28800dc2366fSVenugopal Iyer  */
28810dc2366fSVenugopal Iyer static void
ixgbe_setup_vmdq(ixgbe_t * ixgbe)28820dc2366fSVenugopal Iyer ixgbe_setup_vmdq(ixgbe_t *ixgbe)
28830dc2366fSVenugopal Iyer {
28840dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
288584de666eSRyan Zezeski 	uint32_t vmdctl, i, vtctl, vlnctl;
28860dc2366fSVenugopal Iyer 
28870dc2366fSVenugopal Iyer 	/*
28880dc2366fSVenugopal Iyer 	 * Setup the VMDq Control register, enable VMDq based on
28890dc2366fSVenugopal Iyer 	 * packet destination MAC address:
28900dc2366fSVenugopal Iyer 	 */
28910dc2366fSVenugopal Iyer 	switch (hw->mac.type) {
28920dc2366fSVenugopal Iyer 	case ixgbe_mac_82598EB:
28930dc2366fSVenugopal Iyer 		/*
28940dc2366fSVenugopal Iyer 		 * VMDq Enable = 1;
28950dc2366fSVenugopal Iyer 		 * VMDq Filter = 0; MAC filtering
28960dc2366fSVenugopal Iyer 		 * Default VMDq output index = 0;
28970dc2366fSVenugopal Iyer 		 */
28980dc2366fSVenugopal Iyer 		vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
28990dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
29000dc2366fSVenugopal Iyer 		break;
29010dc2366fSVenugopal Iyer 
29020dc2366fSVenugopal Iyer 	case ixgbe_mac_82599EB:
290369b5a878SDan McDonald 	case ixgbe_mac_X540:
2904dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
2905dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
290648ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
29070dc2366fSVenugopal Iyer 		/*
29080dc2366fSVenugopal Iyer 		 * Enable VMDq-only.
29090dc2366fSVenugopal Iyer 		 */
29100dc2366fSVenugopal Iyer 		vmdctl = IXGBE_MRQC_VMDQEN;
29110dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl);
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 
29180dc2366fSVenugopal Iyer 		/*
29190dc2366fSVenugopal Iyer 		 * Enable Virtualization and Replication.
29200dc2366fSVenugopal Iyer 		 */
292184de666eSRyan Zezeski 		vtctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
292284de666eSRyan Zezeski 		ixgbe->rx_def_group = vtctl & IXGBE_VT_CTL_POOL_MASK;
292384de666eSRyan Zezeski 		vtctl |= IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
29240dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
29250dc2366fSVenugopal Iyer 
292684de666eSRyan Zezeski 		/*
292784de666eSRyan Zezeski 		 * Enable VLAN filtering and switching (VFTA and VLVF).
292884de666eSRyan Zezeski 		 */
292984de666eSRyan Zezeski 		vlnctl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
293084de666eSRyan Zezeski 		vlnctl |= IXGBE_VLNCTRL_VFE;
293184de666eSRyan Zezeski 		IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctl);
293284de666eSRyan Zezeski 		ixgbe->vlft_enabled = B_TRUE;
293384de666eSRyan Zezeski 
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 		break;
29400dc2366fSVenugopal Iyer 
29410dc2366fSVenugopal Iyer 	default:
29420dc2366fSVenugopal Iyer 		break;
29430dc2366fSVenugopal Iyer 	}
29440dc2366fSVenugopal Iyer }
29450dc2366fSVenugopal Iyer 
29460dc2366fSVenugopal Iyer /*
29470dc2366fSVenugopal Iyer  * ixgbe_setup_vmdq_rss - Setup both vmdq feature and rss feature.
29480dc2366fSVenugopal Iyer  */
29490dc2366fSVenugopal Iyer static void
ixgbe_setup_vmdq_rss(ixgbe_t * ixgbe)29500dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe)
29510dc2366fSVenugopal Iyer {
29520dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
2953dc0cb1cdSDale Ghent 	uint32_t i, mrqc;
295484de666eSRyan Zezeski 	uint32_t vtctl, vmdctl, vlnctl;
29550dc2366fSVenugopal Iyer 
29560dc2366fSVenugopal Iyer 	/*
2957dc0cb1cdSDale Ghent 	 * Initialize RETA/ERETA table
29580dc2366fSVenugopal Iyer 	 */
2959dc0cb1cdSDale Ghent 	ixgbe_setup_rss_table(ixgbe);
29600dc2366fSVenugopal Iyer 
29610dc2366fSVenugopal Iyer 	/*
29620dc2366fSVenugopal Iyer 	 * Enable and setup RSS and VMDq
29630dc2366fSVenugopal Iyer 	 */
29640dc2366fSVenugopal Iyer 	switch (hw->mac.type) {
29650dc2366fSVenugopal Iyer 	case ixgbe_mac_82598EB:
29660dc2366fSVenugopal Iyer 		/*
29670dc2366fSVenugopal Iyer 		 * Enable RSS & Setup RSS Hash functions
29680dc2366fSVenugopal Iyer 		 */
29690dc2366fSVenugopal Iyer 		mrqc = IXGBE_MRQC_RSSEN |
29700dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4 |
29710dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
29720dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
29730dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
29740dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
29750dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6 |
29760dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
29770dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
29780dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
29790dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
29800dc2366fSVenugopal Iyer 
29810dc2366fSVenugopal Iyer 		/*
29820dc2366fSVenugopal Iyer 		 * Enable and Setup VMDq
29830dc2366fSVenugopal Iyer 		 * VMDq Filter = 0; MAC filtering
29840dc2366fSVenugopal Iyer 		 * Default VMDq output index = 0;
29850dc2366fSVenugopal Iyer 		 */
29860dc2366fSVenugopal Iyer 		vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
29870dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
29880dc2366fSVenugopal Iyer 		break;
29890dc2366fSVenugopal Iyer 
29900dc2366fSVenugopal Iyer 	case ixgbe_mac_82599EB:
299169b5a878SDan McDonald 	case ixgbe_mac_X540:
2992dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
2993dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
299448ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
29950dc2366fSVenugopal Iyer 		/*
29960dc2366fSVenugopal Iyer 		 * Enable RSS & Setup RSS Hash functions
29970dc2366fSVenugopal Iyer 		 */
29980dc2366fSVenugopal Iyer 		mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 |
29990dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
30000dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
30010dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
30020dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
30030dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6 |
30040dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
30050dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
30060dc2366fSVenugopal Iyer 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
30070dc2366fSVenugopal Iyer 
30080dc2366fSVenugopal Iyer 		/*
30090dc2366fSVenugopal Iyer 		 * Enable VMDq+RSS.
30100dc2366fSVenugopal Iyer 		 */
30110dc2366fSVenugopal Iyer 		if (ixgbe->num_rx_groups > 32)  {
30120dc2366fSVenugopal Iyer 			mrqc = mrqc | IXGBE_MRQC_VMDQRSS64EN;
30130dc2366fSVenugopal Iyer 		} else {
30140dc2366fSVenugopal Iyer 			mrqc = mrqc | IXGBE_MRQC_VMDQRSS32EN;
30150dc2366fSVenugopal Iyer 		}
30160dc2366fSVenugopal Iyer 
30170dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
30180dc2366fSVenugopal Iyer 
30190dc2366fSVenugopal Iyer 		for (i = 0; i < hw->mac.num_rar_entries; i++) {
30200dc2366fSVenugopal Iyer 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0);
30210dc2366fSVenugopal Iyer 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0);
30220dc2366fSVenugopal Iyer 		}
30230dc2366fSVenugopal Iyer 		break;
30240dc2366fSVenugopal Iyer 
30250dc2366fSVenugopal Iyer 	default:
30260dc2366fSVenugopal Iyer 		break;
30270dc2366fSVenugopal Iyer 
30280dc2366fSVenugopal Iyer 	}
30290dc2366fSVenugopal Iyer 
303069b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82599EB ||
3031dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
3032dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
303348ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_x ||
303448ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_a) {
30350dc2366fSVenugopal Iyer 		/*
30360dc2366fSVenugopal Iyer 		 * Enable Virtualization and Replication.
30370dc2366fSVenugopal Iyer 		 */
303884de666eSRyan Zezeski 		vtctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
303984de666eSRyan Zezeski 		ixgbe->rx_def_group = vtctl & IXGBE_VT_CTL_POOL_MASK;
304084de666eSRyan Zezeski 		vtctl |= IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
30410dc2366fSVenugopal Iyer 		vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
30420dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
30430dc2366fSVenugopal Iyer 
304484de666eSRyan Zezeski 		/*
304584de666eSRyan Zezeski 		 * Enable VLAN filtering and switching (VFTA and VLVF).
304684de666eSRyan Zezeski 		 */
304784de666eSRyan Zezeski 		vlnctl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
304884de666eSRyan Zezeski 		vlnctl |= IXGBE_VLNCTRL_VFE;
304984de666eSRyan Zezeski 		IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctl);
305084de666eSRyan Zezeski 		ixgbe->vlft_enabled = B_TRUE;
305184de666eSRyan Zezeski 
30520dc2366fSVenugopal Iyer 		/*
30530dc2366fSVenugopal Iyer 		 * Enable receiving packets to all VFs
30540dc2366fSVenugopal Iyer 		 */
30550dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL);
30560dc2366fSVenugopal Iyer 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL);
30570dc2366fSVenugopal Iyer 	}
30580dc2366fSVenugopal Iyer }
30590dc2366fSVenugopal Iyer 
3060dc0cb1cdSDale Ghent /*
3061dc0cb1cdSDale Ghent  * ixgbe_setup_rss_table - Setup RSS table
3062dc0cb1cdSDale Ghent  */
3063dc0cb1cdSDale Ghent static void
ixgbe_setup_rss_table(ixgbe_t * ixgbe)3064dc0cb1cdSDale Ghent ixgbe_setup_rss_table(ixgbe_t *ixgbe)
3065dc0cb1cdSDale Ghent {
3066dc0cb1cdSDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
3067dc0cb1cdSDale Ghent 	uint32_t i, j;
3068dc0cb1cdSDale Ghent 	uint32_t random;
3069dc0cb1cdSDale Ghent 	uint32_t reta;
3070dc0cb1cdSDale Ghent 	uint32_t ring_per_group;
3071dc0cb1cdSDale Ghent 	uint32_t ring;
3072dc0cb1cdSDale Ghent 	uint32_t table_size;
3073dc0cb1cdSDale Ghent 	uint32_t index_mult;
3074dc0cb1cdSDale Ghent 	uint32_t rxcsum;
3075dc0cb1cdSDale Ghent 
3076dc0cb1cdSDale Ghent 	/*
3077dc0cb1cdSDale Ghent 	 * Set multiplier for RETA setup and table size based on MAC type.
3078dc0cb1cdSDale Ghent 	 * RETA table sizes vary by model:
3079dc0cb1cdSDale Ghent 	 *
3080dc0cb1cdSDale Ghent 	 * 82598, 82599, X540: 128 table entries.
3081dc0cb1cdSDale Ghent 	 * X550: 512 table entries.
3082dc0cb1cdSDale Ghent 	 */
3083dc0cb1cdSDale Ghent 	index_mult = 0x1;
3084dc0cb1cdSDale Ghent 	table_size = 128;
3085dc0cb1cdSDale Ghent 	switch (ixgbe->hw.mac.type) {
3086dc0cb1cdSDale Ghent 	case ixgbe_mac_82598EB:
3087dc0cb1cdSDale Ghent 		index_mult = 0x11;
3088dc0cb1cdSDale Ghent 		break;
3089dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
3090dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
309148ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
3092dc0cb1cdSDale Ghent 		table_size = 512;
3093dc0cb1cdSDale Ghent 		break;
3094dc0cb1cdSDale Ghent 	default:
3095dc0cb1cdSDale Ghent 		break;
3096dc0cb1cdSDale Ghent 	}
3097dc0cb1cdSDale Ghent 
3098dc0cb1cdSDale Ghent 	/*
3099dc0cb1cdSDale Ghent 	 * Fill out RSS redirection table. The configuation of the indices is
3100dc0cb1cdSDale Ghent 	 * hardware-dependent.
3101dc0cb1cdSDale Ghent 	 *
3102dc0cb1cdSDale Ghent 	 *  82598: 8 bits wide containing two 4 bit RSS indices
3103dc0cb1cdSDale Ghent 	 *  82599, X540: 8 bits wide containing one 4 bit RSS index
3104dc0cb1cdSDale Ghent 	 *  X550: 8 bits wide containing one 6 bit RSS index
3105dc0cb1cdSDale Ghent 	 */
3106dc0cb1cdSDale Ghent 	reta = 0;
3107dc0cb1cdSDale Ghent 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
3108dc0cb1cdSDale Ghent 
3109dc0cb1cdSDale Ghent 	for (i = 0, j = 0; i < table_size; i++, j++) {
3110dc0cb1cdSDale Ghent 		if (j == ring_per_group) j = 0;
3111dc0cb1cdSDale Ghent 
3112dc0cb1cdSDale Ghent 		/*
3113dc0cb1cdSDale Ghent 		 * The low 8 bits are for hash value (n+0);
3114dc0cb1cdSDale Ghent 		 * The next 8 bits are for hash value (n+1), etc.
3115dc0cb1cdSDale Ghent 		 */
3116dc0cb1cdSDale Ghent 		ring = (j * index_mult);
3117dc0cb1cdSDale Ghent 		reta = reta >> 8;
3118dc0cb1cdSDale Ghent 		reta = reta | (((uint32_t)ring) << 24);
3119dc0cb1cdSDale Ghent 
3120483bfec1SToomas Soome 		if ((i & 3) == 3) {
3121dc0cb1cdSDale Ghent 			/*
3122dc0cb1cdSDale Ghent 			 * The first 128 table entries are programmed into the
3123dc0cb1cdSDale Ghent 			 * RETA register, with any beyond that (eg; on X550)
3124dc0cb1cdSDale Ghent 			 * into ERETA.
3125dc0cb1cdSDale Ghent 			 */
3126dc0cb1cdSDale Ghent 			if (i < 128)
3127dc0cb1cdSDale Ghent 				IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
3128dc0cb1cdSDale Ghent 			else
3129dc0cb1cdSDale Ghent 				IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32),
3130dc0cb1cdSDale Ghent 				    reta);
3131dc0cb1cdSDale Ghent 			reta = 0;
3132483bfec1SToomas Soome 		}
3133dc0cb1cdSDale Ghent 	}
3134dc0cb1cdSDale Ghent 
3135dc0cb1cdSDale Ghent 	/*
3136dc0cb1cdSDale Ghent 	 * Fill out hash function seeds with a random constant
3137dc0cb1cdSDale Ghent 	 */
3138dc0cb1cdSDale Ghent 	for (i = 0; i < 10; i++) {
3139dc0cb1cdSDale Ghent 		(void) random_get_pseudo_bytes((uint8_t *)&random,
3140dc0cb1cdSDale Ghent 		    sizeof (uint32_t));
3141dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random);
3142dc0cb1cdSDale Ghent 	}
3143dc0cb1cdSDale Ghent 
3144dc0cb1cdSDale Ghent 	/*
3145dc0cb1cdSDale Ghent 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
3146dc0cb1cdSDale Ghent 	 * It is an adapter hardware limitation that Packet Checksum is
3147dc0cb1cdSDale Ghent 	 * mutually exclusive with RSS.
3148dc0cb1cdSDale Ghent 	 */
3149dc0cb1cdSDale Ghent 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
3150dc0cb1cdSDale Ghent 	rxcsum |= IXGBE_RXCSUM_PCSD;
3151dc0cb1cdSDale Ghent 	rxcsum &= ~IXGBE_RXCSUM_IPPCSE;
3152dc0cb1cdSDale Ghent 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
3153dc0cb1cdSDale Ghent }
3154dc0cb1cdSDale Ghent 
31559da57d7bSbt /*
31569da57d7bSbt  * ixgbe_init_unicst - Initialize the unicast addresses.
31579da57d7bSbt  */
31589da57d7bSbt static void
ixgbe_init_unicst(ixgbe_t * ixgbe)31599da57d7bSbt ixgbe_init_unicst(ixgbe_t *ixgbe)
31609da57d7bSbt {
31619da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
3162da14cebeSEric Cheng 	uint8_t *mac_addr;
31639da57d7bSbt 	int slot;
31649da57d7bSbt 	/*
31659da57d7bSbt 	 * Here we should consider two situations:
31669da57d7bSbt 	 *
3167da14cebeSEric Cheng 	 * 1. Chipset is initialized at the first time,
3168da14cebeSEric Cheng 	 *    Clear all the multiple unicast addresses.
31699da57d7bSbt 	 *
31709da57d7bSbt 	 * 2. Chipset is reset
31719da57d7bSbt 	 *    Recover the multiple unicast addresses from the
31729da57d7bSbt 	 *    software data structure to the RAR registers.
31739da57d7bSbt 	 */
31749da57d7bSbt 	if (!ixgbe->unicst_init) {
31759da57d7bSbt 		/*
31769da57d7bSbt 		 * Initialize the multiple unicast addresses
31779da57d7bSbt 		 */
31780dc2366fSVenugopal Iyer 		ixgbe->unicst_total = hw->mac.num_rar_entries;
3179da14cebeSEric Cheng 		ixgbe->unicst_avail = ixgbe->unicst_total;
3180da14cebeSEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3181da14cebeSEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
3182da14cebeSEric Cheng 			bzero(mac_addr, ETHERADDRL);
3183afac708dSToomas Soome 			(void) ixgbe_set_rar(hw, slot, mac_addr, 0, 0);
31849da57d7bSbt 			ixgbe->unicst_addr[slot].mac.set = 0;
3185da14cebeSEric Cheng 		}
31869da57d7bSbt 		ixgbe->unicst_init = B_TRUE;
31879da57d7bSbt 	} else {
31889da57d7bSbt 		/* Re-configure the RAR registers */
3189da14cebeSEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3190da14cebeSEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
3191da14cebeSEric Cheng 			if (ixgbe->unicst_addr[slot].mac.set == 1) {
3192da14cebeSEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
31930dc2366fSVenugopal Iyer 				    ixgbe->unicst_addr[slot].mac.group_index,
31940dc2366fSVenugopal Iyer 				    IXGBE_RAH_AV);
3195da14cebeSEric Cheng 			} else {
3196da14cebeSEric Cheng 				bzero(mac_addr, ETHERADDRL);
3197afac708dSToomas Soome 				(void) ixgbe_set_rar(hw, slot, mac_addr, 0, 0);
3198da14cebeSEric Cheng 			}
3199da14cebeSEric Cheng 		}
32009da57d7bSbt 	}
32019da57d7bSbt }
3202da14cebeSEric Cheng 
3203da14cebeSEric Cheng /*
3204da14cebeSEric Cheng  * ixgbe_unicst_find - Find the slot for the specified unicast address
3205da14cebeSEric Cheng  */
3206da14cebeSEric Cheng int
ixgbe_unicst_find(ixgbe_t * ixgbe,const uint8_t * mac_addr)3207da14cebeSEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr)
3208da14cebeSEric Cheng {
3209da14cebeSEric Cheng 	int slot;
3210da14cebeSEric Cheng 
3211da14cebeSEric Cheng 	ASSERT(mutex_owned(&ixgbe->gen_lock));
3212da14cebeSEric Cheng 
3213da14cebeSEric Cheng 	for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3214da14cebeSEric Cheng 		if (bcmp(ixgbe->unicst_addr[slot].mac.addr,
3215da14cebeSEric Cheng 		    mac_addr, ETHERADDRL) == 0)
3216da14cebeSEric Cheng 			return (slot);
3217da14cebeSEric Cheng 	}
3218da14cebeSEric Cheng 
3219da14cebeSEric Cheng 	return (-1);
3220da14cebeSEric Cheng }
3221da14cebeSEric Cheng 
322284de666eSRyan Zezeski /*
322384de666eSRyan Zezeski  * Restore the HW state to match the SW state during restart.
322484de666eSRyan Zezeski  */
322584de666eSRyan Zezeski static int
ixgbe_init_vlan(ixgbe_t * ixgbe)322684de666eSRyan Zezeski ixgbe_init_vlan(ixgbe_t *ixgbe)
322784de666eSRyan Zezeski {
322884de666eSRyan Zezeski 	/*
322984de666eSRyan Zezeski 	 * The device is starting for the first time; there is nothing
323084de666eSRyan Zezeski 	 * to do.
323184de666eSRyan Zezeski 	 */
323284de666eSRyan Zezeski 	if (!ixgbe->vlft_init) {
323384de666eSRyan Zezeski 		ixgbe->vlft_init = B_TRUE;
323484de666eSRyan Zezeski 		return (IXGBE_SUCCESS);
323584de666eSRyan Zezeski 	}
323684de666eSRyan Zezeski 
323784de666eSRyan Zezeski 	for (uint_t i = 0; i < ixgbe->num_rx_groups; i++) {
323884de666eSRyan Zezeski 		int			ret;
323984de666eSRyan Zezeski 		boolean_t		vlvf_bypass;
324084de666eSRyan Zezeski 		ixgbe_rx_group_t	*rxg = &ixgbe->rx_groups[i];
324184de666eSRyan Zezeski 		struct ixgbe_hw		*hw = &ixgbe->hw;
324284de666eSRyan Zezeski 
324384de666eSRyan Zezeski 		if (rxg->aupe) {
324484de666eSRyan Zezeski 			uint32_t vml2flt;
324584de666eSRyan Zezeski 
324684de666eSRyan Zezeski 			vml2flt = IXGBE_READ_REG(hw, IXGBE_VMOLR(rxg->index));
324784de666eSRyan Zezeski 			vml2flt |= IXGBE_VMOLR_AUPE;
324884de666eSRyan Zezeski 			IXGBE_WRITE_REG(hw, IXGBE_VMOLR(rxg->index), vml2flt);
324984de666eSRyan Zezeski 		}
325084de666eSRyan Zezeski 
325184de666eSRyan Zezeski 		vlvf_bypass = (rxg->index == ixgbe->rx_def_group);
325284de666eSRyan Zezeski 		for (ixgbe_vlan_t *vlp = list_head(&rxg->vlans); vlp != NULL;
325384de666eSRyan Zezeski 		    vlp = list_next(&rxg->vlans, vlp)) {
325484de666eSRyan Zezeski 			ret = ixgbe_set_vfta(hw, vlp->ixvl_vid, rxg->index,
325584de666eSRyan Zezeski 			    B_TRUE, vlvf_bypass);
325684de666eSRyan Zezeski 
325784de666eSRyan Zezeski 			if (ret != IXGBE_SUCCESS) {
325884de666eSRyan Zezeski 				ixgbe_error(ixgbe, "Failed to program VFTA"
325984de666eSRyan Zezeski 				    " for group %u, VID: %u, ret: %d.",
326084de666eSRyan Zezeski 				    rxg->index, vlp->ixvl_vid, ret);
326184de666eSRyan Zezeski 				return (IXGBE_FAILURE);
326284de666eSRyan Zezeski 			}
326384de666eSRyan Zezeski 		}
326484de666eSRyan Zezeski 	}
326584de666eSRyan Zezeski 
326684de666eSRyan Zezeski 	return (IXGBE_SUCCESS);
326784de666eSRyan Zezeski }
326884de666eSRyan Zezeski 
32699da57d7bSbt /*
32709da57d7bSbt  * ixgbe_multicst_add - Add a multicst address.
32719da57d7bSbt  */
32729da57d7bSbt int
ixgbe_multicst_add(ixgbe_t * ixgbe,const uint8_t * multiaddr)32739da57d7bSbt ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr)
32749da57d7bSbt {
32759da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
32769da57d7bSbt 
32779da57d7bSbt 	if ((multiaddr[0] & 01) == 0) {
32789da57d7bSbt 		return (EINVAL);
32799da57d7bSbt 	}
32809da57d7bSbt 
32819da57d7bSbt 	if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) {
32829da57d7bSbt 		return (ENOENT);
32839da57d7bSbt 	}
32849da57d7bSbt 
32859da57d7bSbt 	bcopy(multiaddr,
32869da57d7bSbt 	    &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL);
32879da57d7bSbt 	ixgbe->mcast_count++;
32889da57d7bSbt 
32899da57d7bSbt 	/*
32909da57d7bSbt 	 * Update the multicast table in the hardware
32919da57d7bSbt 	 */
32929da57d7bSbt 	ixgbe_setup_multicst(ixgbe);
32939da57d7bSbt 
32949da57d7bSbt 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
32959da57d7bSbt 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
32969da57d7bSbt 		return (EIO);
32979da57d7bSbt 	}
32989da57d7bSbt 
32999da57d7bSbt 	return (0);
33009da57d7bSbt }
33019da57d7bSbt 
33029da57d7bSbt /*
33039da57d7bSbt  * ixgbe_multicst_remove - Remove a multicst address.
33049da57d7bSbt  */
33059da57d7bSbt int
ixgbe_multicst_remove(ixgbe_t * ixgbe,const uint8_t * multiaddr)33069da57d7bSbt ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr)
33079da57d7bSbt {
33089da57d7bSbt 	int i;
33099da57d7bSbt 
33109da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
33119da57d7bSbt 
33129da57d7bSbt 	for (i = 0; i < ixgbe->mcast_count; i++) {
33139da57d7bSbt 		if (bcmp(multiaddr, &ixgbe->mcast_table[i],
33149da57d7bSbt 		    ETHERADDRL) == 0) {
33159da57d7bSbt 			for (i++; i < ixgbe->mcast_count; i++) {
33169da57d7bSbt 				ixgbe->mcast_table[i - 1] =
33179da57d7bSbt 				    ixgbe->mcast_table[i];
33189da57d7bSbt 			}
33199da57d7bSbt 			ixgbe->mcast_count--;
33209da57d7bSbt 			break;
33219da57d7bSbt 		}
33229da57d7bSbt 	}
33239da57d7bSbt 
33249da57d7bSbt 	/*
33259da57d7bSbt 	 * Update the multicast table in the hardware
33269da57d7bSbt 	 */
33279da57d7bSbt 	ixgbe_setup_multicst(ixgbe);
33289da57d7bSbt 
33299da57d7bSbt 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
33309da57d7bSbt 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
33319da57d7bSbt 		return (EIO);
33329da57d7bSbt 	}
33339da57d7bSbt 
33349da57d7bSbt 	return (0);
33359da57d7bSbt }
33369da57d7bSbt 
33379da57d7bSbt /*
33389da57d7bSbt  * ixgbe_setup_multicast - Setup multicast data structures.
33399da57d7bSbt  *
33409da57d7bSbt  * This routine initializes all of the multicast related structures
33419da57d7bSbt  * and save them in the hardware registers.
33429da57d7bSbt  */
33439da57d7bSbt static void
ixgbe_setup_multicst(ixgbe_t * ixgbe)33449da57d7bSbt ixgbe_setup_multicst(ixgbe_t *ixgbe)
33459da57d7bSbt {
33469da57d7bSbt 	uint8_t *mc_addr_list;
33479da57d7bSbt 	uint32_t mc_addr_count;
33489da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
33499da57d7bSbt 
33509da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
33519da57d7bSbt 
33529da57d7bSbt 	ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES);
33539da57d7bSbt 
33549da57d7bSbt 	mc_addr_list = (uint8_t *)ixgbe->mcast_table;
33559da57d7bSbt 	mc_addr_count = ixgbe->mcast_count;
33569da57d7bSbt 
33579da57d7bSbt 	/*
33589da57d7bSbt 	 * Update the multicast addresses to the MTA registers
33599da57d7bSbt 	 */
33609da57d7bSbt 	(void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
336169b5a878SDan McDonald 	    ixgbe_mc_table_itr, TRUE);
33629da57d7bSbt }
33639da57d7bSbt 
33640dc2366fSVenugopal Iyer /*
33650dc2366fSVenugopal Iyer  * ixgbe_setup_vmdq_rss_conf - Configure vmdq and rss (number and mode).
33660dc2366fSVenugopal Iyer  *
33670dc2366fSVenugopal Iyer  * Configure the rx classification mode (vmdq & rss) and vmdq & rss numbers.
33680dc2366fSVenugopal Iyer  * Different chipsets may have different allowed configuration of vmdq and rss.
33690dc2366fSVenugopal Iyer  */
33700dc2366fSVenugopal Iyer static void
ixgbe_setup_vmdq_rss_conf(ixgbe_t * ixgbe)33710dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe)
33720dc2366fSVenugopal Iyer {
33730dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
33740dc2366fSVenugopal Iyer 	uint32_t ring_per_group;
33750dc2366fSVenugopal Iyer 
33760dc2366fSVenugopal Iyer 	switch (hw->mac.type) {
33770dc2366fSVenugopal Iyer 	case ixgbe_mac_82598EB:
33780dc2366fSVenugopal Iyer 		/*
33790dc2366fSVenugopal Iyer 		 * 82598 supports the following combination:
33800dc2366fSVenugopal Iyer 		 * vmdq no. x rss no.
33810dc2366fSVenugopal Iyer 		 * [5..16]  x 1
33820dc2366fSVenugopal Iyer 		 * [1..4]   x [1..16]
33830dc2366fSVenugopal Iyer 		 * However 8 rss queue per pool (vmdq) is sufficient for
33840dc2366fSVenugopal Iyer 		 * most cases.
33850dc2366fSVenugopal Iyer 		 */
33860dc2366fSVenugopal Iyer 		ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
33870dc2366fSVenugopal Iyer 		if (ixgbe->num_rx_groups > 4) {
33880dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = ixgbe->num_rx_groups;
33890dc2366fSVenugopal Iyer 		} else {
33900dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
33910dc2366fSVenugopal Iyer 			    min(8, ring_per_group);
33920dc2366fSVenugopal Iyer 		}
33930dc2366fSVenugopal Iyer 
33940dc2366fSVenugopal Iyer 		break;
33950dc2366fSVenugopal Iyer 
33960dc2366fSVenugopal Iyer 	case ixgbe_mac_82599EB:
339769b5a878SDan McDonald 	case ixgbe_mac_X540:
3398dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
3399dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
340048ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
34010dc2366fSVenugopal Iyer 		/*
34020dc2366fSVenugopal Iyer 		 * 82599 supports the following combination:
34030dc2366fSVenugopal Iyer 		 * vmdq no. x rss no.
34040dc2366fSVenugopal Iyer 		 * [33..64] x [1..2]
34050dc2366fSVenugopal Iyer 		 * [2..32]  x [1..4]
34060dc2366fSVenugopal Iyer 		 * 1 x [1..16]
34070dc2366fSVenugopal Iyer 		 * However 8 rss queue per pool (vmdq) is sufficient for
34080dc2366fSVenugopal Iyer 		 * most cases.
340969b5a878SDan McDonald 		 *
3410dc0cb1cdSDale Ghent 		 * For now, treat X540 and X550 like the 82599.
34110dc2366fSVenugopal Iyer 		 */
34120dc2366fSVenugopal Iyer 		ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
34130dc2366fSVenugopal Iyer 		if (ixgbe->num_rx_groups == 1) {
34140dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = min(8, ring_per_group);
34150dc2366fSVenugopal Iyer 		} else if (ixgbe->num_rx_groups <= 32) {
34160dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
34170dc2366fSVenugopal Iyer 			    min(4, ring_per_group);
34180dc2366fSVenugopal Iyer 		} else if (ixgbe->num_rx_groups <= 64) {
34190dc2366fSVenugopal Iyer 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
34200dc2366fSVenugopal Iyer 			    min(2, ring_per_group);
34210dc2366fSVenugopal Iyer 		}
34220dc2366fSVenugopal Iyer 		break;
34230dc2366fSVenugopal Iyer 
34240dc2366fSVenugopal Iyer 	default:
34250dc2366fSVenugopal Iyer 		break;
34260dc2366fSVenugopal Iyer 	}
34270dc2366fSVenugopal Iyer 
34280dc2366fSVenugopal Iyer 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
34290dc2366fSVenugopal Iyer 
34300dc2366fSVenugopal Iyer 	if (ixgbe->num_rx_groups == 1 && ring_per_group == 1) {
34310dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
34320dc2366fSVenugopal Iyer 	} else if (ixgbe->num_rx_groups != 1 && ring_per_group == 1) {
34330dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ;
34340dc2366fSVenugopal Iyer 	} else if (ixgbe->num_rx_groups != 1 && ring_per_group != 1) {
34350dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ_RSS;
34360dc2366fSVenugopal Iyer 	} else {
34370dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_RSS;
34380dc2366fSVenugopal Iyer 	}
34390dc2366fSVenugopal Iyer 
344019843f01SPaul Guo 	IXGBE_DEBUGLOG_2(ixgbe, "rx group number:%d, rx ring number:%d",
34410dc2366fSVenugopal Iyer 	    ixgbe->num_rx_groups, ixgbe->num_rx_rings);
34420dc2366fSVenugopal Iyer }
34430dc2366fSVenugopal Iyer 
34449da57d7bSbt /*
34459da57d7bSbt  * ixgbe_get_conf - Get driver configurations set in driver.conf.
34469da57d7bSbt  *
34479da57d7bSbt  * This routine gets user-configured values out of the configuration
34489da57d7bSbt  * file ixgbe.conf.
34499da57d7bSbt  *
34509da57d7bSbt  * For each configurable value, there is a minimum, a maximum, and a
34519da57d7bSbt  * default.
34529da57d7bSbt  * If user does not configure a value, use the default.
34539da57d7bSbt  * If user configures below the minimum, use the minumum.
34549da57d7bSbt  * If user configures above the maximum, use the maxumum.
34559da57d7bSbt  */
34569da57d7bSbt static void
ixgbe_get_conf(ixgbe_t * ixgbe)34579da57d7bSbt ixgbe_get_conf(ixgbe_t *ixgbe)
34589da57d7bSbt {
34599da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
34609da57d7bSbt 	uint32_t flow_control;
34619da57d7bSbt 
34629da57d7bSbt 	/*
34639da57d7bSbt 	 * ixgbe driver supports the following user configurations:
34649da57d7bSbt 	 *
34659da57d7bSbt 	 * Jumbo frame configuration:
34669da57d7bSbt 	 *    default_mtu
34679da57d7bSbt 	 *
34689da57d7bSbt 	 * Ethernet flow control configuration:
34699da57d7bSbt 	 *    flow_control
34709da57d7bSbt 	 *
34719da57d7bSbt 	 * Multiple rings configurations:
34729da57d7bSbt 	 *    tx_queue_number
34739da57d7bSbt 	 *    tx_ring_size
34749da57d7bSbt 	 *    rx_queue_number
34759da57d7bSbt 	 *    rx_ring_size
34769da57d7bSbt 	 *
34779da57d7bSbt 	 * Call ixgbe_get_prop() to get the value for a specific
34789da57d7bSbt 	 * configuration parameter.
34799da57d7bSbt 	 */
34809da57d7bSbt 
34819da57d7bSbt 	/*
34829da57d7bSbt 	 * Jumbo frame configuration - max_frame_size controls host buffer
34839da57d7bSbt 	 * allocation, so includes MTU, ethernet header, vlan tag and
34849da57d7bSbt 	 * frame check sequence.
34859da57d7bSbt 	 */
34869da57d7bSbt 	ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU,
34871fedc51fSWinson Wang - Sun Microsystems - Beijing China 	    MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU);
34889da57d7bSbt 
34899da57d7bSbt 	ixgbe->max_frame_size = ixgbe->default_mtu +
34909da57d7bSbt 	    sizeof (struct ether_vlan_header) + ETHERFCSL;
34919da57d7bSbt 
34929da57d7bSbt 	/*
34939da57d7bSbt 	 * Ethernet flow control configuration
34949da57d7bSbt 	 */
34959da57d7bSbt 	flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL,
3496da14cebeSEric Cheng 	    ixgbe_fc_none, 3, ixgbe_fc_none);
34979da57d7bSbt 	if (flow_control == 3)
34989da57d7bSbt 		flow_control = ixgbe_fc_default;
34999da57d7bSbt 
350073cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
350173cd555cSBin Tu - Sun Microsystems - Beijing China 	 * fc.requested mode is what the user requests.  After autoneg,
350273cd555cSBin Tu - Sun Microsystems - Beijing China 	 * fc.current_mode will be the flow_control mode that was negotiated.
350373cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
350473cd555cSBin Tu - Sun Microsystems - Beijing China 	hw->fc.requested_mode = flow_control;
35059da57d7bSbt 
35069da57d7bSbt 	/*
35079da57d7bSbt 	 * Multiple rings configurations
35089da57d7bSbt 	 */
35099da57d7bSbt 	ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM,
351013740cb2SPaul Guo 	    ixgbe->capab->min_tx_que_num,
351113740cb2SPaul Guo 	    ixgbe->capab->max_tx_que_num,
351213740cb2SPaul Guo 	    ixgbe->capab->def_tx_que_num);
35139da57d7bSbt 	ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE,
35149da57d7bSbt 	    MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE);
35159da57d7bSbt 
35169da57d7bSbt 	ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM,
351713740cb2SPaul Guo 	    ixgbe->capab->min_rx_que_num,
351813740cb2SPaul Guo 	    ixgbe->capab->max_rx_que_num,
351913740cb2SPaul Guo 	    ixgbe->capab->def_rx_que_num);
35209da57d7bSbt 	ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE,
35219da57d7bSbt 	    MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE);
35229da57d7bSbt 
3523da14cebeSEric Cheng 	/*
3524da14cebeSEric Cheng 	 * Multiple groups configuration
3525da14cebeSEric Cheng 	 */
3526da14cebeSEric Cheng 	ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM,
35270dc2366fSVenugopal Iyer 	    ixgbe->capab->min_rx_grp_num, ixgbe->capab->max_rx_grp_num,
35280dc2366fSVenugopal Iyer 	    ixgbe->capab->def_rx_grp_num);
3529da14cebeSEric Cheng 
3530da14cebeSEric Cheng 	ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE,
3531da14cebeSEric Cheng 	    0, 1, DEFAULT_MR_ENABLE);
3532da14cebeSEric Cheng 
3533da14cebeSEric Cheng 	if (ixgbe->mr_enable == B_FALSE) {
3534da14cebeSEric Cheng 		ixgbe->num_tx_rings = 1;
3535da14cebeSEric Cheng 		ixgbe->num_rx_rings = 1;
3536da14cebeSEric Cheng 		ixgbe->num_rx_groups = 1;
35370dc2366fSVenugopal Iyer 		ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
35380dc2366fSVenugopal Iyer 	} else {
35390dc2366fSVenugopal Iyer 		ixgbe->num_rx_rings = ixgbe->num_rx_groups *
35400dc2366fSVenugopal Iyer 		    max(ixgbe->num_rx_rings / ixgbe->num_rx_groups, 1);
35410dc2366fSVenugopal Iyer 		/*
35420dc2366fSVenugopal Iyer 		 * The combination of num_rx_rings and num_rx_groups
35430dc2366fSVenugopal Iyer 		 * may be not supported by h/w. We need to adjust
35440dc2366fSVenugopal Iyer 		 * them to appropriate values.
35450dc2366fSVenugopal Iyer 		 */
35460dc2366fSVenugopal Iyer 		ixgbe_setup_vmdq_rss_conf(ixgbe);
3547da14cebeSEric Cheng 	}
3548da14cebeSEric Cheng 
35499da57d7bSbt 	/*
35509da57d7bSbt 	 * Tunable used to force an interrupt type. The only use is
35519da57d7bSbt 	 * for testing of the lesser interrupt types.
35529da57d7bSbt 	 * 0 = don't force interrupt type
3553da14cebeSEric Cheng 	 * 1 = force interrupt type MSI-X
35549da57d7bSbt 	 * 2 = force interrupt type MSI
35559da57d7bSbt 	 * 3 = force interrupt type Legacy
35569da57d7bSbt 	 */
35579da57d7bSbt 	ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE,
35589da57d7bSbt 	    IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE);
35599da57d7bSbt 
35609da57d7bSbt 	ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE,
3561c971fb7eSgg 	    0, 1, DEFAULT_TX_HCKSUM_ENABLE);
35629da57d7bSbt 	ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE,
3563c971fb7eSgg 	    0, 1, DEFAULT_RX_HCKSUM_ENABLE);
35649da57d7bSbt 	ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE,
3565c971fb7eSgg 	    0, 1, DEFAULT_LSO_ENABLE);
3566ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	ixgbe->lro_enable = ixgbe_get_prop(ixgbe, PROP_LRO_ENABLE,
3567ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	    0, 1, DEFAULT_LRO_ENABLE);
35689da57d7bSbt 	ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE,
3569c971fb7eSgg 	    0, 1, DEFAULT_TX_HEAD_WB_ENABLE);
35705b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->relax_order_enable = ixgbe_get_prop(ixgbe,
35715b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    PROP_RELAX_ORDER_ENABLE, 0, 1, DEFAULT_RELAX_ORDER_ENABLE);
3572c971fb7eSgg 
3573dc0cb1cdSDale Ghent 	/* Head Write Back not recommended for 82599, X540 and X550 */
357469b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82599EB ||
3575dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
3576dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
357748ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_x ||
357848ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_a) {
357973cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe->tx_head_wb_enable = B_FALSE;
358073cd555cSBin Tu - Sun Microsystems - Beijing China 	}
358173cd555cSBin Tu - Sun Microsystems - Beijing China 
3582c971fb7eSgg 	/*
3583c971fb7eSgg 	 * ixgbe LSO needs the tx h/w checksum support.
3584c971fb7eSgg 	 * LSO will be disabled if tx h/w checksum is not
3585c971fb7eSgg 	 * enabled.
3586c971fb7eSgg 	 */
3587c971fb7eSgg 	if (ixgbe->tx_hcksum_enable == B_FALSE) {
3588c971fb7eSgg 		ixgbe->lso_enable = B_FALSE;
3589c971fb7eSgg 	}
35909da57d7bSbt 
3591ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	/*
3592ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 * ixgbe LRO needs the rx h/w checksum support.
3593ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 * LRO will be disabled if rx h/w checksum is not
3594ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 * enabled.
3595ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 */
3596ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	if (ixgbe->rx_hcksum_enable == B_FALSE) {
3597ffd8e883SWinson Wang - Sun Microsystems - Beijing China 		ixgbe->lro_enable = B_FALSE;
3598ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	}
3599ffd8e883SWinson Wang - Sun Microsystems - Beijing China 
3600ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	/*
3601dc0cb1cdSDale Ghent 	 * ixgbe LRO only supported by 82599, X540 and X550
3602ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	 */
360369b5a878SDan McDonald 	if (hw->mac.type == ixgbe_mac_82598EB) {
3604ffd8e883SWinson Wang - Sun Microsystems - Beijing China 		ixgbe->lro_enable = B_FALSE;
3605ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	}
36069da57d7bSbt 	ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD,
36079da57d7bSbt 	    MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD,
36089da57d7bSbt 	    DEFAULT_TX_COPY_THRESHOLD);
36099da57d7bSbt 	ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe,
36109da57d7bSbt 	    PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD,
36119da57d7bSbt 	    MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD);
36129da57d7bSbt 	ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe,
36139da57d7bSbt 	    PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD,
36149da57d7bSbt 	    MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD);
36159da57d7bSbt 	ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe,
36169da57d7bSbt 	    PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD,
36179da57d7bSbt 	    MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD);
36189da57d7bSbt 
36199da57d7bSbt 	ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD,
36209da57d7bSbt 	    MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD,
36219da57d7bSbt 	    DEFAULT_RX_COPY_THRESHOLD);
36229da57d7bSbt 	ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR,
36239da57d7bSbt 	    MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR,
36249da57d7bSbt 	    DEFAULT_RX_LIMIT_PER_INTR);
36259da57d7bSbt 
3626ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING,
3627ea65739eSchenlu chen - Sun Microsystems - Beijing China 	    ixgbe->capab->min_intr_throttle,
3628ea65739eSchenlu chen - Sun Microsystems - Beijing China 	    ixgbe->capab->max_intr_throttle,
3629ea65739eSchenlu chen - Sun Microsystems - Beijing China 	    ixgbe->capab->def_intr_throttle);
363073cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
3631dc0cb1cdSDale Ghent 	 * 82599, X540 and X550 require the interrupt throttling rate is
3632dc0cb1cdSDale Ghent 	 * a multiple of 8. This is enforced by the register definiton.
363373cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
3634dc0cb1cdSDale Ghent 	if (hw->mac.type == ixgbe_mac_82599EB ||
3635dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X540 ||
3636dc0cb1cdSDale Ghent 	    hw->mac.type == ixgbe_mac_X550 ||
363748ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_x ||
363848ed61a7SRobert Mustacchi 	    hw->mac.type == ixgbe_mac_X550EM_a)
3639ea65739eSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8;
364043fab1a9SSaso Kiselkov 
364143fab1a9SSaso Kiselkov 	hw->allow_unsupported_sfp = ixgbe_get_prop(ixgbe,
364243fab1a9SSaso Kiselkov 	    PROP_ALLOW_UNSUPPORTED_SFP, 0, 1, DEFAULT_ALLOW_UNSUPPORTED_SFP);
3643ea65739eSchenlu chen - Sun Microsystems - Beijing China }
3644185c5677SPaul Guo 
3645ea65739eSchenlu chen - Sun Microsystems - Beijing China static void
ixgbe_init_params(ixgbe_t * ixgbe)3646ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_init_params(ixgbe_t *ixgbe)
3647ea65739eSchenlu chen - Sun Microsystems - Beijing China {
3648dc0cb1cdSDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
3649dc0cb1cdSDale Ghent 	ixgbe_link_speed speeds_supported = 0;
3650dc0cb1cdSDale Ghent 	boolean_t negotiate;
3651dc0cb1cdSDale Ghent 
3652dc0cb1cdSDale Ghent 	/*
3653dc0cb1cdSDale Ghent 	 * Get a list of speeds the adapter supports. If the hw struct hasn't
3654dc0cb1cdSDale Ghent 	 * been populated with this information yet, retrieve it from the
3655dc0cb1cdSDale Ghent 	 * adapter and save it to our own variable.
3656dc0cb1cdSDale Ghent 	 *
3657dc0cb1cdSDale Ghent 	 * On certain adapters, such as ones which use SFPs, the contents of
3658dc0cb1cdSDale Ghent 	 * hw->phy.speeds_supported (and hw->phy.autoneg_advertised) are not
3659dc0cb1cdSDale Ghent 	 * updated, so we must rely on calling ixgbe_get_link_capabilities()
3660dc0cb1cdSDale Ghent 	 * in order to ascertain the speeds which we are capable of supporting,
3661dc0cb1cdSDale Ghent 	 * and in the case of SFP-equipped adapters, which speed we are
3662dc0cb1cdSDale Ghent 	 * advertising. If ixgbe_get_link_capabilities() fails for some reason,
3663dc0cb1cdSDale Ghent 	 * we'll go with a default list of speeds as a last resort.
3664dc0cb1cdSDale Ghent 	 */
3665dc0cb1cdSDale Ghent 	speeds_supported = hw->phy.speeds_supported;
3666dc0cb1cdSDale Ghent 
3667dc0cb1cdSDale Ghent 	if (speeds_supported == 0) {
3668dc0cb1cdSDale Ghent 		if (ixgbe_get_link_capabilities(hw, &speeds_supported,
3669dc0cb1cdSDale Ghent 		    &negotiate) != IXGBE_SUCCESS) {
3670dc0cb1cdSDale Ghent 			if (hw->mac.type == ixgbe_mac_82598EB) {
3671dc0cb1cdSDale Ghent 				speeds_supported =
3672dc0cb1cdSDale Ghent 				    IXGBE_LINK_SPEED_82598_AUTONEG;
3673dc0cb1cdSDale Ghent 			} else {
3674dc0cb1cdSDale Ghent 				speeds_supported =
3675dc0cb1cdSDale Ghent 				    IXGBE_LINK_SPEED_82599_AUTONEG;
3676dc0cb1cdSDale Ghent 			}
3677dc0cb1cdSDale Ghent 		}
3678dc0cb1cdSDale Ghent 	}
3679dc0cb1cdSDale Ghent 	ixgbe->speeds_supported = speeds_supported;
3680dc0cb1cdSDale Ghent 
3681dc0cb1cdSDale Ghent 	/*
3682dc0cb1cdSDale Ghent 	 * By default, all supported speeds are enabled and advertised.
3683dc0cb1cdSDale Ghent 	 */
3684dc0cb1cdSDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_10GB_FULL) {
3685dc0cb1cdSDale Ghent 		ixgbe->param_en_10000fdx_cap = 1;
3686dc0cb1cdSDale Ghent 		ixgbe->param_adv_10000fdx_cap = 1;
3687dc0cb1cdSDale Ghent 	} else {
3688dc0cb1cdSDale Ghent 		ixgbe->param_en_10000fdx_cap = 0;
3689dc0cb1cdSDale Ghent 		ixgbe->param_adv_10000fdx_cap = 0;
3690dc0cb1cdSDale Ghent 	}
3691dc0cb1cdSDale Ghent 
3692dc0cb1cdSDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_5GB_FULL) {
3693dc0cb1cdSDale Ghent 		ixgbe->param_en_5000fdx_cap = 1;
3694dc0cb1cdSDale Ghent 		ixgbe->param_adv_5000fdx_cap = 1;
3695dc0cb1cdSDale Ghent 	} else {
3696dc0cb1cdSDale Ghent 		ixgbe->param_en_5000fdx_cap = 0;
3697dc0cb1cdSDale Ghent 		ixgbe->param_adv_5000fdx_cap = 0;
3698dc0cb1cdSDale Ghent 	}
3699dc0cb1cdSDale Ghent 
3700dc0cb1cdSDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_2_5GB_FULL) {
3701dc0cb1cdSDale Ghent 		ixgbe->param_en_2500fdx_cap = 1;
3702dc0cb1cdSDale Ghent 		ixgbe->param_adv_2500fdx_cap = 1;
3703dc0cb1cdSDale Ghent 	} else {
3704dc0cb1cdSDale Ghent 		ixgbe->param_en_2500fdx_cap = 0;
3705dc0cb1cdSDale Ghent 		ixgbe->param_adv_2500fdx_cap = 0;
3706dc0cb1cdSDale Ghent 	}
3707dc0cb1cdSDale Ghent 
3708dc0cb1cdSDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_1GB_FULL) {
3709dc0cb1cdSDale Ghent 		ixgbe->param_en_1000fdx_cap = 1;
3710dc0cb1cdSDale Ghent 		ixgbe->param_adv_1000fdx_cap = 1;
3711dc0cb1cdSDale Ghent 	} else {
3712dc0cb1cdSDale Ghent 		ixgbe->param_en_1000fdx_cap = 0;
3713dc0cb1cdSDale Ghent 		ixgbe->param_adv_1000fdx_cap = 0;
3714dc0cb1cdSDale Ghent 	}
3715dc0cb1cdSDale Ghent 
3716dc0cb1cdSDale Ghent 	if (speeds_supported & IXGBE_LINK_SPEED_100_FULL) {
3717dc0cb1cdSDale Ghent 		ixgbe->param_en_100fdx_cap = 1;
3718dc0cb1cdSDale Ghent 		ixgbe->param_adv_100fdx_cap = 1;
3719dc0cb1cdSDale Ghent 	} else {
3720dc0cb1cdSDale Ghent 		ixgbe->param_en_100fdx_cap = 0;
3721dc0cb1cdSDale Ghent 		ixgbe->param_adv_100fdx_cap = 0;
3722dc0cb1cdSDale Ghent 	}
3723ea65739eSchenlu chen - Sun Microsystems - Beijing China 
3724ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_pause_cap = 1;
3725ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_asym_pause_cap = 1;
3726ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_rem_fault = 0;
3727ea65739eSchenlu chen - Sun Microsystems - Beijing China 
3728ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_adv_autoneg_cap = 1;
3729ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_adv_pause_cap = 1;
3730ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_adv_asym_pause_cap = 1;
3731ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_adv_rem_fault = 0;
3732ea65739eSchenlu chen - Sun Microsystems - Beijing China 
3733ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_10000fdx_cap = 0;
3734dc0cb1cdSDale Ghent 	ixgbe->param_lp_5000fdx_cap = 0;
3735dc0cb1cdSDale Ghent 	ixgbe->param_lp_2500fdx_cap = 0;
3736ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_1000fdx_cap = 0;
3737ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_100fdx_cap = 0;
3738ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_autoneg_cap = 0;
3739ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_pause_cap = 0;
3740ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_asym_pause_cap = 0;
3741ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->param_lp_rem_fault = 0;
37429da57d7bSbt }
37439da57d7bSbt 
37449da57d7bSbt /*
37459da57d7bSbt  * ixgbe_get_prop - Get a property value out of the configuration file
37469da57d7bSbt  * ixgbe.conf.
37479da57d7bSbt  *
37489da57d7bSbt  * Caller provides the name of the property, a default value, a minimum
37499da57d7bSbt  * value, and a maximum value.
37509da57d7bSbt  *
37519da57d7bSbt  * Return configured value of the property, with default, minimum and
37529da57d7bSbt  * maximum properly applied.
37539da57d7bSbt  */
37549da57d7bSbt static int
ixgbe_get_prop(ixgbe_t * ixgbe,char * propname,int minval,int maxval,int defval)37559da57d7bSbt ixgbe_get_prop(ixgbe_t *ixgbe,
37569da57d7bSbt     char *propname,	/* name of the property */
37579da57d7bSbt     int minval,		/* minimum acceptable value */
37589da57d7bSbt     int maxval,		/* maximim acceptable value */
37599da57d7bSbt     int defval)		/* default value */
37609da57d7bSbt {
37619da57d7bSbt 	int value;
37629da57d7bSbt 
37639da57d7bSbt 	/*
37649da57d7bSbt 	 * Call ddi_prop_get_int() to read the conf settings
37659da57d7bSbt 	 */
37669da57d7bSbt 	value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip,
37679da57d7bSbt 	    DDI_PROP_DONTPASS, propname, defval);
37689da57d7bSbt 	if (value > maxval)
37699da57d7bSbt 		value = maxval;
37709da57d7bSbt 
37719da57d7bSbt 	if (value < minval)
37729da57d7bSbt 		value = minval;
37739da57d7bSbt 
37749da57d7bSbt 	return (value);
37759da57d7bSbt }
37769da57d7bSbt 
37779da57d7bSbt /*
37789da57d7bSbt  * ixgbe_driver_setup_link - Using the link properties to setup the link.
37799da57d7bSbt  */
37809da57d7bSbt int
ixgbe_driver_setup_link(ixgbe_t * ixgbe,boolean_t setup_hw)37819da57d7bSbt ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw)
37829da57d7bSbt {
3783dc0cb1cdSDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
3784dc0cb1cdSDale Ghent 	ixgbe_link_speed advertised = 0;
37859da57d7bSbt 
37863cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	/*
3787dc0cb1cdSDale Ghent 	 * Assemble a list of enabled speeds to auto-negotiate with.
37883cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 	 */
3789dc0cb1cdSDale Ghent 	if (ixgbe->param_en_10000fdx_cap == 1)
3790dc0cb1cdSDale Ghent 		advertised |= IXGBE_LINK_SPEED_10GB_FULL;
3791dc0cb1cdSDale Ghent 
3792dc0cb1cdSDale Ghent 	if (ixgbe->param_en_5000fdx_cap == 1)
3793dc0cb1cdSDale Ghent 		advertised |= IXGBE_LINK_SPEED_5GB_FULL;
3794dc0cb1cdSDale Ghent 
3795dc0cb1cdSDale Ghent 	if (ixgbe->param_en_2500fdx_cap == 1)
3796dc0cb1cdSDale Ghent 		advertised |= IXGBE_LINK_SPEED_2_5GB_FULL;
37979da57d7bSbt 
3798dc0cb1cdSDale Ghent 	if (ixgbe->param_en_1000fdx_cap == 1)
3799dc0cb1cdSDale Ghent 		advertised |= IXGBE_LINK_SPEED_1GB_FULL;
38009da57d7bSbt 
3801dc0cb1cdSDale Ghent 	if (ixgbe->param_en_100fdx_cap == 1)
3802dc0cb1cdSDale Ghent 		advertised |= IXGBE_LINK_SPEED_100_FULL;
38039da57d7bSbt 
3804dc0cb1cdSDale Ghent 	/*
3805dc0cb1cdSDale Ghent 	 * As a last resort, autoneg with a default list of speeds.
3806dc0cb1cdSDale Ghent 	 */
3807dc0cb1cdSDale Ghent 	if (ixgbe->param_adv_autoneg_cap == 1 && advertised == 0) {
3808dc0cb1cdSDale Ghent 		ixgbe_notice(ixgbe, "Invalid link settings. Setting link "
3809dc0cb1cdSDale Ghent 		    "to autonegotiate with full capabilities.");
38109da57d7bSbt 
3811dc0cb1cdSDale Ghent 		if (hw->mac.type == ixgbe_mac_82598EB)
3812dc0cb1cdSDale Ghent 			advertised = IXGBE_LINK_SPEED_82598_AUTONEG;
3813dc0cb1cdSDale Ghent 		else
3814dc0cb1cdSDale Ghent 			advertised = IXGBE_LINK_SPEED_82599_AUTONEG;
38159da57d7bSbt 	}
38169da57d7bSbt 
38179da57d7bSbt 	if (setup_hw) {
3818dc0cb1cdSDale Ghent 		if (ixgbe_setup_link(&ixgbe->hw, advertised,
3819dc0cb1cdSDale Ghent 		    ixgbe->param_adv_autoneg_cap) != IXGBE_SUCCESS) {
382073cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe_notice(ixgbe, "Setup link failed on this "
382173cd555cSBin Tu - Sun Microsystems - Beijing China 			    "device.");
38229da57d7bSbt 			return (IXGBE_FAILURE);
382373cd555cSBin Tu - Sun Microsystems - Beijing China 		}
38249da57d7bSbt 	}
38259da57d7bSbt 
38269da57d7bSbt 	return (IXGBE_SUCCESS);
38279da57d7bSbt }
38289da57d7bSbt 
38299da57d7bSbt /*
383062e6e1adSPaul Guo  * ixgbe_driver_link_check - Link status processing.
383162e6e1adSPaul Guo  *
383262e6e1adSPaul Guo  * This function can be called in both kernel context and interrupt context
38339da57d7bSbt  */
383413740cb2SPaul Guo static void
ixgbe_driver_link_check(ixgbe_t * ixgbe)383562e6e1adSPaul Guo ixgbe_driver_link_check(ixgbe_t *ixgbe)
38369da57d7bSbt {
38379da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
38389da57d7bSbt 	ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
38399da57d7bSbt 	boolean_t link_up = B_FALSE;
38409da57d7bSbt 	boolean_t link_changed = B_FALSE;
38419da57d7bSbt 
384262e6e1adSPaul Guo 	ASSERT(mutex_owned(&ixgbe->gen_lock));
38439da57d7bSbt 
3844dc0cb1cdSDale Ghent 	(void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
38459da57d7bSbt 	if (link_up) {
384662e6e1adSPaul Guo 		ixgbe->link_check_complete = B_TRUE;
384762e6e1adSPaul Guo 
384873cd555cSBin Tu - Sun Microsystems - Beijing China 		/* Link is up, enable flow control settings */
384969b5a878SDan McDonald 		(void) ixgbe_fc_enable(hw);
385073cd555cSBin Tu - Sun Microsystems - Beijing China 
38519da57d7bSbt 		/*
38529da57d7bSbt 		 * The Link is up, check whether it was marked as down earlier
38539da57d7bSbt 		 */
38549da57d7bSbt 		if (ixgbe->link_state != LINK_STATE_UP) {
38559da57d7bSbt 			switch (speed) {
385673cd555cSBin Tu - Sun Microsystems - Beijing China 			case IXGBE_LINK_SPEED_10GB_FULL:
385773cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe->link_speed = SPEED_10GB;
385873cd555cSBin Tu - Sun Microsystems - Beijing China 				break;
3859dc0cb1cdSDale Ghent 			case IXGBE_LINK_SPEED_5GB_FULL:
3860dc0cb1cdSDale Ghent 				ixgbe->link_speed = SPEED_5GB;
3861dc0cb1cdSDale Ghent 				break;
3862dc0cb1cdSDale Ghent 			case IXGBE_LINK_SPEED_2_5GB_FULL:
3863dc0cb1cdSDale Ghent 				ixgbe->link_speed = SPEED_2_5GB;
3864dc0cb1cdSDale Ghent 				break;
386573cd555cSBin Tu - Sun Microsystems - Beijing China 			case IXGBE_LINK_SPEED_1GB_FULL:
386673cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe->link_speed = SPEED_1GB;
386773cd555cSBin Tu - Sun Microsystems - Beijing China 				break;
386873cd555cSBin Tu - Sun Microsystems - Beijing China 			case IXGBE_LINK_SPEED_100_FULL:
386973cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe->link_speed = SPEED_100;
38709da57d7bSbt 			}
38719da57d7bSbt 			ixgbe->link_duplex = LINK_DUPLEX_FULL;
38729da57d7bSbt 			ixgbe->link_state = LINK_STATE_UP;
38739da57d7bSbt 			link_changed = B_TRUE;
38749da57d7bSbt 		}
38759da57d7bSbt 	} else {
387662e6e1adSPaul Guo 		if (ixgbe->link_check_complete == B_TRUE ||
387762e6e1adSPaul Guo 		    (ixgbe->link_check_complete == B_FALSE &&
387862e6e1adSPaul Guo 		    gethrtime() >= ixgbe->link_check_hrtime)) {
387962e6e1adSPaul Guo 			/*
388062e6e1adSPaul Guo 			 * The link is really down
388162e6e1adSPaul Guo 			 */
388262e6e1adSPaul Guo 			ixgbe->link_check_complete = B_TRUE;
38839da57d7bSbt 
388462e6e1adSPaul Guo 			if (ixgbe->link_state != LINK_STATE_DOWN) {
388562e6e1adSPaul Guo 				ixgbe->link_speed = 0;
388662e6e1adSPaul Guo 				ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN;
388762e6e1adSPaul Guo 				ixgbe->link_state = LINK_STATE_DOWN;
388862e6e1adSPaul Guo 				link_changed = B_TRUE;
388962e6e1adSPaul Guo 			}
38909da57d7bSbt 		}
38919da57d7bSbt 	}
38929da57d7bSbt 
389362e6e1adSPaul Guo 	/*
389462e6e1adSPaul Guo 	 * If we are in an interrupt context, need to re-enable the
389562e6e1adSPaul Guo 	 * interrupt, which was automasked
389662e6e1adSPaul Guo 	 */
389762e6e1adSPaul Guo 	if (servicing_interrupt() != 0) {
389862e6e1adSPaul Guo 		ixgbe->eims |= IXGBE_EICR_LSC;
389962e6e1adSPaul Guo 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
390062e6e1adSPaul Guo 	}
390113740cb2SPaul Guo 
390213740cb2SPaul Guo 	if (link_changed) {
390313740cb2SPaul Guo 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
390413740cb2SPaul Guo 	}
39059da57d7bSbt }
39069da57d7bSbt 
390773cd555cSBin Tu - Sun Microsystems - Beijing China /*
390873cd555cSBin Tu - Sun Microsystems - Beijing China  * ixgbe_sfp_check - sfp module processing done in taskq only for 82599.
390973cd555cSBin Tu - Sun Microsystems - Beijing China  */
391073cd555cSBin Tu - Sun Microsystems - Beijing China static void
ixgbe_sfp_check(void * arg)391173cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_sfp_check(void *arg)
391273cd555cSBin Tu - Sun Microsystems - Beijing China {
391373cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
391473cd555cSBin Tu - Sun Microsystems - Beijing China 	uint32_t eicr = ixgbe->eicr;
391573cd555cSBin Tu - Sun Microsystems - Beijing China 	struct ixgbe_hw *hw = &ixgbe->hw;
391673cd555cSBin Tu - Sun Microsystems - Beijing China 
391762e6e1adSPaul Guo 	mutex_enter(&ixgbe->gen_lock);
391845d3dd98SRobert Mustacchi 	(void) hw->phy.ops.identify_sfp(hw);
3919dc0cb1cdSDale Ghent 	if (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) {
392073cd555cSBin Tu - Sun Microsystems - Beijing China 		/* clear the interrupt */
3921dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
392273cd555cSBin Tu - Sun Microsystems - Beijing China 
392373cd555cSBin Tu - Sun Microsystems - Beijing China 		/* if link up, do multispeed fiber setup */
39243cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
3925dc0cb1cdSDale Ghent 		    B_TRUE);
392673cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_driver_link_check(ixgbe);
39275b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_get_hw_state(ixgbe);
3928dc0cb1cdSDale Ghent 	} else if (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)) {
392973cd555cSBin Tu - Sun Microsystems - Beijing China 		/* clear the interrupt */
3930dc0cb1cdSDale Ghent 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2_BY_MAC(hw));
393173cd555cSBin Tu - Sun Microsystems - Beijing China 
393273cd555cSBin Tu - Sun Microsystems - Beijing China 		/* if link up, do sfp module setup */
393373cd555cSBin Tu - Sun Microsystems - Beijing China 		(void) hw->mac.ops.setup_sfp(hw);
393473cd555cSBin Tu - Sun Microsystems - Beijing China 
393573cd555cSBin Tu - Sun Microsystems - Beijing China 		/* do multispeed fiber setup */
39363cfa0eb9Schenlu chen - Sun Microsystems - Beijing China 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
3937dc0cb1cdSDale Ghent 		    B_TRUE);
393873cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_driver_link_check(ixgbe);
39395b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_get_hw_state(ixgbe);
394073cd555cSBin Tu - Sun Microsystems - Beijing China 	}
394162e6e1adSPaul Guo 	mutex_exit(&ixgbe->gen_lock);
39425b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39435b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
39445b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * We need to fully re-check the link later.
39455b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
39465b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->link_check_complete = B_FALSE;
39475b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe->link_check_hrtime = gethrtime() +
39485b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
39495b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
39505b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39515b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
39525b6dd21fSchenlu chen - Sun Microsystems - Beijing China  * ixgbe_overtemp_check - overtemp module processing done in taskq
39535b6dd21fSchenlu chen - Sun Microsystems - Beijing China  *
39545b6dd21fSchenlu chen - Sun Microsystems - Beijing China  * This routine will only be called on adapters with temperature sensor.
39555b6dd21fSchenlu chen - Sun Microsystems - Beijing China  * The indication of over-temperature can be either SDP0 interrupt or the link
39565b6dd21fSchenlu chen - Sun Microsystems - Beijing China  * status change interrupt.
39575b6dd21fSchenlu chen - Sun Microsystems - Beijing China  */
39585b6dd21fSchenlu chen - Sun Microsystems - Beijing China static void
ixgbe_overtemp_check(void * arg)39595b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_overtemp_check(void *arg)
39605b6dd21fSchenlu chen - Sun Microsystems - Beijing China {
39615b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
39625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	struct ixgbe_hw *hw = &ixgbe->hw;
39635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	uint32_t eicr = ixgbe->eicr;
39645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_link_speed speed;
39655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	boolean_t link_up;
39665b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39675b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	mutex_enter(&ixgbe->gen_lock);
39685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39695b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* make sure we know current state of link */
3970dc0cb1cdSDale Ghent 	(void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
39715b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39725b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* check over-temp condition */
3973dc0cb1cdSDale Ghent 	if (((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) && (!link_up)) ||
39745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	    (eicr & IXGBE_EICR_LSC)) {
39755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) {
39765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
39775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39785b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			/*
39795b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			 * Disable the adapter interrupts
39805b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			 */
39815b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_disable_adapter_interrupts(ixgbe);
39825b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39835b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			/*
39845b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			 * Disable Rx/Tx units
39855b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			 */
39865b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			(void) ixgbe_stop_adapter(hw);
39875b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39885b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
39895b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_error(ixgbe,
39905b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "Problem: Network adapter has been stopped "
39915b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "because it has overheated");
39925b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_error(ixgbe,
39935b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "Action: Restart the computer. "
39945b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "If the problem persists, power off the system "
39955b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "and replace the adapter");
39965b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
39975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
39985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
39995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* write to clear the interrupt */
40005b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
40015b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
40025b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	mutex_exit(&ixgbe->gen_lock);
400362e6e1adSPaul Guo }
400462e6e1adSPaul Guo 
4005dc0cb1cdSDale Ghent /*
4006dc0cb1cdSDale Ghent  * ixgbe_phy_check - taskq to process interrupts from an external PHY
4007dc0cb1cdSDale Ghent  *
4008dc0cb1cdSDale Ghent  * This routine will only be called on adapters with external PHYs
4009dc0cb1cdSDale Ghent  * (such as X550) that may be trying to raise our attention to some event.
4010dc0cb1cdSDale Ghent  * Currently, this is limited to claiming PHY overtemperature and link status
4011dc0cb1cdSDale Ghent  * change (LSC) events, however this may expand to include other things in
4012dc0cb1cdSDale Ghent  * future adapters.
4013dc0cb1cdSDale Ghent  */
4014dc0cb1cdSDale Ghent static void
ixgbe_phy_check(void * arg)4015dc0cb1cdSDale Ghent ixgbe_phy_check(void *arg)
4016dc0cb1cdSDale Ghent {
4017dc0cb1cdSDale Ghent 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
4018dc0cb1cdSDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
4019dc0cb1cdSDale Ghent 	int rv;
4020dc0cb1cdSDale Ghent 
4021dc0cb1cdSDale Ghent 	mutex_enter(&ixgbe->gen_lock);
4022dc0cb1cdSDale Ghent 
4023dc0cb1cdSDale Ghent 	/*
4024dc0cb1cdSDale Ghent 	 * X550 baseT PHY overtemp and LSC events are handled here.
4025dc0cb1cdSDale Ghent 	 *
4026dc0cb1cdSDale Ghent 	 * If an overtemp event occurs, it will be reflected in the
4027dc0cb1cdSDale Ghent 	 * return value of phy.ops.handle_lasi() and the common code will
4028dc0cb1cdSDale Ghent 	 * automatically power off the baseT PHY. This is our cue to trigger
4029dc0cb1cdSDale Ghent 	 * an FMA event.
4030dc0cb1cdSDale Ghent 	 *
4031dc0cb1cdSDale Ghent 	 * If a link status change event occurs, phy.ops.handle_lasi() will
4032dc0cb1cdSDale Ghent 	 * automatically initiate a link setup between the integrated KR PHY
4033dc0cb1cdSDale Ghent 	 * and the external X557 PHY to ensure that the link speed between
4034dc0cb1cdSDale Ghent 	 * them matches the link speed of the baseT link.
4035dc0cb1cdSDale Ghent 	 */
4036dc0cb1cdSDale Ghent 	rv = ixgbe_handle_lasi(hw);
4037dc0cb1cdSDale Ghent 
4038dc0cb1cdSDale Ghent 	if (rv == IXGBE_ERR_OVERTEMP) {
4039dc0cb1cdSDale Ghent 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
4040dc0cb1cdSDale Ghent 
4041dc0cb1cdSDale Ghent 		/*
4042dc0cb1cdSDale Ghent 		 * Disable the adapter interrupts
4043dc0cb1cdSDale Ghent 		 */
4044dc0cb1cdSDale Ghent 		ixgbe_disable_adapter_interrupts(ixgbe);
4045dc0cb1cdSDale Ghent 
4046dc0cb1cdSDale Ghent 		/*
4047dc0cb1cdSDale Ghent 		 * Disable Rx/Tx units
4048dc0cb1cdSDale Ghent 		 */
4049dc0cb1cdSDale Ghent 		(void) ixgbe_stop_adapter(hw);
4050dc0cb1cdSDale Ghent 
4051dc0cb1cdSDale Ghent 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
4052dc0cb1cdSDale Ghent 		ixgbe_error(ixgbe,
4053dc0cb1cdSDale Ghent 		    "Problem: Network adapter has been stopped due to a "
4054dc0cb1cdSDale Ghent 		    "overtemperature event being detected.");
4055dc0cb1cdSDale Ghent 		ixgbe_error(ixgbe,
4056dc0cb1cdSDale Ghent 		    "Action: Shut down or restart the computer. If the issue "
4057dc0cb1cdSDale Ghent 		    "persists, please take action in accordance with the "
4058dc0cb1cdSDale Ghent 		    "recommendations from your system vendor.");
4059dc0cb1cdSDale Ghent 	}
4060dc0cb1cdSDale Ghent 
4061dc0cb1cdSDale Ghent 	mutex_exit(&ixgbe->gen_lock);
4062dc0cb1cdSDale Ghent }
4063dc0cb1cdSDale Ghent 
406462e6e1adSPaul Guo /*
406562e6e1adSPaul Guo  * ixgbe_link_timer - timer for link status detection
406662e6e1adSPaul Guo  */
406762e6e1adSPaul Guo static void
ixgbe_link_timer(void * arg)406862e6e1adSPaul Guo ixgbe_link_timer(void *arg)
406962e6e1adSPaul Guo {
407062e6e1adSPaul Guo 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
407162e6e1adSPaul Guo 
407262e6e1adSPaul Guo 	mutex_enter(&ixgbe->gen_lock);
407362e6e1adSPaul Guo 	ixgbe_driver_link_check(ixgbe);
407462e6e1adSPaul Guo 	mutex_exit(&ixgbe->gen_lock);
407573cd555cSBin Tu - Sun Microsystems - Beijing China }
407673cd555cSBin Tu - Sun Microsystems - Beijing China 
40779da57d7bSbt /*
40789da57d7bSbt  * ixgbe_local_timer - Driver watchdog function.
40799da57d7bSbt  *
408062e6e1adSPaul Guo  * This function will handle the transmit stall check and other routines.
40819da57d7bSbt  */
40829da57d7bSbt static void
ixgbe_local_timer(void * arg)40839da57d7bSbt ixgbe_local_timer(void *arg)
40849da57d7bSbt {
40859da57d7bSbt 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
40869da57d7bSbt 
40875b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (ixgbe->ixgbe_state & IXGBE_OVERTEMP)
40885b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto out;
40895b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
409062e6e1adSPaul Guo 	if (ixgbe->ixgbe_state & IXGBE_ERROR) {
409162e6e1adSPaul Guo 		ixgbe->reset_count++;
409262e6e1adSPaul Guo 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
409362e6e1adSPaul Guo 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
40945b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		goto out;
409562e6e1adSPaul Guo 	}
409662e6e1adSPaul Guo 
40979da57d7bSbt 	if (ixgbe_stall_check(ixgbe)) {
409862e6e1adSPaul Guo 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL);
409973cd555cSBin Tu - Sun Microsystems - Beijing China 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
410062e6e1adSPaul Guo 
41019da57d7bSbt 		ixgbe->reset_count++;
41029da57d7bSbt 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
41039da57d7bSbt 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
41049da57d7bSbt 	}
4105ffd8e883SWinson Wang - Sun Microsystems - Beijing China 
41065b6dd21fSchenlu chen - Sun Microsystems - Beijing China out:
4107ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	ixgbe_restart_watchdog_timer(ixgbe);
41089da57d7bSbt }
41099da57d7bSbt 
41109da57d7bSbt /*
41119da57d7bSbt  * ixgbe_stall_check - Check for transmit stall.
41129da57d7bSbt  *
41139da57d7bSbt  * This function checks if the adapter is stalled (in transmit).
41149da57d7bSbt  *
41159da57d7bSbt  * It is called each time the watchdog timeout is invoked.
41169da57d7bSbt  * If the transmit descriptor reclaim continuously fails,
41179da57d7bSbt  * the watchdog value will increment by 1. If the watchdog
41189da57d7bSbt  * value exceeds the threshold, the ixgbe is assumed to
41199da57d7bSbt  * have stalled and need to be reset.
41209da57d7bSbt  */
41219da57d7bSbt static boolean_t
ixgbe_stall_check(ixgbe_t * ixgbe)41229da57d7bSbt ixgbe_stall_check(ixgbe_t *ixgbe)
41239da57d7bSbt {
41249da57d7bSbt 	ixgbe_tx_ring_t *tx_ring;
41259da57d7bSbt 	boolean_t result;
41269da57d7bSbt 	int i;
41279da57d7bSbt 
41289da57d7bSbt 	if (ixgbe->link_state != LINK_STATE_UP)
41299da57d7bSbt 		return (B_FALSE);
41309da57d7bSbt 
41319da57d7bSbt 	/*
41329da57d7bSbt 	 * If any tx ring is stalled, we'll reset the chipset
41339da57d7bSbt 	 */
41349da57d7bSbt 	result = B_FALSE;
41359da57d7bSbt 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
41369da57d7bSbt 		tx_ring = &ixgbe->tx_rings[i];
4137ea65739eSchenlu chen - Sun Microsystems - Beijing China 		if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) {
4138185c5677SPaul Guo 			tx_ring->tx_recycle(tx_ring);
4139185c5677SPaul Guo 		}
41409da57d7bSbt 
41419da57d7bSbt 		if (tx_ring->recycle_fail > 0)
41429da57d7bSbt 			tx_ring->stall_watchdog++;
41439da57d7bSbt 		else
41449da57d7bSbt 			tx_ring->stall_watchdog = 0;
41459da57d7bSbt 
41469da57d7bSbt 		if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) {
41479da57d7bSbt 			result = B_TRUE;
41489da57d7bSbt 			break;
41499da57d7bSbt 		}
41509da57d7bSbt 	}
41519da57d7bSbt 
41529da57d7bSbt 	if (result) {
41539da57d7bSbt 		tx_ring->stall_watchdog = 0;
41549da57d7bSbt 		tx_ring->recycle_fail = 0;
41559da57d7bSbt 	}
41569da57d7bSbt 
41579da57d7bSbt 	return (result);
41589da57d7bSbt }
41599da57d7bSbt 
41609da57d7bSbt 
41619da57d7bSbt /*
41629da57d7bSbt  * is_valid_mac_addr - Check if the mac address is valid.
41639da57d7bSbt  */
41649da57d7bSbt static boolean_t
is_valid_mac_addr(uint8_t * mac_addr)41659da57d7bSbt is_valid_mac_addr(uint8_t *mac_addr)
41669da57d7bSbt {
41679da57d7bSbt 	const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 };
41689da57d7bSbt 	const uint8_t addr_test2[6] =
41699da57d7bSbt 	    { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
41709da57d7bSbt 
41719da57d7bSbt 	if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) ||
41729da57d7bSbt 	    !(bcmp(addr_test2, mac_addr, ETHERADDRL)))
41739da57d7bSbt 		return (B_FALSE);
41749da57d7bSbt 
41759da57d7bSbt 	return (B_TRUE);
41769da57d7bSbt }
41779da57d7bSbt 
41789da57d7bSbt static boolean_t
ixgbe_find_mac_address(ixgbe_t * ixgbe)41799da57d7bSbt ixgbe_find_mac_address(ixgbe_t *ixgbe)
41809da57d7bSbt {
41819da57d7bSbt #ifdef __sparc
41829da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
41839da57d7bSbt 	uchar_t *bytes;
41849da57d7bSbt 	struct ether_addr sysaddr;
41859da57d7bSbt 	uint_t nelts;
41869da57d7bSbt 	int err;
41879da57d7bSbt 	boolean_t found = B_FALSE;
41889da57d7bSbt 
41899da57d7bSbt 	/*
41909da57d7bSbt 	 * The "vendor's factory-set address" may already have
41919da57d7bSbt 	 * been extracted from the chip, but if the property
41929da57d7bSbt 	 * "local-mac-address" is set we use that instead.
41939da57d7bSbt 	 *
41949da57d7bSbt 	 * We check whether it looks like an array of 6
41959da57d7bSbt 	 * bytes (which it should, if OBP set it).  If we can't
41969da57d7bSbt 	 * make sense of it this way, we'll ignore it.
41979da57d7bSbt 	 */
41989da57d7bSbt 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
41999da57d7bSbt 	    DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts);
42009da57d7bSbt 	if (err == DDI_PROP_SUCCESS) {
42019da57d7bSbt 		if (nelts == ETHERADDRL) {
42029da57d7bSbt 			while (nelts--)
42039da57d7bSbt 				hw->mac.addr[nelts] = bytes[nelts];
42049da57d7bSbt 			found = B_TRUE;
42059da57d7bSbt 		}
42069da57d7bSbt 		ddi_prop_free(bytes);
42079da57d7bSbt 	}
42089da57d7bSbt 
42099da57d7bSbt 	/*
42109da57d7bSbt 	 * Look up the OBP property "local-mac-address?". If the user has set
42119da57d7bSbt 	 * 'local-mac-address? = false', use "the system address" instead.
42129da57d7bSbt 	 */
42139da57d7bSbt 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0,
42149da57d7bSbt 	    "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) {
42159da57d7bSbt 		if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) {
42169da57d7bSbt 			if (localetheraddr(NULL, &sysaddr) != 0) {
42179da57d7bSbt 				bcopy(&sysaddr, hw->mac.addr, ETHERADDRL);
42189da57d7bSbt 				found = B_TRUE;
42199da57d7bSbt 			}
42209da57d7bSbt 		}
42219da57d7bSbt 		ddi_prop_free(bytes);
42229da57d7bSbt 	}
42239da57d7bSbt 
42249da57d7bSbt 	/*
42259da57d7bSbt 	 * Finally(!), if there's a valid "mac-address" property (created
42269da57d7bSbt 	 * if we netbooted from this interface), we must use this instead
42279da57d7bSbt 	 * of any of the above to ensure that the NFS/install server doesn't
4228dc0cb1cdSDale Ghent 	 * get confused by the address changing as illumos takes over!
42299da57d7bSbt 	 */
42309da57d7bSbt 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
42319da57d7bSbt 	    DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts);
42329da57d7bSbt 	if (err == DDI_PROP_SUCCESS) {
42339da57d7bSbt 		if (nelts == ETHERADDRL) {
42349da57d7bSbt 			while (nelts--)
42359da57d7bSbt 				hw->mac.addr[nelts] = bytes[nelts];
42369da57d7bSbt 			found = B_TRUE;
42379da57d7bSbt 		}
42389da57d7bSbt 		ddi_prop_free(bytes);
42399da57d7bSbt 	}
42409da57d7bSbt 
42419da57d7bSbt 	if (found) {
42429da57d7bSbt 		bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
42439da57d7bSbt 		return (B_TRUE);
42449da57d7bSbt 	}
42459da57d7bSbt #else
42469da57d7bSbt 	_NOTE(ARGUNUSED(ixgbe));
42479da57d7bSbt #endif
42489da57d7bSbt 
42499da57d7bSbt 	return (B_TRUE);
42509da57d7bSbt }
42519da57d7bSbt 
42529da57d7bSbt #pragma inline(ixgbe_arm_watchdog_timer)
42539da57d7bSbt static void
ixgbe_arm_watchdog_timer(ixgbe_t * ixgbe)42549da57d7bSbt ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe)
42559da57d7bSbt {
42569da57d7bSbt 	/*
42579da57d7bSbt 	 * Fire a watchdog timer
42589da57d7bSbt 	 */
42599da57d7bSbt 	ixgbe->watchdog_tid =
42609da57d7bSbt 	    timeout(ixgbe_local_timer,
42619da57d7bSbt 	    (void *)ixgbe, 1 * drv_usectohz(1000000));
42629da57d7bSbt 
42639da57d7bSbt }
42649da57d7bSbt 
42659da57d7bSbt /*
42669da57d7bSbt  * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer.
42679da57d7bSbt  */
42689da57d7bSbt void
ixgbe_enable_watchdog_timer(ixgbe_t * ixgbe)42699da57d7bSbt ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe)
42709da57d7bSbt {
42719da57d7bSbt 	mutex_enter(&ixgbe->watchdog_lock);
42729da57d7bSbt 
42739da57d7bSbt 	if (!ixgbe->watchdog_enable) {
42749da57d7bSbt 		ixgbe->watchdog_enable = B_TRUE;
42759da57d7bSbt 		ixgbe->watchdog_start = B_TRUE;
42769da57d7bSbt 		ixgbe_arm_watchdog_timer(ixgbe);
42779da57d7bSbt 	}
42789da57d7bSbt 
42799da57d7bSbt 	mutex_exit(&ixgbe->watchdog_lock);
42809da57d7bSbt }
42819da57d7bSbt 
42829da57d7bSbt /*
42839da57d7bSbt  * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer.
42849da57d7bSbt  */
42859da57d7bSbt void
ixgbe_disable_watchdog_timer(ixgbe_t * ixgbe)42869da57d7bSbt ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe)
42879da57d7bSbt {
42889da57d7bSbt 	timeout_id_t tid;
42899da57d7bSbt 
42909da57d7bSbt 	mutex_enter(&ixgbe->watchdog_lock);
42919da57d7bSbt 
42929da57d7bSbt 	ixgbe->watchdog_enable = B_FALSE;
42939da57d7bSbt 	ixgbe->watchdog_start = B_FALSE;
42949da57d7bSbt 	tid = ixgbe->watchdog_tid;
42959da57d7bSbt 	ixgbe->watchdog_tid = 0;
42969da57d7bSbt 
42979da57d7bSbt 	mutex_exit(&ixgbe->watchdog_lock);
42989da57d7bSbt 
42999da57d7bSbt 	if (tid != 0)
43009da57d7bSbt 		(void) untimeout(tid);
43019da57d7bSbt }
43029da57d7bSbt 
43039da57d7bSbt /*
43049da57d7bSbt  * ixgbe_start_watchdog_timer - Start the driver watchdog timer.
43059da57d7bSbt  */
430613740cb2SPaul Guo void
ixgbe_start_watchdog_timer(ixgbe_t * ixgbe)43079da57d7bSbt ixgbe_start_watchdog_timer(ixgbe_t *ixgbe)
43089da57d7bSbt {
43099da57d7bSbt 	mutex_enter(&ixgbe->watchdog_lock);
43109da57d7bSbt 
43119da57d7bSbt 	if (ixgbe->watchdog_enable) {
43129da57d7bSbt 		if (!ixgbe->watchdog_start) {
43139da57d7bSbt 			ixgbe->watchdog_start = B_TRUE;
43149da57d7bSbt 			ixgbe_arm_watchdog_timer(ixgbe);
43159da57d7bSbt 		}
43169da57d7bSbt 	}
43179da57d7bSbt 
43189da57d7bSbt 	mutex_exit(&ixgbe->watchdog_lock);
43199da57d7bSbt }
43209da57d7bSbt 
43219da57d7bSbt /*
43229da57d7bSbt  * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer.
43239da57d7bSbt  */
43249da57d7bSbt static void
ixgbe_restart_watchdog_timer(ixgbe_t * ixgbe)43259da57d7bSbt ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe)
43269da57d7bSbt {
43279da57d7bSbt 	mutex_enter(&ixgbe->watchdog_lock);
43289da57d7bSbt 
43299da57d7bSbt 	if (ixgbe->watchdog_start)
43309da57d7bSbt 		ixgbe_arm_watchdog_timer(ixgbe);
43319da57d7bSbt 
43329da57d7bSbt 	mutex_exit(&ixgbe->watchdog_lock);
43339da57d7bSbt }
43349da57d7bSbt 
43359da57d7bSbt /*
43369da57d7bSbt  * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer.
43379da57d7bSbt  */
433813740cb2SPaul Guo void
ixgbe_stop_watchdog_timer(ixgbe_t * ixgbe)43399da57d7bSbt ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe)
43409da57d7bSbt {
43419da57d7bSbt 	timeout_id_t tid;
43429da57d7bSbt 
43439da57d7bSbt 	mutex_enter(&ixgbe->watchdog_lock);
43449da57d7bSbt 
43459da57d7bSbt 	ixgbe->watchdog_start = B_FALSE;
43469da57d7bSbt 	tid = ixgbe->watchdog_tid;
43479da57d7bSbt 	ixgbe->watchdog_tid = 0;
43489da57d7bSbt 
43499da57d7bSbt 	mutex_exit(&ixgbe->watchdog_lock);
43509da57d7bSbt 
43519da57d7bSbt 	if (tid != 0)
43529da57d7bSbt 		(void) untimeout(tid);
43539da57d7bSbt }
43549da57d7bSbt 
43559da57d7bSbt /*
43569da57d7bSbt  * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts.
43579da57d7bSbt  */
43589da57d7bSbt static void
ixgbe_disable_adapter_interrupts(ixgbe_t * ixgbe)43599da57d7bSbt ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe)
43609da57d7bSbt {
43619da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
43629da57d7bSbt 
43639da57d7bSbt 	/*
43649da57d7bSbt 	 * mask all interrupts off
43659da57d7bSbt 	 */
43669da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff);
43679da57d7bSbt 
43689da57d7bSbt 	/*
43699da57d7bSbt 	 * for MSI-X, also disable autoclear
43709da57d7bSbt 	 */
43719da57d7bSbt 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
43729da57d7bSbt 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0);
43739da57d7bSbt 	}
43749da57d7bSbt 
43759da57d7bSbt 	IXGBE_WRITE_FLUSH(hw);
43769da57d7bSbt }
43779da57d7bSbt 
43789da57d7bSbt /*
43799da57d7bSbt  * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts.
43809da57d7bSbt  */
43819da57d7bSbt static void
ixgbe_enable_adapter_interrupts(ixgbe_t * ixgbe)43829da57d7bSbt ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe)
43839da57d7bSbt {
43849da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
438513740cb2SPaul Guo 	uint32_t eiac, eiam;
438613740cb2SPaul Guo 	uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
438713740cb2SPaul Guo 
438813740cb2SPaul Guo 	/* interrupt types to enable */
438913740cb2SPaul Guo 	ixgbe->eims = IXGBE_EIMS_ENABLE_MASK;	/* shared code default */
439013740cb2SPaul Guo 	ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER;	/* minus tcp timer */
439113740cb2SPaul Guo 	ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */
43929da57d7bSbt 
439313740cb2SPaul Guo 	/* enable automask on "other" causes that this adapter can generate */
439413740cb2SPaul Guo 	eiam = ixgbe->capab->other_intr;
43959da57d7bSbt 
43969da57d7bSbt 	/*
43979da57d7bSbt 	 * msi-x mode
43989da57d7bSbt 	 */
43999da57d7bSbt 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
44009da57d7bSbt 		/* enable autoclear but not on bits 29:20 */
440113740cb2SPaul Guo 		eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR);
44029da57d7bSbt 
44039da57d7bSbt 		/* general purpose interrupt enable */
440413740cb2SPaul Guo 		gpie |= (IXGBE_GPIE_MSIX_MODE
440513740cb2SPaul Guo 		    | IXGBE_GPIE_PBA_SUPPORT
440613740cb2SPaul Guo 		    | IXGBE_GPIE_OCD
440713740cb2SPaul Guo 		    | IXGBE_GPIE_EIAME);
44089da57d7bSbt 	/*
44099da57d7bSbt 	 * non-msi-x mode
44109da57d7bSbt 	 */
44119da57d7bSbt 	} else {
44129da57d7bSbt 
44139da57d7bSbt 		/* disable autoclear, leave gpie at default */
44149da57d7bSbt 		eiac = 0;
441513740cb2SPaul Guo 
441673cd555cSBin Tu - Sun Microsystems - Beijing China 		/*
441773cd555cSBin Tu - Sun Microsystems - Beijing China 		 * General purpose interrupt enable.
4418dc0cb1cdSDale Ghent 		 * For 82599, X540 and X550, extended interrupt
4419dc0cb1cdSDale Ghent 		 * automask enable only in MSI or MSI-X mode
442073cd555cSBin Tu - Sun Microsystems - Beijing China 		 */
442169b5a878SDan McDonald 		if ((hw->mac.type == ixgbe_mac_82598EB) ||
442273cd555cSBin Tu - Sun Microsystems - Beijing China 		    (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) {
442373cd555cSBin Tu - Sun Microsystems - Beijing China 			gpie |= IXGBE_GPIE_EIAME;
442473cd555cSBin Tu - Sun Microsystems - Beijing China 		}
442573cd555cSBin Tu - Sun Microsystems - Beijing China 	}
44265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
44275b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/* Enable specific "other" interrupt types */
44285b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
44295b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
44305b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		gpie |= ixgbe->capab->other_gpie;
44315b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
44325b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
44335b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
443469b5a878SDan McDonald 	case ixgbe_mac_X540:
4435dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
4436dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
443748ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
44385b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		gpie |= ixgbe->capab->other_gpie;
44395b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
44405b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		/* Enable RSC Delay 8us when LRO enabled  */
44415b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		if (ixgbe->lro_enable) {
44425b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT);
44435b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
44445b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
44455b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
44465b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	default:
44475b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
4448ffd8e883SWinson Wang - Sun Microsystems - Beijing China 	}
44495b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
445013740cb2SPaul Guo 	/* write to interrupt control registers */
445113740cb2SPaul Guo 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
44529da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac);
445313740cb2SPaul Guo 	IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam);
44549da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
44559da57d7bSbt 	IXGBE_WRITE_FLUSH(hw);
44569da57d7bSbt }
44579da57d7bSbt 
44589da57d7bSbt /*
44599da57d7bSbt  * ixgbe_loopback_ioctl - Loopback support.
44609da57d7bSbt  */
44619da57d7bSbt enum ioc_reply
ixgbe_loopback_ioctl(ixgbe_t * ixgbe,struct iocblk * iocp,mblk_t * mp)44629da57d7bSbt ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp)
44639da57d7bSbt {
44649da57d7bSbt 	lb_info_sz_t *lbsp;
44659da57d7bSbt 	lb_property_t *lbpp;
44669da57d7bSbt 	uint32_t *lbmp;
44679da57d7bSbt 	uint32_t size;
44689da57d7bSbt 	uint32_t value;
44699da57d7bSbt 
44709da57d7bSbt 	if (mp->b_cont == NULL)
44719da57d7bSbt 		return (IOC_INVAL);
44729da57d7bSbt 
44739da57d7bSbt 	switch (iocp->ioc_cmd) {
44749da57d7bSbt 	default:
44759da57d7bSbt 		return (IOC_INVAL);
44769da57d7bSbt 
44779da57d7bSbt 	case LB_GET_INFO_SIZE:
44789da57d7bSbt 		size = sizeof (lb_info_sz_t);
44799da57d7bSbt 		if (iocp->ioc_count != size)
44809da57d7bSbt 			return (IOC_INVAL);
44819da57d7bSbt 
44829da57d7bSbt 		value = sizeof (lb_normal);
44839da57d7bSbt 		value += sizeof (lb_mac);
44841fedc51fSWinson Wang - Sun Microsystems - Beijing China 		value += sizeof (lb_external);
44859da57d7bSbt 
44869da57d7bSbt 		lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr;
44879da57d7bSbt 		*lbsp = value;
44889da57d7bSbt 		break;
44899da57d7bSbt 
44909da57d7bSbt 	case LB_GET_INFO:
44919da57d7bSbt 		value = sizeof (lb_normal);
44929da57d7bSbt 		value += sizeof (lb_mac);
44931fedc51fSWinson Wang - Sun Microsystems - Beijing China 		value += sizeof (lb_external);
44949da57d7bSbt 
44959da57d7bSbt 		size = value;
44969da57d7bSbt 		if (iocp->ioc_count != size)
44979da57d7bSbt 			return (IOC_INVAL);
44989da57d7bSbt 
44999da57d7bSbt 		value = 0;
45009da57d7bSbt 		lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr;
45019da57d7bSbt 
45029da57d7bSbt 		lbpp[value++] = lb_normal;
45039da57d7bSbt 		lbpp[value++] = lb_mac;
45041fedc51fSWinson Wang - Sun Microsystems - Beijing China 		lbpp[value++] = lb_external;
45059da57d7bSbt 		break;
45069da57d7bSbt 
45079da57d7bSbt 	case LB_GET_MODE:
45089da57d7bSbt 		size = sizeof (uint32_t);
45099da57d7bSbt 		if (iocp->ioc_count != size)
45109da57d7bSbt 			return (IOC_INVAL);
45119da57d7bSbt 
45129da57d7bSbt 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
45139da57d7bSbt 		*lbmp = ixgbe->loopback_mode;
45149da57d7bSbt 		break;
45159da57d7bSbt 
45169da57d7bSbt 	case LB_SET_MODE:
45179da57d7bSbt 		size = 0;
45189da57d7bSbt 		if (iocp->ioc_count != sizeof (uint32_t))
45199da57d7bSbt 			return (IOC_INVAL);
45209da57d7bSbt 
45219da57d7bSbt 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
45229da57d7bSbt 		if (!ixgbe_set_loopback_mode(ixgbe, *lbmp))
45239da57d7bSbt 			return (IOC_INVAL);
45249da57d7bSbt 		break;
45259da57d7bSbt 	}
45269da57d7bSbt 
45279da57d7bSbt 	iocp->ioc_count = size;
45289da57d7bSbt 	iocp->ioc_error = 0;
45299da57d7bSbt 
45309da57d7bSbt 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
45319da57d7bSbt 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
45329da57d7bSbt 		return (IOC_INVAL);
45339da57d7bSbt 	}
45349da57d7bSbt 
45359da57d7bSbt 	return (IOC_REPLY);
45369da57d7bSbt }
45379da57d7bSbt 
45389da57d7bSbt /*
45399da57d7bSbt  * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode.
45409da57d7bSbt  */
45419da57d7bSbt static boolean_t
ixgbe_set_loopback_mode(ixgbe_t * ixgbe,uint32_t mode)45429da57d7bSbt ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode)
45439da57d7bSbt {
45449da57d7bSbt 	if (mode == ixgbe->loopback_mode)
45459da57d7bSbt 		return (B_TRUE);
45469da57d7bSbt 
45479da57d7bSbt 	ixgbe->loopback_mode = mode;
45489da57d7bSbt 
45499da57d7bSbt 	if (mode == IXGBE_LB_NONE) {
45509da57d7bSbt 		/*
45519da57d7bSbt 		 * Reset the chip
45529da57d7bSbt 		 */
45539da57d7bSbt 		(void) ixgbe_reset(ixgbe);
45549da57d7bSbt 		return (B_TRUE);
45559da57d7bSbt 	}
45569da57d7bSbt 
45579da57d7bSbt 	mutex_enter(&ixgbe->gen_lock);
45589da57d7bSbt 
45599da57d7bSbt 	switch (mode) {
45609da57d7bSbt 	default:
45619da57d7bSbt 		mutex_exit(&ixgbe->gen_lock);
45629da57d7bSbt 		return (B_FALSE);
45639da57d7bSbt 
45641fedc51fSWinson Wang - Sun Microsystems - Beijing China 	case IXGBE_LB_EXTERNAL:
45651fedc51fSWinson Wang - Sun Microsystems - Beijing China 		break;
45661fedc51fSWinson Wang - Sun Microsystems - Beijing China 
45679da57d7bSbt 	case IXGBE_LB_INTERNAL_MAC:
45689da57d7bSbt 		ixgbe_set_internal_mac_loopback(ixgbe);
45699da57d7bSbt 		break;
45709da57d7bSbt 	}
45719da57d7bSbt 
45729da57d7bSbt 	mutex_exit(&ixgbe->gen_lock);
45739da57d7bSbt 
45749da57d7bSbt 	return (B_TRUE);
45759da57d7bSbt }
45769da57d7bSbt 
45779da57d7bSbt /*
45789da57d7bSbt  * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode.
45799da57d7bSbt  */
45809da57d7bSbt static void
ixgbe_set_internal_mac_loopback(ixgbe_t * ixgbe)45819da57d7bSbt ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe)
45829da57d7bSbt {
45839da57d7bSbt 	struct ixgbe_hw *hw;
45849da57d7bSbt 	uint32_t reg;
45859da57d7bSbt 	uint8_t atlas;
45869da57d7bSbt 
45879da57d7bSbt 	hw = &ixgbe->hw;
45889da57d7bSbt 
45899da57d7bSbt 	/*
45909da57d7bSbt 	 * Setup MAC loopback
45919da57d7bSbt 	 */
45929da57d7bSbt 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0);
45939da57d7bSbt 	reg |= IXGBE_HLREG0_LPBK;
45949da57d7bSbt 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg);
45959da57d7bSbt 
45969da57d7bSbt 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
45979da57d7bSbt 	reg &= ~IXGBE_AUTOC_LMS_MASK;
45989da57d7bSbt 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
45999da57d7bSbt 
46009da57d7bSbt 	/*
46019da57d7bSbt 	 * Disable Atlas Tx lanes to keep packets in loopback and not on wire
46029da57d7bSbt 	 */
46035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
46045b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
46059da57d7bSbt 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
46069da57d7bSbt 		    &atlas);
46079da57d7bSbt 		atlas |= IXGBE_ATLAS_PDN_TX_REG_EN;
46089da57d7bSbt 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
46099da57d7bSbt 		    atlas);
46109da57d7bSbt 
46119da57d7bSbt 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
46129da57d7bSbt 		    &atlas);
46139da57d7bSbt 		atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
46149da57d7bSbt 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
46159da57d7bSbt 		    atlas);
46169da57d7bSbt 
46179da57d7bSbt 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
46189da57d7bSbt 		    &atlas);
46199da57d7bSbt 		atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
46209da57d7bSbt 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
46219da57d7bSbt 		    atlas);
46229da57d7bSbt 
46239da57d7bSbt 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
46249da57d7bSbt 		    &atlas);
46259da57d7bSbt 		atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
46269da57d7bSbt 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
46279da57d7bSbt 		    atlas);
46285b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
46295b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
46305b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
463169b5a878SDan McDonald 	case ixgbe_mac_X540:
4632dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
4633dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
463448ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
463500f1c25aSchenlu chen - Sun Microsystems - Beijing China 		reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
463600f1c25aSchenlu chen - Sun Microsystems - Beijing China 		reg |= (IXGBE_AUTOC_FLU |
463700f1c25aSchenlu chen - Sun Microsystems - Beijing China 		    IXGBE_AUTOC_10G_KX4);
463800f1c25aSchenlu chen - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
463900f1c25aSchenlu chen - Sun Microsystems - Beijing China 
464000f1c25aSchenlu chen - Sun Microsystems - Beijing China 		(void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL,
4641dc0cb1cdSDale Ghent 		    B_FALSE);
46425b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
46435b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
46445b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	default:
46455b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		break;
46469da57d7bSbt 	}
46479da57d7bSbt }
46489da57d7bSbt 
46499da57d7bSbt #pragma inline(ixgbe_intr_rx_work)
46509da57d7bSbt /*
46519da57d7bSbt  * ixgbe_intr_rx_work - RX processing of ISR.
46529da57d7bSbt  */
46539da57d7bSbt static void
ixgbe_intr_rx_work(ixgbe_rx_ring_t * rx_ring)46549da57d7bSbt ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring)
46559da57d7bSbt {
46569da57d7bSbt 	mblk_t *mp;
46579da57d7bSbt 
46589da57d7bSbt 	mutex_enter(&rx_ring->rx_lock);
46599da57d7bSbt 
4660da14cebeSEric Cheng 	mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
46619da57d7bSbt 	mutex_exit(&rx_ring->rx_lock);
46629da57d7bSbt 
46639da57d7bSbt 	if (mp != NULL)
4664da14cebeSEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
4665da14cebeSEric Cheng 		    rx_ring->ring_gen_num);
46669da57d7bSbt }
46679da57d7bSbt 
46689da57d7bSbt #pragma inline(ixgbe_intr_tx_work)
46699da57d7bSbt /*
46709da57d7bSbt  * ixgbe_intr_tx_work - TX processing of ISR.
46719da57d7bSbt  */
46729da57d7bSbt static void
ixgbe_intr_tx_work(ixgbe_tx_ring_t * tx_ring)46739da57d7bSbt ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring)
46749da57d7bSbt {
4675ea65739eSchenlu chen - Sun Microsystems - Beijing China 	ixgbe_t *ixgbe = tx_ring->ixgbe;
4676ea65739eSchenlu chen - Sun Microsystems - Beijing China 
46779da57d7bSbt 	/*
46789da57d7bSbt 	 * Recycle the tx descriptors
46799da57d7bSbt 	 */
46809da57d7bSbt 	tx_ring->tx_recycle(tx_ring);
46819da57d7bSbt 
46829da57d7bSbt 	/*
46839da57d7bSbt 	 * Schedule the re-transmit
46849da57d7bSbt 	 */
46859da57d7bSbt 	if (tx_ring->reschedule &&
4686ea65739eSchenlu chen - Sun Microsystems - Beijing China 	    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) {
46879da57d7bSbt 		tx_ring->reschedule = B_FALSE;
4688da14cebeSEric Cheng 		mac_tx_ring_update(tx_ring->ixgbe->mac_hdl,
4689da14cebeSEric Cheng 		    tx_ring->ring_handle);
4690a9bfd41dSRyan Zezeski 		tx_ring->stat_reschedule++;
46919da57d7bSbt 	}
46929da57d7bSbt }
46939da57d7bSbt 
46949da57d7bSbt #pragma inline(ixgbe_intr_other_work)
46959da57d7bSbt /*
469613740cb2SPaul Guo  * ixgbe_intr_other_work - Process interrupt types other than tx/rx
46979da57d7bSbt  */
46989da57d7bSbt static void
ixgbe_intr_other_work(ixgbe_t * ixgbe,uint32_t eicr)469913740cb2SPaul Guo ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr)
47009da57d7bSbt {
4701dc0cb1cdSDale Ghent 	struct ixgbe_hw *hw = &ixgbe->hw;
4702dc0cb1cdSDale Ghent 
470362e6e1adSPaul Guo 	ASSERT(mutex_owned(&ixgbe->gen_lock));
470462e6e1adSPaul Guo 
47059da57d7bSbt 	/*
470662e6e1adSPaul Guo 	 * handle link status change
47079da57d7bSbt 	 */
470813740cb2SPaul Guo 	if (eicr & IXGBE_EICR_LSC) {
470962e6e1adSPaul Guo 		ixgbe_driver_link_check(ixgbe);
47105b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_get_hw_state(ixgbe);
471113740cb2SPaul Guo 	}
47129da57d7bSbt 
47139da57d7bSbt 	/*
471413740cb2SPaul Guo 	 * check for fan failure on adapters with fans
47159da57d7bSbt 	 */
471613740cb2SPaul Guo 	if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
471713740cb2SPaul Guo 	    (eicr & IXGBE_EICR_GPI_SDP1)) {
47185b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
47199da57d7bSbt 
47205b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		/*
47215b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 * Disable the adapter interrupts
47225b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 */
47235b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_disable_adapter_interrupts(ixgbe);
47245b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
47255b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		/*
47265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 * Disable Rx/Tx units
47275b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 */
47285b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		(void) ixgbe_stop_adapter(&ixgbe->hw);
47295b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
47305b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
47315b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe,
47325b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    "Problem: Network adapter has been stopped "
47335b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    "because the fan has stopped.\n");
47345b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe_error(ixgbe,
47355b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    "Action: Replace the adapter.\n");
47365b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
47375b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		/* re-enable the interrupt, which was automasked */
47385b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->eims |= IXGBE_EICR_GPI_SDP1;
473973cd555cSBin Tu - Sun Microsystems - Beijing China 	}
47409da57d7bSbt 
474173cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
47425b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Do SFP check for adapters with hot-plug capability
474373cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
47445b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if ((ixgbe->capab->flags & IXGBE_FLAG_SFP_PLUG_CAPABLE) &&
4745dc0cb1cdSDale Ghent 	    ((eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) ||
4746dc0cb1cdSDale Ghent 	    (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)))) {
47475b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->eicr = eicr;
474862e6e1adSPaul Guo 		if ((ddi_taskq_dispatch(ixgbe->sfp_taskq,
474973cd555cSBin Tu - Sun Microsystems - Beijing China 		    ixgbe_sfp_check, (void *)ixgbe,
475073cd555cSBin Tu - Sun Microsystems - Beijing China 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
4751185c5677SPaul Guo 			ixgbe_log(ixgbe, "No memory available to dispatch "
4752185c5677SPaul Guo 			    "taskq for SFP check");
475373cd555cSBin Tu - Sun Microsystems - Beijing China 		}
47545b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	}
475562e6e1adSPaul Guo 
47565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	/*
47575b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 * Do over-temperature check for adapters with temp sensor
47585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	 */
47595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if ((ixgbe->capab->flags & IXGBE_FLAG_TEMP_SENSOR_CAPABLE) &&
4760dc0cb1cdSDale Ghent 	    ((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) ||
4761dc0cb1cdSDale Ghent 	    (eicr & IXGBE_EICR_LSC))) {
47625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->eicr = eicr;
47635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		if ((ddi_taskq_dispatch(ixgbe->overtemp_taskq,
47645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    ixgbe_overtemp_check, (void *)ixgbe,
47655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
47665b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			ixgbe_log(ixgbe, "No memory available to dispatch "
47675b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			    "taskq for overtemp check");
47685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		}
476913740cb2SPaul Guo 	}
4770dc0cb1cdSDale Ghent 
4771dc0cb1cdSDale Ghent 	/*
4772dc0cb1cdSDale Ghent 	 * Process an external PHY interrupt
4773dc0cb1cdSDale Ghent 	 */
4774dc0cb1cdSDale Ghent 	if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
4775dc0cb1cdSDale Ghent 	    (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
4776dc0cb1cdSDale Ghent 		ixgbe->eicr = eicr;
4777dc0cb1cdSDale Ghent 		if ((ddi_taskq_dispatch(ixgbe->phy_taskq,
4778dc0cb1cdSDale Ghent 		    ixgbe_phy_check, (void *)ixgbe,
4779dc0cb1cdSDale Ghent 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
4780dc0cb1cdSDale Ghent 			ixgbe_log(ixgbe, "No memory available to dispatch "
4781dc0cb1cdSDale Ghent 			    "taskq for PHY check");
4782dc0cb1cdSDale Ghent 		}
4783dc0cb1cdSDale Ghent 	}
47849da57d7bSbt }
47859da57d7bSbt 
47869da57d7bSbt /*
47879da57d7bSbt  * ixgbe_intr_legacy - Interrupt handler for legacy interrupts.
47889da57d7bSbt  */
47899da57d7bSbt static uint_t
ixgbe_intr_legacy(void * arg1,void * arg2)47909da57d7bSbt ixgbe_intr_legacy(void *arg1, void *arg2)
47919da57d7bSbt {
47929da57d7bSbt 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
47939da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
47949da57d7bSbt 	ixgbe_tx_ring_t *tx_ring;
4795da14cebeSEric Cheng 	ixgbe_rx_ring_t *rx_ring;
47969da57d7bSbt 	uint32_t eicr;
47979da57d7bSbt 	mblk_t *mp;
47989da57d7bSbt 	boolean_t tx_reschedule;
47999da57d7bSbt 	uint_t result;
48009da57d7bSbt 
480113740cb2SPaul Guo 	_NOTE(ARGUNUSED(arg2));
48029da57d7bSbt 
48039da57d7bSbt 	mutex_enter(&ixgbe->gen_lock);
48049da57d7bSbt 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
48059da57d7bSbt 		mutex_exit(&ixgbe->gen_lock);
48069da57d7bSbt 		return (DDI_INTR_UNCLAIMED);
48079da57d7bSbt 	}
48089da57d7bSbt 
48099da57d7bSbt 	mp = NULL;
48109da57d7bSbt 	tx_reschedule = B_FALSE;
48119da57d7bSbt 
48129da57d7bSbt 	/*
48139da57d7bSbt 	 * Any bit set in eicr: claim this interrupt
48149da57d7bSbt 	 */
48159da57d7bSbt 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
481662e6e1adSPaul Guo 
481762e6e1adSPaul Guo 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
481819843f01SPaul Guo 		mutex_exit(&ixgbe->gen_lock);
481962e6e1adSPaul Guo 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
482062e6e1adSPaul Guo 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
482162e6e1adSPaul Guo 		return (DDI_INTR_CLAIMED);
482262e6e1adSPaul Guo 	}
482362e6e1adSPaul Guo 
48249da57d7bSbt 	if (eicr) {
48259da57d7bSbt 		/*
48269da57d7bSbt 		 * For legacy interrupt, we have only one interrupt,
48279da57d7bSbt 		 * so we have only one rx ring and one tx ring enabled.
48289da57d7bSbt 		 */
48299da57d7bSbt 		ASSERT(ixgbe->num_rx_rings == 1);
48309da57d7bSbt 		ASSERT(ixgbe->num_tx_rings == 1);
48319da57d7bSbt 
48329da57d7bSbt 		/*
4833da14cebeSEric Cheng 		 * For legacy interrupt, rx rings[0] will use RTxQ[0].
48349da57d7bSbt 		 */
4835da14cebeSEric Cheng 		if (eicr & 0x1) {
483673cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE;
483773cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
483873cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
48399da57d7bSbt 			/*
48409da57d7bSbt 			 * Clean the rx descriptors
48419da57d7bSbt 			 */
4842da14cebeSEric Cheng 			rx_ring = &ixgbe->rx_rings[0];
4843da14cebeSEric Cheng 			mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
4844da14cebeSEric Cheng 		}
48459da57d7bSbt 
4846da14cebeSEric Cheng 		/*
4847da14cebeSEric Cheng 		 * For legacy interrupt, tx rings[0] will use RTxQ[1].
4848da14cebeSEric Cheng 		 */
4849da14cebeSEric Cheng 		if (eicr & 0x2) {
48509da57d7bSbt 			/*
48519da57d7bSbt 			 * Recycle the tx descriptors
48529da57d7bSbt 			 */
48539da57d7bSbt 			tx_ring = &ixgbe->tx_rings[0];
48549da57d7bSbt 			tx_ring->tx_recycle(tx_ring);
48559da57d7bSbt 
48569da57d7bSbt 			/*
48579da57d7bSbt 			 * Schedule the re-transmit
48589da57d7bSbt 			 */
48599da57d7bSbt 			tx_reschedule = (tx_ring->reschedule &&
4860ea65739eSchenlu chen - Sun Microsystems - Beijing China 			    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh));
48619da57d7bSbt 		}
48629da57d7bSbt 
486313740cb2SPaul Guo 		/* any interrupt type other than tx/rx */
486413740cb2SPaul Guo 		if (eicr & ixgbe->capab->other_intr) {
48655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			switch (hw->mac.type) {
48665b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82598EB:
486773cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
48685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
48695b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
48705b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82599EB:
487169b5a878SDan McDonald 			case ixgbe_mac_X540:
4872dc0cb1cdSDale Ghent 			case ixgbe_mac_X550:
4873dc0cb1cdSDale Ghent 			case ixgbe_mac_X550EM_x:
487448ed61a7SRobert Mustacchi 			case ixgbe_mac_X550EM_a:
487573cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe->eimc = IXGBE_82599_OTHER_INTR;
487673cd555cSBin Tu - Sun Microsystems - Beijing China 				IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
48775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
48785b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
48795b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			default:
48805b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
488173cd555cSBin Tu - Sun Microsystems - Beijing China 			}
488213740cb2SPaul Guo 			ixgbe_intr_other_work(ixgbe, eicr);
488373cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
48849da57d7bSbt 		}
48859da57d7bSbt 
488613740cb2SPaul Guo 		mutex_exit(&ixgbe->gen_lock);
488713740cb2SPaul Guo 
48889da57d7bSbt 		result = DDI_INTR_CLAIMED;
48899da57d7bSbt 	} else {
489013740cb2SPaul Guo 		mutex_exit(&ixgbe->gen_lock);
489113740cb2SPaul Guo 
48929da57d7bSbt 		/*
48939da57d7bSbt 		 * No interrupt cause bits set: don't claim this interrupt.
48949da57d7bSbt 		 */
48959da57d7bSbt 		result = DDI_INTR_UNCLAIMED;
48969da57d7bSbt 	}
48979da57d7bSbt 
489813740cb2SPaul Guo 	/* re-enable the interrupts which were automasked */
489913740cb2SPaul Guo 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
49009da57d7bSbt 
49019da57d7bSbt 	/*
49029da57d7bSbt 	 * Do the following work outside of the gen_lock
49039da57d7bSbt 	 */
490473cd555cSBin Tu - Sun Microsystems - Beijing China 	if (mp != NULL) {
4905da14cebeSEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
4906da14cebeSEric Cheng 		    rx_ring->ring_gen_num);
490773cd555cSBin Tu - Sun Microsystems - Beijing China 	}
49089da57d7bSbt 
49099da57d7bSbt 	if (tx_reschedule)  {
49109da57d7bSbt 		tx_ring->reschedule = B_FALSE;
4911da14cebeSEric Cheng 		mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle);
4912a9bfd41dSRyan Zezeski 		tx_ring->stat_reschedule++;
49139da57d7bSbt 	}
49149da57d7bSbt 
49159da57d7bSbt 	return (result);
49169da57d7bSbt }
49179da57d7bSbt 
49189da57d7bSbt /*
49199da57d7bSbt  * ixgbe_intr_msi - Interrupt handler for MSI.
49209da57d7bSbt  */
49219da57d7bSbt static uint_t
ixgbe_intr_msi(void * arg1,void * arg2)49229da57d7bSbt ixgbe_intr_msi(void *arg1, void *arg2)
49239da57d7bSbt {
49249da57d7bSbt 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
49259da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
49269da57d7bSbt 	uint32_t eicr;
49279da57d7bSbt 
492813740cb2SPaul Guo 	_NOTE(ARGUNUSED(arg2));
492913740cb2SPaul Guo 
49309da57d7bSbt 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
49319da57d7bSbt 
493262e6e1adSPaul Guo 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
493362e6e1adSPaul Guo 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
493462e6e1adSPaul Guo 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
493562e6e1adSPaul Guo 		return (DDI_INTR_CLAIMED);
493662e6e1adSPaul Guo 	}
493762e6e1adSPaul Guo 
49389da57d7bSbt 	/*
49399da57d7bSbt 	 * For MSI interrupt, we have only one vector,
49409da57d7bSbt 	 * so we have only one rx ring and one tx ring enabled.
49419da57d7bSbt 	 */
49429da57d7bSbt 	ASSERT(ixgbe->num_rx_rings == 1);
49439da57d7bSbt 	ASSERT(ixgbe->num_tx_rings == 1);
49449da57d7bSbt 
49459da57d7bSbt 	/*
4946da14cebeSEric Cheng 	 * For MSI interrupt, rx rings[0] will use RTxQ[0].
49479da57d7bSbt 	 */
4948da14cebeSEric Cheng 	if (eicr & 0x1) {
49499da57d7bSbt 		ixgbe_intr_rx_work(&ixgbe->rx_rings[0]);
4950da14cebeSEric Cheng 	}
4951da14cebeSEric Cheng 
4952da14cebeSEric Cheng 	/*
4953da14cebeSEric Cheng 	 * For MSI interrupt, tx rings[0] will use RTxQ[1].
4954da14cebeSEric Cheng 	 */
4955da14cebeSEric Cheng 	if (eicr & 0x2) {
49569da57d7bSbt 		ixgbe_intr_tx_work(&ixgbe->tx_rings[0]);
49579da57d7bSbt 	}
49589da57d7bSbt 
495913740cb2SPaul Guo 	/* any interrupt type other than tx/rx */
496013740cb2SPaul Guo 	if (eicr & ixgbe->capab->other_intr) {
496113740cb2SPaul Guo 		mutex_enter(&ixgbe->gen_lock);
49625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		switch (hw->mac.type) {
49635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82598EB:
496473cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
49655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
49665b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
49675b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82599EB:
496869b5a878SDan McDonald 		case ixgbe_mac_X540:
4969dc0cb1cdSDale Ghent 		case ixgbe_mac_X550:
4970dc0cb1cdSDale Ghent 		case ixgbe_mac_X550EM_x:
497148ed61a7SRobert Mustacchi 		case ixgbe_mac_X550EM_a:
497273cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe->eimc = IXGBE_82599_OTHER_INTR;
497373cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
49745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
49755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
49765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		default:
49775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
497873cd555cSBin Tu - Sun Microsystems - Beijing China 		}
497913740cb2SPaul Guo 		ixgbe_intr_other_work(ixgbe, eicr);
498073cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
498113740cb2SPaul Guo 		mutex_exit(&ixgbe->gen_lock);
49829da57d7bSbt 	}
49839da57d7bSbt 
498413740cb2SPaul Guo 	/* re-enable the interrupts which were automasked */
498513740cb2SPaul Guo 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
498613740cb2SPaul Guo 
49879da57d7bSbt 	return (DDI_INTR_CLAIMED);
49889da57d7bSbt }
49899da57d7bSbt 
49909da57d7bSbt /*
499173cd555cSBin Tu - Sun Microsystems - Beijing China  * ixgbe_intr_msix - Interrupt handler for MSI-X.
49929da57d7bSbt  */
49939da57d7bSbt static uint_t
ixgbe_intr_msix(void * arg1,void * arg2)499473cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_msix(void *arg1, void *arg2)
49959da57d7bSbt {
499673cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1;
4997da14cebeSEric Cheng 	ixgbe_t *ixgbe = vect->ixgbe;
499873cd555cSBin Tu - Sun Microsystems - Beijing China 	struct ixgbe_hw *hw = &ixgbe->hw;
499973cd555cSBin Tu - Sun Microsystems - Beijing China 	uint32_t eicr;
5000da14cebeSEric Cheng 	int r_idx = 0;
50019da57d7bSbt 
500213740cb2SPaul Guo 	_NOTE(ARGUNUSED(arg2));
500313740cb2SPaul Guo 
50049da57d7bSbt 	/*
5005da14cebeSEric Cheng 	 * Clean each rx ring that has its bit set in the map
50069da57d7bSbt 	 */
50079da57d7bSbt 	r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1));
50089da57d7bSbt 	while (r_idx >= 0) {
50099da57d7bSbt 		ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]);
50109da57d7bSbt 		r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
50119da57d7bSbt 		    (ixgbe->num_rx_rings - 1));
50129da57d7bSbt 	}
50139da57d7bSbt 
5014da14cebeSEric Cheng 	/*
5015da14cebeSEric Cheng 	 * Clean each tx ring that has its bit set in the map
5016da14cebeSEric Cheng 	 */
5017da14cebeSEric Cheng 	r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1));
5018da14cebeSEric Cheng 	while (r_idx >= 0) {
5019da14cebeSEric Cheng 		ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]);
5020da14cebeSEric Cheng 		r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
5021da14cebeSEric Cheng 		    (ixgbe->num_tx_rings - 1));
5022da14cebeSEric Cheng 	}
5023da14cebeSEric Cheng 
50249da57d7bSbt 
50259da57d7bSbt 	/*
502673cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Clean other interrupt (link change) that has its bit set in the map
50279da57d7bSbt 	 */
502873cd555cSBin Tu - Sun Microsystems - Beijing China 	if (BT_TEST(vect->other_map, 0) == 1) {
502973cd555cSBin Tu - Sun Microsystems - Beijing China 		eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
50309da57d7bSbt 
503162e6e1adSPaul Guo 		if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) !=
503262e6e1adSPaul Guo 		    DDI_FM_OK) {
503362e6e1adSPaul Guo 			ddi_fm_service_impact(ixgbe->dip,
503462e6e1adSPaul Guo 			    DDI_SERVICE_DEGRADED);
503562e6e1adSPaul Guo 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
503662e6e1adSPaul Guo 			return (DDI_INTR_CLAIMED);
503762e6e1adSPaul Guo 		}
503862e6e1adSPaul Guo 
503973cd555cSBin Tu - Sun Microsystems - Beijing China 		/*
50405b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		 * Check "other" cause bits: any interrupt type other than tx/rx
504173cd555cSBin Tu - Sun Microsystems - Beijing China 		 */
504273cd555cSBin Tu - Sun Microsystems - Beijing China 		if (eicr & ixgbe->capab->other_intr) {
50435b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			mutex_enter(&ixgbe->gen_lock);
50445b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			switch (hw->mac.type) {
50455b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82598EB:
504673cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
504773cd555cSBin Tu - Sun Microsystems - Beijing China 				ixgbe_intr_other_work(ixgbe, eicr);
50485b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
50495b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
50505b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			case ixgbe_mac_82599EB:
505169b5a878SDan McDonald 			case ixgbe_mac_X540:
5052dc0cb1cdSDale Ghent 			case ixgbe_mac_X550:
5053dc0cb1cdSDale Ghent 			case ixgbe_mac_X550EM_x:
505448ed61a7SRobert Mustacchi 			case ixgbe_mac_X550EM_a:
50555b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
50565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				ixgbe_intr_other_work(ixgbe, eicr);
50575b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
50585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
50595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			default:
50605b6dd21fSchenlu chen - Sun Microsystems - Beijing China 				break;
506173cd555cSBin Tu - Sun Microsystems - Beijing China 			}
50625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			mutex_exit(&ixgbe->gen_lock);
506373cd555cSBin Tu - Sun Microsystems - Beijing China 		}
506473cd555cSBin Tu - Sun Microsystems - Beijing China 
506573cd555cSBin Tu - Sun Microsystems - Beijing China 		/* re-enable the interrupts which were automasked */
506673cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
506773cd555cSBin Tu - Sun Microsystems - Beijing China 	}
506813740cb2SPaul Guo 
50699da57d7bSbt 	return (DDI_INTR_CLAIMED);
50709da57d7bSbt }
50719da57d7bSbt 
50729da57d7bSbt /*
50739da57d7bSbt  * ixgbe_alloc_intrs - Allocate interrupts for the driver.
50749da57d7bSbt  *
50759da57d7bSbt  * Normal sequence is to try MSI-X; if not sucessful, try MSI;
50769da57d7bSbt  * if not successful, try Legacy.
50779da57d7bSbt  * ixgbe->intr_force can be used to force sequence to start with
50789da57d7bSbt  * any of the 3 types.
50799da57d7bSbt  * If MSI-X is not used, number of tx/rx rings is forced to 1.
50809da57d7bSbt  */
50819da57d7bSbt static int
ixgbe_alloc_intrs(ixgbe_t * ixgbe)50829da57d7bSbt ixgbe_alloc_intrs(ixgbe_t *ixgbe)
50839da57d7bSbt {
50849da57d7bSbt 	dev_info_t *devinfo;
50859da57d7bSbt 	int intr_types;
50869da57d7bSbt 	int rc;
50879da57d7bSbt 
50889da57d7bSbt 	devinfo = ixgbe->dip;
50899da57d7bSbt 
50909da57d7bSbt 	/*
50919da57d7bSbt 	 * Get supported interrupt types
50929da57d7bSbt 	 */
50939da57d7bSbt 	rc = ddi_intr_get_supported_types(devinfo, &intr_types);
50949da57d7bSbt 
50959da57d7bSbt 	if (rc != DDI_SUCCESS) {
50969da57d7bSbt 		ixgbe_log(ixgbe,
50979da57d7bSbt 		    "Get supported interrupt types failed: %d", rc);
50989da57d7bSbt 		return (IXGBE_FAILURE);
50999da57d7bSbt 	}
51009da57d7bSbt 	IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types);
51019da57d7bSbt 
51029da57d7bSbt 	ixgbe->intr_type = 0;
51039da57d7bSbt 
51049da57d7bSbt 	/*
51059da57d7bSbt 	 * Install MSI-X interrupts
51069da57d7bSbt 	 */
51079da57d7bSbt 	if ((intr_types & DDI_INTR_TYPE_MSIX) &&
51089da57d7bSbt 	    (ixgbe->intr_force <= IXGBE_INTR_MSIX)) {
51099da57d7bSbt 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX);
51109da57d7bSbt 		if (rc == IXGBE_SUCCESS)
51119da57d7bSbt 			return (IXGBE_SUCCESS);
51129da57d7bSbt 
51139da57d7bSbt 		ixgbe_log(ixgbe,
51149da57d7bSbt 		    "Allocate MSI-X failed, trying MSI interrupts...");
51159da57d7bSbt 	}
51169da57d7bSbt 
51179da57d7bSbt 	/*
5118da14cebeSEric Cheng 	 * MSI-X not used, force rings and groups to 1
51199da57d7bSbt 	 */
51209da57d7bSbt 	ixgbe->num_rx_rings = 1;
5121da14cebeSEric Cheng 	ixgbe->num_rx_groups = 1;
51229da57d7bSbt 	ixgbe->num_tx_rings = 1;
51230dc2366fSVenugopal Iyer 	ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
51249da57d7bSbt 	ixgbe_log(ixgbe,
5125da14cebeSEric Cheng 	    "MSI-X not used, force rings and groups number to 1");
51269da57d7bSbt 
51279da57d7bSbt 	/*
51289da57d7bSbt 	 * Install MSI interrupts
51299da57d7bSbt 	 */
51309da57d7bSbt 	if ((intr_types & DDI_INTR_TYPE_MSI) &&
51319da57d7bSbt 	    (ixgbe->intr_force <= IXGBE_INTR_MSI)) {
51329da57d7bSbt 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI);
51339da57d7bSbt 		if (rc == IXGBE_SUCCESS)
51349da57d7bSbt 			return (IXGBE_SUCCESS);
51359da57d7bSbt 
51369da57d7bSbt 		ixgbe_log(ixgbe,
51379da57d7bSbt 		    "Allocate MSI failed, trying Legacy interrupts...");
51389da57d7bSbt 	}
51399da57d7bSbt 
51409da57d7bSbt 	/*
51419da57d7bSbt 	 * Install legacy interrupts
51429da57d7bSbt 	 */
51439da57d7bSbt 	if (intr_types & DDI_INTR_TYPE_FIXED) {
5144dc0cb1cdSDale Ghent 		/*
5145dc0cb1cdSDale Ghent 		 * Disallow legacy interrupts for X550. X550 has a silicon
5146dc0cb1cdSDale Ghent 		 * bug which prevents Shared Legacy interrupts from working.
5147dc0cb1cdSDale Ghent 		 * For details, please reference:
5148dc0cb1cdSDale Ghent 		 *
5149dc0cb1cdSDale Ghent 		 * Intel Ethernet Controller X550 Specification Update rev. 2.1
5150dc0cb1cdSDale Ghent 		 * May 2016, erratum 22: PCIe Interrupt Status Bit
5151dc0cb1cdSDale Ghent 		 */
5152dc0cb1cdSDale Ghent 		if (ixgbe->hw.mac.type == ixgbe_mac_X550 ||
5153dc0cb1cdSDale Ghent 		    ixgbe->hw.mac.type == ixgbe_mac_X550EM_x ||
515448ed61a7SRobert Mustacchi 		    ixgbe->hw.mac.type == ixgbe_mac_X550EM_a ||
5155dc0cb1cdSDale Ghent 		    ixgbe->hw.mac.type == ixgbe_mac_X550_vf ||
515648ed61a7SRobert Mustacchi 		    ixgbe->hw.mac.type == ixgbe_mac_X550EM_x_vf ||
515748ed61a7SRobert Mustacchi 		    ixgbe->hw.mac.type == ixgbe_mac_X550EM_a_vf) {
5158dc0cb1cdSDale Ghent 			ixgbe_log(ixgbe,
5159dc0cb1cdSDale Ghent 			    "Legacy interrupts are not supported on this "
5160dc0cb1cdSDale Ghent 			    "adapter. Please use MSI or MSI-X instead.");
5161dc0cb1cdSDale Ghent 			return (IXGBE_FAILURE);
5162dc0cb1cdSDale Ghent 		}
51639da57d7bSbt 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED);
51649da57d7bSbt 		if (rc == IXGBE_SUCCESS)
51659da57d7bSbt 			return (IXGBE_SUCCESS);
51669da57d7bSbt 
51679da57d7bSbt 		ixgbe_log(ixgbe,
51689da57d7bSbt 		    "Allocate Legacy interrupts failed");
51699da57d7bSbt 	}
51709da57d7bSbt 
51719da57d7bSbt 	/*
51729da57d7bSbt 	 * If none of the 3 types succeeded, return failure
51739da57d7bSbt 	 */
51749da57d7bSbt 	return (IXGBE_FAILURE);
51759da57d7bSbt }
51769da57d7bSbt 
51779da57d7bSbt /*
51789da57d7bSbt  * ixgbe_alloc_intr_handles - Allocate interrupt handles.
51799da57d7bSbt  *
51809da57d7bSbt  * For legacy and MSI, only 1 handle is needed.  For MSI-X,
51819da57d7bSbt  * if fewer than 2 handles are available, return failure.
5182da14cebeSEric Cheng  * Upon success, this maps the vectors to rx and tx rings for
5183da14cebeSEric Cheng  * interrupts.
51849da57d7bSbt  */
51859da57d7bSbt static int
ixgbe_alloc_intr_handles(ixgbe_t * ixgbe,int intr_type)51869da57d7bSbt ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type)
51879da57d7bSbt {
51889da57d7bSbt 	dev_info_t *devinfo;
51890dc2366fSVenugopal Iyer 	int request, count, actual;
5190da14cebeSEric Cheng 	int minimum;
51919da57d7bSbt 	int rc;
51920dc2366fSVenugopal Iyer 	uint32_t ring_per_group;
51939da57d7bSbt 
51949da57d7bSbt 	devinfo = ixgbe->dip;
51959da57d7bSbt 
51969da57d7bSbt 	switch (intr_type) {
51979da57d7bSbt 	case DDI_INTR_TYPE_FIXED:
51989da57d7bSbt 		request = 1;	/* Request 1 legacy interrupt handle */
51999da57d7bSbt 		minimum = 1;
52009da57d7bSbt 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy");
52019da57d7bSbt 		break;
52029da57d7bSbt 
52039da57d7bSbt 	case DDI_INTR_TYPE_MSI:
52049da57d7bSbt 		request = 1;	/* Request 1 MSI interrupt handle */
52059da57d7bSbt 		minimum = 1;
52069da57d7bSbt 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI");
52079da57d7bSbt 		break;
52089da57d7bSbt 
52099da57d7bSbt 	case DDI_INTR_TYPE_MSIX:
52109da57d7bSbt 		/*
52119da57d7bSbt 		 * Best number of vectors for the adapter is
52120dc2366fSVenugopal Iyer 		 * (# rx rings + # tx rings), however we will
52130dc2366fSVenugopal Iyer 		 * limit the request number.
52149da57d7bSbt 		 */
52150dc2366fSVenugopal Iyer 		request = min(16, ixgbe->num_rx_rings + ixgbe->num_tx_rings);
521673cd555cSBin Tu - Sun Microsystems - Beijing China 		if (request > ixgbe->capab->max_ring_vect)
521773cd555cSBin Tu - Sun Microsystems - Beijing China 			request = ixgbe->capab->max_ring_vect;
52180dc2366fSVenugopal Iyer 		minimum = 1;
52199da57d7bSbt 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X");
52209da57d7bSbt 		break;
52219da57d7bSbt 
52229da57d7bSbt 	default:
52239da57d7bSbt 		ixgbe_log(ixgbe,
52249da57d7bSbt 		    "invalid call to ixgbe_alloc_intr_handles(): %d\n",
52259da57d7bSbt 		    intr_type);
52269da57d7bSbt 		return (IXGBE_FAILURE);
52279da57d7bSbt 	}
52289da57d7bSbt 	IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d  minimum: %d",
52299da57d7bSbt 	    request, minimum);
52309da57d7bSbt 
52319da57d7bSbt 	/*
52329da57d7bSbt 	 * Get number of supported interrupts
52339da57d7bSbt 	 */
52349da57d7bSbt 	rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
52359da57d7bSbt 	if ((rc != DDI_SUCCESS) || (count < minimum)) {
52369da57d7bSbt 		ixgbe_log(ixgbe,
52379da57d7bSbt 		    "Get interrupt number failed. Return: %d, count: %d",
52389da57d7bSbt 		    rc, count);
52399da57d7bSbt 		return (IXGBE_FAILURE);
52409da57d7bSbt 	}
52419da57d7bSbt 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count);
52429da57d7bSbt 
52439da57d7bSbt 	actual = 0;
52449da57d7bSbt 	ixgbe->intr_cnt = 0;
52450dc2366fSVenugopal Iyer 	ixgbe->intr_cnt_max = 0;
52460dc2366fSVenugopal Iyer 	ixgbe->intr_cnt_min = 0;
52479da57d7bSbt 
52489da57d7bSbt 	/*
52499da57d7bSbt 	 * Allocate an array of interrupt handles
52509da57d7bSbt 	 */
52519da57d7bSbt 	ixgbe->intr_size = request * sizeof (ddi_intr_handle_t);
52529da57d7bSbt 	ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP);
52539da57d7bSbt 
52549da57d7bSbt 	rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0,
52559da57d7bSbt 	    request, &actual, DDI_INTR_ALLOC_NORMAL);
52569da57d7bSbt 	if (rc != DDI_SUCCESS) {
52579da57d7bSbt 		ixgbe_log(ixgbe, "Allocate interrupts failed. "
52589da57d7bSbt 		    "return: %d, request: %d, actual: %d",
52599da57d7bSbt 		    rc, request, actual);
52609da57d7bSbt 		goto alloc_handle_fail;
52619da57d7bSbt 	}
52629da57d7bSbt 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual);
52639da57d7bSbt 
52640dc2366fSVenugopal Iyer 	/*
52650dc2366fSVenugopal Iyer 	 * upper/lower limit of interrupts
52660dc2366fSVenugopal Iyer 	 */
52679da57d7bSbt 	ixgbe->intr_cnt = actual;
52680dc2366fSVenugopal Iyer 	ixgbe->intr_cnt_max = request;
52690dc2366fSVenugopal Iyer 	ixgbe->intr_cnt_min = minimum;
52700dc2366fSVenugopal Iyer 
52710dc2366fSVenugopal Iyer 	/*
52720dc2366fSVenugopal Iyer 	 * rss number per group should not exceed the rx interrupt number,
52730dc2366fSVenugopal Iyer 	 * else need to adjust rx ring number.
52740dc2366fSVenugopal Iyer 	 */
52750dc2366fSVenugopal Iyer 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
52760dc2366fSVenugopal Iyer 	ASSERT((ixgbe->num_rx_rings % ixgbe->num_rx_groups) == 0);
52775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 	if (actual < ring_per_group) {
52785b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		ixgbe->num_rx_rings = ixgbe->num_rx_groups * actual;
52790dc2366fSVenugopal Iyer 		ixgbe_setup_vmdq_rss_conf(ixgbe);
52800dc2366fSVenugopal Iyer 	}
52819da57d7bSbt 
52829da57d7bSbt 	/*
5283da14cebeSEric Cheng 	 * Now we know the actual number of vectors.  Here we map the vector
5284da14cebeSEric Cheng 	 * to other, rx rings and tx ring.
52859da57d7bSbt 	 */
52869da57d7bSbt 	if (actual < minimum) {
52879da57d7bSbt 		ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d",
52889da57d7bSbt 		    actual);
52899da57d7bSbt 		goto alloc_handle_fail;
52909da57d7bSbt 	}
52919da57d7bSbt 
52929da57d7bSbt 	/*
52939da57d7bSbt 	 * Get priority for first vector, assume remaining are all the same
52949da57d7bSbt 	 */
52959da57d7bSbt 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
52969da57d7bSbt 	if (rc != DDI_SUCCESS) {
52979da57d7bSbt 		ixgbe_log(ixgbe,
52989da57d7bSbt 		    "Get interrupt priority failed: %d", rc);
52999da57d7bSbt 		goto alloc_handle_fail;
53009da57d7bSbt 	}
53019da57d7bSbt 
53029da57d7bSbt 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
53039da57d7bSbt 	if (rc != DDI_SUCCESS) {
53049da57d7bSbt 		ixgbe_log(ixgbe,
53059da57d7bSbt 		    "Get interrupt cap failed: %d", rc);
53069da57d7bSbt 		goto alloc_handle_fail;
53079da57d7bSbt 	}
53089da57d7bSbt 
53099da57d7bSbt 	ixgbe->intr_type = intr_type;
53109da57d7bSbt 
53119da57d7bSbt 	return (IXGBE_SUCCESS);
53129da57d7bSbt 
53139da57d7bSbt alloc_handle_fail:
53149da57d7bSbt 	ixgbe_rem_intrs(ixgbe);
53159da57d7bSbt 
53169da57d7bSbt 	return (IXGBE_FAILURE);
53179da57d7bSbt }
53189da57d7bSbt 
53199da57d7bSbt /*
53209da57d7bSbt  * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type.
53219da57d7bSbt  *
53229da57d7bSbt  * Before adding the interrupt handlers, the interrupt vectors have
53239da57d7bSbt  * been allocated, and the rx/tx rings have also been allocated.
53249da57d7bSbt  */
53259da57d7bSbt static int
ixgbe_add_intr_handlers(ixgbe_t * ixgbe)53269da57d7bSbt ixgbe_add_intr_handlers(ixgbe_t *ixgbe)
53279da57d7bSbt {
5328da14cebeSEric Cheng 	int vector = 0;
53299da57d7bSbt 	int rc;
53309da57d7bSbt 
53319da57d7bSbt 	switch (ixgbe->intr_type) {
53329da57d7bSbt 	case DDI_INTR_TYPE_MSIX:
53339da57d7bSbt 		/*
533473cd555cSBin Tu - Sun Microsystems - Beijing China 		 * Add interrupt handler for all vectors
53359da57d7bSbt 		 */
533673cd555cSBin Tu - Sun Microsystems - Beijing China 		for (vector = 0; vector < ixgbe->intr_cnt; vector++) {
53379da57d7bSbt 			/*
53389da57d7bSbt 			 * install pointer to vect_map[vector]
53399da57d7bSbt 			 */
53409da57d7bSbt 			rc = ddi_intr_add_handler(ixgbe->htable[vector],
534173cd555cSBin Tu - Sun Microsystems - Beijing China 			    (ddi_intr_handler_t *)ixgbe_intr_msix,
53429da57d7bSbt 			    (void *)&ixgbe->vect_map[vector], NULL);
53439da57d7bSbt 
53449da57d7bSbt 			if (rc != DDI_SUCCESS) {
53459da57d7bSbt 				ixgbe_log(ixgbe,
534619843f01SPaul Guo 				    "Add interrupt handler failed. "
5347da14cebeSEric Cheng 				    "return: %d, vector: %d", rc, vector);
53489da57d7bSbt 				for (vector--; vector >= 0; vector--) {
53499da57d7bSbt 					(void) ddi_intr_remove_handler(
53509da57d7bSbt 					    ixgbe->htable[vector]);
53519da57d7bSbt 				}
53529da57d7bSbt 				return (IXGBE_FAILURE);
53539da57d7bSbt 			}
5354da14cebeSEric Cheng 		}
53559da57d7bSbt 
53569da57d7bSbt 		break;
53579da57d7bSbt 
53589da57d7bSbt 	case DDI_INTR_TYPE_MSI:
53599da57d7bSbt 		/*
53609da57d7bSbt 		 * Add interrupt handlers for the only vector
53619da57d7bSbt 		 */
53629da57d7bSbt 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
53639da57d7bSbt 		    (ddi_intr_handler_t *)ixgbe_intr_msi,
53649da57d7bSbt 		    (void *)ixgbe, NULL);
53659da57d7bSbt 
53669da57d7bSbt 		if (rc != DDI_SUCCESS) {
53679da57d7bSbt 			ixgbe_log(ixgbe,
53689da57d7bSbt 			    "Add MSI interrupt handler failed: %d", rc);
53699da57d7bSbt 			return (IXGBE_FAILURE);
53709da57d7bSbt 		}
53719da57d7bSbt 
53729da57d7bSbt 		break;
53739da57d7bSbt 
53749da57d7bSbt 	case DDI_INTR_TYPE_FIXED:
53759da57d7bSbt 		/*
53769da57d7bSbt 		 * Add interrupt handlers for the only vector
53779da57d7bSbt 		 */
53789da57d7bSbt 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
53799da57d7bSbt 		    (ddi_intr_handler_t *)ixgbe_intr_legacy,
53809da57d7bSbt 		    (void *)ixgbe, NULL);
53819da57d7bSbt 
53829da57d7bSbt 		if (rc != DDI_SUCCESS) {
53839da57d7bSbt 			ixgbe_log(ixgbe,
53849da57d7bSbt 			    "Add legacy interrupt handler failed: %d", rc);
53859da57d7bSbt 			return (IXGBE_FAILURE);
53869da57d7bSbt 		}
53879da57d7bSbt 
53889da57d7bSbt 		break;
53899da57d7bSbt 
53909da57d7bSbt 	default:
53919da57d7bSbt 		return (IXGBE_FAILURE);
53929da57d7bSbt 	}
53939da57d7bSbt 
53949da57d7bSbt 	return (IXGBE_SUCCESS);
53959da57d7bSbt }
53969da57d7bSbt 
53979da57d7bSbt #pragma inline(ixgbe_map_rxring_to_vector)
53989da57d7bSbt /*
53999da57d7bSbt  * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector.
54009da57d7bSbt  */
54019da57d7bSbt static void
ixgbe_map_rxring_to_vector(ixgbe_t * ixgbe,int r_idx,int v_idx)54029da57d7bSbt ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx)
54039da57d7bSbt {
54049da57d7bSbt 	/*
54059da57d7bSbt 	 * Set bit in map
54069da57d7bSbt 	 */
54079da57d7bSbt 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
54089da57d7bSbt 
54099da57d7bSbt 	/*
54109da57d7bSbt 	 * Count bits set
54119da57d7bSbt 	 */
54129da57d7bSbt 	ixgbe->vect_map[v_idx].rxr_cnt++;
54139da57d7bSbt 
54149da57d7bSbt 	/*
54159da57d7bSbt 	 * Remember bit position
54169da57d7bSbt 	 */
5417da14cebeSEric Cheng 	ixgbe->rx_rings[r_idx].intr_vector = v_idx;
54189da57d7bSbt 	ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx;
54199da57d7bSbt }
54209da57d7bSbt 
54219da57d7bSbt #pragma inline(ixgbe_map_txring_to_vector)
54229da57d7bSbt /*
54239da57d7bSbt  * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector.
54249da57d7bSbt  */
54259da57d7bSbt static void
ixgbe_map_txring_to_vector(ixgbe_t * ixgbe,int t_idx,int v_idx)54269da57d7bSbt ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx)
54279da57d7bSbt {
54289da57d7bSbt 	/*
54299da57d7bSbt 	 * Set bit in map
54309da57d7bSbt 	 */
54319da57d7bSbt 	BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx);
54329da57d7bSbt 
54339da57d7bSbt 	/*
54349da57d7bSbt 	 * Count bits set
54359da57d7bSbt 	 */
54369da57d7bSbt 	ixgbe->vect_map[v_idx].txr_cnt++;
54379da57d7bSbt 
54389da57d7bSbt 	/*
54399da57d7bSbt 	 * Remember bit position
54409da57d7bSbt 	 */
5441da14cebeSEric Cheng 	ixgbe->tx_rings[t_idx].intr_vector = v_idx;
54429da57d7bSbt 	ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx;
54439da57d7bSbt }
54449da57d7bSbt 
54459da57d7bSbt /*
5446da14cebeSEric Cheng  * ixgbe_setup_ivar - Set the given entry in the given interrupt vector
54479da57d7bSbt  * allocation register (IVAR).
544873cd555cSBin Tu - Sun Microsystems - Beijing China  * cause:
544973cd555cSBin Tu - Sun Microsystems - Beijing China  *   -1 : other cause
545073cd555cSBin Tu - Sun Microsystems - Beijing China  *    0 : rx
545173cd555cSBin Tu - Sun Microsystems - Beijing China  *    1 : tx
54529da57d7bSbt  */
54539da57d7bSbt static void
ixgbe_setup_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,uint8_t msix_vector,int8_t cause)545473cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector,
545573cd555cSBin Tu - Sun Microsystems - Beijing China     int8_t cause)
54569da57d7bSbt {
54579da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
54589da57d7bSbt 	u32 ivar, index;
54599da57d7bSbt 
546073cd555cSBin Tu - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
546173cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
546273cd555cSBin Tu - Sun Microsystems - Beijing China 		msix_vector |= IXGBE_IVAR_ALLOC_VAL;
546373cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
546473cd555cSBin Tu - Sun Microsystems - Beijing China 			cause = 0;
546573cd555cSBin Tu - Sun Microsystems - Beijing China 		}
546673cd555cSBin Tu - Sun Microsystems - Beijing China 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
546773cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
546873cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3)));
546973cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3)));
547073cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
547173cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
54725b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
547373cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
547469b5a878SDan McDonald 	case ixgbe_mac_X540:
5475dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
5476dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
547748ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
547873cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
547973cd555cSBin Tu - Sun Microsystems - Beijing China 			/* other causes */
548073cd555cSBin Tu - Sun Microsystems - Beijing China 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
548173cd555cSBin Tu - Sun Microsystems - Beijing China 			index = (intr_alloc_entry & 1) * 8;
548273cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
548373cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar &= ~(0xFF << index);
548473cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar |= (msix_vector << index);
548573cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
548673cd555cSBin Tu - Sun Microsystems - Beijing China 		} else {
548773cd555cSBin Tu - Sun Microsystems - Beijing China 			/* tx or rx causes */
548873cd555cSBin Tu - Sun Microsystems - Beijing China 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
548973cd555cSBin Tu - Sun Microsystems - Beijing China 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
549073cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw,
549173cd555cSBin Tu - Sun Microsystems - Beijing China 			    IXGBE_IVAR(intr_alloc_entry >> 1));
549273cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar &= ~(0xFF << index);
549373cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar |= (msix_vector << index);
549473cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
549573cd555cSBin Tu - Sun Microsystems - Beijing China 			    ivar);
549673cd555cSBin Tu - Sun Microsystems - Beijing China 		}
549773cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
54985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
549973cd555cSBin Tu - Sun Microsystems - Beijing China 	default:
550073cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
550173cd555cSBin Tu - Sun Microsystems - Beijing China 	}
5502da14cebeSEric Cheng }
5503da14cebeSEric Cheng 
5504da14cebeSEric Cheng /*
5505da14cebeSEric Cheng  * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of
5506da14cebeSEric Cheng  * given interrupt vector allocation register (IVAR).
550773cd555cSBin Tu - Sun Microsystems - Beijing China  * cause:
550873cd555cSBin Tu - Sun Microsystems - Beijing China  *   -1 : other cause
550973cd555cSBin Tu - Sun Microsystems - Beijing China  *    0 : rx
551073cd555cSBin Tu - Sun Microsystems - Beijing China  *    1 : tx
5511da14cebeSEric Cheng  */
5512da14cebeSEric Cheng static void
ixgbe_enable_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,int8_t cause)551373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
5514da14cebeSEric Cheng {
5515da14cebeSEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
5516da14cebeSEric Cheng 	u32 ivar, index;
5517da14cebeSEric Cheng 
551873cd555cSBin Tu - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
551973cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
552073cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
552173cd555cSBin Tu - Sun Microsystems - Beijing China 			cause = 0;
552273cd555cSBin Tu - Sun Microsystems - Beijing China 		}
552373cd555cSBin Tu - Sun Microsystems - Beijing China 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
552473cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
552573cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 *
552673cd555cSBin Tu - Sun Microsystems - Beijing China 		    (intr_alloc_entry & 0x3)));
552773cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
552873cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
55295b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
553073cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
553169b5a878SDan McDonald 	case ixgbe_mac_X540:
5532dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
5533dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
553448ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
553573cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
553673cd555cSBin Tu - Sun Microsystems - Beijing China 			/* other causes */
553773cd555cSBin Tu - Sun Microsystems - Beijing China 			index = (intr_alloc_entry & 1) * 8;
553873cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
553973cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
554073cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
554173cd555cSBin Tu - Sun Microsystems - Beijing China 		} else {
554273cd555cSBin Tu - Sun Microsystems - Beijing China 			/* tx or rx causes */
554373cd555cSBin Tu - Sun Microsystems - Beijing China 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
554473cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw,
554573cd555cSBin Tu - Sun Microsystems - Beijing China 			    IXGBE_IVAR(intr_alloc_entry >> 1));
554673cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
554773cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
554873cd555cSBin Tu - Sun Microsystems - Beijing China 			    ivar);
554973cd555cSBin Tu - Sun Microsystems - Beijing China 		}
555073cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
55515b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
555273cd555cSBin Tu - Sun Microsystems - Beijing China 	default:
555373cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
555473cd555cSBin Tu - Sun Microsystems - Beijing China 	}
5555da14cebeSEric Cheng }
5556da14cebeSEric Cheng 
5557da14cebeSEric Cheng /*
555873cd555cSBin Tu - Sun Microsystems - Beijing China  * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of
5559da14cebeSEric Cheng  * given interrupt vector allocation register (IVAR).
556073cd555cSBin Tu - Sun Microsystems - Beijing China  * cause:
556173cd555cSBin Tu - Sun Microsystems - Beijing China  *   -1 : other cause
556273cd555cSBin Tu - Sun Microsystems - Beijing China  *    0 : rx
556373cd555cSBin Tu - Sun Microsystems - Beijing China  *    1 : tx
5564da14cebeSEric Cheng  */
5565da14cebeSEric Cheng static void
ixgbe_disable_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,int8_t cause)556673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
5567da14cebeSEric Cheng {
5568da14cebeSEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
5569da14cebeSEric Cheng 	u32 ivar, index;
5570da14cebeSEric Cheng 
557173cd555cSBin Tu - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
557273cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
557373cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
557473cd555cSBin Tu - Sun Microsystems - Beijing China 			cause = 0;
557573cd555cSBin Tu - Sun Microsystems - Beijing China 		}
557673cd555cSBin Tu - Sun Microsystems - Beijing China 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
557773cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
557873cd555cSBin Tu - Sun Microsystems - Beijing China 		ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 *
557973cd555cSBin Tu - Sun Microsystems - Beijing China 		    (intr_alloc_entry & 0x3)));
558073cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
558173cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
55825b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
558373cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
558469b5a878SDan McDonald 	case ixgbe_mac_X540:
5585dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
5586dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
558748ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
558873cd555cSBin Tu - Sun Microsystems - Beijing China 		if (cause == -1) {
558973cd555cSBin Tu - Sun Microsystems - Beijing China 			/* other causes */
559073cd555cSBin Tu - Sun Microsystems - Beijing China 			index = (intr_alloc_entry & 1) * 8;
559173cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
559273cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
559373cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
559473cd555cSBin Tu - Sun Microsystems - Beijing China 		} else {
559573cd555cSBin Tu - Sun Microsystems - Beijing China 			/* tx or rx causes */
559673cd555cSBin Tu - Sun Microsystems - Beijing China 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
559773cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar = IXGBE_READ_REG(hw,
559873cd555cSBin Tu - Sun Microsystems - Beijing China 			    IXGBE_IVAR(intr_alloc_entry >> 1));
559973cd555cSBin Tu - Sun Microsystems - Beijing China 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
560073cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
560173cd555cSBin Tu - Sun Microsystems - Beijing China 			    ivar);
560273cd555cSBin Tu - Sun Microsystems - Beijing China 		}
560373cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
56045b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
560573cd555cSBin Tu - Sun Microsystems - Beijing China 	default:
560673cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
560773cd555cSBin Tu - Sun Microsystems - Beijing China 	}
56089da57d7bSbt }
56099da57d7bSbt 
56100dc2366fSVenugopal Iyer /*
56110dc2366fSVenugopal Iyer  * Convert the rx ring index driver maintained to the rx ring index
56120dc2366fSVenugopal Iyer  * in h/w.
56130dc2366fSVenugopal Iyer  */
56140dc2366fSVenugopal Iyer static uint32_t
ixgbe_get_hw_rx_index(ixgbe_t * ixgbe,uint32_t sw_rx_index)56150dc2366fSVenugopal Iyer ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index)
56160dc2366fSVenugopal Iyer {
56170dc2366fSVenugopal Iyer 
56180dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
56190dc2366fSVenugopal Iyer 	uint32_t rx_ring_per_group, hw_rx_index;
56200dc2366fSVenugopal Iyer 
56210dc2366fSVenugopal Iyer 	if (ixgbe->classify_mode == IXGBE_CLASSIFY_RSS ||
56220dc2366fSVenugopal Iyer 	    ixgbe->classify_mode == IXGBE_CLASSIFY_NONE) {
56230dc2366fSVenugopal Iyer 		return (sw_rx_index);
56240dc2366fSVenugopal Iyer 	} else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ) {
56255b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		switch (hw->mac.type) {
56265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82598EB:
56270dc2366fSVenugopal Iyer 			return (sw_rx_index);
56285b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
56295b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82599EB:
563069b5a878SDan McDonald 		case ixgbe_mac_X540:
5631dc0cb1cdSDale Ghent 		case ixgbe_mac_X550:
5632dc0cb1cdSDale Ghent 		case ixgbe_mac_X550EM_x:
563348ed61a7SRobert Mustacchi 		case ixgbe_mac_X550EM_a:
56340dc2366fSVenugopal Iyer 			return (sw_rx_index * 2);
56355b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
56365b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		default:
56375b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
56380dc2366fSVenugopal Iyer 		}
56390dc2366fSVenugopal Iyer 	} else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) {
56400dc2366fSVenugopal Iyer 		rx_ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
56410dc2366fSVenugopal Iyer 
56425b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		switch (hw->mac.type) {
56435b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82598EB:
56440dc2366fSVenugopal Iyer 			hw_rx_index = (sw_rx_index / rx_ring_per_group) *
56450dc2366fSVenugopal Iyer 			    16 + (sw_rx_index % rx_ring_per_group);
56460dc2366fSVenugopal Iyer 			return (hw_rx_index);
56475b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
56485b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		case ixgbe_mac_82599EB:
564969b5a878SDan McDonald 		case ixgbe_mac_X540:
5650dc0cb1cdSDale Ghent 		case ixgbe_mac_X550:
5651dc0cb1cdSDale Ghent 		case ixgbe_mac_X550EM_x:
565248ed61a7SRobert Mustacchi 		case ixgbe_mac_X550EM_a:
56530dc2366fSVenugopal Iyer 			if (ixgbe->num_rx_groups > 32) {
56540dc2366fSVenugopal Iyer 				hw_rx_index = (sw_rx_index /
56550dc2366fSVenugopal Iyer 				    rx_ring_per_group) * 2 +
56560dc2366fSVenugopal Iyer 				    (sw_rx_index % rx_ring_per_group);
56570dc2366fSVenugopal Iyer 			} else {
56580dc2366fSVenugopal Iyer 				hw_rx_index = (sw_rx_index /
56590dc2366fSVenugopal Iyer 				    rx_ring_per_group) * 4 +
56600dc2366fSVenugopal Iyer 				    (sw_rx_index % rx_ring_per_group);
56610dc2366fSVenugopal Iyer 			}
56620dc2366fSVenugopal Iyer 			return (hw_rx_index);
56635b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
56645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 		default:
56655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 			break;
56660dc2366fSVenugopal Iyer 		}
56670dc2366fSVenugopal Iyer 	}
56680dc2366fSVenugopal Iyer 
56690dc2366fSVenugopal Iyer 	/*
56700dc2366fSVenugopal Iyer 	 * Should never reach. Just to make compiler happy.
56710dc2366fSVenugopal Iyer 	 */
56720dc2366fSVenugopal Iyer 	return (sw_rx_index);
56730dc2366fSVenugopal Iyer }
56740dc2366fSVenugopal Iyer 
56759da57d7bSbt /*
567673cd555cSBin Tu - Sun Microsystems - Beijing China  * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors.
56779da57d7bSbt  *
567873cd555cSBin Tu - Sun Microsystems - Beijing China  * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt
567973cd555cSBin Tu - Sun Microsystems - Beijing China  * to vector[0 - (intr_cnt -1)].
56809da57d7bSbt  */
56819da57d7bSbt static int
ixgbe_map_intrs_to_vectors(ixgbe_t * ixgbe)568273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe)
56839da57d7bSbt {
56849da57d7bSbt 	int i, vector = 0;
56859da57d7bSbt 
56869da57d7bSbt 	/* initialize vector map */
56879da57d7bSbt 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
568873cd555cSBin Tu - Sun Microsystems - Beijing China 	for (i = 0; i < ixgbe->intr_cnt; i++) {
568973cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe->vect_map[i].ixgbe = ixgbe;
569073cd555cSBin Tu - Sun Microsystems - Beijing China 	}
56919da57d7bSbt 
56929da57d7bSbt 	/*
5693da14cebeSEric Cheng 	 * non-MSI-X case is very simple: rx rings[0] on RTxQ[0],
5694da14cebeSEric Cheng 	 * tx rings[0] on RTxQ[1].
56959da57d7bSbt 	 */
56969da57d7bSbt 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
56979da57d7bSbt 		ixgbe_map_rxring_to_vector(ixgbe, 0, 0);
5698da14cebeSEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, 0, 1);
56999da57d7bSbt 		return (IXGBE_SUCCESS);
57009da57d7bSbt 	}
57019da57d7bSbt 
57029da57d7bSbt 	/*
570373cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Interrupts/vectors mapping for MSI-X
57049da57d7bSbt 	 */
57059da57d7bSbt 
57069da57d7bSbt 	/*
570773cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Map other interrupt to vector 0,
570873cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Set bit in map and count the bits set.
570973cd555cSBin Tu - Sun Microsystems - Beijing China 	 */
571073cd555cSBin Tu - Sun Microsystems - Beijing China 	BT_SET(ixgbe->vect_map[vector].other_map, 0);
571173cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe->vect_map[vector].other_cnt++;
571273cd555cSBin Tu - Sun Microsystems - Beijing China 
571373cd555cSBin Tu - Sun Microsystems - Beijing China 	/*
571473cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Map rx ring interrupts to vectors
57159da57d7bSbt 	 */
5716da14cebeSEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
5717da14cebeSEric Cheng 		ixgbe_map_rxring_to_vector(ixgbe, i, vector);
571873cd555cSBin Tu - Sun Microsystems - Beijing China 		vector = (vector +1) % ixgbe->intr_cnt;
5719da14cebeSEric Cheng 	}
57209da57d7bSbt 
57219da57d7bSbt 	/*
572273cd555cSBin Tu - Sun Microsystems - Beijing China 	 * Map tx ring interrupts to vectors
57239da57d7bSbt 	 */
5724da14cebeSEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
5725da14cebeSEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, i, vector);
572673cd555cSBin Tu - Sun Microsystems - Beijing China 		vector = (vector +1) % ixgbe->intr_cnt;
57279da57d7bSbt 	}
57289da57d7bSbt 
57299da57d7bSbt 	return (IXGBE_SUCCESS);
57309da57d7bSbt }
57319da57d7bSbt 
57329da57d7bSbt /*
57339da57d7bSbt  * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s).
57349da57d7bSbt  *
5735da14cebeSEric Cheng  * This relies on ring/vector mapping already set up in the
57369da57d7bSbt  * vect_map[] structures
57379da57d7bSbt  */
57389da57d7bSbt static void
ixgbe_setup_adapter_vector(ixgbe_t * ixgbe)57399da57d7bSbt ixgbe_setup_adapter_vector(ixgbe_t *ixgbe)
57409da57d7bSbt {
57419da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
574273cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_intr_vector_t *vect;	/* vector bitmap */
5743da14cebeSEric Cheng 	int r_idx;	/* ring index */
5744da14cebeSEric Cheng 	int v_idx;	/* vector index */
57450dc2366fSVenugopal Iyer 	uint32_t hw_index;
57469da57d7bSbt 
57479da57d7bSbt 	/*
57489da57d7bSbt 	 * Clear any previous entries
57499da57d7bSbt 	 */
575073cd555cSBin Tu - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
575173cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82598EB:
575273cd555cSBin Tu - Sun Microsystems - Beijing China 		for (v_idx = 0; v_idx < 25; v_idx++)
575373cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
575473cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
57555b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
575673cd555cSBin Tu - Sun Microsystems - Beijing China 	case ixgbe_mac_82599EB:
575769b5a878SDan McDonald 	case ixgbe_mac_X540:
5758dc0cb1cdSDale Ghent 	case ixgbe_mac_X550:
5759dc0cb1cdSDale Ghent 	case ixgbe_mac_X550EM_x:
576048ed61a7SRobert Mustacchi 	case ixgbe_mac_X550EM_a:
576173cd555cSBin Tu - Sun Microsystems - Beijing China 		for (v_idx = 0; v_idx < 64; v_idx++)
576273cd555cSBin Tu - Sun Microsystems - Beijing China 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
576373cd555cSBin Tu - Sun Microsystems - Beijing China 		IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0);
576473cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
57655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
576673cd555cSBin Tu - Sun Microsystems - Beijing China 	default:
576773cd555cSBin Tu - Sun Microsystems - Beijing China 		break;
576873cd555cSBin Tu - Sun Microsystems - Beijing China 	}
57699da57d7bSbt 
57709da57d7bSbt 	/*
5771da14cebeSEric Cheng 	 * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and
5772da14cebeSEric Cheng 	 * tx rings[0] will use RTxQ[1].
5773da14cebeSEric Cheng 	 */
5774da14cebeSEric Cheng 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
577573cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_setup_ivar(ixgbe, 0, 0, 0);
577673cd555cSBin Tu - Sun Microsystems - Beijing China 		ixgbe_setup_ivar(ixgbe, 0, 1, 1);
5777da14cebeSEric Cheng 		return;
5778da14cebeSEric Cheng 	}
5779da14cebeSEric Cheng 
5780da14cebeSEric Cheng 	/*
578173cd555cSBin Tu - Sun Microsystems - Beijing China 	 * For MSI-X interrupt, "Other" is always on vector[0].
57829da57d7bSbt 	 */
578373cd555cSBin Tu - Sun Microsystems - Beijing China 	ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1);
57849da57d7bSbt 
57859da57d7bSbt 	/*
57869da57d7bSbt 	 * For each interrupt vector, populate the IVAR table
57879da57d7bSbt 	 */
57889da57d7bSbt 	for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) {
57899da57d7bSbt 		vect = &ixgbe->vect_map[v_idx];
57909da57d7bSbt 
57919da57d7bSbt 		/*
57929da57d7bSbt 		 * For each rx ring bit set
57939da57d7bSbt 		 */
57949da57d7bSbt 		r_idx = bt_getlowbit(vect->rx_map, 0,
57959da57d7bSbt 		    (ixgbe->num_rx_rings - 1));
57969da57d7bSbt 
57979da57d7bSbt 		while (r_idx >= 0) {
57980dc2366fSVenugopal Iyer 			hw_index = ixgbe->rx_rings[r_idx].hw_index;
57990dc2366fSVenugopal Iyer 			ixgbe_setup_ivar(ixgbe, hw_index, v_idx, 0);
58009da57d7bSbt 			r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
58019da57d7bSbt 			    (ixgbe->num_rx_rings - 1));
58029da57d7bSbt 		}
58039da57d7bSbt 
58049da57d7bSbt 		/*
58059da57d7bSbt 		 * For each tx ring bit set
58069da57d7bSbt 		 */
58079da57d7bSbt 		r_idx = bt_getlowbit(vect->tx_map, 0,
58089da57d7bSbt 		    (ixgbe->num_tx_rings - 1));
58099da57d7bSbt 
58109da57d7bSbt 		while (r_idx >= 0) {
581173cd555cSBin Tu - Sun Microsystems - Beijing China 			ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1);
58129da57d7bSbt 			r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
58139da57d7bSbt 			    (ixgbe->num_tx_rings - 1));
58149da57d7bSbt 		}
58159da57d7bSbt 	}
58169da57d7bSbt }
58179da57d7bSbt 
58189da57d7bSbt /*
58199da57d7bSbt  * ixgbe_rem_intr_handlers - Remove the interrupt handlers.
58209da57d7bSbt  */
58219da57d7bSbt static void
ixgbe_rem_intr_handlers(ixgbe_t * ixgbe)58229da57d7bSbt ixgbe_rem_intr_handlers(ixgbe_t *ixgbe)
58239da57d7bSbt {
58249da57d7bSbt 	int i;
58259da57d7bSbt 	int rc;
58269da57d7bSbt 
58279da57d7bSbt 	for (i = 0; i < ixgbe->intr_cnt; i++) {
58289da57d7bSbt 		rc = ddi_intr_remove_handler(ixgbe->htable[i]);
58299da57d7bSbt 		if (rc != DDI_SUCCESS) {
58309da57d7bSbt 			IXGBE_DEBUGLOG_1(ixgbe,
58319da57d7bSbt 			    "Remove intr handler failed: %d", rc);
58329da57d7bSbt 		}
58339da57d7bSbt 	}
58349da57d7bSbt }
58359da57d7bSbt 
58369da57d7bSbt /*
58379da57d7bSbt  * ixgbe_rem_intrs - Remove the allocated interrupts.
58389da57d7bSbt  */
58399da57d7bSbt static void
ixgbe_rem_intrs(ixgbe_t * ixgbe)58409da57d7bSbt ixgbe_rem_intrs(ixgbe_t *ixgbe)
58419da57d7bSbt {
58429da57d7bSbt 	int i;
58439da57d7bSbt 	int rc;
58449da57d7bSbt 
58459da57d7bSbt 	for (i = 0; i < ixgbe->intr_cnt; i++) {
58469da57d7bSbt 		rc = ddi_intr_free(ixgbe->htable[i]);
58479da57d7bSbt 		if (rc != DDI_SUCCESS) {
58489da57d7bSbt 			IXGBE_DEBUGLOG_1(ixgbe,
58499da57d7bSbt 			    "Free intr failed: %d", rc);
58509da57d7bSbt 		}
58519da57d7bSbt 	}
58529da57d7bSbt 
58539da57d7bSbt 	kmem_free(ixgbe->htable, ixgbe->intr_size);
58549da57d7bSbt 	ixgbe->htable = NULL;
58559da57d7bSbt }
58569da57d7bSbt 
58579da57d7bSbt /*
58589da57d7bSbt  * ixgbe_enable_intrs - Enable all the ddi interrupts.
58599da57d7bSbt  */
58609da57d7bSbt static int
ixgbe_enable_intrs(ixgbe_t * ixgbe)58619da57d7bSbt ixgbe_enable_intrs(ixgbe_t *ixgbe)
58629da57d7bSbt {
58639da57d7bSbt 	int i;
58649da57d7bSbt 	int rc;
58659da57d7bSbt 
58669da57d7bSbt 	/*
58679da57d7bSbt 	 * Enable interrupts
58689da57d7bSbt 	 */
58699da57d7bSbt 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
58709da57d7bSbt 		/*
58719da57d7bSbt 		 * Call ddi_intr_block_enable() for MSI
58729da57d7bSbt 		 */
58739da57d7bSbt 		rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt);
58749da57d7bSbt 		if (rc != DDI_SUCCESS) {
58759da57d7bSbt 			ixgbe_log(ixgbe,
58769da57d7bSbt 			    "Enable block intr failed: %d", rc);
58779da57d7bSbt 			return (IXGBE_FAILURE);
58789da57d7bSbt 		}
58799da57d7bSbt 	} else {
58809da57d7bSbt 		/*
58819da57d7bSbt 		 * Call ddi_intr_enable() for Legacy/MSI non block enable
58829da57d7bSbt 		 */
58839da57d7bSbt 		for (i = 0; i < ixgbe->intr_cnt; i++) {
58849da57d7bSbt 			rc = ddi_intr_enable(ixgbe->htable[i]);
58859da57d7bSbt 			if (rc != DDI_SUCCESS) {
58869da57d7bSbt 				ixgbe_log(ixgbe,
58879da57d7bSbt 				    "Enable intr failed: %d", rc);
58889da57d7bSbt 				return (IXGBE_FAILURE);
58899da57d7bSbt 			}
58909da57d7bSbt 		}
58919da57d7bSbt 	}
58929da57d7bSbt 
58939da57d7bSbt 	return (IXGBE_SUCCESS);
58949da57d7bSbt }
58959da57d7bSbt 
58969da57d7bSbt /*
58979da57d7bSbt  * ixgbe_disable_intrs - Disable all the interrupts.
58989da57d7bSbt  */
58999da57d7bSbt static int
ixgbe_disable_intrs(ixgbe_t * ixgbe)59009da57d7bSbt ixgbe_disable_intrs(ixgbe_t *ixgbe)
59019da57d7bSbt {
59029da57d7bSbt 	int i;
59039da57d7bSbt 	int rc;
59049da57d7bSbt 
59059da57d7bSbt 	/*
59069da57d7bSbt 	 * Disable all interrupts
59079da57d7bSbt 	 */
59089da57d7bSbt 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
59099da57d7bSbt 		rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt);
59109da57d7bSbt 		if (rc != DDI_SUCCESS) {
59119da57d7bSbt 			ixgbe_log(ixgbe,
59129da57d7bSbt 			    "Disable block intr failed: %d", rc);
59139da57d7bSbt 			return (IXGBE_FAILURE);
59149da57d7bSbt 		}
59159da57d7bSbt 	} else {
59169da57d7bSbt 		for (i = 0; i < ixgbe->intr_cnt; i++) {
59179da57d7bSbt 			rc = ddi_intr_disable(ixgbe->htable[i]);
59189da57d7bSbt 			if (rc != DDI_SUCCESS) {
59199da57d7bSbt 				ixgbe_log(ixgbe,
59209da57d7bSbt 				    "Disable intr failed: %d", rc);
59219da57d7bSbt 				return (IXGBE_FAILURE);
59229da57d7bSbt 			}
59239da57d7bSbt 		}
59249da57d7bSbt 	}
59259da57d7bSbt 
59269da57d7bSbt 	return (IXGBE_SUCCESS);
59279da57d7bSbt }
59289da57d7bSbt 
59299da57d7bSbt /*
59309da57d7bSbt  * ixgbe_get_hw_state - Get and save parameters related to adapter hardware.
59319da57d7bSbt  */
59329da57d7bSbt static void
ixgbe_get_hw_state(ixgbe_t * ixgbe)59339da57d7bSbt ixgbe_get_hw_state(ixgbe_t *ixgbe)
59349da57d7bSbt {
59359da57d7bSbt 	struct ixgbe_hw *hw = &ixgbe->hw;
5936dc0cb1cdSDale Ghent 	ixgbe_link_speed speed = 0;
593713740cb2SPaul Guo 	boolean_t link_up = B_FALSE;
59389da57d7bSbt 	uint32_t pcs1g_anlp = 0;
59399da57d7bSbt 
59409da57d7bSbt 	ASSERT(mutex_owned(&ixgbe->gen_lock));
59419da57d7bSbt 	ixgbe->param_lp_1000fdx_cap = 0;
59429da57d7bSbt 	ixgbe->param_lp_100fdx_cap  = 0;
59439da57d7bSbt 
594413740cb2SPaul Guo 	/* check for link, don't wait */
5945dc0cb1cdSDale Ghent 	(void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
5946*633c5e5cSRobert Mustacchi 	ixgbe->phys_supported = ixgbe_get_supported_physical_layer(hw);
59475b6dd21fSchenlu chen - Sun Microsystems - Beijing China 
5948dc0cb1cdSDale Ghent 	/*
5949dc0cb1cdSDale Ghent 	 * Update the observed Link Partner's capabilities. Not all adapters
5950dc0cb1cdSDale Ghent 	 * can provide full information on the LP's capable speeds, so we
5951dc0cb1cdSDale Ghent 	 * provide what we can.
5952dc0cb1cdSDale Ghent 	 */
595313740cb2SPaul Guo 	if (link_up) {
59549da57d7bSbt 		pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
59559da57d7bSbt 
59569da57d7bSbt 		ixgbe->param_lp_1000fdx_cap =
59579da57d7bSbt 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
59589da57d7bSbt 		ixgbe->param_lp_100fdx_cap =
59599da57d7bSbt 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
59609da57d7bSbt 	}
59619da57d7bSbt 
5962dc0cb1cdSDale Ghent 	/*
5963dc0cb1cdSDale Ghent 	 * Update GLD's notion of the adapter's currently advertised speeds.
5964dc0cb1cdSDale Ghent 	 * Since the common code doesn't always record the current autonegotiate
5965dc0cb1cdSDale Ghent 	 * settings in the phy struct for all parts (specifically, adapters with
5966dc0cb1cdSDale Ghent 	 * SFPs) we first test to see if it is 0, and if so, we fall back to
5967dc0cb1cdSDale Ghent 	 * using the adapter's speed capabilities which we saved during instance
5968dc0cb1cdSDale Ghent 	 * init in ixgbe_init_params().
5969dc0cb1cdSDale Ghent 	 *
5970dc0cb1cdSDale Ghent 	 * Adapters with SFPs will always be shown as advertising all of their
5971dc0cb1cdSDale Ghent 	 * supported speeds, and adapters with baseT PHYs (where the phy struct
5972dc0cb1cdSDale Ghent 	 * is maintained by the common code) will always have a factual view of
5973dc0cb1cdSDale Ghent 	 * their currently-advertised speeds. In the case of SFPs, this is
5974dc0cb1cdSDale Ghent 	 * acceptable as we default to advertising all speeds that the adapter
5975dc0cb1cdSDale Ghent 	 * claims to support, and those properties are immutable; unlike on
5976dc0cb1cdSDale Ghent 	 * baseT (copper) PHYs, where speeds can be enabled or disabled at will.
5977dc0cb1cdSDale Ghent 	 */
5978dc0cb1cdSDale Ghent 	speed = hw->phy.autoneg_advertised;
5979dc0cb1cdSDale Ghent 	if (speed == 0)
5980dc0cb1cdSDale Ghent 		speed = ixgbe->speeds_supported;
5981dc0cb1cdSDale Ghent 
5982dc0cb1cdSDale Ghent 	ixgbe->param_adv_10000fdx_cap =
5983dc0cb1cdSDale Ghent 	    (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 1 : 0;
5984dc0cb1cdSDale Ghent 	ixgbe->param_adv_5000fdx_cap =
5985dc0cb1cdSDale Ghent 	    (speed & IXGBE_LINK_SPEED_5GB_FULL) ? 1 : 0;
5986dc0cb1cdSDale Ghent 	ixgbe->param_adv_2500fdx_cap =
5987dc0cb1cdSDale Ghent 	    (speed & IXGBE_LINK_SPEED_2_5GB_FULL) ? 1 : 0;
5988dc0cb1cdSDale Ghent 	ixgbe->param_adv_1000fdx_cap =
5989dc0cb1cdSDale Ghent 	    (speed & IXGBE_LINK_SPEED_1GB_FULL) ? 1 : 0;
5990dc0cb1cdSDale Ghent 	ixgbe->param_adv_100fdx_cap =
5991dc0cb1cdSDale Ghent 	    (speed & IXGBE_LINK_SPEED_100_FULL) ? 1 : 0;
59929da57d7bSbt }
59939da57d7bSbt 
59949da57d7bSbt /*
59959da57d7bSbt  * ixgbe_get_driver_control - Notify that driver is in control of device.
59969da57d7bSbt  */
59979da57d7bSbt static void
ixgbe_get_driver_control(struct ixgbe_hw * hw)59989da57d7bSbt ixgbe_get_driver_control(struct ixgbe_hw *hw)
59999da57d7bSbt {
60009da57d7bSbt 	uint32_t ctrl_ext;
60019da57d7bSbt 
60029da57d7bSbt 	/*
60039da57d7bSbt 	 * Notify firmware that driver is in control of device
60049da57d7bSbt 	 */
60059da57d7bSbt 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
60069da57d7bSbt 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
60079da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
60089da57d7bSbt }
60099da57d7bSbt 
60109da57d7bSbt /*
60119da57d7bSbt  * ixgbe_release_driver_control - Notify that driver is no longer in control
60129da57d7bSbt  * of device.
60139da57d7bSbt  */
60149da57d7bSbt static void
ixgbe_release_driver_control(struct ixgbe_hw * hw)60159da57d7bSbt ixgbe_release_driver_control(struct ixgbe_hw *hw)
60169da57d7bSbt {
60179da57d7bSbt 	uint32_t ctrl_ext;
60189da57d7bSbt 
60199da57d7bSbt 	/*
60209da57d7bSbt 	 * Notify firmware that driver is no longer in control of device
60219da57d7bSbt 	 */
60229da57d7bSbt 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
60239da57d7bSbt 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
60249da57d7bSbt 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
60259da57d7bSbt }
60269da57d7bSbt 
60279da57d7bSbt /*
60289da57d7bSbt  * ixgbe_atomic_reserve - Atomic decrease operation.
60299da57d7bSbt  */
60309da57d7bSbt int
ixgbe_atomic_reserve(uint32_t * count_p,uint32_t n)60319da57d7bSbt ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n)
60329da57d7bSbt {
60339da57d7bSbt 	uint32_t oldval;
60349da57d7bSbt 	uint32_t newval;
60359da57d7bSbt 
60369da57d7bSbt 	/*
60379da57d7bSbt 	 * ATOMICALLY
60389da57d7bSbt 	 */
60399da57d7bSbt 	do {
60409da57d7bSbt 		oldval = *count_p;
60419da57d7bSbt 		if (oldval < n)
60429da57d7bSbt 			return (-1);
60439da57d7bSbt 		newval = oldval - n;
60449da57d7bSbt 	} while (atomic_cas_32(count_p, oldval, newval) != oldval);
60459da57d7bSbt 
60469da57d7bSbt 	return (newval);
60479da57d7bSbt }
60489da57d7bSbt 
60499da57d7bSbt /*
60509da57d7bSbt  * ixgbe_mc_table_itr - Traverse the entries in the multicast table.
60519da57d7bSbt  */
60529da57d7bSbt static uint8_t *
ixgbe_mc_table_itr(struct ixgbe_hw * hw,uint8_t ** upd_ptr,uint32_t * vmdq)60539da57d7bSbt ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq)
60549da57d7bSbt {
60559da57d7bSbt 	uint8_t *addr = *upd_ptr;
60569da57d7bSbt 	uint8_t *new_ptr;
60579da57d7bSbt 
605813740cb2SPaul Guo 	_NOTE(ARGUNUSED(hw));
605913740cb2SPaul Guo 	_NOTE(ARGUNUSED(vmdq));
606013740cb2SPaul Guo 
60619da57d7bSbt 	new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS;
60629da57d7bSbt 	*upd_ptr = new_ptr;
60639da57d7bSbt 	return (addr);
60649da57d7bSbt }
60659da57d7bSbt 
60669da57d7bSbt /*
60679da57d7bSbt  * FMA support
60689da57d7bSbt  */
60699da57d7bSbt int
ixgbe_check_acc_handle(ddi_acc_handle_t handle)60709da57d7bSbt ixgbe_check_acc_handle(ddi_acc_handle_t handle)
60719da57d7bSbt {
60729da57d7bSbt 	ddi_fm_error_t de;
60739da57d7bSbt 
60749da57d7bSbt 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
60759da57d7bSbt 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
60769da57d7bSbt 	return (de.fme_status);
60779da57d7bSbt }
60789da57d7bSbt 
60799da57d7bSbt int
ixgbe_check_dma_handle(ddi_dma_handle_t handle)60809da57d7bSbt ixgbe_check_dma_handle(ddi_dma_handle_t handle)
60819da57d7bSbt {
60829da57d7bSbt 	ddi_fm_error_t de;
60839da57d7bSbt 
60849da57d7bSbt 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
60859da57d7bSbt 	return (de.fme_status);
60869da57d7bSbt }
60879da57d7bSbt 
60889da57d7bSbt /*
60899da57d7bSbt  * ixgbe_fm_error_cb - The IO fault service error handling callback function.
60909da57d7bSbt  */
60919da57d7bSbt static int
ixgbe_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)60929da57d7bSbt ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
60939da57d7bSbt {
60949da57d7bSbt 	_NOTE(ARGUNUSED(impl_data));
60959da57d7bSbt 	/*
60969da57d7bSbt 	 * as the driver can always deal with an error in any dma or
60979da57d7bSbt 	 * access handle, we can just return the fme_status value.
60989da57d7bSbt 	 */
60999da57d7bSbt 	pci_ereport_post(dip, err, NULL);
61009da57d7bSbt 	return (err->fme_status);
61019da57d7bSbt }
61029da57d7bSbt 
61039da57d7bSbt static void
ixgbe_fm_init(ixgbe_t * ixgbe)61049da57d7bSbt ixgbe_fm_init(ixgbe_t *ixgbe)
61059da57d7bSbt {
61069da57d7bSbt 	ddi_iblock_cookie_t iblk;
6107837c1ac4SStephen Hanson 	int fma_dma_flag;
61089da57d7bSbt 
61099da57d7bSbt 	/*
61109da57d7bSbt 	 * Only register with IO Fault Services if we have some capability
61119da57d7bSbt 	 */
61129da57d7bSbt 	if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
61139da57d7bSbt 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
61149da57d7bSbt 	} else {
61159da57d7bSbt 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
61169da57d7bSbt 	}
61179da57d7bSbt 
61189da57d7bSbt 	if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
61199da57d7bSbt 		fma_dma_flag = 1;
61209da57d7bSbt 	} else {
61219da57d7bSbt 		fma_dma_flag = 0;
61229da57d7bSbt 	}
61239da57d7bSbt 
6124837c1ac4SStephen Hanson 	ixgbe_set_fma_flags(fma_dma_flag);
61259da57d7bSbt 
61269da57d7bSbt 	if (ixgbe->fm_capabilities) {
61279da57d7bSbt 
61289da57d7bSbt 		/*
61299da57d7bSbt 		 * Register capabilities with IO Fault Services
61309da57d7bSbt 		 */
61319da57d7bSbt 		ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk);
61329da57d7bSbt 
61339da57d7bSbt 		/*
61349da57d7bSbt 		 * Initialize pci ereport capabilities if ereport capable
61359da57d7bSbt 		 */
61369da57d7bSbt 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
61379da57d7bSbt 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
61389da57d7bSbt 			pci_ereport_setup(ixgbe->dip);
61399da57d7bSbt 
61409da57d7bSbt 		/*
61419da57d7bSbt 		 * Register error callback if error callback capable
61429da57d7bSbt 		 */
61439da57d7bSbt 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
61449da57d7bSbt 			ddi_fm_handler_register(ixgbe->dip,
61459da57d7bSbt 			    ixgbe_fm_error_cb, (void*) ixgbe);
61469da57d7bSbt 	}
61479da57d7bSbt }
61489da57d7bSbt 
61499da57d7bSbt static void
ixgbe_fm_fini(ixgbe_t * ixgbe)61509da57d7bSbt ixgbe_fm_fini(ixgbe_t *ixgbe)
61519da57d7bSbt {
61529da57d7bSbt 	/*
61539da57d7bSbt 	 * Only unregister FMA capabilities if they are registered
61549da57d7bSbt 	 */
61559da57d7bSbt 	if (ixgbe->fm_capabilities) {
61569da57d7bSbt 
61579da57d7bSbt 		/*
61589da57d7bSbt 		 * Release any resources allocated by pci_ereport_setup()
61599da57d7bSbt 		 */
61609da57d7bSbt 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
61619da57d7bSbt 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
61629da57d7bSbt 			pci_ereport_teardown(ixgbe->dip);
61639da57d7bSbt 
61649da57d7bSbt 		/*
61659da57d7bSbt 		 * Un-register error callback if error callback capable
61669da57d7bSbt 		 */
61679da57d7bSbt 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
61689da57d7bSbt 			ddi_fm_handler_unregister(ixgbe->dip);
61699da57d7bSbt 
61709da57d7bSbt 		/*
61719da57d7bSbt 		 * Unregister from IO Fault Service
61729da57d7bSbt 		 */
61739da57d7bSbt 		ddi_fm_fini(ixgbe->dip);
61749da57d7bSbt 	}
61759da57d7bSbt }
61769da57d7bSbt 
61779da57d7bSbt void
ixgbe_fm_ereport(ixgbe_t * ixgbe,char * detail)61789da57d7bSbt ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail)
61799da57d7bSbt {
61809da57d7bSbt 	uint64_t ena;
61819da57d7bSbt 	char buf[FM_MAX_CLASS];
61829da57d7bSbt 
61839da57d7bSbt 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
61849da57d7bSbt 	ena = fm_ena_generate(0, FM_ENA_FMT1);
61859da57d7bSbt 	if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) {
61869da57d7bSbt 		ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP,
61879da57d7bSbt 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
61889da57d7bSbt 	}
61899da57d7bSbt }
6190da14cebeSEric Cheng 
6191da14cebeSEric Cheng static int
ixgbe_ring_start(mac_ring_driver_t rh,uint64_t mr_gen_num)6192da14cebeSEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
6193da14cebeSEric Cheng {
6194da14cebeSEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh;
6195da14cebeSEric Cheng 
6196da14cebeSEric Cheng 	mutex_enter(&rx_ring->rx_lock);
6197da14cebeSEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
6198da14cebeSEric Cheng 	mutex_exit(&rx_ring->rx_lock);
6199da14cebeSEric Cheng 	return (0);
6200da14cebeSEric Cheng }
6201da14cebeSEric Cheng 
62020dc2366fSVenugopal Iyer /*
62030dc2366fSVenugopal Iyer  * Get the global ring index by a ring index within a group.
62040dc2366fSVenugopal Iyer  */
62050dc2366fSVenugopal Iyer static int
ixgbe_get_rx_ring_index(ixgbe_t * ixgbe,int gindex,int rindex)62060dc2366fSVenugopal Iyer ixgbe_get_rx_ring_index(ixgbe_t *ixgbe, int gindex, int rindex)
62070dc2366fSVenugopal Iyer {
62080dc2366fSVenugopal Iyer 	ixgbe_rx_ring_t *rx_ring;
62090dc2366fSVenugopal Iyer 	int i;
62100dc2366fSVenugopal Iyer 
62110dc2366fSVenugopal Iyer 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
62120dc2366fSVenugopal Iyer 		rx_ring = &ixgbe->rx_rings[i];
62130dc2366fSVenugopal Iyer 		if (rx_ring->group_index == gindex)
62140dc2366fSVenugopal Iyer 			rindex--;
62150dc2366fSVenugopal Iyer 		if (rindex < 0)
62160dc2366fSVenugopal Iyer 			return (i);
62170dc2366fSVenugopal Iyer 	}
62180dc2366fSVenugopal Iyer 
62190dc2366fSVenugopal Iyer 	return (-1);
62200dc2366fSVenugopal Iyer }
62210dc2366fSVenugopal Iyer 
6222da14cebeSEric Cheng /*
6223da14cebeSEric Cheng  * Callback funtion for MAC layer to register all rings.
6224da14cebeSEric Cheng  */
6225da14cebeSEric Cheng /* ARGSUSED */
6226da14cebeSEric Cheng void
ixgbe_fill_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)62270dc2366fSVenugopal Iyer ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index,
6228da14cebeSEric Cheng     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
6229da14cebeSEric Cheng {
6230da14cebeSEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
6231da14cebeSEric Cheng 	mac_intr_t *mintr = &infop->mri_intr;
6232da14cebeSEric Cheng 
6233da14cebeSEric Cheng 	switch (rtype) {
6234da14cebeSEric Cheng 	case MAC_RING_TYPE_RX: {
62350dc2366fSVenugopal Iyer 		/*
62360dc2366fSVenugopal Iyer 		 * 'index' is the ring index within the group.
62370dc2366fSVenugopal Iyer 		 * Need to get the global ring index by searching in groups.
62380dc2366fSVenugopal Iyer 		 */
62390dc2366fSVenugopal Iyer 		int global_ring_index = ixgbe_get_rx_ring_index(
62400dc2366fSVenugopal Iyer 		    ixgbe, group_index, ring_index);
6241da14cebeSEric Cheng 
62420dc2366fSVenugopal Iyer 		ASSERT(global_ring_index >= 0);
62430dc2366fSVenugopal Iyer 
62440dc2366fSVenugopal Iyer 		ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[global_ring_index];
6245da14cebeSEric Cheng 		rx_ring->ring_handle = rh;
6246da14cebeSEric Cheng 
6247da14cebeSEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
6248da14cebeSEric Cheng 		infop->mri_start = ixgbe_ring_start;
6249da14cebeSEric Cheng 		infop->mri_stop = NULL;
6250da14cebeSEric Cheng 		infop->mri_poll = ixgbe_ring_rx_poll;
62510dc2366fSVenugopal Iyer 		infop->mri_stat = ixgbe_rx_ring_stat;
6252da14cebeSEric Cheng 
6253da14cebeSEric Cheng 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
6254da14cebeSEric Cheng 		mintr->mi_enable = ixgbe_rx_ring_intr_enable;
6255da14cebeSEric Cheng 		mintr->mi_disable = ixgbe_rx_ring_intr_disable;
62560dc2366fSVenugopal Iyer 		if (ixgbe->intr_type &
62570dc2366fSVenugopal Iyer 		    (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
62580dc2366fSVenugopal Iyer 			mintr->mi_ddi_handle =
62590dc2366fSVenugopal Iyer 			    ixgbe->htable[rx_ring->intr_vector];
62600dc2366fSVenugopal Iyer 		}
6261da14cebeSEric Cheng 
6262da14cebeSEric Cheng 		break;
6263da14cebeSEric Cheng 	}
6264da14cebeSEric Cheng 	case MAC_RING_TYPE_TX: {
62650dc2366fSVenugopal Iyer 		ASSERT(group_index == -1);
6266da14cebeSEric Cheng 		ASSERT(ring_index < ixgbe->num_tx_rings);
6267da14cebeSEric Cheng 
6268da14cebeSEric Cheng 		ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index];
6269da14cebeSEric Cheng 		tx_ring->ring_handle = rh;
6270da14cebeSEric Cheng 
6271da14cebeSEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
6272da14cebeSEric Cheng 		infop->mri_start = NULL;
6273da14cebeSEric Cheng 		infop->mri_stop = NULL;
6274da14cebeSEric Cheng 		infop->mri_tx = ixgbe_ring_tx;
62750dc2366fSVenugopal Iyer 		infop->mri_stat = ixgbe_tx_ring_stat;
62760dc2366fSVenugopal Iyer 		if (ixgbe->intr_type &
62770dc2366fSVenugopal Iyer 		    (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
62780dc2366fSVenugopal Iyer 			mintr->mi_ddi_handle =
62790dc2366fSVenugopal Iyer 			    ixgbe->htable[tx_ring->intr_vector];
62800dc2366fSVenugopal Iyer 		}
6281da14cebeSEric Cheng 		break;
6282da14cebeSEric Cheng 	}
6283da14cebeSEric Cheng 	default:
6284da14cebeSEric Cheng 		break;
6285da14cebeSEric Cheng 	}
6286da14cebeSEric Cheng }
6287da14cebeSEric Cheng 
6288da14cebeSEric Cheng /*
6289da14cebeSEric Cheng  * Callback funtion for MAC layer to register all groups.
6290da14cebeSEric Cheng  */
6291da14cebeSEric Cheng void
ixgbe_fill_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)6292da14cebeSEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index,
6293da14cebeSEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
6294da14cebeSEric Cheng {
6295da14cebeSEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
629684de666eSRyan Zezeski 	struct ixgbe_hw *hw = &ixgbe->hw;
6297da14cebeSEric Cheng 
6298da14cebeSEric Cheng 	switch (rtype) {
6299da14cebeSEric Cheng 	case MAC_RING_TYPE_RX: {
6300da14cebeSEric Cheng 		ixgbe_rx_group_t *rx_group;
6301da14cebeSEric Cheng 
6302da14cebeSEric Cheng 		rx_group = &ixgbe->rx_groups[index];
6303da14cebeSEric Cheng 		rx_group->group_handle = gh;
6304da14cebeSEric Cheng 
6305da14cebeSEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_group;
6306da14cebeSEric Cheng 		infop->mgi_start = NULL;
6307da14cebeSEric Cheng 		infop->mgi_stop = NULL;
6308da14cebeSEric Cheng 		infop->mgi_addmac = ixgbe_addmac;
6309da14cebeSEric Cheng 		infop->mgi_remmac = ixgbe_remmac;
631084de666eSRyan Zezeski 
631184de666eSRyan Zezeski 		if ((ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ ||
631284de666eSRyan Zezeski 		    ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) &&
631384de666eSRyan Zezeski 		    (hw->mac.type == ixgbe_mac_82599EB ||
631484de666eSRyan Zezeski 		    hw->mac.type == ixgbe_mac_X540 ||
631584de666eSRyan Zezeski 		    hw->mac.type == ixgbe_mac_X550 ||
631684de666eSRyan Zezeski 		    hw->mac.type == ixgbe_mac_X550EM_x)) {
631784de666eSRyan Zezeski 			infop->mgi_addvlan = ixgbe_addvlan;
631884de666eSRyan Zezeski 			infop->mgi_remvlan = ixgbe_remvlan;
631984de666eSRyan Zezeski 		} else {
632084de666eSRyan Zezeski 			infop->mgi_addvlan = NULL;
632184de666eSRyan Zezeski 			infop->mgi_remvlan = NULL;
632284de666eSRyan Zezeski 		}
632384de666eSRyan Zezeski 
6324da14cebeSEric Cheng 		infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups);
6325da14cebeSEric Cheng 
6326da14cebeSEric Cheng 		break;
6327da14cebeSEric Cheng 	}
6328da14cebeSEric Cheng 	case MAC_RING_TYPE_TX:
6329da14cebeSEric Cheng 		break;
6330da14cebeSEric Cheng 	default:
6331da14cebeSEric Cheng 		break;
6332da14cebeSEric Cheng 	}
6333da14cebeSEric Cheng }
6334da14cebeSEric Cheng 
6335da14cebeSEric Cheng /*
6336da14cebeSEric Cheng  * Enable interrupt on the specificed rx ring.
6337da14cebeSEric Cheng  */
6338da14cebeSEric Cheng int
ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)6339da14cebeSEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)
6340da14cebeSEric Cheng {
6341da14cebeSEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
6342da14cebeSEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
6343da14cebeSEric Cheng 	int r_idx = rx_ring->index;
63440dc2366fSVenugopal Iyer 	int hw_r_idx = rx_ring->hw_index;
6345da14cebeSEric Cheng 	int v_idx = rx_ring->intr_vector;
6346da14cebeSEric Cheng 
6347da14cebeSEric Cheng 	mutex_enter(&ixgbe->gen_lock);
63480dc2366fSVenugopal Iyer 	if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
63490dc2366fSVenugopal Iyer 		mutex_exit(&ixgbe->gen_lock);
63500dc2366fSVenugopal Iyer 		/*
63510dc2366fSVenugopal Iyer 		 * Simply return 0.
63520dc2366fSVenugopal Iyer 		 * Interrupts are being adjusted. ixgbe_intr_adjust()
63530dc2366fSVenugopal Iyer 		 * will eventually re-enable the interrupt when it's
63540dc2366fSVenugopal Iyer 		 * done with the adjustment.
63550dc2366fSVenugopal Iyer 		 */
63560dc2366fSVenugopal Iyer 		return (0);
63570dc2366fSVenugopal Iyer 	}
6358da14cebeSEric Cheng 
6359da14cebeSEric Cheng 	/*
6360da14cebeSEric Cheng 	 * To enable interrupt by setting the VAL bit of given interrupt
6361da14cebeSEric Cheng 	 * vector allocation register (IVAR).
6362da14cebeSEric Cheng 	 */
63630dc2366fSVenugopal Iyer 	ixgbe_enable_ivar(ixgbe, hw_r_idx, 0);
6364da14cebeSEric Cheng 
6365da14cebeSEric Cheng 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
6366185c5677SPaul Guo 
6367185c5677SPaul Guo 	/*
636819843f01SPaul Guo 	 * Trigger a Rx interrupt on this ring
6369185c5677SPaul Guo 	 */
6370185c5677SPaul Guo 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx));
6371185c5677SPaul Guo 	IXGBE_WRITE_FLUSH(&ixgbe->hw);
6372185c5677SPaul Guo 
6373da14cebeSEric Cheng 	mutex_exit(&ixgbe->gen_lock);
6374da14cebeSEric Cheng 
6375da14cebeSEric Cheng 	return (0);
6376da14cebeSEric Cheng }
6377da14cebeSEric Cheng 
6378da14cebeSEric Cheng /*
6379da14cebeSEric Cheng  * Disable interrupt on the specificed rx ring.
6380da14cebeSEric Cheng  */
6381da14cebeSEric Cheng int
ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)6382da14cebeSEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)
6383da14cebeSEric Cheng {
6384da14cebeSEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
6385da14cebeSEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
6386da14cebeSEric Cheng 	int r_idx = rx_ring->index;
63870dc2366fSVenugopal Iyer 	int hw_r_idx = rx_ring->hw_index;
6388da14cebeSEric Cheng 	int v_idx = rx_ring->intr_vector;
6389da14cebeSEric Cheng 
6390da14cebeSEric Cheng 	mutex_enter(&ixgbe->gen_lock);
63910dc2366fSVenugopal Iyer 	if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
63920dc2366fSVenugopal Iyer 		mutex_exit(&ixgbe->gen_lock);
63930dc2366fSVenugopal Iyer 		/*
63940dc2366fSVenugopal Iyer 		 * Simply return 0.
63950dc2366fSVenugopal Iyer 		 * In the rare case where an interrupt is being
63960dc2366fSVenugopal Iyer 		 * disabled while interrupts are being adjusted,
63970dc2366fSVenugopal Iyer 		 * we don't fail the operation. No interrupts will
63980dc2366fSVenugopal Iyer 		 * be generated while they are adjusted, and
63990dc2366fSVenugopal Iyer 		 * ixgbe_intr_adjust() will cause the interrupts
64000dc2366fSVenugopal Iyer 		 * to be re-enabled once it completes. Note that
64010dc2366fSVenugopal Iyer 		 * in this case, packets may be delivered to the
64020dc2366fSVenugopal Iyer 		 * stack via interrupts before xgbe_rx_ring_intr_enable()
64030dc2366fSVenugopal Iyer 		 * is called again. This is acceptable since interrupt
64040dc2366fSVenugopal Iyer 		 * adjustment is infrequent, and the stack will be
64050dc2366fSVenugopal Iyer 		 * able to handle these packets.
64060dc2366fSVenugopal Iyer 		 */
64070dc2366fSVenugopal Iyer 		return (0);
64080dc2366fSVenugopal Iyer 	}
6409da14cebeSEric Cheng 
6410da14cebeSEric Cheng 	/*
6411da14cebeSEric Cheng 	 * To disable interrupt by clearing the VAL bit of given interrupt
6412da14cebeSEric Cheng 	 * vector allocation register (IVAR).
6413da14cebeSEric Cheng 	 */
64140dc2366fSVenugopal Iyer 	ixgbe_disable_ivar(ixgbe, hw_r_idx, 0);
6415da14cebeSEric Cheng 
6416da14cebeSEric Cheng 	BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx);
6417da14cebeSEric Cheng 
6418da14cebeSEric Cheng 	mutex_exit(&ixgbe->gen_lock);
6419da14cebeSEric Cheng 
6420da14cebeSEric Cheng 	return (0);
6421da14cebeSEric Cheng }
6422da14cebeSEric Cheng 
642384de666eSRyan Zezeski static ixgbe_vlan_t *
ixgbe_find_vlan(ixgbe_rx_group_t * rx_group,uint16_t vid)642484de666eSRyan Zezeski ixgbe_find_vlan(ixgbe_rx_group_t *rx_group, uint16_t vid)
642584de666eSRyan Zezeski {
642684de666eSRyan Zezeski 	for (ixgbe_vlan_t *vlp = list_head(&rx_group->vlans); vlp != NULL;
642784de666eSRyan Zezeski 	    vlp = list_next(&rx_group->vlans, vlp)) {
642884de666eSRyan Zezeski 		if (vlp->ixvl_vid == vid)
642984de666eSRyan Zezeski 			return (vlp);
643084de666eSRyan Zezeski 	}
643184de666eSRyan Zezeski 
643284de666eSRyan Zezeski 	return (NULL);
643384de666eSRyan Zezeski }
643484de666eSRyan Zezeski 
643584de666eSRyan Zezeski /*
643684de666eSRyan Zezeski  * Attempt to use a VLAN HW filter for this group. If the group is
643784de666eSRyan Zezeski  * interested in untagged packets then set AUPE only. If the group is
643884de666eSRyan Zezeski  * the default then only set the VFTA. Leave the VLVF slots open for
643984de666eSRyan Zezeski  * reserved groups to guarantee their use of HW filtering.
644084de666eSRyan Zezeski  */
644184de666eSRyan Zezeski static int
ixgbe_addvlan(mac_group_driver_t gdriver,uint16_t vid)644284de666eSRyan Zezeski ixgbe_addvlan(mac_group_driver_t gdriver, uint16_t vid)
644384de666eSRyan Zezeski {
644484de666eSRyan Zezeski 	ixgbe_rx_group_t	*rx_group = (ixgbe_rx_group_t *)gdriver;
644584de666eSRyan Zezeski 	ixgbe_t			*ixgbe = rx_group->ixgbe;
644684de666eSRyan Zezeski 	struct ixgbe_hw		*hw = &ixgbe->hw;
644784de666eSRyan Zezeski 	ixgbe_vlan_t		*vlp;
644884de666eSRyan Zezeski 	int			ret;
644984de666eSRyan Zezeski 	boolean_t		is_def_grp;
645084de666eSRyan Zezeski 
645184de666eSRyan Zezeski 	mutex_enter(&ixgbe->gen_lock);
645284de666eSRyan Zezeski 
645384de666eSRyan Zezeski 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
645484de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
645584de666eSRyan Zezeski 		return (ECANCELED);
645684de666eSRyan Zezeski 	}
645784de666eSRyan Zezeski 
645884de666eSRyan Zezeski 	/*
645984de666eSRyan Zezeski 	 * Let's be sure VLAN filtering is enabled.
646084de666eSRyan Zezeski 	 */
646184de666eSRyan Zezeski 	VERIFY3B(ixgbe->vlft_enabled, ==, B_TRUE);
646284de666eSRyan Zezeski 	is_def_grp = (rx_group->index == ixgbe->rx_def_group);
646384de666eSRyan Zezeski 
646484de666eSRyan Zezeski 	/*
646584de666eSRyan Zezeski 	 * VLAN filtering is enabled but we want to receive untagged
646684de666eSRyan Zezeski 	 * traffic on this group -- set the AUPE bit on the group and
646784de666eSRyan Zezeski 	 * leave the VLAN tables alone.
646884de666eSRyan Zezeski 	 */
646984de666eSRyan Zezeski 	if (vid == MAC_VLAN_UNTAGGED) {
647084de666eSRyan Zezeski 		/*
647184de666eSRyan Zezeski 		 * We never enable AUPE on the default group; it is
647284de666eSRyan Zezeski 		 * redundant. Untagged traffic which passes L2
647384de666eSRyan Zezeski 		 * filtering is delivered to the default group if no
647484de666eSRyan Zezeski 		 * other group is interested.
647584de666eSRyan Zezeski 		 */
647684de666eSRyan Zezeski 		if (!is_def_grp) {
647784de666eSRyan Zezeski 			uint32_t vml2flt;
647884de666eSRyan Zezeski 
647984de666eSRyan Zezeski 			vml2flt = IXGBE_READ_REG(hw,
648084de666eSRyan Zezeski 			    IXGBE_VMOLR(rx_group->index));
648184de666eSRyan Zezeski 			vml2flt |= IXGBE_VMOLR_AUPE;
648284de666eSRyan Zezeski 			IXGBE_WRITE_REG(hw, IXGBE_VMOLR(rx_group->index),
648384de666eSRyan Zezeski 			    vml2flt);
648484de666eSRyan Zezeski 			rx_group->aupe = B_TRUE;
648584de666eSRyan Zezeski 		}
648684de666eSRyan Zezeski 
648784de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
648884de666eSRyan Zezeski 		return (0);
648984de666eSRyan Zezeski 	}
649084de666eSRyan Zezeski 
649184de666eSRyan Zezeski 	vlp = ixgbe_find_vlan(rx_group, vid);
649284de666eSRyan Zezeski 	if (vlp != NULL) {
649384de666eSRyan Zezeski 		/* Only the default group supports multiple clients. */
649484de666eSRyan Zezeski 		VERIFY3B(is_def_grp, ==, B_TRUE);
649584de666eSRyan Zezeski 		vlp->ixvl_refs++;
649684de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
649784de666eSRyan Zezeski 		return (0);
649884de666eSRyan Zezeski 	}
649984de666eSRyan Zezeski 
650084de666eSRyan Zezeski 	/*
650184de666eSRyan Zezeski 	 * The default group doesn't require a VLVF entry, only a VFTA
650284de666eSRyan Zezeski 	 * entry. All traffic passing L2 filtering (MPSAR + VFTA) is
650384de666eSRyan Zezeski 	 * delivered to the default group if no other group is
650484de666eSRyan Zezeski 	 * interested. The fourth argument, vlvf_bypass, tells the
650584de666eSRyan Zezeski 	 * ixgbe common code to avoid using a VLVF slot if one isn't
650684de666eSRyan Zezeski 	 * already allocated to this VLAN.
650784de666eSRyan Zezeski 	 *
650884de666eSRyan Zezeski 	 * This logic is meant to reserve VLVF slots for use by
650984de666eSRyan Zezeski 	 * reserved groups: guaranteeing their use of HW filtering.
651084de666eSRyan Zezeski 	 */
651184de666eSRyan Zezeski 	ret = ixgbe_set_vfta(hw, vid, rx_group->index, B_TRUE, is_def_grp);
651284de666eSRyan Zezeski 
651384de666eSRyan Zezeski 	if (ret == IXGBE_SUCCESS) {
651484de666eSRyan Zezeski 		vlp = kmem_zalloc(sizeof (ixgbe_vlan_t), KM_SLEEP);
651584de666eSRyan Zezeski 		vlp->ixvl_vid = vid;
651684de666eSRyan Zezeski 		vlp->ixvl_refs = 1;
651784de666eSRyan Zezeski 		list_insert_tail(&rx_group->vlans, vlp);
651884de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
651984de666eSRyan Zezeski 		return (0);
652084de666eSRyan Zezeski 	}
652184de666eSRyan Zezeski 
652284de666eSRyan Zezeski 	/*
652384de666eSRyan Zezeski 	 * We should actually never return ENOSPC because we've set
652484de666eSRyan Zezeski 	 * things up so that every reserved group is guaranteed to
652584de666eSRyan Zezeski 	 * have a VLVF slot.
652684de666eSRyan Zezeski 	 */
652784de666eSRyan Zezeski 	if (ret == IXGBE_ERR_PARAM)
652884de666eSRyan Zezeski 		ret = EINVAL;
652984de666eSRyan Zezeski 	else if (ret == IXGBE_ERR_NO_SPACE)
653084de666eSRyan Zezeski 		ret = ENOSPC;
653184de666eSRyan Zezeski 	else
653284de666eSRyan Zezeski 		ret = EIO;
653384de666eSRyan Zezeski 
653484de666eSRyan Zezeski 	mutex_exit(&ixgbe->gen_lock);
653584de666eSRyan Zezeski 	return (ret);
653684de666eSRyan Zezeski }
653784de666eSRyan Zezeski 
653884de666eSRyan Zezeski /*
653984de666eSRyan Zezeski  * Attempt to remove the VLAN HW filter associated with this group. If
654084de666eSRyan Zezeski  * we are removing a HW filter for the default group then we know only
654184de666eSRyan Zezeski  * the VFTA was set (VLVF is reserved for non-default/reserved
654284de666eSRyan Zezeski  * groups). If the group wishes to stop receiving untagged traffic
654384de666eSRyan Zezeski  * then clear the AUPE but leave the VLAN filters alone.
654484de666eSRyan Zezeski  */
654584de666eSRyan Zezeski static int
ixgbe_remvlan(mac_group_driver_t gdriver,uint16_t vid)654684de666eSRyan Zezeski ixgbe_remvlan(mac_group_driver_t gdriver, uint16_t vid)
654784de666eSRyan Zezeski {
654884de666eSRyan Zezeski 	ixgbe_rx_group_t	*rx_group = (ixgbe_rx_group_t *)gdriver;
654984de666eSRyan Zezeski 	ixgbe_t			*ixgbe = rx_group->ixgbe;
655084de666eSRyan Zezeski 	struct ixgbe_hw		*hw = &ixgbe->hw;
655184de666eSRyan Zezeski 	int			ret;
655284de666eSRyan Zezeski 	ixgbe_vlan_t		*vlp;
655384de666eSRyan Zezeski 	boolean_t		is_def_grp;
655484de666eSRyan Zezeski 
655584de666eSRyan Zezeski 	mutex_enter(&ixgbe->gen_lock);
655684de666eSRyan Zezeski 
655784de666eSRyan Zezeski 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
655884de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
655984de666eSRyan Zezeski 		return (ECANCELED);
656084de666eSRyan Zezeski 	}
656184de666eSRyan Zezeski 
656284de666eSRyan Zezeski 	is_def_grp = (rx_group->index == ixgbe->rx_def_group);
656384de666eSRyan Zezeski 
656484de666eSRyan Zezeski 	/* See the AUPE comment in ixgbe_addvlan(). */
656584de666eSRyan Zezeski 	if (vid == MAC_VLAN_UNTAGGED) {
656684de666eSRyan Zezeski 		if (!is_def_grp) {
656784de666eSRyan Zezeski 			uint32_t vml2flt;
656884de666eSRyan Zezeski 
656984de666eSRyan Zezeski 			vml2flt = IXGBE_READ_REG(hw,
657084de666eSRyan Zezeski 			    IXGBE_VMOLR(rx_group->index));
657184de666eSRyan Zezeski 			vml2flt &= ~IXGBE_VMOLR_AUPE;
657284de666eSRyan Zezeski 			IXGBE_WRITE_REG(hw,
657384de666eSRyan Zezeski 			    IXGBE_VMOLR(rx_group->index), vml2flt);
657484de666eSRyan Zezeski 			rx_group->aupe = B_FALSE;
657584de666eSRyan Zezeski 		}
657684de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
657784de666eSRyan Zezeski 		return (0);
657884de666eSRyan Zezeski 	}
657984de666eSRyan Zezeski 
658084de666eSRyan Zezeski 	vlp = ixgbe_find_vlan(rx_group, vid);
658184de666eSRyan Zezeski 	if (vlp == NULL) {
658284de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
658384de666eSRyan Zezeski 		return (ENOENT);
658484de666eSRyan Zezeski 	}
658584de666eSRyan Zezeski 
658684de666eSRyan Zezeski 	/*
658784de666eSRyan Zezeski 	 * See the comment in ixgbe_addvlan() about is_def_grp and
658884de666eSRyan Zezeski 	 * vlvf_bypass.
658984de666eSRyan Zezeski 	 */
659084de666eSRyan Zezeski 	if (vlp->ixvl_refs == 1) {
659184de666eSRyan Zezeski 		ret = ixgbe_set_vfta(hw, vid, rx_group->index, B_FALSE,
659284de666eSRyan Zezeski 		    is_def_grp);
659384de666eSRyan Zezeski 	} else {
659484de666eSRyan Zezeski 		/*
659584de666eSRyan Zezeski 		 * Only the default group can have multiple clients.
659684de666eSRyan Zezeski 		 * If there is more than one client, leave the
659784de666eSRyan Zezeski 		 * VFTA[vid] bit alone.
659884de666eSRyan Zezeski 		 */
659984de666eSRyan Zezeski 		VERIFY3B(is_def_grp, ==, B_TRUE);
660084de666eSRyan Zezeski 		VERIFY3U(vlp->ixvl_refs, >, 1);
660184de666eSRyan Zezeski 		vlp->ixvl_refs--;
660284de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
660384de666eSRyan Zezeski 		return (0);
660484de666eSRyan Zezeski 	}
660584de666eSRyan Zezeski 
660684de666eSRyan Zezeski 	if (ret != IXGBE_SUCCESS) {
660784de666eSRyan Zezeski 		mutex_exit(&ixgbe->gen_lock);
660884de666eSRyan Zezeski 		/* IXGBE_ERR_PARAM should be the only possible error here. */
660984de666eSRyan Zezeski 		if (ret == IXGBE_ERR_PARAM)
661084de666eSRyan Zezeski 			return (EINVAL);
661184de666eSRyan Zezeski 		else
661284de666eSRyan Zezeski 			return (EIO);
661384de666eSRyan Zezeski 	}
661484de666eSRyan Zezeski 
661584de666eSRyan Zezeski 	VERIFY3U(vlp->ixvl_refs, ==, 1);
661684de666eSRyan Zezeski 	vlp->ixvl_refs = 0;
661784de666eSRyan Zezeski 	list_remove(&rx_group->vlans, vlp);
661884de666eSRyan Zezeski 	kmem_free(vlp, sizeof (ixgbe_vlan_t));
661984de666eSRyan Zezeski 
662084de666eSRyan Zezeski 	/*
662184de666eSRyan Zezeski 	 * Calling ixgbe_set_vfta() on a non-default group may have
662284de666eSRyan Zezeski 	 * cleared the VFTA[vid] bit even though the default group
662384de666eSRyan Zezeski 	 * still has clients using the vid. This happens because the
662484de666eSRyan Zezeski 	 * ixgbe common code doesn't ref count the use of VLANs. Check
662584de666eSRyan Zezeski 	 * for any use of vid on the default group and make sure the
662684de666eSRyan Zezeski 	 * VFTA[vid] bit is set. This operation is idempotent: setting
662784de666eSRyan Zezeski 	 * VFTA[vid] to true if already true won't hurt anything.
662884de666eSRyan Zezeski 	 */
662984de666eSRyan Zezeski 	if (!is_def_grp) {
663084de666eSRyan Zezeski 		ixgbe_rx_group_t *defgrp;
663184de666eSRyan Zezeski 
663284de666eSRyan Zezeski 		defgrp = &ixgbe->rx_groups[ixgbe->rx_def_group];
663384de666eSRyan Zezeski 		vlp = ixgbe_find_vlan(defgrp, vid);
663484de666eSRyan Zezeski 		if (vlp != NULL) {
663584de666eSRyan Zezeski 			/* This shouldn't fail, but if it does return EIO. */
663684de666eSRyan Zezeski 			ret = ixgbe_set_vfta(hw, vid, rx_group->index, B_TRUE,
663784de666eSRyan Zezeski 			    B_TRUE);
663884de666eSRyan Zezeski 			if (ret != IXGBE_SUCCESS) {
663984de666eSRyan Zezeski 				mutex_exit(&ixgbe->gen_lock);
664084de666eSRyan Zezeski 				return (EIO);
664184de666eSRyan Zezeski 			}
664284de666eSRyan Zezeski 		}
664384de666eSRyan Zezeski 	}
664484de666eSRyan Zezeski 
664584de666eSRyan Zezeski 	mutex_exit(&ixgbe->gen_lock);
664684de666eSRyan Zezeski 	return (0);
664784de666eSRyan Zezeski }
664884de666eSRyan Zezeski 
6649da14cebeSEric Cheng /*
6650da14cebeSEric Cheng  * Add a mac address.
6651da14cebeSEric Cheng  */
6652da14cebeSEric Cheng static int
ixgbe_addmac(void * arg,const uint8_t * mac_addr)6653da14cebeSEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr)
6654da14cebeSEric Cheng {
6655da14cebeSEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
6656da14cebeSEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
66570dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
66580dc2366fSVenugopal Iyer 	int slot, i;
6659da14cebeSEric Cheng 
6660da14cebeSEric Cheng 	mutex_enter(&ixgbe->gen_lock);
6661da14cebeSEric Cheng 
6662da14cebeSEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
6663da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6664da14cebeSEric Cheng 		return (ECANCELED);
6665da14cebeSEric Cheng 	}
6666da14cebeSEric Cheng 
6667da14cebeSEric Cheng 	if (ixgbe->unicst_avail == 0) {
6668da14cebeSEric Cheng 		/* no slots available */
6669da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6670da14cebeSEric Cheng 		return (ENOSPC);
6671da14cebeSEric Cheng 	}
6672da14cebeSEric Cheng 
66730dc2366fSVenugopal Iyer 	/*
66740dc2366fSVenugopal Iyer 	 * The first ixgbe->num_rx_groups slots are reserved for each respective
66750dc2366fSVenugopal Iyer 	 * group. The rest slots are shared by all groups. While adding a
66760dc2366fSVenugopal Iyer 	 * MAC address, reserved slots are firstly checked then the shared
66770dc2366fSVenugopal Iyer 	 * slots are searched.
66780dc2366fSVenugopal Iyer 	 */
66790dc2366fSVenugopal Iyer 	slot = -1;
66800dc2366fSVenugopal Iyer 	if (ixgbe->unicst_addr[rx_group->index].mac.set == 1) {
66810dc2366fSVenugopal Iyer 		for (i = ixgbe->num_rx_groups; i < ixgbe->unicst_total; i++) {
66820dc2366fSVenugopal Iyer 			if (ixgbe->unicst_addr[i].mac.set == 0) {
66830dc2366fSVenugopal Iyer 				slot = i;
66840dc2366fSVenugopal Iyer 				break;
66850dc2366fSVenugopal Iyer 			}
66860dc2366fSVenugopal Iyer 		}
66870dc2366fSVenugopal Iyer 	} else {
66880dc2366fSVenugopal Iyer 		slot = rx_group->index;
6689da14cebeSEric Cheng 	}
6690da14cebeSEric Cheng 
66910dc2366fSVenugopal Iyer 	if (slot == -1) {
66920dc2366fSVenugopal Iyer 		/* no slots available */
66930dc2366fSVenugopal Iyer 		mutex_exit(&ixgbe->gen_lock);
66940dc2366fSVenugopal Iyer 		return (ENOSPC);
6695da14cebeSEric Cheng 	}
6696da14cebeSEric Cheng 
66970dc2366fSVenugopal Iyer 	bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
66980dc2366fSVenugopal Iyer 	(void) ixgbe_set_rar(hw, slot, ixgbe->unicst_addr[slot].mac.addr,
66990dc2366fSVenugopal Iyer 	    rx_group->index, IXGBE_RAH_AV);
67000dc2366fSVenugopal Iyer 	ixgbe->unicst_addr[slot].mac.set = 1;
67010dc2366fSVenugopal Iyer 	ixgbe->unicst_addr[slot].mac.group_index = rx_group->index;
67020dc2366fSVenugopal Iyer 	ixgbe->unicst_avail--;
67030dc2366fSVenugopal Iyer 
6704da14cebeSEric Cheng 	mutex_exit(&ixgbe->gen_lock);
6705da14cebeSEric Cheng 
67060dc2366fSVenugopal Iyer 	return (0);
6707da14cebeSEric Cheng }
6708da14cebeSEric Cheng 
6709da14cebeSEric Cheng /*
6710da14cebeSEric Cheng  * Remove a mac address.
6711da14cebeSEric Cheng  */
6712da14cebeSEric Cheng static int
ixgbe_remmac(void * arg,const uint8_t * mac_addr)6713da14cebeSEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr)
6714da14cebeSEric Cheng {
6715da14cebeSEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
6716da14cebeSEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
67170dc2366fSVenugopal Iyer 	struct ixgbe_hw *hw = &ixgbe->hw;
6718da14cebeSEric Cheng 	int slot;
6719da14cebeSEric Cheng 
6720da14cebeSEric Cheng 	mutex_enter(&ixgbe->gen_lock);
6721da14cebeSEric Cheng 
6722da14cebeSEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
6723da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6724da14cebeSEric Cheng 		return (ECANCELED);
6725da14cebeSEric Cheng 	}
6726da14cebeSEric Cheng 
6727da14cebeSEric Cheng 	slot = ixgbe_unicst_find(ixgbe, mac_addr);
6728da14cebeSEric Cheng 	if (slot == -1) {
6729da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6730da14cebeSEric Cheng 		return (EINVAL);
6731da14cebeSEric Cheng 	}
6732da14cebeSEric Cheng 
6733da14cebeSEric Cheng 	if (ixgbe->unicst_addr[slot].mac.set == 0) {
6734da14cebeSEric Cheng 		mutex_exit(&ixgbe->gen_lock);
6735da14cebeSEric Cheng 		return (EINVAL);
6736da14cebeSEric Cheng 	}
6737da14cebeSEric Cheng 
6738da14cebeSEric Cheng 	bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
67390dc2366fSVenugopal Iyer 	(void) ixgbe_clear_rar(hw, slot);
67400dc2366fSVenugopal Iyer 	ixgbe->unicst_addr[slot].mac.set = 0;
67410dc2366fSVenugopal Iyer 	ixgbe->unicst_avail++;
6742da14cebeSEric Cheng 
6743da14cebeSEric Cheng 	mutex_exit(&ixgbe->gen_lock);
6744da14cebeSEric Cheng 
67450dc2366fSVenugopal Iyer 	return (0);
6746da14cebeSEric Cheng }
6747f2fe7acaSRobert Mustacchi 
6748f2fe7acaSRobert Mustacchi static int
ixgbe_ufm_fill_image(ddi_ufm_handle_t * ufmh,void * arg,uint_t imgno,ddi_ufm_image_t * imgp)6749f2fe7acaSRobert Mustacchi ixgbe_ufm_fill_image(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
6750f2fe7acaSRobert Mustacchi     ddi_ufm_image_t *imgp)
6751f2fe7acaSRobert Mustacchi {
6752f2fe7acaSRobert Mustacchi 	ixgbe_t *ixgbe = arg;
6753f2fe7acaSRobert Mustacchi 	const char *type;
6754f2fe7acaSRobert Mustacchi 
6755f2fe7acaSRobert Mustacchi 	if (imgno != 0) {
6756f2fe7acaSRobert Mustacchi 		return (EINVAL);
6757f2fe7acaSRobert Mustacchi 	}
6758f2fe7acaSRobert Mustacchi 
6759f2fe7acaSRobert Mustacchi 	ddi_ufm_image_set_desc(imgp, "NVM");
6760f2fe7acaSRobert Mustacchi 	ddi_ufm_image_set_nslots(imgp, 1);
6761f2fe7acaSRobert Mustacchi 	switch (ixgbe->hw.eeprom.type) {
6762f2fe7acaSRobert Mustacchi 	case ixgbe_eeprom_spi:
6763f2fe7acaSRobert Mustacchi 		type = "SPI EEPROM";
6764f2fe7acaSRobert Mustacchi 		break;
6765f2fe7acaSRobert Mustacchi 	case ixgbe_flash:
6766f2fe7acaSRobert Mustacchi 		type = "Flash";
6767f2fe7acaSRobert Mustacchi 		break;
6768f2fe7acaSRobert Mustacchi 	default:
6769f2fe7acaSRobert Mustacchi 		type = NULL;
6770f2fe7acaSRobert Mustacchi 		break;
6771f2fe7acaSRobert Mustacchi 	}
6772f2fe7acaSRobert Mustacchi 
6773f2fe7acaSRobert Mustacchi 	if (type != NULL) {
6774f2fe7acaSRobert Mustacchi 		nvlist_t *nvl;
6775f2fe7acaSRobert Mustacchi 
6776f2fe7acaSRobert Mustacchi 		nvl = fnvlist_alloc();
6777f2fe7acaSRobert Mustacchi 		fnvlist_add_string(nvl, "image-type", type);
6778f2fe7acaSRobert Mustacchi 		/*
6779f2fe7acaSRobert Mustacchi 		 * The DDI takes ownership of the nvlist_t at this point.
6780f2fe7acaSRobert Mustacchi 		 */
6781f2fe7acaSRobert Mustacchi 		ddi_ufm_image_set_misc(imgp, nvl);
6782f2fe7acaSRobert Mustacchi 	}
6783f2fe7acaSRobert Mustacchi 
6784f2fe7acaSRobert Mustacchi 	return (0);
6785f2fe7acaSRobert Mustacchi }
6786f2fe7acaSRobert Mustacchi 
6787f2fe7acaSRobert Mustacchi static int
ixgbe_ufm_fill_slot(ddi_ufm_handle_t * ufmh,void * arg,uint_t imgno,uint_t slotno,ddi_ufm_slot_t * slotp)6788f2fe7acaSRobert Mustacchi ixgbe_ufm_fill_slot(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
6789f2fe7acaSRobert Mustacchi     uint_t slotno, ddi_ufm_slot_t *slotp)
6790f2fe7acaSRobert Mustacchi {
6791f2fe7acaSRobert Mustacchi 	ixgbe_t *ixgbe = arg;
6792f2fe7acaSRobert Mustacchi 
6793f2fe7acaSRobert Mustacchi 	if (imgno != 0 || slotno != 0) {
6794f2fe7acaSRobert Mustacchi 		return (EINVAL);
6795f2fe7acaSRobert Mustacchi 	}
6796f2fe7acaSRobert Mustacchi 
6797f2fe7acaSRobert Mustacchi 	/*
6798f2fe7acaSRobert Mustacchi 	 * Unfortunately there is no generic versioning in the ixgbe family
6799f2fe7acaSRobert Mustacchi 	 * eeprom parts.
6800f2fe7acaSRobert Mustacchi 	 */
6801f2fe7acaSRobert Mustacchi 	ddi_ufm_slot_set_version(slotp, "unknown");
6802f2fe7acaSRobert Mustacchi 	ddi_ufm_slot_set_attrs(slotp, DDI_UFM_ATTR_ACTIVE |
6803f2fe7acaSRobert Mustacchi 	    DDI_UFM_ATTR_READABLE | DDI_UFM_ATTR_WRITEABLE);
6804f2fe7acaSRobert Mustacchi 	ddi_ufm_slot_set_imgsize(slotp, ixgbe->hw.eeprom.word_size * 2);
6805f2fe7acaSRobert Mustacchi 
6806f2fe7acaSRobert Mustacchi 	return (0);
6807f2fe7acaSRobert Mustacchi }
6808f2fe7acaSRobert Mustacchi 
6809f2fe7acaSRobert Mustacchi static int
ixgbe_ufm_getcaps(ddi_ufm_handle_t * ufmh,void * arg,ddi_ufm_cap_t * caps)6810f2fe7acaSRobert Mustacchi ixgbe_ufm_getcaps(ddi_ufm_handle_t *ufmh, void *arg, ddi_ufm_cap_t *caps)
6811f2fe7acaSRobert Mustacchi {
6812f2fe7acaSRobert Mustacchi 	ixgbe_t *ixgbe = arg;
6813f2fe7acaSRobert Mustacchi 
6814f2fe7acaSRobert Mustacchi 	*caps = 0;
6815f2fe7acaSRobert Mustacchi 	switch (ixgbe->hw.eeprom.type) {
6816f2fe7acaSRobert Mustacchi 	case ixgbe_eeprom_spi:
6817f2fe7acaSRobert Mustacchi 	case ixgbe_flash:
6818f2fe7acaSRobert Mustacchi 		*caps |= DDI_UFM_CAP_REPORT;
6819f2fe7acaSRobert Mustacchi 		if (ixgbe->hw.eeprom.ops.read_buffer != NULL) {
6820f2fe7acaSRobert Mustacchi 			*caps |= DDI_UFM_CAP_READIMG;
6821f2fe7acaSRobert Mustacchi 		}
6822f2fe7acaSRobert Mustacchi 		break;
6823f2fe7acaSRobert Mustacchi 	default:
6824f2fe7acaSRobert Mustacchi 		break;
6825f2fe7acaSRobert Mustacchi 	}
6826f2fe7acaSRobert Mustacchi 
6827f2fe7acaSRobert Mustacchi 	return (0);
6828f2fe7acaSRobert Mustacchi }
6829f2fe7acaSRobert Mustacchi 
6830f2fe7acaSRobert Mustacchi static int
ixgbe_ufm_readimg(ddi_ufm_handle_t * ufmh,void * arg,uint_t imgno,uint_t slotno,uint64_t len,uint64_t offset,void * buf,uint64_t * nread)6831f2fe7acaSRobert Mustacchi ixgbe_ufm_readimg(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
6832f2fe7acaSRobert Mustacchi     uint_t slotno, uint64_t len, uint64_t offset, void *buf, uint64_t *nread)
6833f2fe7acaSRobert Mustacchi {
6834f2fe7acaSRobert Mustacchi 	int ret;
6835f2fe7acaSRobert Mustacchi 	uint16_t wordoff, nwords, *buf16 = buf;
6836f2fe7acaSRobert Mustacchi 	ixgbe_t *ixgbe = arg;
6837f2fe7acaSRobert Mustacchi 	uint32_t imgsize = ixgbe->hw.eeprom.word_size * 2;
6838f2fe7acaSRobert Mustacchi 
6839f2fe7acaSRobert Mustacchi 	if (imgno != 0 || slotno != 0) {
6840f2fe7acaSRobert Mustacchi 		return (EINVAL);
6841f2fe7acaSRobert Mustacchi 	}
6842f2fe7acaSRobert Mustacchi 
6843f2fe7acaSRobert Mustacchi 	if (len > imgsize || offset > imgsize || len + offset > imgsize) {
6844f2fe7acaSRobert Mustacchi 		return (EINVAL);
6845f2fe7acaSRobert Mustacchi 	}
6846f2fe7acaSRobert Mustacchi 
6847f2fe7acaSRobert Mustacchi 	if (ixgbe->hw.eeprom.ops.read_buffer == NULL) {
6848f2fe7acaSRobert Mustacchi 		return (ENOTSUP);
6849f2fe7acaSRobert Mustacchi 	}
6850f2fe7acaSRobert Mustacchi 
6851f2fe7acaSRobert Mustacchi 	/*
6852f2fe7acaSRobert Mustacchi 	 * Hardware provides us a means to read 16-bit words. For the time
6853f2fe7acaSRobert Mustacchi 	 * being, restrict offset and length to be 2 byte aligned. We should
6854f2fe7acaSRobert Mustacchi 	 * probably reduce this restriction. We could probably just use a bounce
6855f2fe7acaSRobert Mustacchi 	 * buffer.
6856f2fe7acaSRobert Mustacchi 	 */
6857f2fe7acaSRobert Mustacchi 	if ((offset % 2) != 0 || (len % 2) != 0) {
6858f2fe7acaSRobert Mustacchi 		return (EINVAL);
6859f2fe7acaSRobert Mustacchi 	}
6860f2fe7acaSRobert Mustacchi 
6861f2fe7acaSRobert Mustacchi 	wordoff = offset >> 1;
6862f2fe7acaSRobert Mustacchi 	nwords = len >> 1;
6863f2fe7acaSRobert Mustacchi 	mutex_enter(&ixgbe->gen_lock);
6864f2fe7acaSRobert Mustacchi 	ret = ixgbe_read_eeprom_buffer(&ixgbe->hw, wordoff, nwords, buf16);
6865f2fe7acaSRobert Mustacchi 	mutex_exit(&ixgbe->gen_lock);
6866f2fe7acaSRobert Mustacchi 
6867f2fe7acaSRobert Mustacchi 	if (ret == 0) {
6868f2fe7acaSRobert Mustacchi 		uint16_t i;
6869f2fe7acaSRobert Mustacchi 		*nread = len;
6870f2fe7acaSRobert Mustacchi 		for (i = 0; i < nwords; i++) {
6871f2fe7acaSRobert Mustacchi 			buf16[i] = LE_16(buf16[i]);
6872f2fe7acaSRobert Mustacchi 		}
6873f2fe7acaSRobert Mustacchi 	} else {
6874f2fe7acaSRobert Mustacchi 		ret = EIO;
6875f2fe7acaSRobert Mustacchi 	}
6876f2fe7acaSRobert Mustacchi 
6877f2fe7acaSRobert Mustacchi 	return (ret);
6878f2fe7acaSRobert Mustacchi }
6879