xref: /onnv-gate/usr/src/uts/common/io/ixgbe/ixgbe_main.c (revision 11233:c1a4ffd5eff0)
16621Sbt150084 /*
26621Sbt150084  * CDDL HEADER START
36621Sbt150084  *
49353SSamuel.Tu@Sun.COM  * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
56621Sbt150084  * The contents of this file are subject to the terms of the
66621Sbt150084  * Common Development and Distribution License (the "License").
76621Sbt150084  * You may not use this file except in compliance with the License.
86621Sbt150084  *
97656SSherry.Moore@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107656SSherry.Moore@Sun.COM  * or http://www.opensolaris.org/os/licensing.
116621Sbt150084  * See the License for the specific language governing permissions
126621Sbt150084  * and limitations under the License.
136621Sbt150084  *
147656SSherry.Moore@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
157656SSherry.Moore@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
166621Sbt150084  * If applicable, add the following below this CDDL HEADER, with the
176621Sbt150084  * fields enclosed by brackets "[]" replaced with your own identifying
186621Sbt150084  * information: Portions Copyright [yyyy] [name of copyright owner]
196621Sbt150084  *
206621Sbt150084  * CDDL HEADER END
216621Sbt150084  */
226621Sbt150084 
236621Sbt150084 /*
248490SPaul.Guo@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
257656SSherry.Moore@Sun.COM  * Use is subject to license terms.
267656SSherry.Moore@Sun.COM  */
277656SSherry.Moore@Sun.COM 
286621Sbt150084 #include "ixgbe_sw.h"
296621Sbt150084 
3010998SChenlu.Chen@Sun.COM static char ident[] = "Intel 10Gb Ethernet";
31*11233SPaul.Guo@Sun.COM static char ixgbe_version[] = "ixgbe 1.1.3";
326621Sbt150084 
336621Sbt150084 /*
346621Sbt150084  * Local function protoypes
356621Sbt150084  */
366621Sbt150084 static int ixgbe_register_mac(ixgbe_t *);
376621Sbt150084 static int ixgbe_identify_hardware(ixgbe_t *);
386621Sbt150084 static int ixgbe_regs_map(ixgbe_t *);
396621Sbt150084 static void ixgbe_init_properties(ixgbe_t *);
406621Sbt150084 static int ixgbe_init_driver_settings(ixgbe_t *);
416621Sbt150084 static void ixgbe_init_locks(ixgbe_t *);
426621Sbt150084 static void ixgbe_destroy_locks(ixgbe_t *);
436621Sbt150084 static int ixgbe_init(ixgbe_t *);
446621Sbt150084 static int ixgbe_chip_start(ixgbe_t *);
456621Sbt150084 static void ixgbe_chip_stop(ixgbe_t *);
466621Sbt150084 static int ixgbe_reset(ixgbe_t *);
476621Sbt150084 static void ixgbe_tx_clean(ixgbe_t *);
486621Sbt150084 static boolean_t ixgbe_tx_drain(ixgbe_t *);
496621Sbt150084 static boolean_t ixgbe_rx_drain(ixgbe_t *);
506621Sbt150084 static int ixgbe_alloc_rings(ixgbe_t *);
516621Sbt150084 static void ixgbe_free_rings(ixgbe_t *);
5210376SChenlu.Chen@Sun.COM static int ixgbe_alloc_rx_data(ixgbe_t *);
5310376SChenlu.Chen@Sun.COM static void ixgbe_free_rx_data(ixgbe_t *);
546621Sbt150084 static void ixgbe_setup_rings(ixgbe_t *);
556621Sbt150084 static void ixgbe_setup_rx(ixgbe_t *);
566621Sbt150084 static void ixgbe_setup_tx(ixgbe_t *);
576621Sbt150084 static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *);
586621Sbt150084 static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *);
596621Sbt150084 static void ixgbe_setup_rss(ixgbe_t *);
606621Sbt150084 static void ixgbe_init_unicst(ixgbe_t *);
618275SEric Cheng static int ixgbe_unicst_set(ixgbe_t *, const uint8_t *, int);
628275SEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *);
636621Sbt150084 static void ixgbe_setup_multicst(ixgbe_t *);
646621Sbt150084 static void ixgbe_get_hw_state(ixgbe_t *);
656621Sbt150084 static void ixgbe_get_conf(ixgbe_t *);
6610376SChenlu.Chen@Sun.COM static void ixgbe_init_params(ixgbe_t *);
676621Sbt150084 static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int);
68*11233SPaul.Guo@Sun.COM static void ixgbe_driver_link_check(ixgbe_t *);
699353SSamuel.Tu@Sun.COM static void ixgbe_sfp_check(void *);
70*11233SPaul.Guo@Sun.COM static void ixgbe_link_timer(void *);
716621Sbt150084 static void ixgbe_local_timer(void *);
726621Sbt150084 static void ixgbe_arm_watchdog_timer(ixgbe_t *);
736621Sbt150084 static void ixgbe_restart_watchdog_timer(ixgbe_t *);
746621Sbt150084 static void ixgbe_disable_adapter_interrupts(ixgbe_t *);
756621Sbt150084 static void ixgbe_enable_adapter_interrupts(ixgbe_t *);
766621Sbt150084 static boolean_t is_valid_mac_addr(uint8_t *);
776621Sbt150084 static boolean_t ixgbe_stall_check(ixgbe_t *);
786621Sbt150084 static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t);
796621Sbt150084 static void ixgbe_set_internal_mac_loopback(ixgbe_t *);
806621Sbt150084 static boolean_t ixgbe_find_mac_address(ixgbe_t *);
816621Sbt150084 static int ixgbe_alloc_intrs(ixgbe_t *);
826621Sbt150084 static int ixgbe_alloc_intr_handles(ixgbe_t *, int);
836621Sbt150084 static int ixgbe_add_intr_handlers(ixgbe_t *);
846621Sbt150084 static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int);
856621Sbt150084 static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int);
869353SSamuel.Tu@Sun.COM static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t);
879353SSamuel.Tu@Sun.COM static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t);
889353SSamuel.Tu@Sun.COM static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t);
899353SSamuel.Tu@Sun.COM static int ixgbe_map_intrs_to_vectors(ixgbe_t *);
906621Sbt150084 static void ixgbe_setup_adapter_vector(ixgbe_t *);
916621Sbt150084 static void ixgbe_rem_intr_handlers(ixgbe_t *);
926621Sbt150084 static void ixgbe_rem_intrs(ixgbe_t *);
936621Sbt150084 static int ixgbe_enable_intrs(ixgbe_t *);
946621Sbt150084 static int ixgbe_disable_intrs(ixgbe_t *);
956621Sbt150084 static uint_t ixgbe_intr_legacy(void *, void *);
966621Sbt150084 static uint_t ixgbe_intr_msi(void *, void *);
979353SSamuel.Tu@Sun.COM static uint_t ixgbe_intr_msix(void *, void *);
986621Sbt150084 static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *);
996621Sbt150084 static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *);
1008490SPaul.Guo@Sun.COM static void ixgbe_intr_other_work(ixgbe_t *, uint32_t);
1016621Sbt150084 static void ixgbe_get_driver_control(struct ixgbe_hw *);
1028275SEric Cheng static int ixgbe_addmac(void *, const uint8_t *);
1038275SEric Cheng static int ixgbe_remmac(void *, const uint8_t *);
1046621Sbt150084 static void ixgbe_release_driver_control(struct ixgbe_hw *);
1056621Sbt150084 
1066621Sbt150084 static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t);
1076621Sbt150084 static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t);
1086621Sbt150084 static int ixgbe_resume(dev_info_t *);
1096621Sbt150084 static int ixgbe_suspend(dev_info_t *);
1106621Sbt150084 static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *);
1116621Sbt150084 static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *);
1126621Sbt150084 
1136621Sbt150084 static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
1146621Sbt150084     const void *impl_data);
1156621Sbt150084 static void ixgbe_fm_init(ixgbe_t *);
1166621Sbt150084 static void ixgbe_fm_fini(ixgbe_t *);
1176621Sbt150084 
11810376SChenlu.Chen@Sun.COM mac_priv_prop_t ixgbe_priv_props[] = {
11910376SChenlu.Chen@Sun.COM 	{"_tx_copy_thresh", MAC_PROP_PERM_RW},
12010376SChenlu.Chen@Sun.COM 	{"_tx_recycle_thresh", MAC_PROP_PERM_RW},
12110376SChenlu.Chen@Sun.COM 	{"_tx_overload_thresh", MAC_PROP_PERM_RW},
12210376SChenlu.Chen@Sun.COM 	{"_tx_resched_thresh", MAC_PROP_PERM_RW},
12310376SChenlu.Chen@Sun.COM 	{"_rx_copy_thresh", MAC_PROP_PERM_RW},
12410376SChenlu.Chen@Sun.COM 	{"_rx_limit_per_intr", MAC_PROP_PERM_RW},
12510376SChenlu.Chen@Sun.COM 	{"_intr_throttling", MAC_PROP_PERM_RW},
12610376SChenlu.Chen@Sun.COM 	{"_adv_pause_cap", MAC_PROP_PERM_READ},
12710376SChenlu.Chen@Sun.COM 	{"_adv_asym_pause_cap", MAC_PROP_PERM_READ}
12810376SChenlu.Chen@Sun.COM };
12910376SChenlu.Chen@Sun.COM 
13010376SChenlu.Chen@Sun.COM #define	IXGBE_MAX_PRIV_PROPS \
13110376SChenlu.Chen@Sun.COM 	(sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t))
13210376SChenlu.Chen@Sun.COM 
1336621Sbt150084 static struct cb_ops ixgbe_cb_ops = {
1346621Sbt150084 	nulldev,		/* cb_open */
1356621Sbt150084 	nulldev,		/* cb_close */
1366621Sbt150084 	nodev,			/* cb_strategy */
1376621Sbt150084 	nodev,			/* cb_print */
1386621Sbt150084 	nodev,			/* cb_dump */
1396621Sbt150084 	nodev,			/* cb_read */
1406621Sbt150084 	nodev,			/* cb_write */
1416621Sbt150084 	nodev,			/* cb_ioctl */
1426621Sbt150084 	nodev,			/* cb_devmap */
1436621Sbt150084 	nodev,			/* cb_mmap */
1446621Sbt150084 	nodev,			/* cb_segmap */
1456621Sbt150084 	nochpoll,		/* cb_chpoll */
1466621Sbt150084 	ddi_prop_op,		/* cb_prop_op */
1476621Sbt150084 	NULL,			/* cb_stream */
1486621Sbt150084 	D_MP | D_HOTPLUG,	/* cb_flag */
1496621Sbt150084 	CB_REV,			/* cb_rev */
1506621Sbt150084 	nodev,			/* cb_aread */
1516621Sbt150084 	nodev			/* cb_awrite */
1526621Sbt150084 };
1536621Sbt150084 
1546621Sbt150084 static struct dev_ops ixgbe_dev_ops = {
1556621Sbt150084 	DEVO_REV,		/* devo_rev */
1566621Sbt150084 	0,			/* devo_refcnt */
1576621Sbt150084 	NULL,			/* devo_getinfo */
1586621Sbt150084 	nulldev,		/* devo_identify */
1596621Sbt150084 	nulldev,		/* devo_probe */
1606621Sbt150084 	ixgbe_attach,		/* devo_attach */
1616621Sbt150084 	ixgbe_detach,		/* devo_detach */
1626621Sbt150084 	nodev,			/* devo_reset */
1636621Sbt150084 	&ixgbe_cb_ops,		/* devo_cb_ops */
1646621Sbt150084 	NULL,			/* devo_bus_ops */
1657656SSherry.Moore@Sun.COM 	ddi_power,		/* devo_power */
1667656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
1676621Sbt150084 };
1686621Sbt150084 
1696621Sbt150084 static struct modldrv ixgbe_modldrv = {
1706621Sbt150084 	&mod_driverops,		/* Type of module.  This one is a driver */
1716621Sbt150084 	ident,			/* Discription string */
1726621Sbt150084 	&ixgbe_dev_ops		/* driver ops */
1736621Sbt150084 };
1746621Sbt150084 
1756621Sbt150084 static struct modlinkage ixgbe_modlinkage = {
1766621Sbt150084 	MODREV_1, &ixgbe_modldrv, NULL
1776621Sbt150084 };
1786621Sbt150084 
1796621Sbt150084 /*
1806621Sbt150084  * Access attributes for register mapping
1816621Sbt150084  */
1826621Sbt150084 ddi_device_acc_attr_t ixgbe_regs_acc_attr = {
1836621Sbt150084 	DDI_DEVICE_ATTR_V0,
1846621Sbt150084 	DDI_STRUCTURE_LE_ACC,
1856621Sbt150084 	DDI_STRICTORDER_ACC,
1866621Sbt150084 	DDI_FLAGERR_ACC
1876621Sbt150084 };
1886621Sbt150084 
1896621Sbt150084 /*
1906621Sbt150084  * Loopback property
1916621Sbt150084  */
1926621Sbt150084 static lb_property_t lb_normal = {
1936621Sbt150084 	normal,	"normal", IXGBE_LB_NONE
1946621Sbt150084 };
1956621Sbt150084 
1966621Sbt150084 static lb_property_t lb_mac = {
1976621Sbt150084 	internal, "MAC", IXGBE_LB_INTERNAL_MAC
1986621Sbt150084 };
1996621Sbt150084 
20011150SZhen.W@Sun.COM static lb_property_t lb_external = {
20111150SZhen.W@Sun.COM 	external, "External", IXGBE_LB_EXTERNAL
20211150SZhen.W@Sun.COM };
20311150SZhen.W@Sun.COM 
20410376SChenlu.Chen@Sun.COM #define	IXGBE_M_CALLBACK_FLAGS \
20510376SChenlu.Chen@Sun.COM 	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
2066621Sbt150084 
2076621Sbt150084 static mac_callbacks_t ixgbe_m_callbacks = {
2086621Sbt150084 	IXGBE_M_CALLBACK_FLAGS,
2096621Sbt150084 	ixgbe_m_stat,
2106621Sbt150084 	ixgbe_m_start,
2116621Sbt150084 	ixgbe_m_stop,
2126621Sbt150084 	ixgbe_m_promisc,
2136621Sbt150084 	ixgbe_m_multicst,
2148275SEric Cheng 	NULL,
2156621Sbt150084 	NULL,
2166621Sbt150084 	ixgbe_m_ioctl,
21710376SChenlu.Chen@Sun.COM 	ixgbe_m_getcapab,
21810376SChenlu.Chen@Sun.COM 	NULL,
21910376SChenlu.Chen@Sun.COM 	NULL,
22010376SChenlu.Chen@Sun.COM 	ixgbe_m_setprop,
22110376SChenlu.Chen@Sun.COM 	ixgbe_m_getprop
2226621Sbt150084 };
2236621Sbt150084 
2246621Sbt150084 /*
2258490SPaul.Guo@Sun.COM  * Initialize capabilities of each supported adapter type
2268490SPaul.Guo@Sun.COM  */
2278490SPaul.Guo@Sun.COM static adapter_info_t ixgbe_82598eb_cap = {
2288490SPaul.Guo@Sun.COM 	64,		/* maximum number of rx queues */
2298490SPaul.Guo@Sun.COM 	1,		/* minimum number of rx queues */
2308490SPaul.Guo@Sun.COM 	8,		/* default number of rx queues */
2318490SPaul.Guo@Sun.COM 	32,		/* maximum number of tx queues */
2328490SPaul.Guo@Sun.COM 	1,		/* minimum number of tx queues */
2338490SPaul.Guo@Sun.COM 	8,		/* default number of tx queues */
23411150SZhen.W@Sun.COM 	16366,		/* maximum MTU size */
23510376SChenlu.Chen@Sun.COM 	0xFFFF,		/* maximum interrupt throttle rate */
23610376SChenlu.Chen@Sun.COM 	0,		/* minimum interrupt throttle rate */
23710376SChenlu.Chen@Sun.COM 	200,		/* default interrupt throttle rate */
2388490SPaul.Guo@Sun.COM 	18,		/* maximum total msix vectors */
2398490SPaul.Guo@Sun.COM 	16,		/* maximum number of ring vectors */
2408490SPaul.Guo@Sun.COM 	2,		/* maximum number of other vectors */
2418490SPaul.Guo@Sun.COM 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
2428490SPaul.Guo@Sun.COM 	(IXGBE_FLAG_DCA_CAPABLE	/* capability flags */
2438490SPaul.Guo@Sun.COM 	| IXGBE_FLAG_RSS_CAPABLE
2448490SPaul.Guo@Sun.COM 	| IXGBE_FLAG_VMDQ_CAPABLE)
2458490SPaul.Guo@Sun.COM };
2468490SPaul.Guo@Sun.COM 
2479353SSamuel.Tu@Sun.COM static adapter_info_t ixgbe_82599eb_cap = {
2489353SSamuel.Tu@Sun.COM 	128,		/* maximum number of rx queues */
2499353SSamuel.Tu@Sun.COM 	1,		/* minimum number of rx queues */
2509353SSamuel.Tu@Sun.COM 	8,		/* default number of rx queues */
2519353SSamuel.Tu@Sun.COM 	128,		/* maximum number of tx queues */
2529353SSamuel.Tu@Sun.COM 	1,		/* minimum number of tx queues */
2539353SSamuel.Tu@Sun.COM 	8,		/* default number of tx queues */
25411150SZhen.W@Sun.COM 	15500,		/* maximum MTU size */
25510376SChenlu.Chen@Sun.COM 	0xFF8,		/* maximum interrupt throttle rate */
25610376SChenlu.Chen@Sun.COM 	0,		/* minimum interrupt throttle rate */
25710376SChenlu.Chen@Sun.COM 	200,		/* default interrupt throttle rate */
2589353SSamuel.Tu@Sun.COM 	64,		/* maximum total msix vectors */
2599353SSamuel.Tu@Sun.COM 	16,		/* maximum number of ring vectors */
2609353SSamuel.Tu@Sun.COM 	2,		/* maximum number of other vectors */
2619353SSamuel.Tu@Sun.COM 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
2629353SSamuel.Tu@Sun.COM 	(IXGBE_FLAG_DCA_CAPABLE	/* capability flags */
2639353SSamuel.Tu@Sun.COM 	| IXGBE_FLAG_RSS_CAPABLE
2649353SSamuel.Tu@Sun.COM 	| IXGBE_FLAG_VMDQ_CAPABLE)
2659353SSamuel.Tu@Sun.COM };
2669353SSamuel.Tu@Sun.COM 
2678490SPaul.Guo@Sun.COM /*
2686621Sbt150084  * Module Initialization Functions.
2696621Sbt150084  */
2706621Sbt150084 
2716621Sbt150084 int
2726621Sbt150084 _init(void)
2736621Sbt150084 {
2746621Sbt150084 	int status;
2756621Sbt150084 
2766621Sbt150084 	mac_init_ops(&ixgbe_dev_ops, MODULE_NAME);
2776621Sbt150084 
2786621Sbt150084 	status = mod_install(&ixgbe_modlinkage);
2796621Sbt150084 
2806621Sbt150084 	if (status != DDI_SUCCESS) {
2816621Sbt150084 		mac_fini_ops(&ixgbe_dev_ops);
2826621Sbt150084 	}
2836621Sbt150084 
2846621Sbt150084 	return (status);
2856621Sbt150084 }
2866621Sbt150084 
2876621Sbt150084 int
2886621Sbt150084 _fini(void)
2896621Sbt150084 {
2906621Sbt150084 	int status;
2916621Sbt150084 
2926621Sbt150084 	status = mod_remove(&ixgbe_modlinkage);
2936621Sbt150084 
2946621Sbt150084 	if (status == DDI_SUCCESS) {
2956621Sbt150084 		mac_fini_ops(&ixgbe_dev_ops);
2966621Sbt150084 	}
2976621Sbt150084 
2986621Sbt150084 	return (status);
2996621Sbt150084 }
3006621Sbt150084 
3016621Sbt150084 int
3026621Sbt150084 _info(struct modinfo *modinfop)
3036621Sbt150084 {
3046621Sbt150084 	int status;
3056621Sbt150084 
3066621Sbt150084 	status = mod_info(&ixgbe_modlinkage, modinfop);
3076621Sbt150084 
3086621Sbt150084 	return (status);
3096621Sbt150084 }
3106621Sbt150084 
3116621Sbt150084 /*
3126621Sbt150084  * ixgbe_attach - Driver attach.
3136621Sbt150084  *
3146621Sbt150084  * This function is the device specific initialization entry
3156621Sbt150084  * point. This entry point is required and must be written.
3166621Sbt150084  * The DDI_ATTACH command must be provided in the attach entry
3176621Sbt150084  * point. When attach() is called with cmd set to DDI_ATTACH,
3186621Sbt150084  * all normal kernel services (such as kmem_alloc(9F)) are
3196621Sbt150084  * available for use by the driver.
3206621Sbt150084  *
3216621Sbt150084  * The attach() function will be called once for each instance
3226621Sbt150084  * of  the  device  on  the  system with cmd set to DDI_ATTACH.
3236621Sbt150084  * Until attach() succeeds, the only driver entry points which
3246621Sbt150084  * may be called are open(9E) and getinfo(9E).
3256621Sbt150084  */
3266621Sbt150084 static int
3276621Sbt150084 ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3286621Sbt150084 {
3296621Sbt150084 	ixgbe_t *ixgbe;
3306621Sbt150084 	struct ixgbe_osdep *osdep;
3316621Sbt150084 	struct ixgbe_hw *hw;
3326621Sbt150084 	int instance;
3338490SPaul.Guo@Sun.COM 	char taskqname[32];
3346621Sbt150084 
3356621Sbt150084 	/*
3366621Sbt150084 	 * Check the command and perform corresponding operations
3376621Sbt150084 	 */
3386621Sbt150084 	switch (cmd) {
3396621Sbt150084 	default:
3406621Sbt150084 		return (DDI_FAILURE);
3416621Sbt150084 
3426621Sbt150084 	case DDI_RESUME:
3436621Sbt150084 		return (ixgbe_resume(devinfo));
3446621Sbt150084 
3456621Sbt150084 	case DDI_ATTACH:
3466621Sbt150084 		break;
3476621Sbt150084 	}
3486621Sbt150084 
3496621Sbt150084 	/* Get the device instance */
3506621Sbt150084 	instance = ddi_get_instance(devinfo);
3516621Sbt150084 
3526621Sbt150084 	/* Allocate memory for the instance data structure */
3536621Sbt150084 	ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP);
3546621Sbt150084 
3556621Sbt150084 	ixgbe->dip = devinfo;
3566621Sbt150084 	ixgbe->instance = instance;
3576621Sbt150084 
3586621Sbt150084 	hw = &ixgbe->hw;
3596621Sbt150084 	osdep = &ixgbe->osdep;
3606621Sbt150084 	hw->back = osdep;
3616621Sbt150084 	osdep->ixgbe = ixgbe;
3626621Sbt150084 
3636621Sbt150084 	/* Attach the instance pointer to the dev_info data structure */
3646621Sbt150084 	ddi_set_driver_private(devinfo, ixgbe);
3656621Sbt150084 
3666621Sbt150084 	/*
3676621Sbt150084 	 * Initialize for fma support
3686621Sbt150084 	 */
3697167Sgg161487 	ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE,
3706621Sbt150084 	    0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
3716621Sbt150084 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
3726621Sbt150084 	ixgbe_fm_init(ixgbe);
3736621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT;
3746621Sbt150084 
3756621Sbt150084 	/*
3766621Sbt150084 	 * Map PCI config space registers
3776621Sbt150084 	 */
3786621Sbt150084 	if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
3796621Sbt150084 		ixgbe_error(ixgbe, "Failed to map PCI configurations");
3806621Sbt150084 		goto attach_fail;
3816621Sbt150084 	}
3826621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
3836621Sbt150084 
3846621Sbt150084 	/*
3856621Sbt150084 	 * Identify the chipset family
3866621Sbt150084 	 */
3876621Sbt150084 	if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) {
3886621Sbt150084 		ixgbe_error(ixgbe, "Failed to identify hardware");
3896621Sbt150084 		goto attach_fail;
3906621Sbt150084 	}
3916621Sbt150084 
3926621Sbt150084 	/*
3936621Sbt150084 	 * Map device registers
3946621Sbt150084 	 */
3956621Sbt150084 	if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) {
3966621Sbt150084 		ixgbe_error(ixgbe, "Failed to map device registers");
3976621Sbt150084 		goto attach_fail;
3986621Sbt150084 	}
3996621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP;
4006621Sbt150084 
4016621Sbt150084 	/*
4026621Sbt150084 	 * Initialize driver parameters
4036621Sbt150084 	 */
4046621Sbt150084 	ixgbe_init_properties(ixgbe);
4056621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS;
4066621Sbt150084 
4076621Sbt150084 	/*
4086621Sbt150084 	 * Allocate interrupts
4096621Sbt150084 	 */
4106621Sbt150084 	if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) {
4116621Sbt150084 		ixgbe_error(ixgbe, "Failed to allocate interrupts");
4126621Sbt150084 		goto attach_fail;
4136621Sbt150084 	}
4146621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
4156621Sbt150084 
4166621Sbt150084 	/*
4176621Sbt150084 	 * Allocate rx/tx rings based on the ring numbers.
4186621Sbt150084 	 * The actual numbers of rx/tx rings are decided by the number of
4196621Sbt150084 	 * allocated interrupt vectors, so we should allocate the rings after
4206621Sbt150084 	 * interrupts are allocated.
4216621Sbt150084 	 */
4226621Sbt150084 	if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) {
4236621Sbt150084 		ixgbe_error(ixgbe, "Failed to allocate rx and tx rings");
4246621Sbt150084 		goto attach_fail;
4256621Sbt150084 	}
4266621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS;
4276621Sbt150084 
4286621Sbt150084 	/*
4296621Sbt150084 	 * Map rings to interrupt vectors
4306621Sbt150084 	 */
4319353SSamuel.Tu@Sun.COM 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
4329353SSamuel.Tu@Sun.COM 		ixgbe_error(ixgbe, "Failed to map interrupts to vectors");
4336621Sbt150084 		goto attach_fail;
4346621Sbt150084 	}
4356621Sbt150084 
4366621Sbt150084 	/*
4376621Sbt150084 	 * Add interrupt handlers
4386621Sbt150084 	 */
4396621Sbt150084 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
4406621Sbt150084 		ixgbe_error(ixgbe, "Failed to add interrupt handlers");
4416621Sbt150084 		goto attach_fail;
4426621Sbt150084 	}
4436621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
4446621Sbt150084 
4456621Sbt150084 	/*
446*11233SPaul.Guo@Sun.COM 	 * Create a taskq for sfp-change
4478490SPaul.Guo@Sun.COM 	 */
4488490SPaul.Guo@Sun.COM 	(void) sprintf(taskqname, "ixgbe%d_taskq", instance);
449*11233SPaul.Guo@Sun.COM 	if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname,
4508490SPaul.Guo@Sun.COM 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
4518490SPaul.Guo@Sun.COM 		ixgbe_error(ixgbe, "taskq_create failed");
4528490SPaul.Guo@Sun.COM 		goto attach_fail;
4538490SPaul.Guo@Sun.COM 	}
454*11233SPaul.Guo@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ;
4558490SPaul.Guo@Sun.COM 
4568490SPaul.Guo@Sun.COM 	/*
4576621Sbt150084 	 * Initialize driver parameters
4586621Sbt150084 	 */
4596621Sbt150084 	if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) {
4606621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize driver settings");
4616621Sbt150084 		goto attach_fail;
4626621Sbt150084 	}
4636621Sbt150084 
4646621Sbt150084 	/*
4656621Sbt150084 	 * Initialize mutexes for this device.
4666621Sbt150084 	 * Do this before enabling the interrupt handler and
4676621Sbt150084 	 * register the softint to avoid the condition where
4686621Sbt150084 	 * interrupt handler can try using uninitialized mutex.
4696621Sbt150084 	 */
4706621Sbt150084 	ixgbe_init_locks(ixgbe);
4716621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS;
4726621Sbt150084 
4736621Sbt150084 	/*
4746621Sbt150084 	 * Initialize chipset hardware
4756621Sbt150084 	 */
4766621Sbt150084 	if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) {
4776621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize adapter");
4786621Sbt150084 		goto attach_fail;
4796621Sbt150084 	}
480*11233SPaul.Guo@Sun.COM 	ixgbe->link_check_complete = B_FALSE;
481*11233SPaul.Guo@Sun.COM 	ixgbe->link_check_hrtime = gethrtime() +
482*11233SPaul.Guo@Sun.COM 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
4836621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_INIT;
4846621Sbt150084 
4856621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) {
4866621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
4876621Sbt150084 		goto attach_fail;
4886621Sbt150084 	}
4896621Sbt150084 
4906621Sbt150084 	/*
4916621Sbt150084 	 * Initialize statistics
4926621Sbt150084 	 */
4936621Sbt150084 	if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) {
4946621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize statistics");
4956621Sbt150084 		goto attach_fail;
4966621Sbt150084 	}
4976621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_STATS;
4986621Sbt150084 
4996621Sbt150084 	/*
5006621Sbt150084 	 * Register the driver to the MAC
5016621Sbt150084 	 */
5026621Sbt150084 	if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) {
5036621Sbt150084 		ixgbe_error(ixgbe, "Failed to register MAC");
5046621Sbt150084 		goto attach_fail;
5056621Sbt150084 	}
5068490SPaul.Guo@Sun.COM 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
5076621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_MAC;
5086621Sbt150084 
509*11233SPaul.Guo@Sun.COM 	ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe,
510*11233SPaul.Guo@Sun.COM 	    IXGBE_CYCLIC_PERIOD, DDI_IPL_0);
511*11233SPaul.Guo@Sun.COM 	if (ixgbe->periodic_id == 0) {
512*11233SPaul.Guo@Sun.COM 		ixgbe_error(ixgbe, "Failed to add the link check timer");
513*11233SPaul.Guo@Sun.COM 		goto attach_fail;
514*11233SPaul.Guo@Sun.COM 	}
515*11233SPaul.Guo@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER;
516*11233SPaul.Guo@Sun.COM 
5176621Sbt150084 	/*
5186621Sbt150084 	 * Now that mutex locks are initialized, and the chip is also
5196621Sbt150084 	 * initialized, enable interrupts.
5206621Sbt150084 	 */
5216621Sbt150084 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
5226621Sbt150084 		ixgbe_error(ixgbe, "Failed to enable DDI interrupts");
5236621Sbt150084 		goto attach_fail;
5246621Sbt150084 	}
5256621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
5266621Sbt150084 
52710998SChenlu.Chen@Sun.COM 	ixgbe_log(ixgbe, "%s", ixgbe_version);
528*11233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED);
5296621Sbt150084 
5306621Sbt150084 	return (DDI_SUCCESS);
5316621Sbt150084 
5326621Sbt150084 attach_fail:
5336621Sbt150084 	ixgbe_unconfigure(devinfo, ixgbe);
5346621Sbt150084 	return (DDI_FAILURE);
5356621Sbt150084 }
5366621Sbt150084 
5376621Sbt150084 /*
5386621Sbt150084  * ixgbe_detach - Driver detach.
5396621Sbt150084  *
5406621Sbt150084  * The detach() function is the complement of the attach routine.
5416621Sbt150084  * If cmd is set to DDI_DETACH, detach() is used to remove  the
5426621Sbt150084  * state  associated  with  a  given  instance of a device node
5436621Sbt150084  * prior to the removal of that instance from the system.
5446621Sbt150084  *
5456621Sbt150084  * The detach() function will be called once for each  instance
5466621Sbt150084  * of the device for which there has been a successful attach()
5476621Sbt150084  * once there are no longer  any  opens  on  the  device.
5486621Sbt150084  *
5496621Sbt150084  * Interrupts routine are disabled, All memory allocated by this
5506621Sbt150084  * driver are freed.
5516621Sbt150084  */
5526621Sbt150084 static int
5536621Sbt150084 ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
5546621Sbt150084 {
5556621Sbt150084 	ixgbe_t *ixgbe;
5566621Sbt150084 
5576621Sbt150084 	/*
5586621Sbt150084 	 * Check detach command
5596621Sbt150084 	 */
5606621Sbt150084 	switch (cmd) {
5616621Sbt150084 	default:
5626621Sbt150084 		return (DDI_FAILURE);
5636621Sbt150084 
5646621Sbt150084 	case DDI_SUSPEND:
5656621Sbt150084 		return (ixgbe_suspend(devinfo));
5666621Sbt150084 
5676621Sbt150084 	case DDI_DETACH:
5686621Sbt150084 		break;
5696621Sbt150084 	}
5706621Sbt150084 
5716621Sbt150084 	/*
5726621Sbt150084 	 * Get the pointer to the driver private data structure
5736621Sbt150084 	 */
5746621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
5756621Sbt150084 	if (ixgbe == NULL)
5766621Sbt150084 		return (DDI_FAILURE);
5776621Sbt150084 
5786621Sbt150084 	/*
5796621Sbt150084 	 * If the device is still running, it needs to be stopped first.
5806621Sbt150084 	 * This check is necessary because under some specific circumstances,
5816621Sbt150084 	 * the detach routine can be called without stopping the interface
5826621Sbt150084 	 * first.
5836621Sbt150084 	 */
5846621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
585*11233SPaul.Guo@Sun.COM 		atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
586*11233SPaul.Guo@Sun.COM 		mutex_enter(&ixgbe->gen_lock);
58710376SChenlu.Chen@Sun.COM 		ixgbe_stop(ixgbe, B_TRUE);
5886621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
5896621Sbt150084 		/* Disable and stop the watchdog timer */
5906621Sbt150084 		ixgbe_disable_watchdog_timer(ixgbe);
591*11233SPaul.Guo@Sun.COM 	}
5926621Sbt150084 
5936621Sbt150084 	/*
5946621Sbt150084 	 * Check if there are still rx buffers held by the upper layer.
5956621Sbt150084 	 * If so, fail the detach.
5966621Sbt150084 	 */
5976621Sbt150084 	if (!ixgbe_rx_drain(ixgbe))
5986621Sbt150084 		return (DDI_FAILURE);
5996621Sbt150084 
6006621Sbt150084 	/*
6016621Sbt150084 	 * Do the remaining unconfigure routines
6026621Sbt150084 	 */
6036621Sbt150084 	ixgbe_unconfigure(devinfo, ixgbe);
6046621Sbt150084 
6056621Sbt150084 	return (DDI_SUCCESS);
6066621Sbt150084 }
6076621Sbt150084 
6086621Sbt150084 static void
6096621Sbt150084 ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe)
6106621Sbt150084 {
6116621Sbt150084 	/*
6126621Sbt150084 	 * Disable interrupt
6136621Sbt150084 	 */
6146621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
6156621Sbt150084 		(void) ixgbe_disable_intrs(ixgbe);
6166621Sbt150084 	}
6176621Sbt150084 
6186621Sbt150084 	/*
619*11233SPaul.Guo@Sun.COM 	 * remove the link check timer
620*11233SPaul.Guo@Sun.COM 	 */
621*11233SPaul.Guo@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) {
622*11233SPaul.Guo@Sun.COM 		if (ixgbe->periodic_id != NULL) {
623*11233SPaul.Guo@Sun.COM 			ddi_periodic_delete(ixgbe->periodic_id);
624*11233SPaul.Guo@Sun.COM 			ixgbe->periodic_id = NULL;
625*11233SPaul.Guo@Sun.COM 		}
626*11233SPaul.Guo@Sun.COM 	}
627*11233SPaul.Guo@Sun.COM 
628*11233SPaul.Guo@Sun.COM 	/*
6296621Sbt150084 	 * Unregister MAC
6306621Sbt150084 	 */
6316621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) {
6326621Sbt150084 		(void) mac_unregister(ixgbe->mac_hdl);
6336621Sbt150084 	}
6346621Sbt150084 
6356621Sbt150084 	/*
6366621Sbt150084 	 * Free statistics
6376621Sbt150084 	 */
6386621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) {
6396621Sbt150084 		kstat_delete((kstat_t *)ixgbe->ixgbe_ks);
6406621Sbt150084 	}
6416621Sbt150084 
6426621Sbt150084 	/*
6436621Sbt150084 	 * Remove interrupt handlers
6446621Sbt150084 	 */
6456621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
6466621Sbt150084 		ixgbe_rem_intr_handlers(ixgbe);
6476621Sbt150084 	}
6486621Sbt150084 
6496621Sbt150084 	/*
650*11233SPaul.Guo@Sun.COM 	 * Remove taskq for sfp-status-change
6518490SPaul.Guo@Sun.COM 	 */
652*11233SPaul.Guo@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) {
653*11233SPaul.Guo@Sun.COM 		ddi_taskq_destroy(ixgbe->sfp_taskq);
6548490SPaul.Guo@Sun.COM 	}
6558490SPaul.Guo@Sun.COM 
6568490SPaul.Guo@Sun.COM 	/*
6576621Sbt150084 	 * Remove interrupts
6586621Sbt150084 	 */
6596621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) {
6606621Sbt150084 		ixgbe_rem_intrs(ixgbe);
6616621Sbt150084 	}
6626621Sbt150084 
6636621Sbt150084 	/*
6646621Sbt150084 	 * Remove driver properties
6656621Sbt150084 	 */
6666621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) {
6676621Sbt150084 		(void) ddi_prop_remove_all(devinfo);
6686621Sbt150084 	}
6696621Sbt150084 
6706621Sbt150084 	/*
6716621Sbt150084 	 * Stop the chipset
6726621Sbt150084 	 */
6736621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) {
6746621Sbt150084 		mutex_enter(&ixgbe->gen_lock);
6756621Sbt150084 		ixgbe_chip_stop(ixgbe);
6766621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
6776621Sbt150084 	}
6786621Sbt150084 
6796621Sbt150084 	/*
6806621Sbt150084 	 * Free register handle
6816621Sbt150084 	 */
6826621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
6836621Sbt150084 		if (ixgbe->osdep.reg_handle != NULL)
6846621Sbt150084 			ddi_regs_map_free(&ixgbe->osdep.reg_handle);
6856621Sbt150084 	}
6866621Sbt150084 
6876621Sbt150084 	/*
6886621Sbt150084 	 * Free PCI config handle
6896621Sbt150084 	 */
6906621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) {
6916621Sbt150084 		if (ixgbe->osdep.cfg_handle != NULL)
6926621Sbt150084 			pci_config_teardown(&ixgbe->osdep.cfg_handle);
6936621Sbt150084 	}
6946621Sbt150084 
6956621Sbt150084 	/*
6966621Sbt150084 	 * Free locks
6976621Sbt150084 	 */
6986621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) {
6996621Sbt150084 		ixgbe_destroy_locks(ixgbe);
7006621Sbt150084 	}
7016621Sbt150084 
7026621Sbt150084 	/*
7036621Sbt150084 	 * Free the rx/tx rings
7046621Sbt150084 	 */
7056621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) {
7066621Sbt150084 		ixgbe_free_rings(ixgbe);
7076621Sbt150084 	}
7086621Sbt150084 
7096621Sbt150084 	/*
7106621Sbt150084 	 * Unregister FMA capabilities
7116621Sbt150084 	 */
7126621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) {
7136621Sbt150084 		ixgbe_fm_fini(ixgbe);
7146621Sbt150084 	}
7156621Sbt150084 
7166621Sbt150084 	/*
7176621Sbt150084 	 * Free the driver data structure
7186621Sbt150084 	 */
7196621Sbt150084 	kmem_free(ixgbe, sizeof (ixgbe_t));
7206621Sbt150084 
7216621Sbt150084 	ddi_set_driver_private(devinfo, NULL);
7226621Sbt150084 }
7236621Sbt150084 
7246621Sbt150084 /*
7256621Sbt150084  * ixgbe_register_mac - Register the driver and its function pointers with
7266621Sbt150084  * the GLD interface.
7276621Sbt150084  */
7286621Sbt150084 static int
7296621Sbt150084 ixgbe_register_mac(ixgbe_t *ixgbe)
7306621Sbt150084 {
7316621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
7326621Sbt150084 	mac_register_t *mac;
7336621Sbt150084 	int status;
7346621Sbt150084 
7356621Sbt150084 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
7366621Sbt150084 		return (IXGBE_FAILURE);
7376621Sbt150084 
7386621Sbt150084 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
7396621Sbt150084 	mac->m_driver = ixgbe;
7406621Sbt150084 	mac->m_dip = ixgbe->dip;
7416621Sbt150084 	mac->m_src_addr = hw->mac.addr;
7426621Sbt150084 	mac->m_callbacks = &ixgbe_m_callbacks;
7436621Sbt150084 	mac->m_min_sdu = 0;
7446621Sbt150084 	mac->m_max_sdu = ixgbe->default_mtu;
7456621Sbt150084 	mac->m_margin = VLAN_TAGSZ;
74610376SChenlu.Chen@Sun.COM 	mac->m_priv_props = ixgbe_priv_props;
74710376SChenlu.Chen@Sun.COM 	mac->m_priv_prop_count = IXGBE_MAX_PRIV_PROPS;
7488275SEric Cheng 	mac->m_v12n = MAC_VIRT_LEVEL1;
7496621Sbt150084 
7506621Sbt150084 	status = mac_register(mac, &ixgbe->mac_hdl);
7516621Sbt150084 
7526621Sbt150084 	mac_free(mac);
7536621Sbt150084 
7546621Sbt150084 	return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE);
7556621Sbt150084 }
7566621Sbt150084 
7576621Sbt150084 /*
7586621Sbt150084  * ixgbe_identify_hardware - Identify the type of the chipset.
7596621Sbt150084  */
7606621Sbt150084 static int
7616621Sbt150084 ixgbe_identify_hardware(ixgbe_t *ixgbe)
7626621Sbt150084 {
7636621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
7646621Sbt150084 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
7656621Sbt150084 
7666621Sbt150084 	/*
7676621Sbt150084 	 * Get the device id
7686621Sbt150084 	 */
7696621Sbt150084 	hw->vendor_id =
7706621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
7716621Sbt150084 	hw->device_id =
7726621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
7736621Sbt150084 	hw->revision_id =
7746621Sbt150084 	    pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
7756621Sbt150084 	hw->subsystem_device_id =
7766621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
7776621Sbt150084 	hw->subsystem_vendor_id =
7786621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
7796621Sbt150084 
7808490SPaul.Guo@Sun.COM 	/*
7818490SPaul.Guo@Sun.COM 	 * Set the mac type of the adapter based on the device id
7828490SPaul.Guo@Sun.COM 	 */
7838490SPaul.Guo@Sun.COM 	if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) {
7848490SPaul.Guo@Sun.COM 		return (IXGBE_FAILURE);
7858490SPaul.Guo@Sun.COM 	}
7868490SPaul.Guo@Sun.COM 
7878490SPaul.Guo@Sun.COM 	/*
7888490SPaul.Guo@Sun.COM 	 * Install adapter capabilities
7898490SPaul.Guo@Sun.COM 	 */
7908490SPaul.Guo@Sun.COM 	switch (hw->mac.type) {
7918490SPaul.Guo@Sun.COM 	case ixgbe_mac_82598EB:
7929353SSamuel.Tu@Sun.COM 		ixgbe_log(ixgbe, "identify 82598 adapter\n");
7938490SPaul.Guo@Sun.COM 		ixgbe->capab = &ixgbe_82598eb_cap;
7948490SPaul.Guo@Sun.COM 
7958490SPaul.Guo@Sun.COM 		if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) {
7968490SPaul.Guo@Sun.COM 			ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
7978490SPaul.Guo@Sun.COM 			ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1;
7988490SPaul.Guo@Sun.COM 		}
7999353SSamuel.Tu@Sun.COM 		ixgbe->capab->other_intr |= IXGBE_EICR_LSC;
8009353SSamuel.Tu@Sun.COM 
8019353SSamuel.Tu@Sun.COM 		break;
8029353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
8039353SSamuel.Tu@Sun.COM 		ixgbe_log(ixgbe, "identify 82599 adapter\n");
8049353SSamuel.Tu@Sun.COM 		ixgbe->capab = &ixgbe_82599eb_cap;
8059353SSamuel.Tu@Sun.COM 
8069353SSamuel.Tu@Sun.COM 		ixgbe->capab->other_intr = (IXGBE_EICR_GPI_SDP1 |
8079353SSamuel.Tu@Sun.COM 		    IXGBE_EICR_GPI_SDP2 | IXGBE_EICR_LSC);
8088490SPaul.Guo@Sun.COM 
8098490SPaul.Guo@Sun.COM 		break;
8108490SPaul.Guo@Sun.COM 	default:
8118490SPaul.Guo@Sun.COM 		ixgbe_log(ixgbe,
8128490SPaul.Guo@Sun.COM 		    "adapter not supported in ixgbe_identify_hardware(): %d\n",
8138490SPaul.Guo@Sun.COM 		    hw->mac.type);
8148490SPaul.Guo@Sun.COM 		return (IXGBE_FAILURE);
8158490SPaul.Guo@Sun.COM 	}
8168490SPaul.Guo@Sun.COM 
8176621Sbt150084 	return (IXGBE_SUCCESS);
8186621Sbt150084 }
8196621Sbt150084 
8206621Sbt150084 /*
8216621Sbt150084  * ixgbe_regs_map - Map the device registers.
8226621Sbt150084  *
8236621Sbt150084  */
8246621Sbt150084 static int
8256621Sbt150084 ixgbe_regs_map(ixgbe_t *ixgbe)
8266621Sbt150084 {
8276621Sbt150084 	dev_info_t *devinfo = ixgbe->dip;
8286621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
8296621Sbt150084 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
8306621Sbt150084 	off_t mem_size;
8316621Sbt150084 
8326621Sbt150084 	/*
8336621Sbt150084 	 * First get the size of device registers to be mapped.
8346621Sbt150084 	 */
8359353SSamuel.Tu@Sun.COM 	if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size)
8369353SSamuel.Tu@Sun.COM 	    != DDI_SUCCESS) {
8376621Sbt150084 		return (IXGBE_FAILURE);
8386621Sbt150084 	}
8396621Sbt150084 
8406621Sbt150084 	/*
8416621Sbt150084 	 * Call ddi_regs_map_setup() to map registers
8426621Sbt150084 	 */
8439353SSamuel.Tu@Sun.COM 	if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET,
8446621Sbt150084 	    (caddr_t *)&hw->hw_addr, 0,
8456621Sbt150084 	    mem_size, &ixgbe_regs_acc_attr,
8466621Sbt150084 	    &osdep->reg_handle)) != DDI_SUCCESS) {
8476621Sbt150084 		return (IXGBE_FAILURE);
8486621Sbt150084 	}
8496621Sbt150084 
8506621Sbt150084 	return (IXGBE_SUCCESS);
8516621Sbt150084 }
8526621Sbt150084 
8536621Sbt150084 /*
8546621Sbt150084  * ixgbe_init_properties - Initialize driver properties.
8556621Sbt150084  */
8566621Sbt150084 static void
8576621Sbt150084 ixgbe_init_properties(ixgbe_t *ixgbe)
8586621Sbt150084 {
8596621Sbt150084 	/*
8606621Sbt150084 	 * Get conf file properties, including link settings
8616621Sbt150084 	 * jumbo frames, ring number, descriptor number, etc.
8626621Sbt150084 	 */
8636621Sbt150084 	ixgbe_get_conf(ixgbe);
86410376SChenlu.Chen@Sun.COM 
86510376SChenlu.Chen@Sun.COM 	ixgbe_init_params(ixgbe);
8666621Sbt150084 }
8676621Sbt150084 
8686621Sbt150084 /*
8696621Sbt150084  * ixgbe_init_driver_settings - Initialize driver settings.
8706621Sbt150084  *
8716621Sbt150084  * The settings include hardware function pointers, bus information,
8726621Sbt150084  * rx/tx rings settings, link state, and any other parameters that
8736621Sbt150084  * need to be setup during driver initialization.
8746621Sbt150084  */
8756621Sbt150084 static int
8766621Sbt150084 ixgbe_init_driver_settings(ixgbe_t *ixgbe)
8776621Sbt150084 {
8786621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
8798275SEric Cheng 	dev_info_t *devinfo = ixgbe->dip;
8806621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
8816621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
8826621Sbt150084 	uint32_t rx_size;
8836621Sbt150084 	uint32_t tx_size;
8846621Sbt150084 	int i;
8856621Sbt150084 
8866621Sbt150084 	/*
8876621Sbt150084 	 * Initialize chipset specific hardware function pointers
8886621Sbt150084 	 */
8896621Sbt150084 	if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) {
8906621Sbt150084 		return (IXGBE_FAILURE);
8916621Sbt150084 	}
8926621Sbt150084 
8936621Sbt150084 	/*
8948275SEric Cheng 	 * Get the system page size
8958275SEric Cheng 	 */
8968275SEric Cheng 	ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1);
8978275SEric Cheng 
8988275SEric Cheng 	/*
8996621Sbt150084 	 * Set rx buffer size
9006621Sbt150084 	 *
9016621Sbt150084 	 * The IP header alignment room is counted in the calculation.
9026621Sbt150084 	 * The rx buffer size is in unit of 1K that is required by the
9036621Sbt150084 	 * chipset hardware.
9046621Sbt150084 	 */
9056621Sbt150084 	rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
9066621Sbt150084 	ixgbe->rx_buf_size = ((rx_size >> 10) +
9076621Sbt150084 	    ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
9086621Sbt150084 
9096621Sbt150084 	/*
9106621Sbt150084 	 * Set tx buffer size
9116621Sbt150084 	 */
9126621Sbt150084 	tx_size = ixgbe->max_frame_size;
9136621Sbt150084 	ixgbe->tx_buf_size = ((tx_size >> 10) +
9146621Sbt150084 	    ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
9156621Sbt150084 
9166621Sbt150084 	/*
9176621Sbt150084 	 * Initialize rx/tx rings parameters
9186621Sbt150084 	 */
9196621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
9206621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
9216621Sbt150084 		rx_ring->index = i;
9226621Sbt150084 		rx_ring->ixgbe = ixgbe;
9236621Sbt150084 	}
9246621Sbt150084 
9256621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
9266621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
9276621Sbt150084 		tx_ring->index = i;
9286621Sbt150084 		tx_ring->ixgbe = ixgbe;
9296621Sbt150084 		if (ixgbe->tx_head_wb_enable)
9306621Sbt150084 			tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb;
9316621Sbt150084 		else
9326621Sbt150084 			tx_ring->tx_recycle = ixgbe_tx_recycle_legacy;
9336621Sbt150084 
9346621Sbt150084 		tx_ring->ring_size = ixgbe->tx_ring_size;
9356621Sbt150084 		tx_ring->free_list_size = ixgbe->tx_ring_size +
9366621Sbt150084 		    (ixgbe->tx_ring_size >> 1);
9376621Sbt150084 	}
9386621Sbt150084 
9396621Sbt150084 	/*
9406621Sbt150084 	 * Initialize values of interrupt throttling rate
9416621Sbt150084 	 */
9429353SSamuel.Tu@Sun.COM 	for (i = 1; i < MAX_INTR_VECTOR; i++)
9436621Sbt150084 		ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0];
9446621Sbt150084 
9456621Sbt150084 	/*
9466621Sbt150084 	 * The initial link state should be "unknown"
9476621Sbt150084 	 */
9486621Sbt150084 	ixgbe->link_state = LINK_STATE_UNKNOWN;
9499353SSamuel.Tu@Sun.COM 
9506621Sbt150084 	return (IXGBE_SUCCESS);
9516621Sbt150084 }
9526621Sbt150084 
9536621Sbt150084 /*
9546621Sbt150084  * ixgbe_init_locks - Initialize locks.
9556621Sbt150084  */
9566621Sbt150084 static void
9576621Sbt150084 ixgbe_init_locks(ixgbe_t *ixgbe)
9586621Sbt150084 {
9596621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
9606621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
9616621Sbt150084 	int i;
9626621Sbt150084 
9636621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
9646621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
9656621Sbt150084 		mutex_init(&rx_ring->rx_lock, NULL,
9666621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
9676621Sbt150084 	}
9686621Sbt150084 
9696621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
9706621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
9716621Sbt150084 		mutex_init(&tx_ring->tx_lock, NULL,
9726621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
9736621Sbt150084 		mutex_init(&tx_ring->recycle_lock, NULL,
9746621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
9756621Sbt150084 		mutex_init(&tx_ring->tcb_head_lock, NULL,
9766621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
9776621Sbt150084 		mutex_init(&tx_ring->tcb_tail_lock, NULL,
9786621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
9796621Sbt150084 	}
9806621Sbt150084 
9816621Sbt150084 	mutex_init(&ixgbe->gen_lock, NULL,
9826621Sbt150084 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
9836621Sbt150084 
9846621Sbt150084 	mutex_init(&ixgbe->watchdog_lock, NULL,
9856621Sbt150084 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
9866621Sbt150084 }
9876621Sbt150084 
9886621Sbt150084 /*
9896621Sbt150084  * ixgbe_destroy_locks - Destroy locks.
9906621Sbt150084  */
9916621Sbt150084 static void
9926621Sbt150084 ixgbe_destroy_locks(ixgbe_t *ixgbe)
9936621Sbt150084 {
9946621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
9956621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
9966621Sbt150084 	int i;
9976621Sbt150084 
9986621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
9996621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
10006621Sbt150084 		mutex_destroy(&rx_ring->rx_lock);
10016621Sbt150084 	}
10026621Sbt150084 
10036621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
10046621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
10056621Sbt150084 		mutex_destroy(&tx_ring->tx_lock);
10066621Sbt150084 		mutex_destroy(&tx_ring->recycle_lock);
10076621Sbt150084 		mutex_destroy(&tx_ring->tcb_head_lock);
10086621Sbt150084 		mutex_destroy(&tx_ring->tcb_tail_lock);
10096621Sbt150084 	}
10106621Sbt150084 
10116621Sbt150084 	mutex_destroy(&ixgbe->gen_lock);
10126621Sbt150084 	mutex_destroy(&ixgbe->watchdog_lock);
10136621Sbt150084 }
10146621Sbt150084 
10156621Sbt150084 static int
10166621Sbt150084 ixgbe_resume(dev_info_t *devinfo)
10176621Sbt150084 {
10186621Sbt150084 	ixgbe_t *ixgbe;
1019*11233SPaul.Guo@Sun.COM 	int i;
10206621Sbt150084 
10216621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
10226621Sbt150084 	if (ixgbe == NULL)
10236621Sbt150084 		return (DDI_FAILURE);
10246621Sbt150084 
10256621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
10266621Sbt150084 
10276621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
102810376SChenlu.Chen@Sun.COM 		if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
10296621Sbt150084 			mutex_exit(&ixgbe->gen_lock);
10306621Sbt150084 			return (DDI_FAILURE);
10316621Sbt150084 		}
10326621Sbt150084 
10336621Sbt150084 		/*
10346621Sbt150084 		 * Enable and start the watchdog timer
10356621Sbt150084 		 */
10366621Sbt150084 		ixgbe_enable_watchdog_timer(ixgbe);
10376621Sbt150084 	}
10386621Sbt150084 
1039*11233SPaul.Guo@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED);
1040*11233SPaul.Guo@Sun.COM 
1041*11233SPaul.Guo@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
1042*11233SPaul.Guo@Sun.COM 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
1043*11233SPaul.Guo@Sun.COM 			mac_tx_ring_update(ixgbe->mac_hdl,
1044*11233SPaul.Guo@Sun.COM 			    ixgbe->tx_rings[i].ring_handle);
1045*11233SPaul.Guo@Sun.COM 		}
1046*11233SPaul.Guo@Sun.COM 	}
10476621Sbt150084 
10486621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
10496621Sbt150084 
10506621Sbt150084 	return (DDI_SUCCESS);
10516621Sbt150084 }
10526621Sbt150084 
10536621Sbt150084 static int
10546621Sbt150084 ixgbe_suspend(dev_info_t *devinfo)
10556621Sbt150084 {
10566621Sbt150084 	ixgbe_t *ixgbe;
10576621Sbt150084 
10586621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
10596621Sbt150084 	if (ixgbe == NULL)
10606621Sbt150084 		return (DDI_FAILURE);
10616621Sbt150084 
10626621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
10636621Sbt150084 
1064*11233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED);
106510376SChenlu.Chen@Sun.COM 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
106610376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
106710376SChenlu.Chen@Sun.COM 		return (DDI_SUCCESS);
106810376SChenlu.Chen@Sun.COM 	}
106910376SChenlu.Chen@Sun.COM 	ixgbe_stop(ixgbe, B_FALSE);
10706621Sbt150084 
10716621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
10726621Sbt150084 
10736621Sbt150084 	/*
10746621Sbt150084 	 * Disable and stop the watchdog timer
10756621Sbt150084 	 */
10766621Sbt150084 	ixgbe_disable_watchdog_timer(ixgbe);
10776621Sbt150084 
10786621Sbt150084 	return (DDI_SUCCESS);
10796621Sbt150084 }
10806621Sbt150084 
10816621Sbt150084 /*
10826621Sbt150084  * ixgbe_init - Initialize the device.
10836621Sbt150084  */
10846621Sbt150084 static int
10856621Sbt150084 ixgbe_init(ixgbe_t *ixgbe)
10866621Sbt150084 {
10876621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
10886621Sbt150084 
10896621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
10906621Sbt150084 
10916621Sbt150084 	/*
10926621Sbt150084 	 * Reset chipset to put the hardware in a known state
10936621Sbt150084 	 * before we try to do anything with the eeprom.
10946621Sbt150084 	 */
10956621Sbt150084 	if (ixgbe_reset_hw(hw) != IXGBE_SUCCESS) {
10966621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
10976621Sbt150084 		goto init_fail;
10986621Sbt150084 	}
10996621Sbt150084 
11006621Sbt150084 	/*
11016621Sbt150084 	 * Need to init eeprom before validating the checksum.
11026621Sbt150084 	 */
11036621Sbt150084 	if (ixgbe_init_eeprom_params(hw) < 0) {
11046621Sbt150084 		ixgbe_error(ixgbe,
11056621Sbt150084 		    "Unable to intitialize the eeprom interface.");
11066621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11076621Sbt150084 		goto init_fail;
11086621Sbt150084 	}
11096621Sbt150084 
11106621Sbt150084 	/*
11116621Sbt150084 	 * NVM validation
11126621Sbt150084 	 */
11136621Sbt150084 	if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
11146621Sbt150084 		/*
11156621Sbt150084 		 * Some PCI-E parts fail the first check due to
11166621Sbt150084 		 * the link being in sleep state.  Call it again,
11176621Sbt150084 		 * if it fails a second time it's a real issue.
11186621Sbt150084 		 */
11196621Sbt150084 		if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
11206621Sbt150084 			ixgbe_error(ixgbe,
11216621Sbt150084 			    "Invalid NVM checksum. Please contact "
11226621Sbt150084 			    "the vendor to update the NVM.");
11236621Sbt150084 			ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11246621Sbt150084 			goto init_fail;
11256621Sbt150084 		}
11266621Sbt150084 	}
11276621Sbt150084 
11286621Sbt150084 	/*
11296621Sbt150084 	 * Setup default flow control thresholds - enable/disable
11306621Sbt150084 	 * & flow control type is controlled by ixgbe.conf
11316621Sbt150084 	 */
11326621Sbt150084 	hw->fc.high_water = DEFAULT_FCRTH;
11336621Sbt150084 	hw->fc.low_water = DEFAULT_FCRTL;
11346621Sbt150084 	hw->fc.pause_time = DEFAULT_FCPAUSE;
11356621Sbt150084 	hw->fc.send_xon = B_TRUE;
11366621Sbt150084 
11376621Sbt150084 	/*
11386621Sbt150084 	 * Initialize link settings
11396621Sbt150084 	 */
11406621Sbt150084 	(void) ixgbe_driver_setup_link(ixgbe, B_FALSE);
11416621Sbt150084 
11426621Sbt150084 	/*
11436621Sbt150084 	 * Initialize the chipset hardware
11446621Sbt150084 	 */
11456621Sbt150084 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
11466621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11476621Sbt150084 		goto init_fail;
11486621Sbt150084 	}
11496621Sbt150084 
11506621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
11516621Sbt150084 		goto init_fail;
11526621Sbt150084 	}
11536621Sbt150084 
11546621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
11556621Sbt150084 	return (IXGBE_SUCCESS);
11566621Sbt150084 
11576621Sbt150084 init_fail:
11586621Sbt150084 	/*
11596621Sbt150084 	 * Reset PHY
11606621Sbt150084 	 */
11616621Sbt150084 	(void) ixgbe_reset_phy(hw);
11626621Sbt150084 
11636621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
11646621Sbt150084 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
11656621Sbt150084 	return (IXGBE_FAILURE);
11666621Sbt150084 }
11676621Sbt150084 
11686621Sbt150084 /*
11696621Sbt150084  * ixgbe_chip_start - Initialize and start the chipset hardware.
11706621Sbt150084  */
11716621Sbt150084 static int
11726621Sbt150084 ixgbe_chip_start(ixgbe_t *ixgbe)
11736621Sbt150084 {
11746621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
117510305SPaul.Guo@Sun.COM 	int ret_val, i;
11766621Sbt150084 
11776621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
11786621Sbt150084 
11796621Sbt150084 	/*
11806621Sbt150084 	 * Get the mac address
11816621Sbt150084 	 * This function should handle SPARC case correctly.
11826621Sbt150084 	 */
11836621Sbt150084 	if (!ixgbe_find_mac_address(ixgbe)) {
11846621Sbt150084 		ixgbe_error(ixgbe, "Failed to get the mac address");
11856621Sbt150084 		return (IXGBE_FAILURE);
11866621Sbt150084 	}
11876621Sbt150084 
11886621Sbt150084 	/*
11896621Sbt150084 	 * Validate the mac address
11906621Sbt150084 	 */
11916621Sbt150084 	(void) ixgbe_init_rx_addrs(hw);
11926621Sbt150084 	if (!is_valid_mac_addr(hw->mac.addr)) {
11936621Sbt150084 		ixgbe_error(ixgbe, "Invalid mac address");
11946621Sbt150084 		return (IXGBE_FAILURE);
11956621Sbt150084 	}
11966621Sbt150084 
11976621Sbt150084 	/*
11986621Sbt150084 	 * Configure/Initialize hardware
11996621Sbt150084 	 */
120010305SPaul.Guo@Sun.COM 	ret_val = ixgbe_init_hw(hw);
120110305SPaul.Guo@Sun.COM 	if (ret_val != IXGBE_SUCCESS) {
120210305SPaul.Guo@Sun.COM 		if (ret_val == IXGBE_ERR_EEPROM_VERSION) {
120310305SPaul.Guo@Sun.COM 			ixgbe_error(ixgbe,
120410305SPaul.Guo@Sun.COM 			    "This 82599 device is pre-release and contains"
120510305SPaul.Guo@Sun.COM 			    " outdated firmware, please contact your hardware"
120610305SPaul.Guo@Sun.COM 			    " vendor for a replacement.");
120710305SPaul.Guo@Sun.COM 		} else {
120810305SPaul.Guo@Sun.COM 			ixgbe_error(ixgbe, "Failed to initialize hardware");
120910305SPaul.Guo@Sun.COM 			return (IXGBE_FAILURE);
121010305SPaul.Guo@Sun.COM 		}
12116621Sbt150084 	}
12126621Sbt150084 
12136621Sbt150084 	/*
12146621Sbt150084 	 * Setup adapter interrupt vectors
12156621Sbt150084 	 */
12166621Sbt150084 	ixgbe_setup_adapter_vector(ixgbe);
12176621Sbt150084 
12186621Sbt150084 	/*
12196621Sbt150084 	 * Initialize unicast addresses.
12206621Sbt150084 	 */
12216621Sbt150084 	ixgbe_init_unicst(ixgbe);
12226621Sbt150084 
12236621Sbt150084 	/*
12246621Sbt150084 	 * Setup and initialize the mctable structures.
12256621Sbt150084 	 */
12266621Sbt150084 	ixgbe_setup_multicst(ixgbe);
12276621Sbt150084 
12286621Sbt150084 	/*
12296621Sbt150084 	 * Set interrupt throttling rate
12306621Sbt150084 	 */
12319353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->intr_cnt; i++) {
12326621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]);
12339353SSamuel.Tu@Sun.COM 	}
12346621Sbt150084 
12356621Sbt150084 	/*
12366621Sbt150084 	 * Save the state of the phy
12376621Sbt150084 	 */
12386621Sbt150084 	ixgbe_get_hw_state(ixgbe);
12396621Sbt150084 
12406621Sbt150084 	/*
12416621Sbt150084 	 * Make sure driver has control
12426621Sbt150084 	 */
12436621Sbt150084 	ixgbe_get_driver_control(hw);
12446621Sbt150084 
12456621Sbt150084 	return (IXGBE_SUCCESS);
12466621Sbt150084 }
12476621Sbt150084 
12486621Sbt150084 /*
12496621Sbt150084  * ixgbe_chip_stop - Stop the chipset hardware
12506621Sbt150084  */
12516621Sbt150084 static void
12526621Sbt150084 ixgbe_chip_stop(ixgbe_t *ixgbe)
12536621Sbt150084 {
12546621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
12556621Sbt150084 
12566621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
12576621Sbt150084 
12586621Sbt150084 	/*
12596621Sbt150084 	 * Tell firmware driver is no longer in control
12606621Sbt150084 	 */
12616621Sbt150084 	ixgbe_release_driver_control(hw);
12626621Sbt150084 
12636621Sbt150084 	/*
12646621Sbt150084 	 * Reset the chipset
12656621Sbt150084 	 */
12666621Sbt150084 	(void) ixgbe_reset_hw(hw);
12676621Sbt150084 
12686621Sbt150084 	/*
12696621Sbt150084 	 * Reset PHY
12706621Sbt150084 	 */
12716621Sbt150084 	(void) ixgbe_reset_phy(hw);
12726621Sbt150084 }
12736621Sbt150084 
12746621Sbt150084 /*
12756621Sbt150084  * ixgbe_reset - Reset the chipset and re-start the driver.
12766621Sbt150084  *
12776621Sbt150084  * It involves stopping and re-starting the chipset,
12786621Sbt150084  * and re-configuring the rx/tx rings.
12796621Sbt150084  */
12806621Sbt150084 static int
12816621Sbt150084 ixgbe_reset(ixgbe_t *ixgbe)
12826621Sbt150084 {
1283*11233SPaul.Guo@Sun.COM 	int i;
1284*11233SPaul.Guo@Sun.COM 
128510376SChenlu.Chen@Sun.COM 	/*
128610376SChenlu.Chen@Sun.COM 	 * Disable and stop the watchdog timer
128710376SChenlu.Chen@Sun.COM 	 */
128810376SChenlu.Chen@Sun.COM 	ixgbe_disable_watchdog_timer(ixgbe);
12896621Sbt150084 
12906621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
12916621Sbt150084 
12926621Sbt150084 	ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED);
1293*11233SPaul.Guo@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
12946621Sbt150084 
129510376SChenlu.Chen@Sun.COM 	ixgbe_stop(ixgbe, B_FALSE);
129610376SChenlu.Chen@Sun.COM 
129710376SChenlu.Chen@Sun.COM 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
129810376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
129910376SChenlu.Chen@Sun.COM 		return (IXGBE_FAILURE);
13006621Sbt150084 	}
13016621Sbt150084 
1302*11233SPaul.Guo@Sun.COM 	/*
1303*11233SPaul.Guo@Sun.COM 	 * After resetting, need to recheck the link status.
1304*11233SPaul.Guo@Sun.COM 	 */
1305*11233SPaul.Guo@Sun.COM 	ixgbe->link_check_complete = B_FALSE;
1306*11233SPaul.Guo@Sun.COM 	ixgbe->link_check_hrtime = gethrtime() +
1307*11233SPaul.Guo@Sun.COM 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
1308*11233SPaul.Guo@Sun.COM 
1309*11233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED);
1310*11233SPaul.Guo@Sun.COM 
1311*11233SPaul.Guo@Sun.COM 	if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) {
1312*11233SPaul.Guo@Sun.COM 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
1313*11233SPaul.Guo@Sun.COM 			mac_tx_ring_update(ixgbe->mac_hdl,
1314*11233SPaul.Guo@Sun.COM 			    ixgbe->tx_rings[i].ring_handle);
1315*11233SPaul.Guo@Sun.COM 		}
1316*11233SPaul.Guo@Sun.COM 	}
1317*11233SPaul.Guo@Sun.COM 
13186621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
13196621Sbt150084 
132010376SChenlu.Chen@Sun.COM 	/*
132110376SChenlu.Chen@Sun.COM 	 * Enable and start the watchdog timer
132210376SChenlu.Chen@Sun.COM 	 */
132310376SChenlu.Chen@Sun.COM 	ixgbe_enable_watchdog_timer(ixgbe);
132410376SChenlu.Chen@Sun.COM 
13256621Sbt150084 	return (IXGBE_SUCCESS);
13266621Sbt150084 }
13276621Sbt150084 
13286621Sbt150084 /*
13296621Sbt150084  * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources.
13306621Sbt150084  */
13316621Sbt150084 static void
13326621Sbt150084 ixgbe_tx_clean(ixgbe_t *ixgbe)
13336621Sbt150084 {
13346621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
13356621Sbt150084 	tx_control_block_t *tcb;
13366621Sbt150084 	link_list_t pending_list;
13376621Sbt150084 	uint32_t desc_num;
13386621Sbt150084 	int i, j;
13396621Sbt150084 
13406621Sbt150084 	LINK_LIST_INIT(&pending_list);
13416621Sbt150084 
13426621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
13436621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
13446621Sbt150084 
13456621Sbt150084 		mutex_enter(&tx_ring->recycle_lock);
13466621Sbt150084 
13476621Sbt150084 		/*
13486621Sbt150084 		 * Clean the pending tx data - the pending packets in the
13496621Sbt150084 		 * work_list that have no chances to be transmitted again.
13506621Sbt150084 		 *
13516621Sbt150084 		 * We must ensure the chipset is stopped or the link is down
13526621Sbt150084 		 * before cleaning the transmit packets.
13536621Sbt150084 		 */
13546621Sbt150084 		desc_num = 0;
13556621Sbt150084 		for (j = 0; j < tx_ring->ring_size; j++) {
13566621Sbt150084 			tcb = tx_ring->work_list[j];
13576621Sbt150084 			if (tcb != NULL) {
13586621Sbt150084 				desc_num += tcb->desc_num;
13596621Sbt150084 
13606621Sbt150084 				tx_ring->work_list[j] = NULL;
13616621Sbt150084 
13626621Sbt150084 				ixgbe_free_tcb(tcb);
13636621Sbt150084 
13646621Sbt150084 				LIST_PUSH_TAIL(&pending_list, &tcb->link);
13656621Sbt150084 			}
13666621Sbt150084 		}
13676621Sbt150084 
13686621Sbt150084 		if (desc_num > 0) {
13696621Sbt150084 			atomic_add_32(&tx_ring->tbd_free, desc_num);
13706621Sbt150084 			ASSERT(tx_ring->tbd_free == tx_ring->ring_size);
13716621Sbt150084 
13726621Sbt150084 			/*
13736621Sbt150084 			 * Reset the head and tail pointers of the tbd ring;
13746621Sbt150084 			 * Reset the writeback head if it's enable.
13756621Sbt150084 			 */
13766621Sbt150084 			tx_ring->tbd_head = 0;
13776621Sbt150084 			tx_ring->tbd_tail = 0;
13786621Sbt150084 			if (ixgbe->tx_head_wb_enable)
13796621Sbt150084 				*tx_ring->tbd_head_wb = 0;
13806621Sbt150084 
13816621Sbt150084 			IXGBE_WRITE_REG(&ixgbe->hw,
13826621Sbt150084 			    IXGBE_TDH(tx_ring->index), 0);
13836621Sbt150084 			IXGBE_WRITE_REG(&ixgbe->hw,
13846621Sbt150084 			    IXGBE_TDT(tx_ring->index), 0);
13856621Sbt150084 		}
13866621Sbt150084 
13876621Sbt150084 		mutex_exit(&tx_ring->recycle_lock);
13886621Sbt150084 
13896621Sbt150084 		/*
13906621Sbt150084 		 * Add the tx control blocks in the pending list to
13916621Sbt150084 		 * the free list.
13926621Sbt150084 		 */
13936621Sbt150084 		ixgbe_put_free_list(tx_ring, &pending_list);
13946621Sbt150084 	}
13956621Sbt150084 }
13966621Sbt150084 
13976621Sbt150084 /*
13986621Sbt150084  * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be
13996621Sbt150084  * transmitted.
14006621Sbt150084  */
14016621Sbt150084 static boolean_t
14026621Sbt150084 ixgbe_tx_drain(ixgbe_t *ixgbe)
14036621Sbt150084 {
14046621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
14056621Sbt150084 	boolean_t done;
14066621Sbt150084 	int i, j;
14076621Sbt150084 
14086621Sbt150084 	/*
14096621Sbt150084 	 * Wait for a specific time to allow pending tx packets
14106621Sbt150084 	 * to be transmitted.
14116621Sbt150084 	 *
14126621Sbt150084 	 * Check the counter tbd_free to see if transmission is done.
14136621Sbt150084 	 * No lock protection is needed here.
14146621Sbt150084 	 *
14156621Sbt150084 	 * Return B_TRUE if all pending packets have been transmitted;
14166621Sbt150084 	 * Otherwise return B_FALSE;
14176621Sbt150084 	 */
14186621Sbt150084 	for (i = 0; i < TX_DRAIN_TIME; i++) {
14196621Sbt150084 
14206621Sbt150084 		done = B_TRUE;
14216621Sbt150084 		for (j = 0; j < ixgbe->num_tx_rings; j++) {
14226621Sbt150084 			tx_ring = &ixgbe->tx_rings[j];
14236621Sbt150084 			done = done &&
14246621Sbt150084 			    (tx_ring->tbd_free == tx_ring->ring_size);
14256621Sbt150084 		}
14266621Sbt150084 
14276621Sbt150084 		if (done)
14286621Sbt150084 			break;
14296621Sbt150084 
14306621Sbt150084 		msec_delay(1);
14316621Sbt150084 	}
14326621Sbt150084 
14336621Sbt150084 	return (done);
14346621Sbt150084 }
14356621Sbt150084 
14366621Sbt150084 /*
14376621Sbt150084  * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer.
14386621Sbt150084  */
14396621Sbt150084 static boolean_t
14406621Sbt150084 ixgbe_rx_drain(ixgbe_t *ixgbe)
14416621Sbt150084 {
144210376SChenlu.Chen@Sun.COM 	boolean_t done = B_TRUE;
144310376SChenlu.Chen@Sun.COM 	int i;
14446621Sbt150084 
14456621Sbt150084 	/*
14466621Sbt150084 	 * Polling the rx free list to check if those rx buffers held by
14476621Sbt150084 	 * the upper layer are released.
14486621Sbt150084 	 *
14496621Sbt150084 	 * Check the counter rcb_free to see if all pending buffers are
14506621Sbt150084 	 * released. No lock protection is needed here.
14516621Sbt150084 	 *
14526621Sbt150084 	 * Return B_TRUE if all pending buffers have been released;
14536621Sbt150084 	 * Otherwise return B_FALSE;
14546621Sbt150084 	 */
14556621Sbt150084 	for (i = 0; i < RX_DRAIN_TIME; i++) {
145610376SChenlu.Chen@Sun.COM 		done = (ixgbe->rcb_pending == 0);
14576621Sbt150084 
14586621Sbt150084 		if (done)
14596621Sbt150084 			break;
14606621Sbt150084 
14616621Sbt150084 		msec_delay(1);
14626621Sbt150084 	}
14636621Sbt150084 
14646621Sbt150084 	return (done);
14656621Sbt150084 }
14666621Sbt150084 
14676621Sbt150084 /*
14686621Sbt150084  * ixgbe_start - Start the driver/chipset.
14696621Sbt150084  */
14706621Sbt150084 int
147110376SChenlu.Chen@Sun.COM ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer)
14726621Sbt150084 {
14736621Sbt150084 	int i;
14746621Sbt150084 
14756621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
14766621Sbt150084 
147710376SChenlu.Chen@Sun.COM 	if (alloc_buffer) {
147810376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) {
147910376SChenlu.Chen@Sun.COM 			ixgbe_error(ixgbe,
148010376SChenlu.Chen@Sun.COM 			    "Failed to allocate software receive rings");
148110376SChenlu.Chen@Sun.COM 			return (IXGBE_FAILURE);
148210376SChenlu.Chen@Sun.COM 		}
148310376SChenlu.Chen@Sun.COM 
148410376SChenlu.Chen@Sun.COM 		/* Allocate buffers for all the rx/tx rings */
148510376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) {
148610376SChenlu.Chen@Sun.COM 			ixgbe_error(ixgbe, "Failed to allocate DMA resource");
148710376SChenlu.Chen@Sun.COM 			return (IXGBE_FAILURE);
148810376SChenlu.Chen@Sun.COM 		}
148910376SChenlu.Chen@Sun.COM 
149010376SChenlu.Chen@Sun.COM 		ixgbe->tx_ring_init = B_TRUE;
149110376SChenlu.Chen@Sun.COM 	} else {
149210376SChenlu.Chen@Sun.COM 		ixgbe->tx_ring_init = B_FALSE;
149310376SChenlu.Chen@Sun.COM 	}
149410376SChenlu.Chen@Sun.COM 
14956621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++)
14966621Sbt150084 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
14976621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++)
14986621Sbt150084 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
14996621Sbt150084 
15006621Sbt150084 	/*
15016621Sbt150084 	 * Start the chipset hardware
15026621Sbt150084 	 */
15036621Sbt150084 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
15046621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
15056621Sbt150084 		goto start_failure;
15066621Sbt150084 	}
15076621Sbt150084 
15086621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
15096621Sbt150084 		goto start_failure;
15106621Sbt150084 	}
15116621Sbt150084 
15126621Sbt150084 	/*
15136621Sbt150084 	 * Setup the rx/tx rings
15146621Sbt150084 	 */
15156621Sbt150084 	ixgbe_setup_rings(ixgbe);
15166621Sbt150084 
15176621Sbt150084 	/*
1518*11233SPaul.Guo@Sun.COM 	 * ixgbe_start() will be called when resetting, however if reset
1519*11233SPaul.Guo@Sun.COM 	 * happens, we need to clear the ERROR and STALL flags before
1520*11233SPaul.Guo@Sun.COM 	 * enabling the interrupts.
1521*11233SPaul.Guo@Sun.COM 	 */
1522*11233SPaul.Guo@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR | IXGBE_STALL));
1523*11233SPaul.Guo@Sun.COM 
1524*11233SPaul.Guo@Sun.COM 	/*
15256621Sbt150084 	 * Enable adapter interrupts
15266621Sbt150084 	 * The interrupts must be enabled after the driver state is START
15276621Sbt150084 	 */
15286621Sbt150084 	ixgbe_enable_adapter_interrupts(ixgbe);
15296621Sbt150084 
15306621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
15316621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
15326621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
15336621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
15346621Sbt150084 
15356621Sbt150084 	return (IXGBE_SUCCESS);
15366621Sbt150084 
15376621Sbt150084 start_failure:
15386621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
15396621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
15406621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
15416621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
15426621Sbt150084 
15436621Sbt150084 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
15446621Sbt150084 
15456621Sbt150084 	return (IXGBE_FAILURE);
15466621Sbt150084 }
15476621Sbt150084 
15486621Sbt150084 /*
15496621Sbt150084  * ixgbe_stop - Stop the driver/chipset.
15506621Sbt150084  */
15516621Sbt150084 void
155210376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer)
15536621Sbt150084 {
15546621Sbt150084 	int i;
15556621Sbt150084 
15566621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
15576621Sbt150084 
15586621Sbt150084 	/*
15596621Sbt150084 	 * Disable the adapter interrupts
15606621Sbt150084 	 */
15616621Sbt150084 	ixgbe_disable_adapter_interrupts(ixgbe);
15626621Sbt150084 
15636621Sbt150084 	/*
15646621Sbt150084 	 * Drain the pending tx packets
15656621Sbt150084 	 */
15666621Sbt150084 	(void) ixgbe_tx_drain(ixgbe);
15676621Sbt150084 
15686621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++)
15696621Sbt150084 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
15706621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++)
15716621Sbt150084 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
15726621Sbt150084 
15736621Sbt150084 	/*
15746621Sbt150084 	 * Stop the chipset hardware
15756621Sbt150084 	 */
15766621Sbt150084 	ixgbe_chip_stop(ixgbe);
15776621Sbt150084 
15786621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
15796621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
15806621Sbt150084 	}
15816621Sbt150084 
15826621Sbt150084 	/*
15836621Sbt150084 	 * Clean the pending tx data/resources
15846621Sbt150084 	 */
15856621Sbt150084 	ixgbe_tx_clean(ixgbe);
15866621Sbt150084 
15876621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
15886621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
15896621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
15906621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
159110376SChenlu.Chen@Sun.COM 
159210376SChenlu.Chen@Sun.COM 	if (ixgbe->link_state == LINK_STATE_UP) {
159310376SChenlu.Chen@Sun.COM 		ixgbe->link_state = LINK_STATE_UNKNOWN;
159410376SChenlu.Chen@Sun.COM 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
159510376SChenlu.Chen@Sun.COM 	}
159610376SChenlu.Chen@Sun.COM 
159710376SChenlu.Chen@Sun.COM 	if (free_buffer) {
159810376SChenlu.Chen@Sun.COM 		/*
159910376SChenlu.Chen@Sun.COM 		 * Release the DMA/memory resources of rx/tx rings
160010376SChenlu.Chen@Sun.COM 		 */
160110376SChenlu.Chen@Sun.COM 		ixgbe_free_dma(ixgbe);
160210376SChenlu.Chen@Sun.COM 		ixgbe_free_rx_data(ixgbe);
160310376SChenlu.Chen@Sun.COM 	}
16046621Sbt150084 }
16056621Sbt150084 
16066621Sbt150084 /*
16076621Sbt150084  * ixgbe_alloc_rings - Allocate memory space for rx/tx rings.
16086621Sbt150084  */
16096621Sbt150084 static int
16106621Sbt150084 ixgbe_alloc_rings(ixgbe_t *ixgbe)
16116621Sbt150084 {
16126621Sbt150084 	/*
16136621Sbt150084 	 * Allocate memory space for rx rings
16146621Sbt150084 	 */
16156621Sbt150084 	ixgbe->rx_rings = kmem_zalloc(
16166621Sbt150084 	    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings,
16176621Sbt150084 	    KM_NOSLEEP);
16186621Sbt150084 
16196621Sbt150084 	if (ixgbe->rx_rings == NULL) {
16206621Sbt150084 		return (IXGBE_FAILURE);
16216621Sbt150084 	}
16226621Sbt150084 
16236621Sbt150084 	/*
16246621Sbt150084 	 * Allocate memory space for tx rings
16256621Sbt150084 	 */
16266621Sbt150084 	ixgbe->tx_rings = kmem_zalloc(
16276621Sbt150084 	    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings,
16286621Sbt150084 	    KM_NOSLEEP);
16296621Sbt150084 
16306621Sbt150084 	if (ixgbe->tx_rings == NULL) {
16316621Sbt150084 		kmem_free(ixgbe->rx_rings,
16326621Sbt150084 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
16336621Sbt150084 		ixgbe->rx_rings = NULL;
16346621Sbt150084 		return (IXGBE_FAILURE);
16356621Sbt150084 	}
16366621Sbt150084 
16378275SEric Cheng 	/*
16388275SEric Cheng 	 * Allocate memory space for rx ring groups
16398275SEric Cheng 	 */
16408275SEric Cheng 	ixgbe->rx_groups = kmem_zalloc(
16418275SEric Cheng 	    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups,
16428275SEric Cheng 	    KM_NOSLEEP);
16438275SEric Cheng 
16448275SEric Cheng 	if (ixgbe->rx_groups == NULL) {
16458275SEric Cheng 		kmem_free(ixgbe->rx_rings,
16468275SEric Cheng 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
16478275SEric Cheng 		kmem_free(ixgbe->tx_rings,
16488275SEric Cheng 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
16498275SEric Cheng 		ixgbe->rx_rings = NULL;
16508275SEric Cheng 		ixgbe->tx_rings = NULL;
16518275SEric Cheng 		return (IXGBE_FAILURE);
16528275SEric Cheng 	}
16538275SEric Cheng 
16546621Sbt150084 	return (IXGBE_SUCCESS);
16556621Sbt150084 }
16566621Sbt150084 
16576621Sbt150084 /*
16586621Sbt150084  * ixgbe_free_rings - Free the memory space of rx/tx rings.
16596621Sbt150084  */
16606621Sbt150084 static void
16616621Sbt150084 ixgbe_free_rings(ixgbe_t *ixgbe)
16626621Sbt150084 {
16636621Sbt150084 	if (ixgbe->rx_rings != NULL) {
16646621Sbt150084 		kmem_free(ixgbe->rx_rings,
16656621Sbt150084 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
16666621Sbt150084 		ixgbe->rx_rings = NULL;
16676621Sbt150084 	}
16686621Sbt150084 
16696621Sbt150084 	if (ixgbe->tx_rings != NULL) {
16706621Sbt150084 		kmem_free(ixgbe->tx_rings,
16716621Sbt150084 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
16726621Sbt150084 		ixgbe->tx_rings = NULL;
16736621Sbt150084 	}
16748275SEric Cheng 
16758275SEric Cheng 	if (ixgbe->rx_groups != NULL) {
16768275SEric Cheng 		kmem_free(ixgbe->rx_groups,
16778275SEric Cheng 		    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups);
16788275SEric Cheng 		ixgbe->rx_groups = NULL;
16798275SEric Cheng 	}
16806621Sbt150084 }
16816621Sbt150084 
168210376SChenlu.Chen@Sun.COM static int
168310376SChenlu.Chen@Sun.COM ixgbe_alloc_rx_data(ixgbe_t *ixgbe)
168410376SChenlu.Chen@Sun.COM {
168510376SChenlu.Chen@Sun.COM 	ixgbe_rx_ring_t *rx_ring;
168610376SChenlu.Chen@Sun.COM 	int i;
168710376SChenlu.Chen@Sun.COM 
168810376SChenlu.Chen@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
168910376SChenlu.Chen@Sun.COM 		rx_ring = &ixgbe->rx_rings[i];
169010376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS)
169110376SChenlu.Chen@Sun.COM 			goto alloc_rx_rings_failure;
169210376SChenlu.Chen@Sun.COM 	}
169310376SChenlu.Chen@Sun.COM 	return (IXGBE_SUCCESS);
169410376SChenlu.Chen@Sun.COM 
169510376SChenlu.Chen@Sun.COM alloc_rx_rings_failure:
169610376SChenlu.Chen@Sun.COM 	ixgbe_free_rx_data(ixgbe);
169710376SChenlu.Chen@Sun.COM 	return (IXGBE_FAILURE);
169810376SChenlu.Chen@Sun.COM }
169910376SChenlu.Chen@Sun.COM 
170010376SChenlu.Chen@Sun.COM static void
170110376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe_t *ixgbe)
170210376SChenlu.Chen@Sun.COM {
170310376SChenlu.Chen@Sun.COM 	ixgbe_rx_ring_t *rx_ring;
170410376SChenlu.Chen@Sun.COM 	ixgbe_rx_data_t *rx_data;
170510376SChenlu.Chen@Sun.COM 	int i;
170610376SChenlu.Chen@Sun.COM 
170710376SChenlu.Chen@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
170810376SChenlu.Chen@Sun.COM 		rx_ring = &ixgbe->rx_rings[i];
170910376SChenlu.Chen@Sun.COM 
171010376SChenlu.Chen@Sun.COM 		mutex_enter(&ixgbe->rx_pending_lock);
171110376SChenlu.Chen@Sun.COM 		rx_data = rx_ring->rx_data;
171210376SChenlu.Chen@Sun.COM 
171310376SChenlu.Chen@Sun.COM 		if (rx_data != NULL) {
171410376SChenlu.Chen@Sun.COM 			rx_data->flag |= IXGBE_RX_STOPPED;
171510376SChenlu.Chen@Sun.COM 
171610376SChenlu.Chen@Sun.COM 			if (rx_data->rcb_pending == 0) {
171710376SChenlu.Chen@Sun.COM 				ixgbe_free_rx_ring_data(rx_data);
171810376SChenlu.Chen@Sun.COM 				rx_ring->rx_data = NULL;
171910376SChenlu.Chen@Sun.COM 			}
172010376SChenlu.Chen@Sun.COM 		}
172110376SChenlu.Chen@Sun.COM 
172210376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->rx_pending_lock);
172310376SChenlu.Chen@Sun.COM 	}
172410376SChenlu.Chen@Sun.COM }
172510376SChenlu.Chen@Sun.COM 
17266621Sbt150084 /*
17276621Sbt150084  * ixgbe_setup_rings - Setup rx/tx rings.
17286621Sbt150084  */
17296621Sbt150084 static void
17306621Sbt150084 ixgbe_setup_rings(ixgbe_t *ixgbe)
17316621Sbt150084 {
17326621Sbt150084 	/*
17336621Sbt150084 	 * Setup the rx/tx rings, including the following:
17346621Sbt150084 	 *
17356621Sbt150084 	 * 1. Setup the descriptor ring and the control block buffers;
17366621Sbt150084 	 * 2. Initialize necessary registers for receive/transmit;
17376621Sbt150084 	 * 3. Initialize software pointers/parameters for receive/transmit;
17386621Sbt150084 	 */
17396621Sbt150084 	ixgbe_setup_rx(ixgbe);
17406621Sbt150084 
17416621Sbt150084 	ixgbe_setup_tx(ixgbe);
17426621Sbt150084 }
17436621Sbt150084 
17446621Sbt150084 static void
17456621Sbt150084 ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring)
17466621Sbt150084 {
17476621Sbt150084 	ixgbe_t *ixgbe = rx_ring->ixgbe;
174810376SChenlu.Chen@Sun.COM 	ixgbe_rx_data_t *rx_data = rx_ring->rx_data;
17496621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
17506621Sbt150084 	rx_control_block_t *rcb;
17516621Sbt150084 	union ixgbe_adv_rx_desc	*rbd;
17526621Sbt150084 	uint32_t size;
17536621Sbt150084 	uint32_t buf_low;
17546621Sbt150084 	uint32_t buf_high;
17556621Sbt150084 	uint32_t reg_val;
17566621Sbt150084 	int i;
17576621Sbt150084 
17586621Sbt150084 	ASSERT(mutex_owned(&rx_ring->rx_lock));
17596621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
17606621Sbt150084 
17616621Sbt150084 	for (i = 0; i < ixgbe->rx_ring_size; i++) {
176210376SChenlu.Chen@Sun.COM 		rcb = rx_data->work_list[i];
176310376SChenlu.Chen@Sun.COM 		rbd = &rx_data->rbd_ring[i];
17646621Sbt150084 
17656621Sbt150084 		rbd->read.pkt_addr = rcb->rx_buf.dma_address;
17666621Sbt150084 		rbd->read.hdr_addr = NULL;
17676621Sbt150084 	}
17686621Sbt150084 
17696621Sbt150084 	/*
17706621Sbt150084 	 * Initialize the length register
17716621Sbt150084 	 */
177210376SChenlu.Chen@Sun.COM 	size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc);
17736621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->index), size);
17746621Sbt150084 
17756621Sbt150084 	/*
17766621Sbt150084 	 * Initialize the base address registers
17776621Sbt150084 	 */
177810376SChenlu.Chen@Sun.COM 	buf_low = (uint32_t)rx_data->rbd_area.dma_address;
177910376SChenlu.Chen@Sun.COM 	buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32);
17806621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->index), buf_high);
17816621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->index), buf_low);
17826621Sbt150084 
17836621Sbt150084 	/*
17846621Sbt150084 	 * Setup head & tail pointers
17856621Sbt150084 	 */
178610376SChenlu.Chen@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->index), rx_data->ring_size - 1);
17876621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->index), 0);
17886621Sbt150084 
178910376SChenlu.Chen@Sun.COM 	rx_data->rbd_next = 0;
17906621Sbt150084 
17916621Sbt150084 	/*
17926621Sbt150084 	 * Setup the Receive Descriptor Control Register (RXDCTL)
17936621Sbt150084 	 * PTHRESH=32 descriptors (half the internal cache)
17946621Sbt150084 	 * HTHRESH=0 descriptors (to minimize latency on fetch)
17956621Sbt150084 	 * WTHRESH defaults to 1 (writeback each descriptor)
17966621Sbt150084 	 */
17976621Sbt150084 	reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->index));
17986621Sbt150084 	reg_val |= IXGBE_RXDCTL_ENABLE;	/* enable queue */
17999353SSamuel.Tu@Sun.COM 
18009353SSamuel.Tu@Sun.COM 	/* Not a valid value for 82599 */
18019353SSamuel.Tu@Sun.COM 	if (hw->mac.type < ixgbe_mac_82599EB) {
18029353SSamuel.Tu@Sun.COM 		reg_val |= 0x0020;	/* pthresh */
18039353SSamuel.Tu@Sun.COM 	}
18046621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->index), reg_val);
18056621Sbt150084 
18069353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
18079353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
18089353SSamuel.Tu@Sun.COM 		reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS);
18099353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
18109353SSamuel.Tu@Sun.COM 	}
18119353SSamuel.Tu@Sun.COM 
18126621Sbt150084 	/*
18136621Sbt150084 	 * Setup the Split and Replication Receive Control Register.
18146621Sbt150084 	 * Set the rx buffer size and the advanced descriptor type.
18156621Sbt150084 	 */
18166621Sbt150084 	reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) |
18176621Sbt150084 	    IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
18189353SSamuel.Tu@Sun.COM 	reg_val |= IXGBE_SRRCTL_DROP_EN;
18196621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->index), reg_val);
18206621Sbt150084 }
18216621Sbt150084 
18226621Sbt150084 static void
18236621Sbt150084 ixgbe_setup_rx(ixgbe_t *ixgbe)
18246621Sbt150084 {
18256621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
18266621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
18278275SEric Cheng 	ixgbe_rx_group_t *rx_group;
18286621Sbt150084 	uint32_t reg_val;
18298275SEric Cheng 	uint32_t ring_mapping;
18306621Sbt150084 	int i;
18316621Sbt150084 
18329353SSamuel.Tu@Sun.COM 	/* PSRTYPE must be configured for 82599 */
18339353SSamuel.Tu@Sun.COM 	reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
18349353SSamuel.Tu@Sun.COM 	    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
18359353SSamuel.Tu@Sun.COM #define	IXGBE_PSRTYPE_L2_PKT	0x00001000
18369353SSamuel.Tu@Sun.COM 	reg_val |= IXGBE_PSRTYPE_L2_PKT;
18379353SSamuel.Tu@Sun.COM 	reg_val |= 0xE0000000;
18389353SSamuel.Tu@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val);
18399353SSamuel.Tu@Sun.COM 
18406621Sbt150084 	/*
18416621Sbt150084 	 * Set filter control in FCTRL to accept broadcast packets and do
18426621Sbt150084 	 * not pass pause frames to host.  Flow control settings are already
18436621Sbt150084 	 * in this register, so preserve them.
18446621Sbt150084 	 */
18456621Sbt150084 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
18466621Sbt150084 	reg_val |= IXGBE_FCTRL_BAM;	/* broadcast accept mode */
18476621Sbt150084 	reg_val |= IXGBE_FCTRL_DPF;	/* discard pause frames */
18486621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val);
18496621Sbt150084 
18506621Sbt150084 	/*
18516621Sbt150084 	 * Enable the receive unit.  This must be done after filter
18526621Sbt150084 	 * control is set in FCTRL.
18536621Sbt150084 	 */
18546621Sbt150084 	reg_val = (IXGBE_RXCTRL_RXEN	/* Enable Receive Unit */
18556621Sbt150084 	    | IXGBE_RXCTRL_DMBYPS);	/* descriptor monitor bypass */
18566621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
18576621Sbt150084 
18586621Sbt150084 	/*
18596621Sbt150084 	 * ixgbe_setup_rx_ring must be called after configuring RXCTRL
18606621Sbt150084 	 */
18616621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
18626621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
18636621Sbt150084 		ixgbe_setup_rx_ring(rx_ring);
18646621Sbt150084 	}
18656621Sbt150084 
18666621Sbt150084 	/*
18678275SEric Cheng 	 * Setup rx groups.
18688275SEric Cheng 	 */
18698275SEric Cheng 	for (i = 0; i < ixgbe->num_rx_groups; i++) {
18708275SEric Cheng 		rx_group = &ixgbe->rx_groups[i];
18718275SEric Cheng 		rx_group->index = i;
18728275SEric Cheng 		rx_group->ixgbe = ixgbe;
18738275SEric Cheng 	}
18748275SEric Cheng 
18758275SEric Cheng 	/*
18768275SEric Cheng 	 * Setup the per-ring statistics mapping.
18778275SEric Cheng 	 */
18788275SEric Cheng 	ring_mapping = 0;
18798275SEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
18808275SEric Cheng 		ring_mapping |= (i & 0xF) << (8 * (i & 0x3));
18818275SEric Cheng 		if ((i & 0x3) == 0x3) {
18828275SEric Cheng 			IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i >> 2), ring_mapping);
18838275SEric Cheng 			ring_mapping = 0;
18848275SEric Cheng 		}
18858275SEric Cheng 	}
18868275SEric Cheng 	if ((i & 0x3) != 0x3)
18878275SEric Cheng 		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i >> 2), ring_mapping);
18888275SEric Cheng 
18898275SEric Cheng 	/*
18909353SSamuel.Tu@Sun.COM 	 * The Max Frame Size in MHADD/MAXFRS will be internally increased
18919353SSamuel.Tu@Sun.COM 	 * by four bytes if the packet has a VLAN field, so includes MTU,
18929353SSamuel.Tu@Sun.COM 	 * ethernet header and frame check sequence.
18939353SSamuel.Tu@Sun.COM 	 * Register is MAXFRS in 82599.
18946621Sbt150084 	 */
18956621Sbt150084 	reg_val = (ixgbe->default_mtu + sizeof (struct ether_header)
18966621Sbt150084 	    + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT;
18976621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val);
18986621Sbt150084 
18996621Sbt150084 	/*
19006621Sbt150084 	 * Setup Jumbo Frame enable bit
19016621Sbt150084 	 */
19026621Sbt150084 	if (ixgbe->default_mtu > ETHERMTU) {
19036621Sbt150084 		reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
19046621Sbt150084 		reg_val |= IXGBE_HLREG0_JUMBOEN;
19056621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
19066621Sbt150084 	}
19076621Sbt150084 
19086621Sbt150084 	/*
19096621Sbt150084 	 * Hardware checksum settings
19106621Sbt150084 	 */
19116621Sbt150084 	if (ixgbe->rx_hcksum_enable) {
19126621Sbt150084 		reg_val = IXGBE_RXCSUM_IPPCSE;	/* IP checksum */
19136621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val);
19146621Sbt150084 	}
19156621Sbt150084 
19166621Sbt150084 	/*
19176621Sbt150084 	 * Setup RSS for multiple receive queues
19186621Sbt150084 	 */
19196621Sbt150084 	if (ixgbe->num_rx_rings > 1)
19206621Sbt150084 		ixgbe_setup_rss(ixgbe);
19216621Sbt150084 }
19226621Sbt150084 
19236621Sbt150084 static void
19246621Sbt150084 ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring)
19256621Sbt150084 {
19266621Sbt150084 	ixgbe_t *ixgbe = tx_ring->ixgbe;
19276621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
19286621Sbt150084 	uint32_t size;
19296621Sbt150084 	uint32_t buf_low;
19306621Sbt150084 	uint32_t buf_high;
19316621Sbt150084 	uint32_t reg_val;
19326621Sbt150084 
19336621Sbt150084 	ASSERT(mutex_owned(&tx_ring->tx_lock));
19346621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
19356621Sbt150084 
19366621Sbt150084 	/*
19376621Sbt150084 	 * Initialize the length register
19386621Sbt150084 	 */
19396621Sbt150084 	size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc);
19406621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size);
19416621Sbt150084 
19426621Sbt150084 	/*
19436621Sbt150084 	 * Initialize the base address registers
19446621Sbt150084 	 */
19456621Sbt150084 	buf_low = (uint32_t)tx_ring->tbd_area.dma_address;
19466621Sbt150084 	buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32);
19476621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low);
19486621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high);
19496621Sbt150084 
19506621Sbt150084 	/*
19516621Sbt150084 	 * Setup head & tail pointers
19526621Sbt150084 	 */
19536621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0);
19546621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0);
19556621Sbt150084 
19566621Sbt150084 	/*
19576621Sbt150084 	 * Setup head write-back
19586621Sbt150084 	 */
19596621Sbt150084 	if (ixgbe->tx_head_wb_enable) {
19606621Sbt150084 		/*
19616621Sbt150084 		 * The memory of the head write-back is allocated using
19626621Sbt150084 		 * the extra tbd beyond the tail of the tbd ring.
19636621Sbt150084 		 */
19646621Sbt150084 		tx_ring->tbd_head_wb = (uint32_t *)
19656621Sbt150084 		    ((uintptr_t)tx_ring->tbd_area.address + size);
19666621Sbt150084 		*tx_ring->tbd_head_wb = 0;
19676621Sbt150084 
19686621Sbt150084 		buf_low = (uint32_t)
19696621Sbt150084 		    (tx_ring->tbd_area.dma_address + size);
19706621Sbt150084 		buf_high = (uint32_t)
19716621Sbt150084 		    ((tx_ring->tbd_area.dma_address + size) >> 32);
19726621Sbt150084 
19736621Sbt150084 		/* Set the head write-back enable bit */
19746621Sbt150084 		buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE;
19756621Sbt150084 
19766621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low);
19776621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high);
19786621Sbt150084 
19796621Sbt150084 		/*
19806621Sbt150084 		 * Turn off relaxed ordering for head write back or it will
19816621Sbt150084 		 * cause problems with the tx recycling
19826621Sbt150084 		 */
19836621Sbt150084 		reg_val = IXGBE_READ_REG(hw,
19846621Sbt150084 		    IXGBE_DCA_TXCTRL(tx_ring->index));
19856621Sbt150084 		reg_val &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
19866621Sbt150084 		IXGBE_WRITE_REG(hw,
19876621Sbt150084 		    IXGBE_DCA_TXCTRL(tx_ring->index), reg_val);
19886621Sbt150084 	} else {
19896621Sbt150084 		tx_ring->tbd_head_wb = NULL;
19906621Sbt150084 	}
19916621Sbt150084 
19926621Sbt150084 	tx_ring->tbd_head = 0;
19936621Sbt150084 	tx_ring->tbd_tail = 0;
19946621Sbt150084 	tx_ring->tbd_free = tx_ring->ring_size;
19956621Sbt150084 
199610376SChenlu.Chen@Sun.COM 	if (ixgbe->tx_ring_init == B_TRUE) {
19976621Sbt150084 		tx_ring->tcb_head = 0;
19986621Sbt150084 		tx_ring->tcb_tail = 0;
19996621Sbt150084 		tx_ring->tcb_free = tx_ring->free_list_size;
20006621Sbt150084 	}
20016621Sbt150084 
20026621Sbt150084 	/*
20037245Sgg161487 	 * Initialize the s/w context structure
20046621Sbt150084 	 */
20057245Sgg161487 	bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t));
20066621Sbt150084 }
20076621Sbt150084 
20086621Sbt150084 static void
20096621Sbt150084 ixgbe_setup_tx(ixgbe_t *ixgbe)
20106621Sbt150084 {
20117167Sgg161487 	struct ixgbe_hw *hw = &ixgbe->hw;
20126621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
20137167Sgg161487 	uint32_t reg_val;
20148275SEric Cheng 	uint32_t ring_mapping;
20156621Sbt150084 	int i;
20166621Sbt150084 
20176621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
20186621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
20196621Sbt150084 		ixgbe_setup_tx_ring(tx_ring);
20206621Sbt150084 	}
20217167Sgg161487 
20227167Sgg161487 	/*
20238275SEric Cheng 	 * Setup the per-ring statistics mapping.
20248275SEric Cheng 	 */
20258275SEric Cheng 	ring_mapping = 0;
20268275SEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
20278275SEric Cheng 		ring_mapping |= (i & 0xF) << (8 * (i & 0x3));
20288275SEric Cheng 		if ((i & 0x3) == 0x3) {
20299353SSamuel.Tu@Sun.COM 			if (hw->mac.type >= ixgbe_mac_82599EB) {
20309353SSamuel.Tu@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2),
20319353SSamuel.Tu@Sun.COM 				    ring_mapping);
20329353SSamuel.Tu@Sun.COM 			} else {
20339353SSamuel.Tu@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2),
20349353SSamuel.Tu@Sun.COM 				    ring_mapping);
20359353SSamuel.Tu@Sun.COM 			}
20368275SEric Cheng 			ring_mapping = 0;
20378275SEric Cheng 		}
20388275SEric Cheng 	}
20398275SEric Cheng 	if ((i & 0x3) != 0x3)
20409353SSamuel.Tu@Sun.COM 		if (hw->mac.type >= ixgbe_mac_82599EB) {
20419353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping);
20429353SSamuel.Tu@Sun.COM 		} else {
20439353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping);
20449353SSamuel.Tu@Sun.COM 		}
20458275SEric Cheng 
20468275SEric Cheng 	/*
20477167Sgg161487 	 * Enable CRC appending and TX padding (for short tx frames)
20487167Sgg161487 	 */
20497167Sgg161487 	reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
20507167Sgg161487 	reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN;
20517167Sgg161487 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
20529353SSamuel.Tu@Sun.COM 
20539353SSamuel.Tu@Sun.COM 	/*
20549353SSamuel.Tu@Sun.COM 	 * enable DMA for 82599 parts
20559353SSamuel.Tu@Sun.COM 	 */
20569353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
20579353SSamuel.Tu@Sun.COM 	/* DMATXCTL.TE must be set after all Tx config is complete */
20589353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
20599353SSamuel.Tu@Sun.COM 		reg_val |= IXGBE_DMATXCTL_TE;
20609353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val);
20619353SSamuel.Tu@Sun.COM 	}
20629353SSamuel.Tu@Sun.COM 
20639353SSamuel.Tu@Sun.COM 	/*
20649353SSamuel.Tu@Sun.COM 	 * Enabling tx queues ..
20659353SSamuel.Tu@Sun.COM 	 * For 82599 must be done after DMATXCTL.TE is set
20669353SSamuel.Tu@Sun.COM 	 */
20679353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
20689353SSamuel.Tu@Sun.COM 		tx_ring = &ixgbe->tx_rings[i];
20699353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index));
20709353SSamuel.Tu@Sun.COM 		reg_val |= IXGBE_TXDCTL_ENABLE;
20719353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val);
20729353SSamuel.Tu@Sun.COM 	}
20736621Sbt150084 }
20746621Sbt150084 
20756621Sbt150084 /*
20766621Sbt150084  * ixgbe_setup_rss - Setup receive-side scaling feature.
20776621Sbt150084  */
20786621Sbt150084 static void
20796621Sbt150084 ixgbe_setup_rss(ixgbe_t *ixgbe)
20806621Sbt150084 {
20816621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
20827167Sgg161487 	uint32_t i, mrqc, rxcsum;
20836621Sbt150084 	uint32_t random;
20846621Sbt150084 	uint32_t reta;
20856621Sbt150084 
20866621Sbt150084 	/*
20876621Sbt150084 	 * Fill out redirection table
20886621Sbt150084 	 */
20896621Sbt150084 	reta = 0;
20906621Sbt150084 	for (i = 0; i < 128; i++) {
20917167Sgg161487 		reta = (reta << 8) | (i % ixgbe->num_rx_rings);
20927167Sgg161487 		if ((i & 3) == 3)
20936621Sbt150084 			IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
20946621Sbt150084 	}
20956621Sbt150084 
20966621Sbt150084 	/*
20976621Sbt150084 	 * Fill out hash function seeds with a random constant
20986621Sbt150084 	 */
20996621Sbt150084 	for (i = 0; i < 10; i++) {
21006621Sbt150084 		(void) random_get_pseudo_bytes((uint8_t *)&random,
21016621Sbt150084 		    sizeof (uint32_t));
21026621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random);
21036621Sbt150084 	}
21046621Sbt150084 
21056621Sbt150084 	/*
21067167Sgg161487 	 * Enable RSS & perform hash on these packet types
21076621Sbt150084 	 */
21086621Sbt150084 	mrqc = IXGBE_MRQC_RSSEN |
21096621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4 |
21106621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
21116621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
21126621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
21136621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
21146621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6 |
21156621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
21166621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
21176621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
21186621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
21196621Sbt150084 
21206621Sbt150084 	/*
21216621Sbt150084 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
21226621Sbt150084 	 * It is an adapter hardware limitation that Packet Checksum is
21236621Sbt150084 	 * mutually exclusive with RSS.
21246621Sbt150084 	 */
21256621Sbt150084 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
21266621Sbt150084 	rxcsum |= IXGBE_RXCSUM_PCSD;
21276621Sbt150084 	rxcsum &= ~IXGBE_RXCSUM_IPPCSE;
21286621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
21296621Sbt150084 }
21306621Sbt150084 
21316621Sbt150084 /*
21326621Sbt150084  * ixgbe_init_unicst - Initialize the unicast addresses.
21336621Sbt150084  */
21346621Sbt150084 static void
21356621Sbt150084 ixgbe_init_unicst(ixgbe_t *ixgbe)
21366621Sbt150084 {
21376621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
21388275SEric Cheng 	uint8_t *mac_addr;
21396621Sbt150084 	int slot;
21406621Sbt150084 	/*
21416621Sbt150084 	 * Here we should consider two situations:
21426621Sbt150084 	 *
21438275SEric Cheng 	 * 1. Chipset is initialized at the first time,
21448275SEric Cheng 	 *    Clear all the multiple unicast addresses.
21456621Sbt150084 	 *
21466621Sbt150084 	 * 2. Chipset is reset
21476621Sbt150084 	 *    Recover the multiple unicast addresses from the
21486621Sbt150084 	 *    software data structure to the RAR registers.
21496621Sbt150084 	 */
21506621Sbt150084 	if (!ixgbe->unicst_init) {
21516621Sbt150084 		/*
21526621Sbt150084 		 * Initialize the multiple unicast addresses
21536621Sbt150084 		 */
21546621Sbt150084 		ixgbe->unicst_total = MAX_NUM_UNICAST_ADDRESSES;
21558275SEric Cheng 		ixgbe->unicst_avail = ixgbe->unicst_total;
21568275SEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
21578275SEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
21588275SEric Cheng 			bzero(mac_addr, ETHERADDRL);
21598275SEric Cheng 			(void) ixgbe_set_rar(hw, slot, mac_addr, NULL, NULL);
21606621Sbt150084 			ixgbe->unicst_addr[slot].mac.set = 0;
21618275SEric Cheng 		}
21626621Sbt150084 		ixgbe->unicst_init = B_TRUE;
21636621Sbt150084 	} else {
21646621Sbt150084 		/* Re-configure the RAR registers */
21658275SEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
21668275SEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
21678275SEric Cheng 			if (ixgbe->unicst_addr[slot].mac.set == 1) {
21688275SEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
21698275SEric Cheng 				    NULL, IXGBE_RAH_AV);
21708275SEric Cheng 			} else {
21718275SEric Cheng 				bzero(mac_addr, ETHERADDRL);
21728275SEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
21738275SEric Cheng 				    NULL, NULL);
21748275SEric Cheng 			}
21758275SEric Cheng 		}
21766621Sbt150084 	}
21776621Sbt150084 }
21788275SEric Cheng 
21796621Sbt150084 /*
21806621Sbt150084  * ixgbe_unicst_set - Set the unicast address to the specified slot.
21816621Sbt150084  */
21826621Sbt150084 int
21836621Sbt150084 ixgbe_unicst_set(ixgbe_t *ixgbe, const uint8_t *mac_addr,
21848275SEric Cheng     int slot)
21856621Sbt150084 {
21866621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
21876621Sbt150084 
21886621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
21896621Sbt150084 
21906621Sbt150084 	/*
21916621Sbt150084 	 * Save the unicast address in the software data structure
21926621Sbt150084 	 */
21936621Sbt150084 	bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
21946621Sbt150084 
21956621Sbt150084 	/*
21966621Sbt150084 	 * Set the unicast address to the RAR register
21976621Sbt150084 	 */
21988275SEric Cheng 	(void) ixgbe_set_rar(hw, slot, (uint8_t *)mac_addr, NULL, IXGBE_RAH_AV);
21996621Sbt150084 
22006621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
22016621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
22026621Sbt150084 		return (EIO);
22036621Sbt150084 	}
22046621Sbt150084 
22056621Sbt150084 	return (0);
22066621Sbt150084 }
22076621Sbt150084 
22086621Sbt150084 /*
22098275SEric Cheng  * ixgbe_unicst_find - Find the slot for the specified unicast address
22108275SEric Cheng  */
22118275SEric Cheng int
22128275SEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr)
22138275SEric Cheng {
22148275SEric Cheng 	int slot;
22158275SEric Cheng 
22168275SEric Cheng 	ASSERT(mutex_owned(&ixgbe->gen_lock));
22178275SEric Cheng 
22188275SEric Cheng 	for (slot = 0; slot < ixgbe->unicst_total; slot++) {
22198275SEric Cheng 		if (bcmp(ixgbe->unicst_addr[slot].mac.addr,
22208275SEric Cheng 		    mac_addr, ETHERADDRL) == 0)
22218275SEric Cheng 			return (slot);
22228275SEric Cheng 	}
22238275SEric Cheng 
22248275SEric Cheng 	return (-1);
22258275SEric Cheng }
22268275SEric Cheng 
22278275SEric Cheng /*
22286621Sbt150084  * ixgbe_multicst_add - Add a multicst address.
22296621Sbt150084  */
22306621Sbt150084 int
22316621Sbt150084 ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr)
22326621Sbt150084 {
22336621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
22346621Sbt150084 
22356621Sbt150084 	if ((multiaddr[0] & 01) == 0) {
22366621Sbt150084 		return (EINVAL);
22376621Sbt150084 	}
22386621Sbt150084 
22396621Sbt150084 	if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) {
22406621Sbt150084 		return (ENOENT);
22416621Sbt150084 	}
22426621Sbt150084 
22436621Sbt150084 	bcopy(multiaddr,
22446621Sbt150084 	    &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL);
22456621Sbt150084 	ixgbe->mcast_count++;
22466621Sbt150084 
22476621Sbt150084 	/*
22486621Sbt150084 	 * Update the multicast table in the hardware
22496621Sbt150084 	 */
22506621Sbt150084 	ixgbe_setup_multicst(ixgbe);
22516621Sbt150084 
22526621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
22536621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
22546621Sbt150084 		return (EIO);
22556621Sbt150084 	}
22566621Sbt150084 
22576621Sbt150084 	return (0);
22586621Sbt150084 }
22596621Sbt150084 
22606621Sbt150084 /*
22616621Sbt150084  * ixgbe_multicst_remove - Remove a multicst address.
22626621Sbt150084  */
22636621Sbt150084 int
22646621Sbt150084 ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr)
22656621Sbt150084 {
22666621Sbt150084 	int i;
22676621Sbt150084 
22686621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
22696621Sbt150084 
22706621Sbt150084 	for (i = 0; i < ixgbe->mcast_count; i++) {
22716621Sbt150084 		if (bcmp(multiaddr, &ixgbe->mcast_table[i],
22726621Sbt150084 		    ETHERADDRL) == 0) {
22736621Sbt150084 			for (i++; i < ixgbe->mcast_count; i++) {
22746621Sbt150084 				ixgbe->mcast_table[i - 1] =
22756621Sbt150084 				    ixgbe->mcast_table[i];
22766621Sbt150084 			}
22776621Sbt150084 			ixgbe->mcast_count--;
22786621Sbt150084 			break;
22796621Sbt150084 		}
22806621Sbt150084 	}
22816621Sbt150084 
22826621Sbt150084 	/*
22836621Sbt150084 	 * Update the multicast table in the hardware
22846621Sbt150084 	 */
22856621Sbt150084 	ixgbe_setup_multicst(ixgbe);
22866621Sbt150084 
22876621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
22886621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
22896621Sbt150084 		return (EIO);
22906621Sbt150084 	}
22916621Sbt150084 
22926621Sbt150084 	return (0);
22936621Sbt150084 }
22946621Sbt150084 
22956621Sbt150084 /*
22966621Sbt150084  * ixgbe_setup_multicast - Setup multicast data structures.
22976621Sbt150084  *
22986621Sbt150084  * This routine initializes all of the multicast related structures
22996621Sbt150084  * and save them in the hardware registers.
23006621Sbt150084  */
23016621Sbt150084 static void
23026621Sbt150084 ixgbe_setup_multicst(ixgbe_t *ixgbe)
23036621Sbt150084 {
23046621Sbt150084 	uint8_t *mc_addr_list;
23056621Sbt150084 	uint32_t mc_addr_count;
23066621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
23076621Sbt150084 
23086621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
23096621Sbt150084 
23106621Sbt150084 	ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES);
23116621Sbt150084 
23126621Sbt150084 	mc_addr_list = (uint8_t *)ixgbe->mcast_table;
23136621Sbt150084 	mc_addr_count = ixgbe->mcast_count;
23146621Sbt150084 
23156621Sbt150084 	/*
23166621Sbt150084 	 * Update the multicast addresses to the MTA registers
23176621Sbt150084 	 */
23186621Sbt150084 	(void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
23196621Sbt150084 	    ixgbe_mc_table_itr);
23206621Sbt150084 }
23216621Sbt150084 
23226621Sbt150084 /*
23236621Sbt150084  * ixgbe_get_conf - Get driver configurations set in driver.conf.
23246621Sbt150084  *
23256621Sbt150084  * This routine gets user-configured values out of the configuration
23266621Sbt150084  * file ixgbe.conf.
23276621Sbt150084  *
23286621Sbt150084  * For each configurable value, there is a minimum, a maximum, and a
23296621Sbt150084  * default.
23306621Sbt150084  * If user does not configure a value, use the default.
23316621Sbt150084  * If user configures below the minimum, use the minumum.
23326621Sbt150084  * If user configures above the maximum, use the maxumum.
23336621Sbt150084  */
23346621Sbt150084 static void
23356621Sbt150084 ixgbe_get_conf(ixgbe_t *ixgbe)
23366621Sbt150084 {
23376621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
23386621Sbt150084 	uint32_t flow_control;
23396621Sbt150084 
23406621Sbt150084 	/*
23416621Sbt150084 	 * ixgbe driver supports the following user configurations:
23426621Sbt150084 	 *
23436621Sbt150084 	 * Jumbo frame configuration:
23446621Sbt150084 	 *    default_mtu
23456621Sbt150084 	 *
23466621Sbt150084 	 * Ethernet flow control configuration:
23476621Sbt150084 	 *    flow_control
23486621Sbt150084 	 *
23496621Sbt150084 	 * Multiple rings configurations:
23506621Sbt150084 	 *    tx_queue_number
23516621Sbt150084 	 *    tx_ring_size
23526621Sbt150084 	 *    rx_queue_number
23536621Sbt150084 	 *    rx_ring_size
23546621Sbt150084 	 *
23556621Sbt150084 	 * Call ixgbe_get_prop() to get the value for a specific
23566621Sbt150084 	 * configuration parameter.
23576621Sbt150084 	 */
23586621Sbt150084 
23596621Sbt150084 	/*
23606621Sbt150084 	 * Jumbo frame configuration - max_frame_size controls host buffer
23616621Sbt150084 	 * allocation, so includes MTU, ethernet header, vlan tag and
23626621Sbt150084 	 * frame check sequence.
23636621Sbt150084 	 */
23646621Sbt150084 	ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU,
236511150SZhen.W@Sun.COM 	    MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU);
23666621Sbt150084 
23676621Sbt150084 	ixgbe->max_frame_size = ixgbe->default_mtu +
23686621Sbt150084 	    sizeof (struct ether_vlan_header) + ETHERFCSL;
23696621Sbt150084 
23706621Sbt150084 	/*
23716621Sbt150084 	 * Ethernet flow control configuration
23726621Sbt150084 	 */
23736621Sbt150084 	flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL,
23748275SEric Cheng 	    ixgbe_fc_none, 3, ixgbe_fc_none);
23756621Sbt150084 	if (flow_control == 3)
23766621Sbt150084 		flow_control = ixgbe_fc_default;
23776621Sbt150084 
23789353SSamuel.Tu@Sun.COM 	/*
23799353SSamuel.Tu@Sun.COM 	 * fc.requested mode is what the user requests.  After autoneg,
23809353SSamuel.Tu@Sun.COM 	 * fc.current_mode will be the flow_control mode that was negotiated.
23819353SSamuel.Tu@Sun.COM 	 */
23829353SSamuel.Tu@Sun.COM 	hw->fc.requested_mode = flow_control;
23836621Sbt150084 
23846621Sbt150084 	/*
23856621Sbt150084 	 * Multiple rings configurations
23866621Sbt150084 	 */
23876621Sbt150084 	ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM,
23888490SPaul.Guo@Sun.COM 	    ixgbe->capab->min_tx_que_num,
23898490SPaul.Guo@Sun.COM 	    ixgbe->capab->max_tx_que_num,
23908490SPaul.Guo@Sun.COM 	    ixgbe->capab->def_tx_que_num);
23916621Sbt150084 	ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE,
23926621Sbt150084 	    MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE);
23936621Sbt150084 
23946621Sbt150084 	ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM,
23958490SPaul.Guo@Sun.COM 	    ixgbe->capab->min_rx_que_num,
23968490SPaul.Guo@Sun.COM 	    ixgbe->capab->max_rx_que_num,
23978490SPaul.Guo@Sun.COM 	    ixgbe->capab->def_rx_que_num);
23986621Sbt150084 	ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE,
23996621Sbt150084 	    MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE);
24006621Sbt150084 
24016621Sbt150084 	/*
24028275SEric Cheng 	 * Multiple groups configuration
24038275SEric Cheng 	 */
24048275SEric Cheng 	ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM,
24058275SEric Cheng 	    MIN_RX_GROUP_NUM, MAX_RX_GROUP_NUM, DEFAULT_RX_GROUP_NUM);
24068275SEric Cheng 
24078275SEric Cheng 	ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE,
24088275SEric Cheng 	    0, 1, DEFAULT_MR_ENABLE);
24098275SEric Cheng 
24108275SEric Cheng 	if (ixgbe->mr_enable == B_FALSE) {
24118275SEric Cheng 		ixgbe->num_tx_rings = 1;
24128275SEric Cheng 		ixgbe->num_rx_rings = 1;
24138275SEric Cheng 		ixgbe->num_rx_groups = 1;
24148275SEric Cheng 	}
24158275SEric Cheng 
24168275SEric Cheng 	/*
24176621Sbt150084 	 * Tunable used to force an interrupt type. The only use is
24186621Sbt150084 	 * for testing of the lesser interrupt types.
24196621Sbt150084 	 * 0 = don't force interrupt type
24208275SEric Cheng 	 * 1 = force interrupt type MSI-X
24216621Sbt150084 	 * 2 = force interrupt type MSI
24226621Sbt150084 	 * 3 = force interrupt type Legacy
24236621Sbt150084 	 */
24246621Sbt150084 	ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE,
24256621Sbt150084 	    IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE);
24266621Sbt150084 
24276621Sbt150084 	ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE,
24287167Sgg161487 	    0, 1, DEFAULT_TX_HCKSUM_ENABLE);
24296621Sbt150084 	ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE,
24307167Sgg161487 	    0, 1, DEFAULT_RX_HCKSUM_ENABLE);
24316621Sbt150084 	ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE,
24327167Sgg161487 	    0, 1, DEFAULT_LSO_ENABLE);
24336621Sbt150084 	ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE,
24347167Sgg161487 	    0, 1, DEFAULT_TX_HEAD_WB_ENABLE);
24357167Sgg161487 
24369353SSamuel.Tu@Sun.COM 	/* Head Write Back not recommended for 82599 */
24379353SSamuel.Tu@Sun.COM 	if (hw->mac.type >= ixgbe_mac_82599EB) {
24389353SSamuel.Tu@Sun.COM 		ixgbe->tx_head_wb_enable = B_FALSE;
24399353SSamuel.Tu@Sun.COM 	}
24409353SSamuel.Tu@Sun.COM 
24417167Sgg161487 	/*
24427167Sgg161487 	 * ixgbe LSO needs the tx h/w checksum support.
24437167Sgg161487 	 * LSO will be disabled if tx h/w checksum is not
24447167Sgg161487 	 * enabled.
24457167Sgg161487 	 */
24467167Sgg161487 	if (ixgbe->tx_hcksum_enable == B_FALSE) {
24477167Sgg161487 		ixgbe->lso_enable = B_FALSE;
24487167Sgg161487 	}
24496621Sbt150084 
24506621Sbt150084 	ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD,
24516621Sbt150084 	    MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD,
24526621Sbt150084 	    DEFAULT_TX_COPY_THRESHOLD);
24536621Sbt150084 	ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe,
24546621Sbt150084 	    PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD,
24556621Sbt150084 	    MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD);
24566621Sbt150084 	ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe,
24576621Sbt150084 	    PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD,
24586621Sbt150084 	    MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD);
24596621Sbt150084 	ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe,
24606621Sbt150084 	    PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD,
24616621Sbt150084 	    MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD);
24626621Sbt150084 
24636621Sbt150084 	ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD,
24646621Sbt150084 	    MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD,
24656621Sbt150084 	    DEFAULT_RX_COPY_THRESHOLD);
24666621Sbt150084 	ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR,
24676621Sbt150084 	    MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR,
24686621Sbt150084 	    DEFAULT_RX_LIMIT_PER_INTR);
24696621Sbt150084 
247010376SChenlu.Chen@Sun.COM 	ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING,
247110376SChenlu.Chen@Sun.COM 	    ixgbe->capab->min_intr_throttle,
247210376SChenlu.Chen@Sun.COM 	    ixgbe->capab->max_intr_throttle,
247310376SChenlu.Chen@Sun.COM 	    ixgbe->capab->def_intr_throttle);
24749353SSamuel.Tu@Sun.COM 	/*
247510376SChenlu.Chen@Sun.COM 	 * 82599 requires the interupt throttling rate is
247610376SChenlu.Chen@Sun.COM 	 * a multiple of 8. This is enforced by the register
247710376SChenlu.Chen@Sun.COM 	 * definiton.
24789353SSamuel.Tu@Sun.COM 	 */
247910376SChenlu.Chen@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB)
248010376SChenlu.Chen@Sun.COM 		ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8;
248110376SChenlu.Chen@Sun.COM }
248210376SChenlu.Chen@Sun.COM 
248310376SChenlu.Chen@Sun.COM static void
248410376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe_t *ixgbe)
248510376SChenlu.Chen@Sun.COM {
248610376SChenlu.Chen@Sun.COM 	ixgbe->param_en_10000fdx_cap = 1;
248710376SChenlu.Chen@Sun.COM 	ixgbe->param_en_1000fdx_cap = 1;
248810376SChenlu.Chen@Sun.COM 	ixgbe->param_en_100fdx_cap = 1;
248910376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_10000fdx_cap = 1;
249010376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_1000fdx_cap = 1;
249110376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_100fdx_cap = 1;
249210376SChenlu.Chen@Sun.COM 
249310376SChenlu.Chen@Sun.COM 	ixgbe->param_pause_cap = 1;
249410376SChenlu.Chen@Sun.COM 	ixgbe->param_asym_pause_cap = 1;
249510376SChenlu.Chen@Sun.COM 	ixgbe->param_rem_fault = 0;
249610376SChenlu.Chen@Sun.COM 
249710376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_autoneg_cap = 1;
249810376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_pause_cap = 1;
249910376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_asym_pause_cap = 1;
250010376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_rem_fault = 0;
250110376SChenlu.Chen@Sun.COM 
250210376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_10000fdx_cap = 0;
250310376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_1000fdx_cap = 0;
250410376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_100fdx_cap = 0;
250510376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_autoneg_cap = 0;
250610376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_pause_cap = 0;
250710376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_asym_pause_cap = 0;
250810376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_rem_fault = 0;
25096621Sbt150084 }
25106621Sbt150084 
25116621Sbt150084 /*
25126621Sbt150084  * ixgbe_get_prop - Get a property value out of the configuration file
25136621Sbt150084  * ixgbe.conf.
25146621Sbt150084  *
25156621Sbt150084  * Caller provides the name of the property, a default value, a minimum
25166621Sbt150084  * value, and a maximum value.
25176621Sbt150084  *
25186621Sbt150084  * Return configured value of the property, with default, minimum and
25196621Sbt150084  * maximum properly applied.
25206621Sbt150084  */
25216621Sbt150084 static int
25226621Sbt150084 ixgbe_get_prop(ixgbe_t *ixgbe,
25236621Sbt150084     char *propname,	/* name of the property */
25246621Sbt150084     int minval,		/* minimum acceptable value */
25256621Sbt150084     int maxval,		/* maximim acceptable value */
25266621Sbt150084     int defval)		/* default value */
25276621Sbt150084 {
25286621Sbt150084 	int value;
25296621Sbt150084 
25306621Sbt150084 	/*
25316621Sbt150084 	 * Call ddi_prop_get_int() to read the conf settings
25326621Sbt150084 	 */
25336621Sbt150084 	value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip,
25346621Sbt150084 	    DDI_PROP_DONTPASS, propname, defval);
25356621Sbt150084 	if (value > maxval)
25366621Sbt150084 		value = maxval;
25376621Sbt150084 
25386621Sbt150084 	if (value < minval)
25396621Sbt150084 		value = minval;
25406621Sbt150084 
25416621Sbt150084 	return (value);
25426621Sbt150084 }
25436621Sbt150084 
25446621Sbt150084 /*
25456621Sbt150084  * ixgbe_driver_setup_link - Using the link properties to setup the link.
25466621Sbt150084  */
25476621Sbt150084 int
25486621Sbt150084 ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw)
25496621Sbt150084 {
255010998SChenlu.Chen@Sun.COM 	u32 autoneg_advertised = 0;
255110998SChenlu.Chen@Sun.COM 
255210998SChenlu.Chen@Sun.COM 	/*
255310998SChenlu.Chen@Sun.COM 	 * No half duplex support with 10Gb parts
255410998SChenlu.Chen@Sun.COM 	 */
255510998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_10000fdx_cap == 1)
255610998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
255710998SChenlu.Chen@Sun.COM 
255810998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_1000fdx_cap == 1)
255910998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
256010998SChenlu.Chen@Sun.COM 
256110998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_100fdx_cap == 1)
256210998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
256310998SChenlu.Chen@Sun.COM 
256410998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_autoneg_cap == 1 && autoneg_advertised == 0) {
256510998SChenlu.Chen@Sun.COM 		ixgbe_notice(ixgbe, "Invalid link settings. Setup link "
256610998SChenlu.Chen@Sun.COM 		    "to autonegotiation with full link capabilities.");
256710998SChenlu.Chen@Sun.COM 
256810998SChenlu.Chen@Sun.COM 		autoneg_advertised = IXGBE_LINK_SPEED_10GB_FULL |
256910998SChenlu.Chen@Sun.COM 		    IXGBE_LINK_SPEED_1GB_FULL |
257010998SChenlu.Chen@Sun.COM 		    IXGBE_LINK_SPEED_100_FULL;
25716621Sbt150084 	}
25726621Sbt150084 
25736621Sbt150084 	if (setup_hw) {
257410998SChenlu.Chen@Sun.COM 		if (ixgbe_setup_link(&ixgbe->hw, autoneg_advertised,
257510998SChenlu.Chen@Sun.COM 		    ixgbe->param_adv_autoneg_cap, B_TRUE) != IXGBE_SUCCESS) {
25769353SSamuel.Tu@Sun.COM 			ixgbe_notice(ixgbe, "Setup link failed on this "
25779353SSamuel.Tu@Sun.COM 			    "device.");
25786621Sbt150084 			return (IXGBE_FAILURE);
25799353SSamuel.Tu@Sun.COM 		}
25806621Sbt150084 	}
25816621Sbt150084 
25826621Sbt150084 	return (IXGBE_SUCCESS);
25836621Sbt150084 }
25846621Sbt150084 
25856621Sbt150084 /*
2586*11233SPaul.Guo@Sun.COM  * ixgbe_driver_link_check - Link status processing.
2587*11233SPaul.Guo@Sun.COM  *
2588*11233SPaul.Guo@Sun.COM  * This function can be called in both kernel context and interrupt context
25896621Sbt150084  */
25908490SPaul.Guo@Sun.COM static void
2591*11233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe_t *ixgbe)
25926621Sbt150084 {
25936621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
25946621Sbt150084 	ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
25956621Sbt150084 	boolean_t link_up = B_FALSE;
25966621Sbt150084 	boolean_t link_changed = B_FALSE;
25976621Sbt150084 
2598*11233SPaul.Guo@Sun.COM 	ASSERT(mutex_owned(&ixgbe->gen_lock));
2599*11233SPaul.Guo@Sun.COM 
2600*11233SPaul.Guo@Sun.COM 	(void) ixgbe_check_link(hw, &speed, &link_up, false);
26016621Sbt150084 	if (link_up) {
2602*11233SPaul.Guo@Sun.COM 		ixgbe->link_check_complete = B_TRUE;
2603*11233SPaul.Guo@Sun.COM 
26049353SSamuel.Tu@Sun.COM 		/* Link is up, enable flow control settings */
26059353SSamuel.Tu@Sun.COM 		(void) ixgbe_fc_enable(hw, 0);
26069353SSamuel.Tu@Sun.COM 
26076621Sbt150084 		/*
26086621Sbt150084 		 * The Link is up, check whether it was marked as down earlier
26096621Sbt150084 		 */
26106621Sbt150084 		if (ixgbe->link_state != LINK_STATE_UP) {
26116621Sbt150084 			switch (speed) {
26129353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_10GB_FULL:
26139353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_10GB;
26149353SSamuel.Tu@Sun.COM 				break;
26159353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_1GB_FULL:
26169353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_1GB;
26179353SSamuel.Tu@Sun.COM 				break;
26189353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_100_FULL:
26199353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_100;
26206621Sbt150084 			}
26216621Sbt150084 			ixgbe->link_duplex = LINK_DUPLEX_FULL;
26226621Sbt150084 			ixgbe->link_state = LINK_STATE_UP;
26236621Sbt150084 			ixgbe->link_down_timeout = 0;
26246621Sbt150084 			link_changed = B_TRUE;
26256621Sbt150084 		}
26266621Sbt150084 	} else {
2627*11233SPaul.Guo@Sun.COM 		if (ixgbe->link_check_complete == B_TRUE ||
2628*11233SPaul.Guo@Sun.COM 		    (ixgbe->link_check_complete == B_FALSE &&
2629*11233SPaul.Guo@Sun.COM 		    gethrtime() >= ixgbe->link_check_hrtime)) {
2630*11233SPaul.Guo@Sun.COM 			/*
2631*11233SPaul.Guo@Sun.COM 			 * The link is really down
2632*11233SPaul.Guo@Sun.COM 			 */
2633*11233SPaul.Guo@Sun.COM 			ixgbe->link_check_complete = B_TRUE;
2634*11233SPaul.Guo@Sun.COM 
2635*11233SPaul.Guo@Sun.COM 			if (ixgbe->link_state != LINK_STATE_DOWN) {
2636*11233SPaul.Guo@Sun.COM 				ixgbe->link_speed = 0;
2637*11233SPaul.Guo@Sun.COM 				ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN;
2638*11233SPaul.Guo@Sun.COM 				ixgbe->link_state = LINK_STATE_DOWN;
2639*11233SPaul.Guo@Sun.COM 				link_changed = B_TRUE;
2640*11233SPaul.Guo@Sun.COM 			}
2641*11233SPaul.Guo@Sun.COM 
2642*11233SPaul.Guo@Sun.COM 			if (ixgbe->ixgbe_state & IXGBE_STARTED) {
2643*11233SPaul.Guo@Sun.COM 				if (ixgbe->link_down_timeout <
2644*11233SPaul.Guo@Sun.COM 				    MAX_LINK_DOWN_TIMEOUT) {
2645*11233SPaul.Guo@Sun.COM 					ixgbe->link_down_timeout++;
2646*11233SPaul.Guo@Sun.COM 				} else if (ixgbe->link_down_timeout ==
2647*11233SPaul.Guo@Sun.COM 				    MAX_LINK_DOWN_TIMEOUT) {
2648*11233SPaul.Guo@Sun.COM 					ixgbe_tx_clean(ixgbe);
2649*11233SPaul.Guo@Sun.COM 					ixgbe->link_down_timeout++;
2650*11233SPaul.Guo@Sun.COM 				}
26516621Sbt150084 			}
26526621Sbt150084 		}
26536621Sbt150084 	}
26546621Sbt150084 
26558490SPaul.Guo@Sun.COM 	/*
26568490SPaul.Guo@Sun.COM 	 * this is only reached after a link-status-change interrupt
26578490SPaul.Guo@Sun.COM 	 * so always get new phy state
26588490SPaul.Guo@Sun.COM 	 */
26598490SPaul.Guo@Sun.COM 	ixgbe_get_hw_state(ixgbe);
26608490SPaul.Guo@Sun.COM 
2661*11233SPaul.Guo@Sun.COM 	/*
2662*11233SPaul.Guo@Sun.COM 	 * If we are in an interrupt context, need to re-enable the
2663*11233SPaul.Guo@Sun.COM 	 * interrupt, which was automasked
2664*11233SPaul.Guo@Sun.COM 	 */
2665*11233SPaul.Guo@Sun.COM 	if (servicing_interrupt() != 0) {
2666*11233SPaul.Guo@Sun.COM 		ixgbe->eims |= IXGBE_EICR_LSC;
2667*11233SPaul.Guo@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
2668*11233SPaul.Guo@Sun.COM 	}
2669*11233SPaul.Guo@Sun.COM 
26708490SPaul.Guo@Sun.COM 	if (link_changed) {
26718490SPaul.Guo@Sun.COM 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
26728490SPaul.Guo@Sun.COM 	}
26736621Sbt150084 }
26746621Sbt150084 
26756621Sbt150084 /*
26769353SSamuel.Tu@Sun.COM  * ixgbe_sfp_check - sfp module processing done in taskq only for 82599.
26779353SSamuel.Tu@Sun.COM  */
26789353SSamuel.Tu@Sun.COM static void
26799353SSamuel.Tu@Sun.COM ixgbe_sfp_check(void *arg)
26809353SSamuel.Tu@Sun.COM {
26819353SSamuel.Tu@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
26829353SSamuel.Tu@Sun.COM 	uint32_t eicr = ixgbe->eicr;
26839353SSamuel.Tu@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
26849353SSamuel.Tu@Sun.COM 
2685*11233SPaul.Guo@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
26869353SSamuel.Tu@Sun.COM 	if (eicr & IXGBE_EICR_GPI_SDP1) {
26879353SSamuel.Tu@Sun.COM 		/* clear the interrupt */
26889353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
26899353SSamuel.Tu@Sun.COM 
26909353SSamuel.Tu@Sun.COM 		/* if link up, do multispeed fiber setup */
269110998SChenlu.Chen@Sun.COM 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
269210998SChenlu.Chen@Sun.COM 		    B_TRUE, B_TRUE);
26939353SSamuel.Tu@Sun.COM 		ixgbe_driver_link_check(ixgbe);
26949353SSamuel.Tu@Sun.COM 	} else if (eicr & IXGBE_EICR_GPI_SDP2) {
26959353SSamuel.Tu@Sun.COM 		/* clear the interrupt */
26969353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
26979353SSamuel.Tu@Sun.COM 
26989353SSamuel.Tu@Sun.COM 		/* if link up, do sfp module setup */
26999353SSamuel.Tu@Sun.COM 		(void) hw->mac.ops.setup_sfp(hw);
27009353SSamuel.Tu@Sun.COM 
27019353SSamuel.Tu@Sun.COM 		/* do multispeed fiber setup */
270210998SChenlu.Chen@Sun.COM 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
270310998SChenlu.Chen@Sun.COM 		    B_TRUE, B_TRUE);
27049353SSamuel.Tu@Sun.COM 		ixgbe_driver_link_check(ixgbe);
27059353SSamuel.Tu@Sun.COM 	}
2706*11233SPaul.Guo@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
2707*11233SPaul.Guo@Sun.COM }
2708*11233SPaul.Guo@Sun.COM 
2709*11233SPaul.Guo@Sun.COM /*
2710*11233SPaul.Guo@Sun.COM  * ixgbe_link_timer - timer for link status detection
2711*11233SPaul.Guo@Sun.COM  */
2712*11233SPaul.Guo@Sun.COM static void
2713*11233SPaul.Guo@Sun.COM ixgbe_link_timer(void *arg)
2714*11233SPaul.Guo@Sun.COM {
2715*11233SPaul.Guo@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
2716*11233SPaul.Guo@Sun.COM 
2717*11233SPaul.Guo@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
2718*11233SPaul.Guo@Sun.COM 	ixgbe_driver_link_check(ixgbe);
2719*11233SPaul.Guo@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
27209353SSamuel.Tu@Sun.COM }
27219353SSamuel.Tu@Sun.COM 
27229353SSamuel.Tu@Sun.COM /*
27236621Sbt150084  * ixgbe_local_timer - Driver watchdog function.
27246621Sbt150084  *
2725*11233SPaul.Guo@Sun.COM  * This function will handle the transmit stall check and other routines.
27266621Sbt150084  */
27276621Sbt150084 static void
27286621Sbt150084 ixgbe_local_timer(void *arg)
27296621Sbt150084 {
27306621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
27316621Sbt150084 
2732*11233SPaul.Guo@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_ERROR) {
27336621Sbt150084 		ixgbe->reset_count++;
27346621Sbt150084 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
27356621Sbt150084 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
2736*11233SPaul.Guo@Sun.COM 		ixgbe_restart_watchdog_timer(ixgbe);
2737*11233SPaul.Guo@Sun.COM 		return;
27386621Sbt150084 	}
27396621Sbt150084 
2740*11233SPaul.Guo@Sun.COM 	if (ixgbe_stall_check(ixgbe)) {
2741*11233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL);
2742*11233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
2743*11233SPaul.Guo@Sun.COM 
2744*11233SPaul.Guo@Sun.COM 		ixgbe->reset_count++;
2745*11233SPaul.Guo@Sun.COM 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
2746*11233SPaul.Guo@Sun.COM 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
2747*11233SPaul.Guo@Sun.COM 		ixgbe_restart_watchdog_timer(ixgbe);
2748*11233SPaul.Guo@Sun.COM 	}
27496621Sbt150084 }
27506621Sbt150084 
27516621Sbt150084 /*
27526621Sbt150084  * ixgbe_stall_check - Check for transmit stall.
27536621Sbt150084  *
27546621Sbt150084  * This function checks if the adapter is stalled (in transmit).
27556621Sbt150084  *
27566621Sbt150084  * It is called each time the watchdog timeout is invoked.
27576621Sbt150084  * If the transmit descriptor reclaim continuously fails,
27586621Sbt150084  * the watchdog value will increment by 1. If the watchdog
27596621Sbt150084  * value exceeds the threshold, the ixgbe is assumed to
27606621Sbt150084  * have stalled and need to be reset.
27616621Sbt150084  */
27626621Sbt150084 static boolean_t
27636621Sbt150084 ixgbe_stall_check(ixgbe_t *ixgbe)
27646621Sbt150084 {
27656621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
27666621Sbt150084 	boolean_t result;
27676621Sbt150084 	int i;
27686621Sbt150084 
27696621Sbt150084 	if (ixgbe->link_state != LINK_STATE_UP)
27706621Sbt150084 		return (B_FALSE);
27716621Sbt150084 
27726621Sbt150084 	/*
27736621Sbt150084 	 * If any tx ring is stalled, we'll reset the chipset
27746621Sbt150084 	 */
27756621Sbt150084 	result = B_FALSE;
27766621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
27776621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
277810376SChenlu.Chen@Sun.COM 		if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) {
277910305SPaul.Guo@Sun.COM 			tx_ring->tx_recycle(tx_ring);
278010305SPaul.Guo@Sun.COM 		}
27816621Sbt150084 
27826621Sbt150084 		if (tx_ring->recycle_fail > 0)
27836621Sbt150084 			tx_ring->stall_watchdog++;
27846621Sbt150084 		else
27856621Sbt150084 			tx_ring->stall_watchdog = 0;
27866621Sbt150084 
27876621Sbt150084 		if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) {
27886621Sbt150084 			result = B_TRUE;
27896621Sbt150084 			break;
27906621Sbt150084 		}
27916621Sbt150084 	}
27926621Sbt150084 
27936621Sbt150084 	if (result) {
27946621Sbt150084 		tx_ring->stall_watchdog = 0;
27956621Sbt150084 		tx_ring->recycle_fail = 0;
27966621Sbt150084 	}
27976621Sbt150084 
27986621Sbt150084 	return (result);
27996621Sbt150084 }
28006621Sbt150084 
28016621Sbt150084 
28026621Sbt150084 /*
28036621Sbt150084  * is_valid_mac_addr - Check if the mac address is valid.
28046621Sbt150084  */
28056621Sbt150084 static boolean_t
28066621Sbt150084 is_valid_mac_addr(uint8_t *mac_addr)
28076621Sbt150084 {
28086621Sbt150084 	const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 };
28096621Sbt150084 	const uint8_t addr_test2[6] =
28106621Sbt150084 	    { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
28116621Sbt150084 
28126621Sbt150084 	if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) ||
28136621Sbt150084 	    !(bcmp(addr_test2, mac_addr, ETHERADDRL)))
28146621Sbt150084 		return (B_FALSE);
28156621Sbt150084 
28166621Sbt150084 	return (B_TRUE);
28176621Sbt150084 }
28186621Sbt150084 
28196621Sbt150084 static boolean_t
28206621Sbt150084 ixgbe_find_mac_address(ixgbe_t *ixgbe)
28216621Sbt150084 {
28226621Sbt150084 #ifdef __sparc
28236621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
28246621Sbt150084 	uchar_t *bytes;
28256621Sbt150084 	struct ether_addr sysaddr;
28266621Sbt150084 	uint_t nelts;
28276621Sbt150084 	int err;
28286621Sbt150084 	boolean_t found = B_FALSE;
28296621Sbt150084 
28306621Sbt150084 	/*
28316621Sbt150084 	 * The "vendor's factory-set address" may already have
28326621Sbt150084 	 * been extracted from the chip, but if the property
28336621Sbt150084 	 * "local-mac-address" is set we use that instead.
28346621Sbt150084 	 *
28356621Sbt150084 	 * We check whether it looks like an array of 6
28366621Sbt150084 	 * bytes (which it should, if OBP set it).  If we can't
28376621Sbt150084 	 * make sense of it this way, we'll ignore it.
28386621Sbt150084 	 */
28396621Sbt150084 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
28406621Sbt150084 	    DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts);
28416621Sbt150084 	if (err == DDI_PROP_SUCCESS) {
28426621Sbt150084 		if (nelts == ETHERADDRL) {
28436621Sbt150084 			while (nelts--)
28446621Sbt150084 				hw->mac.addr[nelts] = bytes[nelts];
28456621Sbt150084 			found = B_TRUE;
28466621Sbt150084 		}
28476621Sbt150084 		ddi_prop_free(bytes);
28486621Sbt150084 	}
28496621Sbt150084 
28506621Sbt150084 	/*
28516621Sbt150084 	 * Look up the OBP property "local-mac-address?". If the user has set
28526621Sbt150084 	 * 'local-mac-address? = false', use "the system address" instead.
28536621Sbt150084 	 */
28546621Sbt150084 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0,
28556621Sbt150084 	    "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) {
28566621Sbt150084 		if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) {
28576621Sbt150084 			if (localetheraddr(NULL, &sysaddr) != 0) {
28586621Sbt150084 				bcopy(&sysaddr, hw->mac.addr, ETHERADDRL);
28596621Sbt150084 				found = B_TRUE;
28606621Sbt150084 			}
28616621Sbt150084 		}
28626621Sbt150084 		ddi_prop_free(bytes);
28636621Sbt150084 	}
28646621Sbt150084 
28656621Sbt150084 	/*
28666621Sbt150084 	 * Finally(!), if there's a valid "mac-address" property (created
28676621Sbt150084 	 * if we netbooted from this interface), we must use this instead
28686621Sbt150084 	 * of any of the above to ensure that the NFS/install server doesn't
28696621Sbt150084 	 * get confused by the address changing as Solaris takes over!
28706621Sbt150084 	 */
28716621Sbt150084 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
28726621Sbt150084 	    DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts);
28736621Sbt150084 	if (err == DDI_PROP_SUCCESS) {
28746621Sbt150084 		if (nelts == ETHERADDRL) {
28756621Sbt150084 			while (nelts--)
28766621Sbt150084 				hw->mac.addr[nelts] = bytes[nelts];
28776621Sbt150084 			found = B_TRUE;
28786621Sbt150084 		}
28796621Sbt150084 		ddi_prop_free(bytes);
28806621Sbt150084 	}
28816621Sbt150084 
28826621Sbt150084 	if (found) {
28836621Sbt150084 		bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
28846621Sbt150084 		return (B_TRUE);
28856621Sbt150084 	}
28866621Sbt150084 #else
28876621Sbt150084 	_NOTE(ARGUNUSED(ixgbe));
28886621Sbt150084 #endif
28896621Sbt150084 
28906621Sbt150084 	return (B_TRUE);
28916621Sbt150084 }
28926621Sbt150084 
28936621Sbt150084 #pragma inline(ixgbe_arm_watchdog_timer)
28946621Sbt150084 static void
28956621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe)
28966621Sbt150084 {
28976621Sbt150084 	/*
28986621Sbt150084 	 * Fire a watchdog timer
28996621Sbt150084 	 */
29006621Sbt150084 	ixgbe->watchdog_tid =
29016621Sbt150084 	    timeout(ixgbe_local_timer,
29026621Sbt150084 	    (void *)ixgbe, 1 * drv_usectohz(1000000));
29036621Sbt150084 
29046621Sbt150084 }
29056621Sbt150084 
29066621Sbt150084 /*
29076621Sbt150084  * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer.
29086621Sbt150084  */
29096621Sbt150084 void
29106621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe)
29116621Sbt150084 {
29126621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
29136621Sbt150084 
29146621Sbt150084 	if (!ixgbe->watchdog_enable) {
29156621Sbt150084 		ixgbe->watchdog_enable = B_TRUE;
29166621Sbt150084 		ixgbe->watchdog_start = B_TRUE;
29176621Sbt150084 		ixgbe_arm_watchdog_timer(ixgbe);
29186621Sbt150084 	}
29196621Sbt150084 
29206621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
29216621Sbt150084 }
29226621Sbt150084 
29236621Sbt150084 /*
29246621Sbt150084  * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer.
29256621Sbt150084  */
29266621Sbt150084 void
29276621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe)
29286621Sbt150084 {
29296621Sbt150084 	timeout_id_t tid;
29306621Sbt150084 
29316621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
29326621Sbt150084 
29336621Sbt150084 	ixgbe->watchdog_enable = B_FALSE;
29346621Sbt150084 	ixgbe->watchdog_start = B_FALSE;
29356621Sbt150084 	tid = ixgbe->watchdog_tid;
29366621Sbt150084 	ixgbe->watchdog_tid = 0;
29376621Sbt150084 
29386621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
29396621Sbt150084 
29406621Sbt150084 	if (tid != 0)
29416621Sbt150084 		(void) untimeout(tid);
29426621Sbt150084 }
29436621Sbt150084 
29446621Sbt150084 /*
29456621Sbt150084  * ixgbe_start_watchdog_timer - Start the driver watchdog timer.
29466621Sbt150084  */
29478490SPaul.Guo@Sun.COM void
29486621Sbt150084 ixgbe_start_watchdog_timer(ixgbe_t *ixgbe)
29496621Sbt150084 {
29506621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
29516621Sbt150084 
29526621Sbt150084 	if (ixgbe->watchdog_enable) {
29536621Sbt150084 		if (!ixgbe->watchdog_start) {
29546621Sbt150084 			ixgbe->watchdog_start = B_TRUE;
29556621Sbt150084 			ixgbe_arm_watchdog_timer(ixgbe);
29566621Sbt150084 		}
29576621Sbt150084 	}
29586621Sbt150084 
29596621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
29606621Sbt150084 }
29616621Sbt150084 
29626621Sbt150084 /*
29636621Sbt150084  * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer.
29646621Sbt150084  */
29656621Sbt150084 static void
29666621Sbt150084 ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe)
29676621Sbt150084 {
29686621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
29696621Sbt150084 
29706621Sbt150084 	if (ixgbe->watchdog_start)
29716621Sbt150084 		ixgbe_arm_watchdog_timer(ixgbe);
29726621Sbt150084 
29736621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
29746621Sbt150084 }
29756621Sbt150084 
29766621Sbt150084 /*
29776621Sbt150084  * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer.
29786621Sbt150084  */
29798490SPaul.Guo@Sun.COM void
29806621Sbt150084 ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe)
29816621Sbt150084 {
29826621Sbt150084 	timeout_id_t tid;
29836621Sbt150084 
29846621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
29856621Sbt150084 
29866621Sbt150084 	ixgbe->watchdog_start = B_FALSE;
29876621Sbt150084 	tid = ixgbe->watchdog_tid;
29886621Sbt150084 	ixgbe->watchdog_tid = 0;
29896621Sbt150084 
29906621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
29916621Sbt150084 
29926621Sbt150084 	if (tid != 0)
29936621Sbt150084 		(void) untimeout(tid);
29946621Sbt150084 }
29956621Sbt150084 
29966621Sbt150084 /*
29976621Sbt150084  * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts.
29986621Sbt150084  */
29996621Sbt150084 static void
30006621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe)
30016621Sbt150084 {
30026621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
30036621Sbt150084 
30046621Sbt150084 	/*
30056621Sbt150084 	 * mask all interrupts off
30066621Sbt150084 	 */
30076621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff);
30086621Sbt150084 
30096621Sbt150084 	/*
30106621Sbt150084 	 * for MSI-X, also disable autoclear
30116621Sbt150084 	 */
30126621Sbt150084 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
30136621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0);
30146621Sbt150084 	}
30156621Sbt150084 
30166621Sbt150084 	IXGBE_WRITE_FLUSH(hw);
30176621Sbt150084 }
30186621Sbt150084 
30196621Sbt150084 /*
30206621Sbt150084  * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts.
30216621Sbt150084  */
30226621Sbt150084 static void
30236621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe)
30246621Sbt150084 {
30256621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
30268490SPaul.Guo@Sun.COM 	uint32_t eiac, eiam;
30278490SPaul.Guo@Sun.COM 	uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
30288490SPaul.Guo@Sun.COM 
30298490SPaul.Guo@Sun.COM 	/* interrupt types to enable */
30308490SPaul.Guo@Sun.COM 	ixgbe->eims = IXGBE_EIMS_ENABLE_MASK;	/* shared code default */
30318490SPaul.Guo@Sun.COM 	ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER;	/* minus tcp timer */
30328490SPaul.Guo@Sun.COM 	ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */
30338490SPaul.Guo@Sun.COM 
30348490SPaul.Guo@Sun.COM 	/* enable automask on "other" causes that this adapter can generate */
30358490SPaul.Guo@Sun.COM 	eiam = ixgbe->capab->other_intr;
30366621Sbt150084 
30376621Sbt150084 	/*
30386621Sbt150084 	 * msi-x mode
30396621Sbt150084 	 */
30406621Sbt150084 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
30416621Sbt150084 		/* enable autoclear but not on bits 29:20 */
30428490SPaul.Guo@Sun.COM 		eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR);
30436621Sbt150084 
30446621Sbt150084 		/* general purpose interrupt enable */
30458490SPaul.Guo@Sun.COM 		gpie |= (IXGBE_GPIE_MSIX_MODE
30468490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_PBA_SUPPORT
30478490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_OCD
30488490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_EIAME);
30496621Sbt150084 	/*
30506621Sbt150084 	 * non-msi-x mode
30516621Sbt150084 	 */
30526621Sbt150084 	} else {
30536621Sbt150084 
30546621Sbt150084 		/* disable autoclear, leave gpie at default */
30556621Sbt150084 		eiac = 0;
30568490SPaul.Guo@Sun.COM 
30579353SSamuel.Tu@Sun.COM 		/*
30589353SSamuel.Tu@Sun.COM 		 * General purpose interrupt enable.
30599353SSamuel.Tu@Sun.COM 		 * For 82599, extended interrupt automask enable
30609353SSamuel.Tu@Sun.COM 		 * only in MSI or MSI-X mode
30619353SSamuel.Tu@Sun.COM 		 */
30629353SSamuel.Tu@Sun.COM 		if ((hw->mac.type < ixgbe_mac_82599EB) ||
30639353SSamuel.Tu@Sun.COM 		    (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) {
30649353SSamuel.Tu@Sun.COM 			gpie |= IXGBE_GPIE_EIAME;
30659353SSamuel.Tu@Sun.COM 		}
30669353SSamuel.Tu@Sun.COM 	}
30679353SSamuel.Tu@Sun.COM 	/* Enable specific interrupts for 82599  */
30689353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
30699353SSamuel.Tu@Sun.COM 		gpie |= IXGBE_SDP2_GPIEN; /* pluggable optics intr */
30709353SSamuel.Tu@Sun.COM 		gpie |= IXGBE_SDP1_GPIEN; /* LSC interrupt */
30716621Sbt150084 	}
30726621Sbt150084 
30738490SPaul.Guo@Sun.COM 	/* write to interrupt control registers */
30748490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
30756621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac);
30768490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam);
30776621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
30786621Sbt150084 	IXGBE_WRITE_FLUSH(hw);
30796621Sbt150084 }
30806621Sbt150084 
30816621Sbt150084 /*
30826621Sbt150084  * ixgbe_loopback_ioctl - Loopback support.
30836621Sbt150084  */
30846621Sbt150084 enum ioc_reply
30856621Sbt150084 ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp)
30866621Sbt150084 {
30876621Sbt150084 	lb_info_sz_t *lbsp;
30886621Sbt150084 	lb_property_t *lbpp;
30896621Sbt150084 	uint32_t *lbmp;
30906621Sbt150084 	uint32_t size;
30916621Sbt150084 	uint32_t value;
30926621Sbt150084 
30936621Sbt150084 	if (mp->b_cont == NULL)
30946621Sbt150084 		return (IOC_INVAL);
30956621Sbt150084 
30966621Sbt150084 	switch (iocp->ioc_cmd) {
30976621Sbt150084 	default:
30986621Sbt150084 		return (IOC_INVAL);
30996621Sbt150084 
31006621Sbt150084 	case LB_GET_INFO_SIZE:
31016621Sbt150084 		size = sizeof (lb_info_sz_t);
31026621Sbt150084 		if (iocp->ioc_count != size)
31036621Sbt150084 			return (IOC_INVAL);
31046621Sbt150084 
31056621Sbt150084 		value = sizeof (lb_normal);
31066621Sbt150084 		value += sizeof (lb_mac);
310711150SZhen.W@Sun.COM 		value += sizeof (lb_external);
31086621Sbt150084 
31096621Sbt150084 		lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr;
31106621Sbt150084 		*lbsp = value;
31116621Sbt150084 		break;
31126621Sbt150084 
31136621Sbt150084 	case LB_GET_INFO:
31146621Sbt150084 		value = sizeof (lb_normal);
31156621Sbt150084 		value += sizeof (lb_mac);
311611150SZhen.W@Sun.COM 		value += sizeof (lb_external);
31176621Sbt150084 
31186621Sbt150084 		size = value;
31196621Sbt150084 		if (iocp->ioc_count != size)
31206621Sbt150084 			return (IOC_INVAL);
31216621Sbt150084 
31226621Sbt150084 		value = 0;
31236621Sbt150084 		lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr;
31246621Sbt150084 
31256621Sbt150084 		lbpp[value++] = lb_normal;
31266621Sbt150084 		lbpp[value++] = lb_mac;
312711150SZhen.W@Sun.COM 		lbpp[value++] = lb_external;
31286621Sbt150084 		break;
31296621Sbt150084 
31306621Sbt150084 	case LB_GET_MODE:
31316621Sbt150084 		size = sizeof (uint32_t);
31326621Sbt150084 		if (iocp->ioc_count != size)
31336621Sbt150084 			return (IOC_INVAL);
31346621Sbt150084 
31356621Sbt150084 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
31366621Sbt150084 		*lbmp = ixgbe->loopback_mode;
31376621Sbt150084 		break;
31386621Sbt150084 
31396621Sbt150084 	case LB_SET_MODE:
31406621Sbt150084 		size = 0;
31416621Sbt150084 		if (iocp->ioc_count != sizeof (uint32_t))
31426621Sbt150084 			return (IOC_INVAL);
31436621Sbt150084 
31446621Sbt150084 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
31456621Sbt150084 		if (!ixgbe_set_loopback_mode(ixgbe, *lbmp))
31466621Sbt150084 			return (IOC_INVAL);
31476621Sbt150084 		break;
31486621Sbt150084 	}
31496621Sbt150084 
31506621Sbt150084 	iocp->ioc_count = size;
31516621Sbt150084 	iocp->ioc_error = 0;
31526621Sbt150084 
31536621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
31546621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
31556621Sbt150084 		return (IOC_INVAL);
31566621Sbt150084 	}
31576621Sbt150084 
31586621Sbt150084 	return (IOC_REPLY);
31596621Sbt150084 }
31606621Sbt150084 
31616621Sbt150084 /*
31626621Sbt150084  * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode.
31636621Sbt150084  */
31646621Sbt150084 static boolean_t
31656621Sbt150084 ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode)
31666621Sbt150084 {
31676621Sbt150084 	if (mode == ixgbe->loopback_mode)
31686621Sbt150084 		return (B_TRUE);
31696621Sbt150084 
31706621Sbt150084 	ixgbe->loopback_mode = mode;
31716621Sbt150084 
31726621Sbt150084 	if (mode == IXGBE_LB_NONE) {
31736621Sbt150084 		/*
31746621Sbt150084 		 * Reset the chip
31756621Sbt150084 		 */
31766621Sbt150084 		(void) ixgbe_reset(ixgbe);
31776621Sbt150084 		return (B_TRUE);
31786621Sbt150084 	}
31796621Sbt150084 
31806621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
31816621Sbt150084 
31826621Sbt150084 	switch (mode) {
31836621Sbt150084 	default:
31846621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
31856621Sbt150084 		return (B_FALSE);
31866621Sbt150084 
318711150SZhen.W@Sun.COM 	case IXGBE_LB_EXTERNAL:
318811150SZhen.W@Sun.COM 		break;
318911150SZhen.W@Sun.COM 
31906621Sbt150084 	case IXGBE_LB_INTERNAL_MAC:
31916621Sbt150084 		ixgbe_set_internal_mac_loopback(ixgbe);
31926621Sbt150084 		break;
31936621Sbt150084 	}
31946621Sbt150084 
31956621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
31966621Sbt150084 
31976621Sbt150084 	return (B_TRUE);
31986621Sbt150084 }
31996621Sbt150084 
32006621Sbt150084 /*
32016621Sbt150084  * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode.
32026621Sbt150084  */
32036621Sbt150084 static void
32046621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe)
32056621Sbt150084 {
32066621Sbt150084 	struct ixgbe_hw *hw;
32076621Sbt150084 	uint32_t reg;
32086621Sbt150084 	uint8_t atlas;
32096621Sbt150084 
32106621Sbt150084 	hw = &ixgbe->hw;
32116621Sbt150084 
32126621Sbt150084 	/*
32136621Sbt150084 	 * Setup MAC loopback
32146621Sbt150084 	 */
32156621Sbt150084 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0);
32166621Sbt150084 	reg |= IXGBE_HLREG0_LPBK;
32176621Sbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg);
32186621Sbt150084 
32196621Sbt150084 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
32206621Sbt150084 	reg &= ~IXGBE_AUTOC_LMS_MASK;
32216621Sbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
32226621Sbt150084 
32236621Sbt150084 	/*
32246621Sbt150084 	 * Disable Atlas Tx lanes to keep packets in loopback and not on wire
32256621Sbt150084 	 */
32266621Sbt150084 	if (hw->mac.type == ixgbe_mac_82598EB) {
32276621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
32286621Sbt150084 		    &atlas);
32296621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_REG_EN;
32306621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
32316621Sbt150084 		    atlas);
32326621Sbt150084 
32336621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
32346621Sbt150084 		    &atlas);
32356621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
32366621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
32376621Sbt150084 		    atlas);
32386621Sbt150084 
32396621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
32406621Sbt150084 		    &atlas);
32416621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
32426621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
32436621Sbt150084 		    atlas);
32446621Sbt150084 
32456621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
32466621Sbt150084 		    &atlas);
32476621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
32486621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
32496621Sbt150084 		    atlas);
32506621Sbt150084 	}
32516621Sbt150084 }
32526621Sbt150084 
32536621Sbt150084 #pragma inline(ixgbe_intr_rx_work)
32546621Sbt150084 /*
32556621Sbt150084  * ixgbe_intr_rx_work - RX processing of ISR.
32566621Sbt150084  */
32576621Sbt150084 static void
32586621Sbt150084 ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring)
32596621Sbt150084 {
32606621Sbt150084 	mblk_t *mp;
32616621Sbt150084 
32626621Sbt150084 	mutex_enter(&rx_ring->rx_lock);
32636621Sbt150084 
32648275SEric Cheng 	mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
32656621Sbt150084 	mutex_exit(&rx_ring->rx_lock);
32666621Sbt150084 
32676621Sbt150084 	if (mp != NULL)
32688275SEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
32698275SEric Cheng 		    rx_ring->ring_gen_num);
32706621Sbt150084 }
32716621Sbt150084 
32726621Sbt150084 #pragma inline(ixgbe_intr_tx_work)
32736621Sbt150084 /*
32746621Sbt150084  * ixgbe_intr_tx_work - TX processing of ISR.
32756621Sbt150084  */
32766621Sbt150084 static void
32776621Sbt150084 ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring)
32786621Sbt150084 {
327910376SChenlu.Chen@Sun.COM 	ixgbe_t *ixgbe = tx_ring->ixgbe;
328010376SChenlu.Chen@Sun.COM 
32816621Sbt150084 	/*
32826621Sbt150084 	 * Recycle the tx descriptors
32836621Sbt150084 	 */
32846621Sbt150084 	tx_ring->tx_recycle(tx_ring);
32856621Sbt150084 
32866621Sbt150084 	/*
32876621Sbt150084 	 * Schedule the re-transmit
32886621Sbt150084 	 */
32896621Sbt150084 	if (tx_ring->reschedule &&
329010376SChenlu.Chen@Sun.COM 	    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) {
32916621Sbt150084 		tx_ring->reschedule = B_FALSE;
32928275SEric Cheng 		mac_tx_ring_update(tx_ring->ixgbe->mac_hdl,
32938275SEric Cheng 		    tx_ring->ring_handle);
32946621Sbt150084 		IXGBE_DEBUG_STAT(tx_ring->stat_reschedule);
32956621Sbt150084 	}
32966621Sbt150084 }
32976621Sbt150084 
32986621Sbt150084 #pragma inline(ixgbe_intr_other_work)
32996621Sbt150084 /*
33008490SPaul.Guo@Sun.COM  * ixgbe_intr_other_work - Process interrupt types other than tx/rx
33016621Sbt150084  */
33026621Sbt150084 static void
33038490SPaul.Guo@Sun.COM ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr)
33046621Sbt150084 {
33059353SSamuel.Tu@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
3306*11233SPaul.Guo@Sun.COM 
3307*11233SPaul.Guo@Sun.COM 	ASSERT(mutex_owned(&ixgbe->gen_lock));
3308*11233SPaul.Guo@Sun.COM 
33098490SPaul.Guo@Sun.COM 	/*
3310*11233SPaul.Guo@Sun.COM 	 * handle link status change
33118490SPaul.Guo@Sun.COM 	 */
33128490SPaul.Guo@Sun.COM 	if (eicr & IXGBE_EICR_LSC) {
3313*11233SPaul.Guo@Sun.COM 		ixgbe_driver_link_check(ixgbe);
33148490SPaul.Guo@Sun.COM 	}
33156621Sbt150084 
33166621Sbt150084 	/*
33178490SPaul.Guo@Sun.COM 	 * check for fan failure on adapters with fans
33186621Sbt150084 	 */
33198490SPaul.Guo@Sun.COM 	if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
33208490SPaul.Guo@Sun.COM 	    (eicr & IXGBE_EICR_GPI_SDP1)) {
33219353SSamuel.Tu@Sun.COM 		if (hw->mac.type < ixgbe_mac_82599EB) {
33229353SSamuel.Tu@Sun.COM 			ixgbe_log(ixgbe,
33239353SSamuel.Tu@Sun.COM 			    "Fan has stopped, replace the adapter\n");
33249353SSamuel.Tu@Sun.COM 
33259353SSamuel.Tu@Sun.COM 			/* re-enable the interrupt, which was automasked */
33269353SSamuel.Tu@Sun.COM 			ixgbe->eims |= IXGBE_EICR_GPI_SDP1;
33279353SSamuel.Tu@Sun.COM 		}
33289353SSamuel.Tu@Sun.COM 	}
33299353SSamuel.Tu@Sun.COM 
33309353SSamuel.Tu@Sun.COM 	/*
33319353SSamuel.Tu@Sun.COM 	 * Do SFP check for 82599
33329353SSamuel.Tu@Sun.COM 	 */
33339353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
3334*11233SPaul.Guo@Sun.COM 		if ((ddi_taskq_dispatch(ixgbe->sfp_taskq,
33359353SSamuel.Tu@Sun.COM 		    ixgbe_sfp_check, (void *)ixgbe,
33369353SSamuel.Tu@Sun.COM 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
333710305SPaul.Guo@Sun.COM 			ixgbe_log(ixgbe, "No memory available to dispatch "
333810305SPaul.Guo@Sun.COM 			    "taskq for SFP check");
33399353SSamuel.Tu@Sun.COM 		}
3340*11233SPaul.Guo@Sun.COM 
3341*11233SPaul.Guo@Sun.COM 		/*
3342*11233SPaul.Guo@Sun.COM 		 * We need to fully re-check the link later.
3343*11233SPaul.Guo@Sun.COM 		 */
3344*11233SPaul.Guo@Sun.COM 		ixgbe->link_check_complete = B_FALSE;
3345*11233SPaul.Guo@Sun.COM 		ixgbe->link_check_hrtime = gethrtime() +
3346*11233SPaul.Guo@Sun.COM 		    (IXGBE_LINK_UP_TIME * 100000000ULL);
33478490SPaul.Guo@Sun.COM 	}
33486621Sbt150084 }
33496621Sbt150084 
33506621Sbt150084 /*
33516621Sbt150084  * ixgbe_intr_legacy - Interrupt handler for legacy interrupts.
33526621Sbt150084  */
33536621Sbt150084 static uint_t
33546621Sbt150084 ixgbe_intr_legacy(void *arg1, void *arg2)
33556621Sbt150084 {
33566621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
33576621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
33586621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
33598275SEric Cheng 	ixgbe_rx_ring_t *rx_ring;
33606621Sbt150084 	uint32_t eicr;
33616621Sbt150084 	mblk_t *mp;
33626621Sbt150084 	boolean_t tx_reschedule;
33636621Sbt150084 	uint_t result;
33646621Sbt150084 
33658490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
33666621Sbt150084 
33676621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
33686621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
33696621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
33706621Sbt150084 		return (DDI_INTR_UNCLAIMED);
33716621Sbt150084 	}
33726621Sbt150084 
33736621Sbt150084 	mp = NULL;
33746621Sbt150084 	tx_reschedule = B_FALSE;
33756621Sbt150084 
33766621Sbt150084 	/*
33776621Sbt150084 	 * Any bit set in eicr: claim this interrupt
33786621Sbt150084 	 */
33796621Sbt150084 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
3380*11233SPaul.Guo@Sun.COM 
3381*11233SPaul.Guo@Sun.COM 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
3382*11233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
3383*11233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
3384*11233SPaul.Guo@Sun.COM 		return (DDI_INTR_CLAIMED);
3385*11233SPaul.Guo@Sun.COM 	}
3386*11233SPaul.Guo@Sun.COM 
33876621Sbt150084 	if (eicr) {
33886621Sbt150084 		/*
33896621Sbt150084 		 * For legacy interrupt, we have only one interrupt,
33906621Sbt150084 		 * so we have only one rx ring and one tx ring enabled.
33916621Sbt150084 		 */
33926621Sbt150084 		ASSERT(ixgbe->num_rx_rings == 1);
33936621Sbt150084 		ASSERT(ixgbe->num_tx_rings == 1);
33946621Sbt150084 
33956621Sbt150084 		/*
33968275SEric Cheng 		 * For legacy interrupt, rx rings[0] will use RTxQ[0].
33976621Sbt150084 		 */
33988275SEric Cheng 		if (eicr & 0x1) {
33999353SSamuel.Tu@Sun.COM 			ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE;
34009353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
34019353SSamuel.Tu@Sun.COM 			ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
34026621Sbt150084 			/*
34036621Sbt150084 			 * Clean the rx descriptors
34046621Sbt150084 			 */
34058275SEric Cheng 			rx_ring = &ixgbe->rx_rings[0];
34068275SEric Cheng 			mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
34078275SEric Cheng 		}
34088275SEric Cheng 
34098275SEric Cheng 		/*
34108275SEric Cheng 		 * For legacy interrupt, tx rings[0] will use RTxQ[1].
34118275SEric Cheng 		 */
34128275SEric Cheng 		if (eicr & 0x2) {
34136621Sbt150084 			/*
34146621Sbt150084 			 * Recycle the tx descriptors
34156621Sbt150084 			 */
34166621Sbt150084 			tx_ring = &ixgbe->tx_rings[0];
34176621Sbt150084 			tx_ring->tx_recycle(tx_ring);
34186621Sbt150084 
34196621Sbt150084 			/*
34206621Sbt150084 			 * Schedule the re-transmit
34216621Sbt150084 			 */
34226621Sbt150084 			tx_reschedule = (tx_ring->reschedule &&
342310376SChenlu.Chen@Sun.COM 			    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh));
34246621Sbt150084 		}
34256621Sbt150084 
34268490SPaul.Guo@Sun.COM 		/* any interrupt type other than tx/rx */
34278490SPaul.Guo@Sun.COM 		if (eicr & ixgbe->capab->other_intr) {
34289353SSamuel.Tu@Sun.COM 			if (hw->mac.type < ixgbe_mac_82599EB) {
34299353SSamuel.Tu@Sun.COM 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
34309353SSamuel.Tu@Sun.COM 			}
34319353SSamuel.Tu@Sun.COM 			if (hw->mac.type == ixgbe_mac_82599EB) {
34329353SSamuel.Tu@Sun.COM 				ixgbe->eimc = IXGBE_82599_OTHER_INTR;
34339353SSamuel.Tu@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
34349353SSamuel.Tu@Sun.COM 			}
34359353SSamuel.Tu@Sun.COM 			ixgbe_intr_other_work(ixgbe, eicr);
34368490SPaul.Guo@Sun.COM 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
34376621Sbt150084 		}
34386621Sbt150084 
34398490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
34408490SPaul.Guo@Sun.COM 
34416621Sbt150084 		result = DDI_INTR_CLAIMED;
34426621Sbt150084 	} else {
34438490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
34448490SPaul.Guo@Sun.COM 
34456621Sbt150084 		/*
34466621Sbt150084 		 * No interrupt cause bits set: don't claim this interrupt.
34476621Sbt150084 		 */
34486621Sbt150084 		result = DDI_INTR_UNCLAIMED;
34496621Sbt150084 	}
34506621Sbt150084 
34518490SPaul.Guo@Sun.COM 	/* re-enable the interrupts which were automasked */
34528490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
34536621Sbt150084 
34546621Sbt150084 	/*
34556621Sbt150084 	 * Do the following work outside of the gen_lock
34566621Sbt150084 	 */
34579353SSamuel.Tu@Sun.COM 	if (mp != NULL) {
34588275SEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
34598275SEric Cheng 		    rx_ring->ring_gen_num);
34609353SSamuel.Tu@Sun.COM 	}
34616621Sbt150084 
34626621Sbt150084 	if (tx_reschedule)  {
34636621Sbt150084 		tx_ring->reschedule = B_FALSE;
34648275SEric Cheng 		mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle);
34656621Sbt150084 		IXGBE_DEBUG_STAT(tx_ring->stat_reschedule);
34666621Sbt150084 	}
34676621Sbt150084 
34686621Sbt150084 	return (result);
34696621Sbt150084 }
34706621Sbt150084 
34716621Sbt150084 /*
34726621Sbt150084  * ixgbe_intr_msi - Interrupt handler for MSI.
34736621Sbt150084  */
34746621Sbt150084 static uint_t
34756621Sbt150084 ixgbe_intr_msi(void *arg1, void *arg2)
34766621Sbt150084 {
34776621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
34786621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
34796621Sbt150084 	uint32_t eicr;
34806621Sbt150084 
34818490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
34828490SPaul.Guo@Sun.COM 
34836621Sbt150084 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
34846621Sbt150084 
3485*11233SPaul.Guo@Sun.COM 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
3486*11233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
3487*11233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
3488*11233SPaul.Guo@Sun.COM 		return (DDI_INTR_CLAIMED);
3489*11233SPaul.Guo@Sun.COM 	}
3490*11233SPaul.Guo@Sun.COM 
34916621Sbt150084 	/*
34926621Sbt150084 	 * For MSI interrupt, we have only one vector,
34936621Sbt150084 	 * so we have only one rx ring and one tx ring enabled.
34946621Sbt150084 	 */
34956621Sbt150084 	ASSERT(ixgbe->num_rx_rings == 1);
34966621Sbt150084 	ASSERT(ixgbe->num_tx_rings == 1);
34976621Sbt150084 
34986621Sbt150084 	/*
34998275SEric Cheng 	 * For MSI interrupt, rx rings[0] will use RTxQ[0].
35006621Sbt150084 	 */
35018275SEric Cheng 	if (eicr & 0x1) {
35026621Sbt150084 		ixgbe_intr_rx_work(&ixgbe->rx_rings[0]);
35038275SEric Cheng 	}
35048275SEric Cheng 
35058275SEric Cheng 	/*
35068275SEric Cheng 	 * For MSI interrupt, tx rings[0] will use RTxQ[1].
35078275SEric Cheng 	 */
35088275SEric Cheng 	if (eicr & 0x2) {
35096621Sbt150084 		ixgbe_intr_tx_work(&ixgbe->tx_rings[0]);
35106621Sbt150084 	}
35116621Sbt150084 
35128490SPaul.Guo@Sun.COM 	/* any interrupt type other than tx/rx */
35138490SPaul.Guo@Sun.COM 	if (eicr & ixgbe->capab->other_intr) {
35148490SPaul.Guo@Sun.COM 		mutex_enter(&ixgbe->gen_lock);
35159353SSamuel.Tu@Sun.COM 		if (hw->mac.type < ixgbe_mac_82599EB) {
35169353SSamuel.Tu@Sun.COM 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
35179353SSamuel.Tu@Sun.COM 		}
35189353SSamuel.Tu@Sun.COM 		if (hw->mac.type == ixgbe_mac_82599EB) {
35199353SSamuel.Tu@Sun.COM 			ixgbe->eimc = IXGBE_82599_OTHER_INTR;
35209353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
35219353SSamuel.Tu@Sun.COM 		}
35229353SSamuel.Tu@Sun.COM 		ixgbe_intr_other_work(ixgbe, eicr);
35238490SPaul.Guo@Sun.COM 		ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
35248490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
35256621Sbt150084 	}
35266621Sbt150084 
35278490SPaul.Guo@Sun.COM 	/* re-enable the interrupts which were automasked */
35288490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
35298490SPaul.Guo@Sun.COM 
35306621Sbt150084 	return (DDI_INTR_CLAIMED);
35316621Sbt150084 }
35326621Sbt150084 
35336621Sbt150084 /*
35349353SSamuel.Tu@Sun.COM  * ixgbe_intr_msix - Interrupt handler for MSI-X.
35356621Sbt150084  */
35366621Sbt150084 static uint_t
35379353SSamuel.Tu@Sun.COM ixgbe_intr_msix(void *arg1, void *arg2)
35386621Sbt150084 {
35399353SSamuel.Tu@Sun.COM 	ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1;
35408275SEric Cheng 	ixgbe_t *ixgbe = vect->ixgbe;
35419353SSamuel.Tu@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
35429353SSamuel.Tu@Sun.COM 	uint32_t eicr;
35438275SEric Cheng 	int r_idx = 0;
35446621Sbt150084 
35458490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
35468490SPaul.Guo@Sun.COM 
35476621Sbt150084 	/*
35488275SEric Cheng 	 * Clean each rx ring that has its bit set in the map
35496621Sbt150084 	 */
35506621Sbt150084 	r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1));
35516621Sbt150084 	while (r_idx >= 0) {
35526621Sbt150084 		ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]);
35536621Sbt150084 		r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
35546621Sbt150084 		    (ixgbe->num_rx_rings - 1));
35556621Sbt150084 	}
35566621Sbt150084 
35578275SEric Cheng 	/*
35588275SEric Cheng 	 * Clean each tx ring that has its bit set in the map
35598275SEric Cheng 	 */
35608275SEric Cheng 	r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1));
35618275SEric Cheng 	while (r_idx >= 0) {
35628275SEric Cheng 		ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]);
35638275SEric Cheng 		r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
35648275SEric Cheng 		    (ixgbe->num_tx_rings - 1));
35658275SEric Cheng 	}
35668275SEric Cheng 
35676621Sbt150084 
35686621Sbt150084 	/*
35699353SSamuel.Tu@Sun.COM 	 * Clean other interrupt (link change) that has its bit set in the map
35706621Sbt150084 	 */
35719353SSamuel.Tu@Sun.COM 	if (BT_TEST(vect->other_map, 0) == 1) {
35729353SSamuel.Tu@Sun.COM 		eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
35739353SSamuel.Tu@Sun.COM 
3574*11233SPaul.Guo@Sun.COM 		if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) !=
3575*11233SPaul.Guo@Sun.COM 		    DDI_FM_OK) {
3576*11233SPaul.Guo@Sun.COM 			ddi_fm_service_impact(ixgbe->dip,
3577*11233SPaul.Guo@Sun.COM 			    DDI_SERVICE_DEGRADED);
3578*11233SPaul.Guo@Sun.COM 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
3579*11233SPaul.Guo@Sun.COM 			return (DDI_INTR_CLAIMED);
3580*11233SPaul.Guo@Sun.COM 		}
3581*11233SPaul.Guo@Sun.COM 
35829353SSamuel.Tu@Sun.COM 		/*
35839353SSamuel.Tu@Sun.COM 		 * Need check cause bits and only other causes will
35849353SSamuel.Tu@Sun.COM 		 * be processed
35859353SSamuel.Tu@Sun.COM 		 */
35869353SSamuel.Tu@Sun.COM 		/* any interrupt type other than tx/rx */
35879353SSamuel.Tu@Sun.COM 		if (eicr & ixgbe->capab->other_intr) {
35889353SSamuel.Tu@Sun.COM 			if (hw->mac.type < ixgbe_mac_82599EB) {
35899353SSamuel.Tu@Sun.COM 				mutex_enter(&ixgbe->gen_lock);
35909353SSamuel.Tu@Sun.COM 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
35919353SSamuel.Tu@Sun.COM 				ixgbe_intr_other_work(ixgbe, eicr);
35929353SSamuel.Tu@Sun.COM 				mutex_exit(&ixgbe->gen_lock);
35939353SSamuel.Tu@Sun.COM 			} else {
35949353SSamuel.Tu@Sun.COM 				if (hw->mac.type == ixgbe_mac_82599EB) {
35959353SSamuel.Tu@Sun.COM 					mutex_enter(&ixgbe->gen_lock);
35969353SSamuel.Tu@Sun.COM 					ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
35979353SSamuel.Tu@Sun.COM 					ixgbe_intr_other_work(ixgbe, eicr);
35989353SSamuel.Tu@Sun.COM 					mutex_exit(&ixgbe->gen_lock);
35999353SSamuel.Tu@Sun.COM 				}
36009353SSamuel.Tu@Sun.COM 			}
36019353SSamuel.Tu@Sun.COM 		}
36029353SSamuel.Tu@Sun.COM 
36039353SSamuel.Tu@Sun.COM 		/* re-enable the interrupts which were automasked */
36049353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
36056621Sbt150084 	}
36066621Sbt150084 
36076621Sbt150084 	return (DDI_INTR_CLAIMED);
36086621Sbt150084 }
36096621Sbt150084 
36106621Sbt150084 /*
36116621Sbt150084  * ixgbe_alloc_intrs - Allocate interrupts for the driver.
36126621Sbt150084  *
36136621Sbt150084  * Normal sequence is to try MSI-X; if not sucessful, try MSI;
36146621Sbt150084  * if not successful, try Legacy.
36156621Sbt150084  * ixgbe->intr_force can be used to force sequence to start with
36166621Sbt150084  * any of the 3 types.
36176621Sbt150084  * If MSI-X is not used, number of tx/rx rings is forced to 1.
36186621Sbt150084  */
36196621Sbt150084 static int
36206621Sbt150084 ixgbe_alloc_intrs(ixgbe_t *ixgbe)
36216621Sbt150084 {
36226621Sbt150084 	dev_info_t *devinfo;
36236621Sbt150084 	int intr_types;
36246621Sbt150084 	int rc;
36256621Sbt150084 
36266621Sbt150084 	devinfo = ixgbe->dip;
36276621Sbt150084 
36286621Sbt150084 	/*
36296621Sbt150084 	 * Get supported interrupt types
36306621Sbt150084 	 */
36316621Sbt150084 	rc = ddi_intr_get_supported_types(devinfo, &intr_types);
36326621Sbt150084 
36336621Sbt150084 	if (rc != DDI_SUCCESS) {
36346621Sbt150084 		ixgbe_log(ixgbe,
36356621Sbt150084 		    "Get supported interrupt types failed: %d", rc);
36366621Sbt150084 		return (IXGBE_FAILURE);
36376621Sbt150084 	}
36386621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types);
36396621Sbt150084 
36406621Sbt150084 	ixgbe->intr_type = 0;
36416621Sbt150084 
36426621Sbt150084 	/*
36436621Sbt150084 	 * Install MSI-X interrupts
36446621Sbt150084 	 */
36456621Sbt150084 	if ((intr_types & DDI_INTR_TYPE_MSIX) &&
36466621Sbt150084 	    (ixgbe->intr_force <= IXGBE_INTR_MSIX)) {
36476621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX);
36486621Sbt150084 		if (rc == IXGBE_SUCCESS)
36496621Sbt150084 			return (IXGBE_SUCCESS);
36506621Sbt150084 
36516621Sbt150084 		ixgbe_log(ixgbe,
36526621Sbt150084 		    "Allocate MSI-X failed, trying MSI interrupts...");
36536621Sbt150084 	}
36546621Sbt150084 
36556621Sbt150084 	/*
36568275SEric Cheng 	 * MSI-X not used, force rings and groups to 1
36576621Sbt150084 	 */
36586621Sbt150084 	ixgbe->num_rx_rings = 1;
36598275SEric Cheng 	ixgbe->num_rx_groups = 1;
36606621Sbt150084 	ixgbe->num_tx_rings = 1;
36616621Sbt150084 	ixgbe_log(ixgbe,
36628275SEric Cheng 	    "MSI-X not used, force rings and groups number to 1");
36636621Sbt150084 
36646621Sbt150084 	/*
36656621Sbt150084 	 * Install MSI interrupts
36666621Sbt150084 	 */
36676621Sbt150084 	if ((intr_types & DDI_INTR_TYPE_MSI) &&
36686621Sbt150084 	    (ixgbe->intr_force <= IXGBE_INTR_MSI)) {
36696621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI);
36706621Sbt150084 		if (rc == IXGBE_SUCCESS)
36716621Sbt150084 			return (IXGBE_SUCCESS);
36726621Sbt150084 
36736621Sbt150084 		ixgbe_log(ixgbe,
36746621Sbt150084 		    "Allocate MSI failed, trying Legacy interrupts...");
36756621Sbt150084 	}
36766621Sbt150084 
36776621Sbt150084 	/*
36786621Sbt150084 	 * Install legacy interrupts
36796621Sbt150084 	 */
36806621Sbt150084 	if (intr_types & DDI_INTR_TYPE_FIXED) {
36816621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED);
36826621Sbt150084 		if (rc == IXGBE_SUCCESS)
36836621Sbt150084 			return (IXGBE_SUCCESS);
36846621Sbt150084 
36856621Sbt150084 		ixgbe_log(ixgbe,
36866621Sbt150084 		    "Allocate Legacy interrupts failed");
36876621Sbt150084 	}
36886621Sbt150084 
36896621Sbt150084 	/*
36906621Sbt150084 	 * If none of the 3 types succeeded, return failure
36916621Sbt150084 	 */
36926621Sbt150084 	return (IXGBE_FAILURE);
36936621Sbt150084 }
36946621Sbt150084 
36956621Sbt150084 /*
36966621Sbt150084  * ixgbe_alloc_intr_handles - Allocate interrupt handles.
36976621Sbt150084  *
36986621Sbt150084  * For legacy and MSI, only 1 handle is needed.  For MSI-X,
36996621Sbt150084  * if fewer than 2 handles are available, return failure.
37008275SEric Cheng  * Upon success, this maps the vectors to rx and tx rings for
37018275SEric Cheng  * interrupts.
37026621Sbt150084  */
37036621Sbt150084 static int
37046621Sbt150084 ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type)
37056621Sbt150084 {
37066621Sbt150084 	dev_info_t *devinfo;
37076621Sbt150084 	int request, count, avail, actual;
37088275SEric Cheng 	int minimum;
37096621Sbt150084 	int rc;
37106621Sbt150084 
37116621Sbt150084 	devinfo = ixgbe->dip;
37126621Sbt150084 
37136621Sbt150084 	switch (intr_type) {
37146621Sbt150084 	case DDI_INTR_TYPE_FIXED:
37156621Sbt150084 		request = 1;	/* Request 1 legacy interrupt handle */
37166621Sbt150084 		minimum = 1;
37176621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy");
37186621Sbt150084 		break;
37196621Sbt150084 
37206621Sbt150084 	case DDI_INTR_TYPE_MSI:
37216621Sbt150084 		request = 1;	/* Request 1 MSI interrupt handle */
37226621Sbt150084 		minimum = 1;
37236621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI");
37246621Sbt150084 		break;
37256621Sbt150084 
37266621Sbt150084 	case DDI_INTR_TYPE_MSIX:
37276621Sbt150084 		/*
37286621Sbt150084 		 * Best number of vectors for the adapter is
37299353SSamuel.Tu@Sun.COM 		 * # rx rings + # tx rings.
37306621Sbt150084 		 */
37319353SSamuel.Tu@Sun.COM 		request = ixgbe->num_rx_rings + ixgbe->num_tx_rings;
37329353SSamuel.Tu@Sun.COM 		if (request > ixgbe->capab->max_ring_vect)
37339353SSamuel.Tu@Sun.COM 			request = ixgbe->capab->max_ring_vect;
37346621Sbt150084 		minimum = 2;
37356621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X");
37366621Sbt150084 		break;
37376621Sbt150084 
37386621Sbt150084 	default:
37396621Sbt150084 		ixgbe_log(ixgbe,
37406621Sbt150084 		    "invalid call to ixgbe_alloc_intr_handles(): %d\n",
37416621Sbt150084 		    intr_type);
37426621Sbt150084 		return (IXGBE_FAILURE);
37436621Sbt150084 	}
37446621Sbt150084 	IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d  minimum: %d",
37456621Sbt150084 	    request, minimum);
37466621Sbt150084 
37476621Sbt150084 	/*
37486621Sbt150084 	 * Get number of supported interrupts
37496621Sbt150084 	 */
37506621Sbt150084 	rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
37516621Sbt150084 	if ((rc != DDI_SUCCESS) || (count < minimum)) {
37526621Sbt150084 		ixgbe_log(ixgbe,
37536621Sbt150084 		    "Get interrupt number failed. Return: %d, count: %d",
37546621Sbt150084 		    rc, count);
37556621Sbt150084 		return (IXGBE_FAILURE);
37566621Sbt150084 	}
37576621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count);
37586621Sbt150084 
37596621Sbt150084 	/*
37606621Sbt150084 	 * Get number of available interrupts
37616621Sbt150084 	 */
37626621Sbt150084 	rc = ddi_intr_get_navail(devinfo, intr_type, &avail);
37636621Sbt150084 	if ((rc != DDI_SUCCESS) || (avail < minimum)) {
37646621Sbt150084 		ixgbe_log(ixgbe,
37656621Sbt150084 		    "Get interrupt available number failed. "
37666621Sbt150084 		    "Return: %d, available: %d", rc, avail);
37676621Sbt150084 		return (IXGBE_FAILURE);
37686621Sbt150084 	}
37696621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts available: %d", avail);
37706621Sbt150084 
37716621Sbt150084 	if (avail < request) {
37726621Sbt150084 		ixgbe_log(ixgbe, "Request %d handles, %d available",
37736621Sbt150084 		    request, avail);
37746621Sbt150084 		request = avail;
37756621Sbt150084 	}
37766621Sbt150084 
37776621Sbt150084 	actual = 0;
37786621Sbt150084 	ixgbe->intr_cnt = 0;
37796621Sbt150084 
37806621Sbt150084 	/*
37816621Sbt150084 	 * Allocate an array of interrupt handles
37826621Sbt150084 	 */
37836621Sbt150084 	ixgbe->intr_size = request * sizeof (ddi_intr_handle_t);
37846621Sbt150084 	ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP);
37856621Sbt150084 
37866621Sbt150084 	rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0,
37876621Sbt150084 	    request, &actual, DDI_INTR_ALLOC_NORMAL);
37886621Sbt150084 	if (rc != DDI_SUCCESS) {
37896621Sbt150084 		ixgbe_log(ixgbe, "Allocate interrupts failed. "
37906621Sbt150084 		    "return: %d, request: %d, actual: %d",
37916621Sbt150084 		    rc, request, actual);
37926621Sbt150084 		goto alloc_handle_fail;
37936621Sbt150084 	}
37946621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual);
37956621Sbt150084 
37966621Sbt150084 	ixgbe->intr_cnt = actual;
37976621Sbt150084 
37986621Sbt150084 	/*
37998275SEric Cheng 	 * Now we know the actual number of vectors.  Here we map the vector
38008275SEric Cheng 	 * to other, rx rings and tx ring.
38016621Sbt150084 	 */
38026621Sbt150084 	if (actual < minimum) {
38036621Sbt150084 		ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d",
38046621Sbt150084 		    actual);
38056621Sbt150084 		goto alloc_handle_fail;
38066621Sbt150084 	}
38076621Sbt150084 
38086621Sbt150084 	/*
38096621Sbt150084 	 * Get priority for first vector, assume remaining are all the same
38106621Sbt150084 	 */
38116621Sbt150084 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
38126621Sbt150084 	if (rc != DDI_SUCCESS) {
38136621Sbt150084 		ixgbe_log(ixgbe,
38146621Sbt150084 		    "Get interrupt priority failed: %d", rc);
38156621Sbt150084 		goto alloc_handle_fail;
38166621Sbt150084 	}
38176621Sbt150084 
38186621Sbt150084 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
38196621Sbt150084 	if (rc != DDI_SUCCESS) {
38206621Sbt150084 		ixgbe_log(ixgbe,
38216621Sbt150084 		    "Get interrupt cap failed: %d", rc);
38226621Sbt150084 		goto alloc_handle_fail;
38236621Sbt150084 	}
38246621Sbt150084 
38256621Sbt150084 	ixgbe->intr_type = intr_type;
38266621Sbt150084 
38276621Sbt150084 	return (IXGBE_SUCCESS);
38286621Sbt150084 
38296621Sbt150084 alloc_handle_fail:
38306621Sbt150084 	ixgbe_rem_intrs(ixgbe);
38316621Sbt150084 
38326621Sbt150084 	return (IXGBE_FAILURE);
38336621Sbt150084 }
38346621Sbt150084 
38356621Sbt150084 /*
38366621Sbt150084  * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type.
38376621Sbt150084  *
38386621Sbt150084  * Before adding the interrupt handlers, the interrupt vectors have
38396621Sbt150084  * been allocated, and the rx/tx rings have also been allocated.
38406621Sbt150084  */
38416621Sbt150084 static int
38426621Sbt150084 ixgbe_add_intr_handlers(ixgbe_t *ixgbe)
38436621Sbt150084 {
38448275SEric Cheng 	int vector = 0;
38456621Sbt150084 	int rc;
38466621Sbt150084 
38476621Sbt150084 	switch (ixgbe->intr_type) {
38486621Sbt150084 	case DDI_INTR_TYPE_MSIX:
38496621Sbt150084 		/*
38509353SSamuel.Tu@Sun.COM 		 * Add interrupt handler for all vectors
38516621Sbt150084 		 */
38529353SSamuel.Tu@Sun.COM 		for (vector = 0; vector < ixgbe->intr_cnt; vector++) {
38536621Sbt150084 			/*
38546621Sbt150084 			 * install pointer to vect_map[vector]
38556621Sbt150084 			 */
38566621Sbt150084 			rc = ddi_intr_add_handler(ixgbe->htable[vector],
38579353SSamuel.Tu@Sun.COM 			    (ddi_intr_handler_t *)ixgbe_intr_msix,
38586621Sbt150084 			    (void *)&ixgbe->vect_map[vector], NULL);
38596621Sbt150084 
38606621Sbt150084 			if (rc != DDI_SUCCESS) {
38616621Sbt150084 				ixgbe_log(ixgbe,
38626621Sbt150084 				    "Add rx interrupt handler failed. "
38638275SEric Cheng 				    "return: %d, vector: %d", rc, vector);
38646621Sbt150084 				for (vector--; vector >= 0; vector--) {
38656621Sbt150084 					(void) ddi_intr_remove_handler(
38666621Sbt150084 					    ixgbe->htable[vector]);
38676621Sbt150084 				}
38686621Sbt150084 				return (IXGBE_FAILURE);
38696621Sbt150084 			}
38706621Sbt150084 		}
38718275SEric Cheng 
38726621Sbt150084 		break;
38736621Sbt150084 
38746621Sbt150084 	case DDI_INTR_TYPE_MSI:
38756621Sbt150084 		/*
38766621Sbt150084 		 * Add interrupt handlers for the only vector
38776621Sbt150084 		 */
38786621Sbt150084 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
38796621Sbt150084 		    (ddi_intr_handler_t *)ixgbe_intr_msi,
38806621Sbt150084 		    (void *)ixgbe, NULL);
38816621Sbt150084 
38826621Sbt150084 		if (rc != DDI_SUCCESS) {
38836621Sbt150084 			ixgbe_log(ixgbe,
38846621Sbt150084 			    "Add MSI interrupt handler failed: %d", rc);
38856621Sbt150084 			return (IXGBE_FAILURE);
38866621Sbt150084 		}
38876621Sbt150084 
38886621Sbt150084 		break;
38896621Sbt150084 
38906621Sbt150084 	case DDI_INTR_TYPE_FIXED:
38916621Sbt150084 		/*
38926621Sbt150084 		 * Add interrupt handlers for the only vector
38936621Sbt150084 		 */
38946621Sbt150084 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
38956621Sbt150084 		    (ddi_intr_handler_t *)ixgbe_intr_legacy,
38966621Sbt150084 		    (void *)ixgbe, NULL);
38976621Sbt150084 
38986621Sbt150084 		if (rc != DDI_SUCCESS) {
38996621Sbt150084 			ixgbe_log(ixgbe,
39006621Sbt150084 			    "Add legacy interrupt handler failed: %d", rc);
39016621Sbt150084 			return (IXGBE_FAILURE);
39026621Sbt150084 		}
39036621Sbt150084 
39046621Sbt150084 		break;
39056621Sbt150084 
39066621Sbt150084 	default:
39076621Sbt150084 		return (IXGBE_FAILURE);
39086621Sbt150084 	}
39096621Sbt150084 
39106621Sbt150084 	return (IXGBE_SUCCESS);
39116621Sbt150084 }
39126621Sbt150084 
39136621Sbt150084 #pragma inline(ixgbe_map_rxring_to_vector)
39146621Sbt150084 /*
39156621Sbt150084  * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector.
39166621Sbt150084  */
39176621Sbt150084 static void
39186621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx)
39196621Sbt150084 {
39206621Sbt150084 	/*
39216621Sbt150084 	 * Set bit in map
39226621Sbt150084 	 */
39236621Sbt150084 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
39246621Sbt150084 
39256621Sbt150084 	/*
39266621Sbt150084 	 * Count bits set
39276621Sbt150084 	 */
39286621Sbt150084 	ixgbe->vect_map[v_idx].rxr_cnt++;
39296621Sbt150084 
39306621Sbt150084 	/*
39316621Sbt150084 	 * Remember bit position
39326621Sbt150084 	 */
39338275SEric Cheng 	ixgbe->rx_rings[r_idx].intr_vector = v_idx;
39346621Sbt150084 	ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx;
39356621Sbt150084 }
39366621Sbt150084 
39376621Sbt150084 #pragma inline(ixgbe_map_txring_to_vector)
39386621Sbt150084 /*
39396621Sbt150084  * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector.
39406621Sbt150084  */
39416621Sbt150084 static void
39426621Sbt150084 ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx)
39436621Sbt150084 {
39446621Sbt150084 	/*
39456621Sbt150084 	 * Set bit in map
39466621Sbt150084 	 */
39476621Sbt150084 	BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx);
39486621Sbt150084 
39496621Sbt150084 	/*
39506621Sbt150084 	 * Count bits set
39516621Sbt150084 	 */
39526621Sbt150084 	ixgbe->vect_map[v_idx].txr_cnt++;
39536621Sbt150084 
39546621Sbt150084 	/*
39556621Sbt150084 	 * Remember bit position
39566621Sbt150084 	 */
39578275SEric Cheng 	ixgbe->tx_rings[t_idx].intr_vector = v_idx;
39586621Sbt150084 	ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx;
39596621Sbt150084 }
39606621Sbt150084 
39616621Sbt150084 /*
39628275SEric Cheng  * ixgbe_setup_ivar - Set the given entry in the given interrupt vector
39636621Sbt150084  * allocation register (IVAR).
39649353SSamuel.Tu@Sun.COM  * cause:
39659353SSamuel.Tu@Sun.COM  *   -1 : other cause
39669353SSamuel.Tu@Sun.COM  *    0 : rx
39679353SSamuel.Tu@Sun.COM  *    1 : tx
39686621Sbt150084  */
39696621Sbt150084 static void
39709353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector,
39719353SSamuel.Tu@Sun.COM     int8_t cause)
39726621Sbt150084 {
39736621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
39746621Sbt150084 	u32 ivar, index;
39756621Sbt150084 
39769353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
39779353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
39789353SSamuel.Tu@Sun.COM 		msix_vector |= IXGBE_IVAR_ALLOC_VAL;
39799353SSamuel.Tu@Sun.COM 		if (cause == -1) {
39809353SSamuel.Tu@Sun.COM 			cause = 0;
39819353SSamuel.Tu@Sun.COM 		}
39829353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
39839353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
39849353SSamuel.Tu@Sun.COM 		ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3)));
39859353SSamuel.Tu@Sun.COM 		ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3)));
39869353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
39879353SSamuel.Tu@Sun.COM 		break;
39889353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
39899353SSamuel.Tu@Sun.COM 		if (cause == -1) {
39909353SSamuel.Tu@Sun.COM 			/* other causes */
39919353SSamuel.Tu@Sun.COM 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
39929353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
39939353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
39949353SSamuel.Tu@Sun.COM 			ivar &= ~(0xFF << index);
39959353SSamuel.Tu@Sun.COM 			ivar |= (msix_vector << index);
39969353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
39979353SSamuel.Tu@Sun.COM 		} else {
39989353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
39999353SSamuel.Tu@Sun.COM 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
40009353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
40019353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
40029353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
40039353SSamuel.Tu@Sun.COM 			ivar &= ~(0xFF << index);
40049353SSamuel.Tu@Sun.COM 			ivar |= (msix_vector << index);
40059353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
40069353SSamuel.Tu@Sun.COM 			    ivar);
40079353SSamuel.Tu@Sun.COM 		}
40089353SSamuel.Tu@Sun.COM 		break;
40099353SSamuel.Tu@Sun.COM 	default:
40109353SSamuel.Tu@Sun.COM 		break;
40119353SSamuel.Tu@Sun.COM 	}
40128275SEric Cheng }
40138275SEric Cheng 
40148275SEric Cheng /*
40158275SEric Cheng  * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of
40168275SEric Cheng  * given interrupt vector allocation register (IVAR).
40179353SSamuel.Tu@Sun.COM  * cause:
40189353SSamuel.Tu@Sun.COM  *   -1 : other cause
40199353SSamuel.Tu@Sun.COM  *    0 : rx
40209353SSamuel.Tu@Sun.COM  *    1 : tx
40218275SEric Cheng  */
40228275SEric Cheng static void
40239353SSamuel.Tu@Sun.COM ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
40248275SEric Cheng {
40258275SEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
40268275SEric Cheng 	u32 ivar, index;
40278275SEric Cheng 
40289353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
40299353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
40309353SSamuel.Tu@Sun.COM 		if (cause == -1) {
40319353SSamuel.Tu@Sun.COM 			cause = 0;
40329353SSamuel.Tu@Sun.COM 		}
40339353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
40349353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
40359353SSamuel.Tu@Sun.COM 		ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 *
40369353SSamuel.Tu@Sun.COM 		    (intr_alloc_entry & 0x3)));
40379353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
40389353SSamuel.Tu@Sun.COM 		break;
40399353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
40409353SSamuel.Tu@Sun.COM 		if (cause == -1) {
40419353SSamuel.Tu@Sun.COM 			/* other causes */
40429353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
40439353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
40449353SSamuel.Tu@Sun.COM 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
40459353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
40469353SSamuel.Tu@Sun.COM 		} else {
40479353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
40489353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
40499353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
40509353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
40519353SSamuel.Tu@Sun.COM 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
40529353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
40539353SSamuel.Tu@Sun.COM 			    ivar);
40549353SSamuel.Tu@Sun.COM 		}
40559353SSamuel.Tu@Sun.COM 		break;
40569353SSamuel.Tu@Sun.COM 	default:
40579353SSamuel.Tu@Sun.COM 		break;
40589353SSamuel.Tu@Sun.COM 	}
40598275SEric Cheng }
40608275SEric Cheng 
40618275SEric Cheng /*
40629353SSamuel.Tu@Sun.COM  * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of
40638275SEric Cheng  * given interrupt vector allocation register (IVAR).
40649353SSamuel.Tu@Sun.COM  * cause:
40659353SSamuel.Tu@Sun.COM  *   -1 : other cause
40669353SSamuel.Tu@Sun.COM  *    0 : rx
40679353SSamuel.Tu@Sun.COM  *    1 : tx
40688275SEric Cheng  */
40698275SEric Cheng static void
40709353SSamuel.Tu@Sun.COM ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
40718275SEric Cheng {
40728275SEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
40738275SEric Cheng 	u32 ivar, index;
40748275SEric Cheng 
40759353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
40769353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
40779353SSamuel.Tu@Sun.COM 		if (cause == -1) {
40789353SSamuel.Tu@Sun.COM 			cause = 0;
40799353SSamuel.Tu@Sun.COM 		}
40809353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
40819353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
40829353SSamuel.Tu@Sun.COM 		ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 *
40839353SSamuel.Tu@Sun.COM 		    (intr_alloc_entry & 0x3)));
40849353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
40859353SSamuel.Tu@Sun.COM 		break;
40869353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
40879353SSamuel.Tu@Sun.COM 		if (cause == -1) {
40889353SSamuel.Tu@Sun.COM 			/* other causes */
40899353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
40909353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
40919353SSamuel.Tu@Sun.COM 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
40929353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
40939353SSamuel.Tu@Sun.COM 		} else {
40949353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
40959353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
40969353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
40979353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
40989353SSamuel.Tu@Sun.COM 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
40999353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
41009353SSamuel.Tu@Sun.COM 			    ivar);
41019353SSamuel.Tu@Sun.COM 		}
41029353SSamuel.Tu@Sun.COM 		break;
41039353SSamuel.Tu@Sun.COM 	default:
41049353SSamuel.Tu@Sun.COM 		break;
41059353SSamuel.Tu@Sun.COM 	}
41066621Sbt150084 }
41076621Sbt150084 
41086621Sbt150084 /*
41099353SSamuel.Tu@Sun.COM  * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors.
41106621Sbt150084  *
41119353SSamuel.Tu@Sun.COM  * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt
41129353SSamuel.Tu@Sun.COM  * to vector[0 - (intr_cnt -1)].
41136621Sbt150084  */
41146621Sbt150084 static int
41159353SSamuel.Tu@Sun.COM ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe)
41166621Sbt150084 {
41176621Sbt150084 	int i, vector = 0;
41186621Sbt150084 
41196621Sbt150084 	/* initialize vector map */
41206621Sbt150084 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
41219353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->intr_cnt; i++) {
41229353SSamuel.Tu@Sun.COM 		ixgbe->vect_map[i].ixgbe = ixgbe;
41239353SSamuel.Tu@Sun.COM 	}
41246621Sbt150084 
41256621Sbt150084 	/*
41268275SEric Cheng 	 * non-MSI-X case is very simple: rx rings[0] on RTxQ[0],
41278275SEric Cheng 	 * tx rings[0] on RTxQ[1].
41286621Sbt150084 	 */
41296621Sbt150084 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
41306621Sbt150084 		ixgbe_map_rxring_to_vector(ixgbe, 0, 0);
41318275SEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, 0, 1);
41326621Sbt150084 		return (IXGBE_SUCCESS);
41336621Sbt150084 	}
41346621Sbt150084 
41356621Sbt150084 	/*
41369353SSamuel.Tu@Sun.COM 	 * Interrupts/vectors mapping for MSI-X
41376621Sbt150084 	 */
41386621Sbt150084 
41396621Sbt150084 	/*
41409353SSamuel.Tu@Sun.COM 	 * Map other interrupt to vector 0,
41419353SSamuel.Tu@Sun.COM 	 * Set bit in map and count the bits set.
41429353SSamuel.Tu@Sun.COM 	 */
41439353SSamuel.Tu@Sun.COM 	BT_SET(ixgbe->vect_map[vector].other_map, 0);
41449353SSamuel.Tu@Sun.COM 	ixgbe->vect_map[vector].other_cnt++;
41459353SSamuel.Tu@Sun.COM 	vector++;
41469353SSamuel.Tu@Sun.COM 
41479353SSamuel.Tu@Sun.COM 	/*
41489353SSamuel.Tu@Sun.COM 	 * Map rx ring interrupts to vectors
41496621Sbt150084 	 */
41508275SEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
41518275SEric Cheng 		ixgbe_map_rxring_to_vector(ixgbe, i, vector);
41529353SSamuel.Tu@Sun.COM 		vector = (vector +1) % ixgbe->intr_cnt;
41538275SEric Cheng 	}
41546621Sbt150084 
41556621Sbt150084 	/*
41569353SSamuel.Tu@Sun.COM 	 * Map tx ring interrupts to vectors
41576621Sbt150084 	 */
41588275SEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
41598275SEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, i, vector);
41609353SSamuel.Tu@Sun.COM 		vector = (vector +1) % ixgbe->intr_cnt;
41616621Sbt150084 	}
41626621Sbt150084 
41636621Sbt150084 	return (IXGBE_SUCCESS);
41646621Sbt150084 }
41656621Sbt150084 
41666621Sbt150084 /*
41676621Sbt150084  * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s).
41686621Sbt150084  *
41698275SEric Cheng  * This relies on ring/vector mapping already set up in the
41706621Sbt150084  * vect_map[] structures
41716621Sbt150084  */
41726621Sbt150084 static void
41736621Sbt150084 ixgbe_setup_adapter_vector(ixgbe_t *ixgbe)
41746621Sbt150084 {
41756621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
41769353SSamuel.Tu@Sun.COM 	ixgbe_intr_vector_t *vect;	/* vector bitmap */
41778275SEric Cheng 	int r_idx;	/* ring index */
41788275SEric Cheng 	int v_idx;	/* vector index */
41796621Sbt150084 
41806621Sbt150084 	/*
41816621Sbt150084 	 * Clear any previous entries
41826621Sbt150084 	 */
41839353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
41849353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
41859353SSamuel.Tu@Sun.COM 		for (v_idx = 0; v_idx < 25; v_idx++)
41869353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
41879353SSamuel.Tu@Sun.COM 
41889353SSamuel.Tu@Sun.COM 		break;
41899353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
41909353SSamuel.Tu@Sun.COM 		for (v_idx = 0; v_idx < 64; v_idx++)
41919353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
41929353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0);
41939353SSamuel.Tu@Sun.COM 
41949353SSamuel.Tu@Sun.COM 		break;
41959353SSamuel.Tu@Sun.COM 	default:
41969353SSamuel.Tu@Sun.COM 		break;
41979353SSamuel.Tu@Sun.COM 	}
41986621Sbt150084 
41996621Sbt150084 	/*
42008275SEric Cheng 	 * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and
42018275SEric Cheng 	 * tx rings[0] will use RTxQ[1].
42026621Sbt150084 	 */
42038275SEric Cheng 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
42049353SSamuel.Tu@Sun.COM 		ixgbe_setup_ivar(ixgbe, 0, 0, 0);
42059353SSamuel.Tu@Sun.COM 		ixgbe_setup_ivar(ixgbe, 0, 1, 1);
42068275SEric Cheng 		return;
42078275SEric Cheng 	}
42088275SEric Cheng 
42098275SEric Cheng 	/*
42109353SSamuel.Tu@Sun.COM 	 * For MSI-X interrupt, "Other" is always on vector[0].
42118275SEric Cheng 	 */
42129353SSamuel.Tu@Sun.COM 	ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1);
42136621Sbt150084 
42146621Sbt150084 	/*
42156621Sbt150084 	 * For each interrupt vector, populate the IVAR table
42166621Sbt150084 	 */
42176621Sbt150084 	for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) {
42186621Sbt150084 		vect = &ixgbe->vect_map[v_idx];
42196621Sbt150084 
42206621Sbt150084 		/*
42216621Sbt150084 		 * For each rx ring bit set
42226621Sbt150084 		 */
42236621Sbt150084 		r_idx = bt_getlowbit(vect->rx_map, 0,
42246621Sbt150084 		    (ixgbe->num_rx_rings - 1));
42256621Sbt150084 
42266621Sbt150084 		while (r_idx >= 0) {
42279353SSamuel.Tu@Sun.COM 			ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 0);
42286621Sbt150084 			r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
42296621Sbt150084 			    (ixgbe->num_rx_rings - 1));
42306621Sbt150084 		}
42316621Sbt150084 
42326621Sbt150084 		/*
42336621Sbt150084 		 * For each tx ring bit set
42346621Sbt150084 		 */
42356621Sbt150084 		r_idx = bt_getlowbit(vect->tx_map, 0,
42366621Sbt150084 		    (ixgbe->num_tx_rings - 1));
42376621Sbt150084 
42386621Sbt150084 		while (r_idx >= 0) {
42399353SSamuel.Tu@Sun.COM 			ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1);
42406621Sbt150084 			r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
42416621Sbt150084 			    (ixgbe->num_tx_rings - 1));
42426621Sbt150084 		}
42436621Sbt150084 	}
42446621Sbt150084 }
42456621Sbt150084 
42466621Sbt150084 /*
42476621Sbt150084  * ixgbe_rem_intr_handlers - Remove the interrupt handlers.
42486621Sbt150084  */
42496621Sbt150084 static void
42506621Sbt150084 ixgbe_rem_intr_handlers(ixgbe_t *ixgbe)
42516621Sbt150084 {
42526621Sbt150084 	int i;
42536621Sbt150084 	int rc;
42546621Sbt150084 
42556621Sbt150084 	for (i = 0; i < ixgbe->intr_cnt; i++) {
42566621Sbt150084 		rc = ddi_intr_remove_handler(ixgbe->htable[i]);
42576621Sbt150084 		if (rc != DDI_SUCCESS) {
42586621Sbt150084 			IXGBE_DEBUGLOG_1(ixgbe,
42596621Sbt150084 			    "Remove intr handler failed: %d", rc);
42606621Sbt150084 		}
42616621Sbt150084 	}
42626621Sbt150084 }
42636621Sbt150084 
42646621Sbt150084 /*
42656621Sbt150084  * ixgbe_rem_intrs - Remove the allocated interrupts.
42666621Sbt150084  */
42676621Sbt150084 static void
42686621Sbt150084 ixgbe_rem_intrs(ixgbe_t *ixgbe)
42696621Sbt150084 {
42706621Sbt150084 	int i;
42716621Sbt150084 	int rc;
42726621Sbt150084 
42736621Sbt150084 	for (i = 0; i < ixgbe->intr_cnt; i++) {
42746621Sbt150084 		rc = ddi_intr_free(ixgbe->htable[i]);
42756621Sbt150084 		if (rc != DDI_SUCCESS) {
42766621Sbt150084 			IXGBE_DEBUGLOG_1(ixgbe,
42776621Sbt150084 			    "Free intr failed: %d", rc);
42786621Sbt150084 		}
42796621Sbt150084 	}
42806621Sbt150084 
42816621Sbt150084 	kmem_free(ixgbe->htable, ixgbe->intr_size);
42826621Sbt150084 	ixgbe->htable = NULL;
42836621Sbt150084 }
42846621Sbt150084 
42856621Sbt150084 /*
42866621Sbt150084  * ixgbe_enable_intrs - Enable all the ddi interrupts.
42876621Sbt150084  */
42886621Sbt150084 static int
42896621Sbt150084 ixgbe_enable_intrs(ixgbe_t *ixgbe)
42906621Sbt150084 {
42916621Sbt150084 	int i;
42926621Sbt150084 	int rc;
42936621Sbt150084 
42946621Sbt150084 	/*
42956621Sbt150084 	 * Enable interrupts
42966621Sbt150084 	 */
42976621Sbt150084 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
42986621Sbt150084 		/*
42996621Sbt150084 		 * Call ddi_intr_block_enable() for MSI
43006621Sbt150084 		 */
43016621Sbt150084 		rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt);
43026621Sbt150084 		if (rc != DDI_SUCCESS) {
43036621Sbt150084 			ixgbe_log(ixgbe,
43046621Sbt150084 			    "Enable block intr failed: %d", rc);
43056621Sbt150084 			return (IXGBE_FAILURE);
43066621Sbt150084 		}
43076621Sbt150084 	} else {
43086621Sbt150084 		/*
43096621Sbt150084 		 * Call ddi_intr_enable() for Legacy/MSI non block enable
43106621Sbt150084 		 */
43116621Sbt150084 		for (i = 0; i < ixgbe->intr_cnt; i++) {
43126621Sbt150084 			rc = ddi_intr_enable(ixgbe->htable[i]);
43136621Sbt150084 			if (rc != DDI_SUCCESS) {
43146621Sbt150084 				ixgbe_log(ixgbe,
43156621Sbt150084 				    "Enable intr failed: %d", rc);
43166621Sbt150084 				return (IXGBE_FAILURE);
43176621Sbt150084 			}
43186621Sbt150084 		}
43196621Sbt150084 	}
43206621Sbt150084 
43216621Sbt150084 	return (IXGBE_SUCCESS);
43226621Sbt150084 }
43236621Sbt150084 
43246621Sbt150084 /*
43256621Sbt150084  * ixgbe_disable_intrs - Disable all the interrupts.
43266621Sbt150084  */
43276621Sbt150084 static int
43286621Sbt150084 ixgbe_disable_intrs(ixgbe_t *ixgbe)
43296621Sbt150084 {
43306621Sbt150084 	int i;
43316621Sbt150084 	int rc;
43326621Sbt150084 
43336621Sbt150084 	/*
43346621Sbt150084 	 * Disable all interrupts
43356621Sbt150084 	 */
43366621Sbt150084 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
43376621Sbt150084 		rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt);
43386621Sbt150084 		if (rc != DDI_SUCCESS) {
43396621Sbt150084 			ixgbe_log(ixgbe,
43406621Sbt150084 			    "Disable block intr failed: %d", rc);
43416621Sbt150084 			return (IXGBE_FAILURE);
43426621Sbt150084 		}
43436621Sbt150084 	} else {
43446621Sbt150084 		for (i = 0; i < ixgbe->intr_cnt; i++) {
43456621Sbt150084 			rc = ddi_intr_disable(ixgbe->htable[i]);
43466621Sbt150084 			if (rc != DDI_SUCCESS) {
43476621Sbt150084 				ixgbe_log(ixgbe,
43486621Sbt150084 				    "Disable intr failed: %d", rc);
43496621Sbt150084 				return (IXGBE_FAILURE);
43506621Sbt150084 			}
43516621Sbt150084 		}
43526621Sbt150084 	}
43536621Sbt150084 
43546621Sbt150084 	return (IXGBE_SUCCESS);
43556621Sbt150084 }
43566621Sbt150084 
43576621Sbt150084 /*
43586621Sbt150084  * ixgbe_get_hw_state - Get and save parameters related to adapter hardware.
43596621Sbt150084  */
43606621Sbt150084 static void
43616621Sbt150084 ixgbe_get_hw_state(ixgbe_t *ixgbe)
43626621Sbt150084 {
43636621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
43648490SPaul.Guo@Sun.COM 	ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
43658490SPaul.Guo@Sun.COM 	boolean_t link_up = B_FALSE;
43666621Sbt150084 	uint32_t pcs1g_anlp = 0;
43676621Sbt150084 	uint32_t pcs1g_ana = 0;
43686621Sbt150084 
43696621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
43706621Sbt150084 	ixgbe->param_lp_1000fdx_cap = 0;
43716621Sbt150084 	ixgbe->param_lp_100fdx_cap  = 0;
43726621Sbt150084 
43738490SPaul.Guo@Sun.COM 	/* check for link, don't wait */
43748490SPaul.Guo@Sun.COM 	(void) ixgbe_check_link(hw, &speed, &link_up, false);
43758490SPaul.Guo@Sun.COM 	if (link_up) {
43766621Sbt150084 		pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
43776621Sbt150084 		pcs1g_ana = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
43786621Sbt150084 
43796621Sbt150084 		ixgbe->param_lp_1000fdx_cap =
43806621Sbt150084 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
43816621Sbt150084 		ixgbe->param_lp_100fdx_cap =
43826621Sbt150084 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
43836621Sbt150084 	}
43846621Sbt150084 
438510376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_1000fdx_cap =
438610376SChenlu.Chen@Sun.COM 	    (pcs1g_ana & IXGBE_PCS1GANA_FDC)  ? 1 : 0;
438710376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_100fdx_cap = (pcs1g_ana & IXGBE_PCS1GANA_FDC)  ? 1 : 0;
43886621Sbt150084 }
43896621Sbt150084 
43906621Sbt150084 /*
43916621Sbt150084  * ixgbe_get_driver_control - Notify that driver is in control of device.
43926621Sbt150084  */
43936621Sbt150084 static void
43946621Sbt150084 ixgbe_get_driver_control(struct ixgbe_hw *hw)
43956621Sbt150084 {
43966621Sbt150084 	uint32_t ctrl_ext;
43976621Sbt150084 
43986621Sbt150084 	/*
43996621Sbt150084 	 * Notify firmware that driver is in control of device
44006621Sbt150084 	 */
44016621Sbt150084 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
44026621Sbt150084 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
44036621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
44046621Sbt150084 }
44056621Sbt150084 
44066621Sbt150084 /*
44076621Sbt150084  * ixgbe_release_driver_control - Notify that driver is no longer in control
44086621Sbt150084  * of device.
44096621Sbt150084  */
44106621Sbt150084 static void
44116621Sbt150084 ixgbe_release_driver_control(struct ixgbe_hw *hw)
44126621Sbt150084 {
44136621Sbt150084 	uint32_t ctrl_ext;
44146621Sbt150084 
44156621Sbt150084 	/*
44166621Sbt150084 	 * Notify firmware that driver is no longer in control of device
44176621Sbt150084 	 */
44186621Sbt150084 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
44196621Sbt150084 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
44206621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
44216621Sbt150084 }
44226621Sbt150084 
44236621Sbt150084 /*
44246621Sbt150084  * ixgbe_atomic_reserve - Atomic decrease operation.
44256621Sbt150084  */
44266621Sbt150084 int
44276621Sbt150084 ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n)
44286621Sbt150084 {
44296621Sbt150084 	uint32_t oldval;
44306621Sbt150084 	uint32_t newval;
44316621Sbt150084 
44326621Sbt150084 	/*
44336621Sbt150084 	 * ATOMICALLY
44346621Sbt150084 	 */
44356621Sbt150084 	do {
44366621Sbt150084 		oldval = *count_p;
44376621Sbt150084 		if (oldval < n)
44386621Sbt150084 			return (-1);
44396621Sbt150084 		newval = oldval - n;
44406621Sbt150084 	} while (atomic_cas_32(count_p, oldval, newval) != oldval);
44416621Sbt150084 
44426621Sbt150084 	return (newval);
44436621Sbt150084 }
44446621Sbt150084 
44456621Sbt150084 /*
44466621Sbt150084  * ixgbe_mc_table_itr - Traverse the entries in the multicast table.
44476621Sbt150084  */
44486621Sbt150084 static uint8_t *
44496621Sbt150084 ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq)
44506621Sbt150084 {
44518490SPaul.Guo@Sun.COM 	uint8_t *addr = *upd_ptr;
44528490SPaul.Guo@Sun.COM 	uint8_t *new_ptr;
44538490SPaul.Guo@Sun.COM 
44546621Sbt150084 	_NOTE(ARGUNUSED(hw));
44556621Sbt150084 	_NOTE(ARGUNUSED(vmdq));
44566621Sbt150084 
44576621Sbt150084 	new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS;
44586621Sbt150084 	*upd_ptr = new_ptr;
44596621Sbt150084 	return (addr);
44606621Sbt150084 }
44616621Sbt150084 
44626621Sbt150084 /*
44636621Sbt150084  * FMA support
44646621Sbt150084  */
44656621Sbt150084 int
44666621Sbt150084 ixgbe_check_acc_handle(ddi_acc_handle_t handle)
44676621Sbt150084 {
44686621Sbt150084 	ddi_fm_error_t de;
44696621Sbt150084 
44706621Sbt150084 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
44716621Sbt150084 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
44726621Sbt150084 	return (de.fme_status);
44736621Sbt150084 }
44746621Sbt150084 
44756621Sbt150084 int
44766621Sbt150084 ixgbe_check_dma_handle(ddi_dma_handle_t handle)
44776621Sbt150084 {
44786621Sbt150084 	ddi_fm_error_t de;
44796621Sbt150084 
44806621Sbt150084 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
44816621Sbt150084 	return (de.fme_status);
44826621Sbt150084 }
44836621Sbt150084 
44846621Sbt150084 /*
44856621Sbt150084  * ixgbe_fm_error_cb - The IO fault service error handling callback function.
44866621Sbt150084  */
44876621Sbt150084 static int
44886621Sbt150084 ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
44896621Sbt150084 {
44906621Sbt150084 	_NOTE(ARGUNUSED(impl_data));
44916621Sbt150084 	/*
44926621Sbt150084 	 * as the driver can always deal with an error in any dma or
44936621Sbt150084 	 * access handle, we can just return the fme_status value.
44946621Sbt150084 	 */
44956621Sbt150084 	pci_ereport_post(dip, err, NULL);
44966621Sbt150084 	return (err->fme_status);
44976621Sbt150084 }
44986621Sbt150084 
44996621Sbt150084 static void
45006621Sbt150084 ixgbe_fm_init(ixgbe_t *ixgbe)
45016621Sbt150084 {
45026621Sbt150084 	ddi_iblock_cookie_t iblk;
45036621Sbt150084 	int fma_acc_flag, fma_dma_flag;
45046621Sbt150084 
45056621Sbt150084 	/*
45066621Sbt150084 	 * Only register with IO Fault Services if we have some capability
45076621Sbt150084 	 */
45086621Sbt150084 	if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
45096621Sbt150084 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
45106621Sbt150084 		fma_acc_flag = 1;
45116621Sbt150084 	} else {
45126621Sbt150084 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
45136621Sbt150084 		fma_acc_flag = 0;
45146621Sbt150084 	}
45156621Sbt150084 
45166621Sbt150084 	if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
45176621Sbt150084 		fma_dma_flag = 1;
45186621Sbt150084 	} else {
45196621Sbt150084 		fma_dma_flag = 0;
45206621Sbt150084 	}
45216621Sbt150084 
45226621Sbt150084 	ixgbe_set_fma_flags(fma_acc_flag, fma_dma_flag);
45236621Sbt150084 
45246621Sbt150084 	if (ixgbe->fm_capabilities) {
45256621Sbt150084 
45266621Sbt150084 		/*
45276621Sbt150084 		 * Register capabilities with IO Fault Services
45286621Sbt150084 		 */
45296621Sbt150084 		ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk);
45306621Sbt150084 
45316621Sbt150084 		/*
45326621Sbt150084 		 * Initialize pci ereport capabilities if ereport capable
45336621Sbt150084 		 */
45346621Sbt150084 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
45356621Sbt150084 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
45366621Sbt150084 			pci_ereport_setup(ixgbe->dip);
45376621Sbt150084 
45386621Sbt150084 		/*
45396621Sbt150084 		 * Register error callback if error callback capable
45406621Sbt150084 		 */
45416621Sbt150084 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
45426621Sbt150084 			ddi_fm_handler_register(ixgbe->dip,
45436621Sbt150084 			    ixgbe_fm_error_cb, (void*) ixgbe);
45446621Sbt150084 	}
45456621Sbt150084 }
45466621Sbt150084 
45476621Sbt150084 static void
45486621Sbt150084 ixgbe_fm_fini(ixgbe_t *ixgbe)
45496621Sbt150084 {
45506621Sbt150084 	/*
45516621Sbt150084 	 * Only unregister FMA capabilities if they are registered
45526621Sbt150084 	 */
45536621Sbt150084 	if (ixgbe->fm_capabilities) {
45546621Sbt150084 
45556621Sbt150084 		/*
45566621Sbt150084 		 * Release any resources allocated by pci_ereport_setup()
45576621Sbt150084 		 */
45586621Sbt150084 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
45596621Sbt150084 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
45606621Sbt150084 			pci_ereport_teardown(ixgbe->dip);
45616621Sbt150084 
45626621Sbt150084 		/*
45636621Sbt150084 		 * Un-register error callback if error callback capable
45646621Sbt150084 		 */
45656621Sbt150084 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
45666621Sbt150084 			ddi_fm_handler_unregister(ixgbe->dip);
45676621Sbt150084 
45686621Sbt150084 		/*
45696621Sbt150084 		 * Unregister from IO Fault Service
45706621Sbt150084 		 */
45716621Sbt150084 		ddi_fm_fini(ixgbe->dip);
45726621Sbt150084 	}
45736621Sbt150084 }
45746621Sbt150084 
45756621Sbt150084 void
45766621Sbt150084 ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail)
45776621Sbt150084 {
45786621Sbt150084 	uint64_t ena;
45796621Sbt150084 	char buf[FM_MAX_CLASS];
45806621Sbt150084 
45816621Sbt150084 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
45826621Sbt150084 	ena = fm_ena_generate(0, FM_ENA_FMT1);
45836621Sbt150084 	if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) {
45846621Sbt150084 		ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP,
45856621Sbt150084 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
45866621Sbt150084 	}
45876621Sbt150084 }
45888275SEric Cheng 
45898275SEric Cheng static int
45908275SEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
45918275SEric Cheng {
45928275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh;
45938275SEric Cheng 
45948275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
45958275SEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
45968275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
45978275SEric Cheng 	return (0);
45988275SEric Cheng }
45998275SEric Cheng 
46008275SEric Cheng /*
46018275SEric Cheng  * Callback funtion for MAC layer to register all rings.
46028275SEric Cheng  */
46038275SEric Cheng /* ARGSUSED */
46048275SEric Cheng void
46058275SEric Cheng ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
46068275SEric Cheng     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
46078275SEric Cheng {
46088275SEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
46098275SEric Cheng 	mac_intr_t *mintr = &infop->mri_intr;
46108275SEric Cheng 
46118275SEric Cheng 	switch (rtype) {
46128275SEric Cheng 	case MAC_RING_TYPE_RX: {
46138275SEric Cheng 		ASSERT(rg_index == 0);
46148275SEric Cheng 		ASSERT(ring_index < ixgbe->num_rx_rings);
46158275SEric Cheng 
46168275SEric Cheng 		ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[ring_index];
46178275SEric Cheng 		rx_ring->ring_handle = rh;
46188275SEric Cheng 
46198275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
46208275SEric Cheng 		infop->mri_start = ixgbe_ring_start;
46218275SEric Cheng 		infop->mri_stop = NULL;
46228275SEric Cheng 		infop->mri_poll = ixgbe_ring_rx_poll;
46238275SEric Cheng 
46248275SEric Cheng 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
46258275SEric Cheng 		mintr->mi_enable = ixgbe_rx_ring_intr_enable;
46268275SEric Cheng 		mintr->mi_disable = ixgbe_rx_ring_intr_disable;
46278275SEric Cheng 
46288275SEric Cheng 		break;
46298275SEric Cheng 	}
46308275SEric Cheng 	case MAC_RING_TYPE_TX: {
46318275SEric Cheng 		ASSERT(rg_index == -1);
46328275SEric Cheng 		ASSERT(ring_index < ixgbe->num_tx_rings);
46338275SEric Cheng 
46348275SEric Cheng 		ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index];
46358275SEric Cheng 		tx_ring->ring_handle = rh;
46368275SEric Cheng 
46378275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
46388275SEric Cheng 		infop->mri_start = NULL;
46398275SEric Cheng 		infop->mri_stop = NULL;
46408275SEric Cheng 		infop->mri_tx = ixgbe_ring_tx;
46418275SEric Cheng 
46428275SEric Cheng 		break;
46438275SEric Cheng 	}
46448275SEric Cheng 	default:
46458275SEric Cheng 		break;
46468275SEric Cheng 	}
46478275SEric Cheng }
46488275SEric Cheng 
46498275SEric Cheng /*
46508275SEric Cheng  * Callback funtion for MAC layer to register all groups.
46518275SEric Cheng  */
46528275SEric Cheng void
46538275SEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index,
46548275SEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
46558275SEric Cheng {
46568275SEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
46578275SEric Cheng 
46588275SEric Cheng 	switch (rtype) {
46598275SEric Cheng 	case MAC_RING_TYPE_RX: {
46608275SEric Cheng 		ixgbe_rx_group_t *rx_group;
46618275SEric Cheng 
46628275SEric Cheng 		rx_group = &ixgbe->rx_groups[index];
46638275SEric Cheng 		rx_group->group_handle = gh;
46648275SEric Cheng 
46658275SEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_group;
46668275SEric Cheng 		infop->mgi_start = NULL;
46678275SEric Cheng 		infop->mgi_stop = NULL;
46688275SEric Cheng 		infop->mgi_addmac = ixgbe_addmac;
46698275SEric Cheng 		infop->mgi_remmac = ixgbe_remmac;
46708275SEric Cheng 		infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups);
46718275SEric Cheng 
46728275SEric Cheng 		break;
46738275SEric Cheng 	}
46748275SEric Cheng 	case MAC_RING_TYPE_TX:
46758275SEric Cheng 		break;
46768275SEric Cheng 	default:
46778275SEric Cheng 		break;
46788275SEric Cheng 	}
46798275SEric Cheng }
46808275SEric Cheng 
46818275SEric Cheng /*
46828275SEric Cheng  * Enable interrupt on the specificed rx ring.
46838275SEric Cheng  */
46848275SEric Cheng int
46858275SEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)
46868275SEric Cheng {
46878275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
46888275SEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
46898275SEric Cheng 	int r_idx = rx_ring->index;
46908275SEric Cheng 	int v_idx = rx_ring->intr_vector;
46918275SEric Cheng 
46928275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
46938275SEric Cheng 	ASSERT(BT_TEST(ixgbe->vect_map[v_idx].rx_map, r_idx) == 0);
46948275SEric Cheng 
46958275SEric Cheng 	/*
46968275SEric Cheng 	 * To enable interrupt by setting the VAL bit of given interrupt
46978275SEric Cheng 	 * vector allocation register (IVAR).
46988275SEric Cheng 	 */
46999353SSamuel.Tu@Sun.COM 	ixgbe_enable_ivar(ixgbe, r_idx, 0);
47008275SEric Cheng 
47018275SEric Cheng 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
470210305SPaul.Guo@Sun.COM 
470310305SPaul.Guo@Sun.COM 	/*
470410305SPaul.Guo@Sun.COM 	 * To trigger a Rx interrupt to on this ring
470510305SPaul.Guo@Sun.COM 	 */
470610305SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx));
470710305SPaul.Guo@Sun.COM 	IXGBE_WRITE_FLUSH(&ixgbe->hw);
470810305SPaul.Guo@Sun.COM 
47098275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
47108275SEric Cheng 
47118275SEric Cheng 	return (0);
47128275SEric Cheng }
47138275SEric Cheng 
47148275SEric Cheng /*
47158275SEric Cheng  * Disable interrupt on the specificed rx ring.
47168275SEric Cheng  */
47178275SEric Cheng int
47188275SEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)
47198275SEric Cheng {
47208275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
47218275SEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
47228275SEric Cheng 	int r_idx = rx_ring->index;
47238275SEric Cheng 	int v_idx = rx_ring->intr_vector;
47248275SEric Cheng 
47258275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
47268275SEric Cheng 	ASSERT(BT_TEST(ixgbe->vect_map[v_idx].rx_map, r_idx) == 1);
47278275SEric Cheng 
47288275SEric Cheng 	/*
47298275SEric Cheng 	 * To disable interrupt by clearing the VAL bit of given interrupt
47308275SEric Cheng 	 * vector allocation register (IVAR).
47318275SEric Cheng 	 */
47329353SSamuel.Tu@Sun.COM 	ixgbe_disable_ivar(ixgbe, r_idx, 0);
47338275SEric Cheng 
47348275SEric Cheng 	BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx);
47358275SEric Cheng 
47368275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
47378275SEric Cheng 
47388275SEric Cheng 	return (0);
47398275SEric Cheng }
47408275SEric Cheng 
47418275SEric Cheng /*
47428275SEric Cheng  * Add a mac address.
47438275SEric Cheng  */
47448275SEric Cheng static int
47458275SEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr)
47468275SEric Cheng {
47478275SEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
47488275SEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
47498275SEric Cheng 	int slot;
47508275SEric Cheng 	int err;
47518275SEric Cheng 
47528275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
47538275SEric Cheng 
47548275SEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
47558275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
47568275SEric Cheng 		return (ECANCELED);
47578275SEric Cheng 	}
47588275SEric Cheng 
47598275SEric Cheng 	if (ixgbe->unicst_avail == 0) {
47608275SEric Cheng 		/* no slots available */
47618275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
47628275SEric Cheng 		return (ENOSPC);
47638275SEric Cheng 	}
47648275SEric Cheng 
47658275SEric Cheng 	for (slot = 0; slot < ixgbe->unicst_total; slot++) {
47668275SEric Cheng 		if (ixgbe->unicst_addr[slot].mac.set == 0)
47678275SEric Cheng 			break;
47688275SEric Cheng 	}
47698275SEric Cheng 
47708275SEric Cheng 	ASSERT((slot >= 0) && (slot < ixgbe->unicst_total));
47718275SEric Cheng 
47728275SEric Cheng 	if ((err = ixgbe_unicst_set(ixgbe, mac_addr, slot)) == 0) {
47738275SEric Cheng 		ixgbe->unicst_addr[slot].mac.set = 1;
47748275SEric Cheng 		ixgbe->unicst_avail--;
47758275SEric Cheng 	}
47768275SEric Cheng 
47778275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
47788275SEric Cheng 
47798275SEric Cheng 	return (err);
47808275SEric Cheng }
47818275SEric Cheng 
47828275SEric Cheng /*
47838275SEric Cheng  * Remove a mac address.
47848275SEric Cheng  */
47858275SEric Cheng static int
47868275SEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr)
47878275SEric Cheng {
47888275SEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
47898275SEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
47908275SEric Cheng 	int slot;
47918275SEric Cheng 	int err;
47928275SEric Cheng 
47938275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
47948275SEric Cheng 
47958275SEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
47968275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
47978275SEric Cheng 		return (ECANCELED);
47988275SEric Cheng 	}
47998275SEric Cheng 
48008275SEric Cheng 	slot = ixgbe_unicst_find(ixgbe, mac_addr);
48018275SEric Cheng 	if (slot == -1) {
48028275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
48038275SEric Cheng 		return (EINVAL);
48048275SEric Cheng 	}
48058275SEric Cheng 
48068275SEric Cheng 	if (ixgbe->unicst_addr[slot].mac.set == 0) {
48078275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
48088275SEric Cheng 		return (EINVAL);
48098275SEric Cheng 	}
48108275SEric Cheng 
48118275SEric Cheng 	bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
48128275SEric Cheng 	if ((err = ixgbe_unicst_set(ixgbe,
48138275SEric Cheng 	    ixgbe->unicst_addr[slot].mac.addr, slot)) == 0) {
48148275SEric Cheng 		ixgbe->unicst_addr[slot].mac.set = 0;
48158275SEric Cheng 		ixgbe->unicst_avail++;
48168275SEric Cheng 	}
48178275SEric Cheng 
48188275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
48198275SEric Cheng 
48208275SEric Cheng 	return (err);
48218275SEric Cheng }
4822