xref: /onnv-gate/usr/src/uts/common/io/ixgbe/ixgbe_main.c (revision 12280:dba4b8072daa)
16621Sbt150084 /*
26621Sbt150084  * CDDL HEADER START
36621Sbt150084  *
46621Sbt150084  * The contents of this file are subject to the terms of the
56621Sbt150084  * Common Development and Distribution License (the "License").
66621Sbt150084  * You may not use this file except in compliance with the License.
76621Sbt150084  *
87656SSherry.Moore@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97656SSherry.Moore@Sun.COM  * or http://www.opensolaris.org/os/licensing.
106621Sbt150084  * See the License for the specific language governing permissions
116621Sbt150084  * and limitations under the License.
126621Sbt150084  *
137656SSherry.Moore@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147656SSherry.Moore@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156621Sbt150084  * If applicable, add the following below this CDDL HEADER, with the
166621Sbt150084  * fields enclosed by brackets "[]" replaced with your own identifying
176621Sbt150084  * information: Portions Copyright [yyyy] [name of copyright owner]
186621Sbt150084  *
196621Sbt150084  * CDDL HEADER END
206621Sbt150084  */
216621Sbt150084 
226621Sbt150084 /*
23*12280SChenlu.Chen@Sun.COM  * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
24*12280SChenlu.Chen@Sun.COM  */
25*12280SChenlu.Chen@Sun.COM 
26*12280SChenlu.Chen@Sun.COM /*
27*12280SChenlu.Chen@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
287656SSherry.Moore@Sun.COM  */
297656SSherry.Moore@Sun.COM 
306621Sbt150084 #include "ixgbe_sw.h"
316621Sbt150084 
3211486SZhen.W@Sun.COM static char ixgbe_ident[] = "Intel 10Gb Ethernet";
33*12280SChenlu.Chen@Sun.COM static char ixgbe_version[] = "ixgbe 1.1.6";
346621Sbt150084 
356621Sbt150084 /*
366621Sbt150084  * Local function protoypes
376621Sbt150084  */
386621Sbt150084 static int ixgbe_register_mac(ixgbe_t *);
396621Sbt150084 static int ixgbe_identify_hardware(ixgbe_t *);
406621Sbt150084 static int ixgbe_regs_map(ixgbe_t *);
416621Sbt150084 static void ixgbe_init_properties(ixgbe_t *);
426621Sbt150084 static int ixgbe_init_driver_settings(ixgbe_t *);
436621Sbt150084 static void ixgbe_init_locks(ixgbe_t *);
446621Sbt150084 static void ixgbe_destroy_locks(ixgbe_t *);
456621Sbt150084 static int ixgbe_init(ixgbe_t *);
466621Sbt150084 static int ixgbe_chip_start(ixgbe_t *);
476621Sbt150084 static void ixgbe_chip_stop(ixgbe_t *);
486621Sbt150084 static int ixgbe_reset(ixgbe_t *);
496621Sbt150084 static void ixgbe_tx_clean(ixgbe_t *);
506621Sbt150084 static boolean_t ixgbe_tx_drain(ixgbe_t *);
516621Sbt150084 static boolean_t ixgbe_rx_drain(ixgbe_t *);
526621Sbt150084 static int ixgbe_alloc_rings(ixgbe_t *);
536621Sbt150084 static void ixgbe_free_rings(ixgbe_t *);
5410376SChenlu.Chen@Sun.COM static int ixgbe_alloc_rx_data(ixgbe_t *);
5510376SChenlu.Chen@Sun.COM static void ixgbe_free_rx_data(ixgbe_t *);
566621Sbt150084 static void ixgbe_setup_rings(ixgbe_t *);
576621Sbt150084 static void ixgbe_setup_rx(ixgbe_t *);
586621Sbt150084 static void ixgbe_setup_tx(ixgbe_t *);
596621Sbt150084 static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *);
606621Sbt150084 static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *);
616621Sbt150084 static void ixgbe_setup_rss(ixgbe_t *);
6211878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq(ixgbe_t *);
6311878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq_rss(ixgbe_t *);
646621Sbt150084 static void ixgbe_init_unicst(ixgbe_t *);
658275SEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *);
666621Sbt150084 static void ixgbe_setup_multicst(ixgbe_t *);
676621Sbt150084 static void ixgbe_get_hw_state(ixgbe_t *);
6811878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe);
696621Sbt150084 static void ixgbe_get_conf(ixgbe_t *);
7010376SChenlu.Chen@Sun.COM static void ixgbe_init_params(ixgbe_t *);
716621Sbt150084 static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int);
7211233SPaul.Guo@Sun.COM static void ixgbe_driver_link_check(ixgbe_t *);
739353SSamuel.Tu@Sun.COM static void ixgbe_sfp_check(void *);
7411233SPaul.Guo@Sun.COM static void ixgbe_link_timer(void *);
756621Sbt150084 static void ixgbe_local_timer(void *);
766621Sbt150084 static void ixgbe_arm_watchdog_timer(ixgbe_t *);
776621Sbt150084 static void ixgbe_restart_watchdog_timer(ixgbe_t *);
786621Sbt150084 static void ixgbe_disable_adapter_interrupts(ixgbe_t *);
796621Sbt150084 static void ixgbe_enable_adapter_interrupts(ixgbe_t *);
806621Sbt150084 static boolean_t is_valid_mac_addr(uint8_t *);
816621Sbt150084 static boolean_t ixgbe_stall_check(ixgbe_t *);
826621Sbt150084 static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t);
836621Sbt150084 static void ixgbe_set_internal_mac_loopback(ixgbe_t *);
846621Sbt150084 static boolean_t ixgbe_find_mac_address(ixgbe_t *);
856621Sbt150084 static int ixgbe_alloc_intrs(ixgbe_t *);
866621Sbt150084 static int ixgbe_alloc_intr_handles(ixgbe_t *, int);
876621Sbt150084 static int ixgbe_add_intr_handlers(ixgbe_t *);
886621Sbt150084 static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int);
896621Sbt150084 static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int);
909353SSamuel.Tu@Sun.COM static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t);
919353SSamuel.Tu@Sun.COM static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t);
929353SSamuel.Tu@Sun.COM static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t);
9311878SVenu.Iyer@Sun.COM static uint32_t ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index);
949353SSamuel.Tu@Sun.COM static int ixgbe_map_intrs_to_vectors(ixgbe_t *);
956621Sbt150084 static void ixgbe_setup_adapter_vector(ixgbe_t *);
966621Sbt150084 static void ixgbe_rem_intr_handlers(ixgbe_t *);
976621Sbt150084 static void ixgbe_rem_intrs(ixgbe_t *);
986621Sbt150084 static int ixgbe_enable_intrs(ixgbe_t *);
996621Sbt150084 static int ixgbe_disable_intrs(ixgbe_t *);
1006621Sbt150084 static uint_t ixgbe_intr_legacy(void *, void *);
1016621Sbt150084 static uint_t ixgbe_intr_msi(void *, void *);
1029353SSamuel.Tu@Sun.COM static uint_t ixgbe_intr_msix(void *, void *);
1036621Sbt150084 static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *);
1046621Sbt150084 static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *);
1058490SPaul.Guo@Sun.COM static void ixgbe_intr_other_work(ixgbe_t *, uint32_t);
1066621Sbt150084 static void ixgbe_get_driver_control(struct ixgbe_hw *);
1078275SEric Cheng static int ixgbe_addmac(void *, const uint8_t *);
1088275SEric Cheng static int ixgbe_remmac(void *, const uint8_t *);
1096621Sbt150084 static void ixgbe_release_driver_control(struct ixgbe_hw *);
1106621Sbt150084 
1116621Sbt150084 static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t);
1126621Sbt150084 static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t);
1136621Sbt150084 static int ixgbe_resume(dev_info_t *);
1146621Sbt150084 static int ixgbe_suspend(dev_info_t *);
1156621Sbt150084 static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *);
1166621Sbt150084 static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *);
11711878SVenu.Iyer@Sun.COM static int ixgbe_cbfunc(dev_info_t *, ddi_cb_action_t, void *, void *, void *);
11811878SVenu.Iyer@Sun.COM static int ixgbe_intr_cb_register(ixgbe_t *);
11911878SVenu.Iyer@Sun.COM static int ixgbe_intr_adjust(ixgbe_t *, ddi_cb_action_t, int);
1206621Sbt150084 
1216621Sbt150084 static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
1226621Sbt150084     const void *impl_data);
1236621Sbt150084 static void ixgbe_fm_init(ixgbe_t *);
1246621Sbt150084 static void ixgbe_fm_fini(ixgbe_t *);
1256621Sbt150084 
12611878SVenu.Iyer@Sun.COM char *ixgbe_priv_props[] = {
12711878SVenu.Iyer@Sun.COM 	"_tx_copy_thresh",
12811878SVenu.Iyer@Sun.COM 	"_tx_recycle_thresh",
12911878SVenu.Iyer@Sun.COM 	"_tx_overload_thresh",
13011878SVenu.Iyer@Sun.COM 	"_tx_resched_thresh",
13111878SVenu.Iyer@Sun.COM 	"_rx_copy_thresh",
13211878SVenu.Iyer@Sun.COM 	"_rx_limit_per_intr",
13311878SVenu.Iyer@Sun.COM 	"_intr_throttling",
13411878SVenu.Iyer@Sun.COM 	"_adv_pause_cap",
13511878SVenu.Iyer@Sun.COM 	"_adv_asym_pause_cap",
13611878SVenu.Iyer@Sun.COM 	NULL
13710376SChenlu.Chen@Sun.COM };
13810376SChenlu.Chen@Sun.COM 
13910376SChenlu.Chen@Sun.COM #define	IXGBE_MAX_PRIV_PROPS \
14010376SChenlu.Chen@Sun.COM 	(sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t))
14110376SChenlu.Chen@Sun.COM 
1426621Sbt150084 static struct cb_ops ixgbe_cb_ops = {
1436621Sbt150084 	nulldev,		/* cb_open */
1446621Sbt150084 	nulldev,		/* cb_close */
1456621Sbt150084 	nodev,			/* cb_strategy */
1466621Sbt150084 	nodev,			/* cb_print */
1476621Sbt150084 	nodev,			/* cb_dump */
1486621Sbt150084 	nodev,			/* cb_read */
1496621Sbt150084 	nodev,			/* cb_write */
1506621Sbt150084 	nodev,			/* cb_ioctl */
1516621Sbt150084 	nodev,			/* cb_devmap */
1526621Sbt150084 	nodev,			/* cb_mmap */
1536621Sbt150084 	nodev,			/* cb_segmap */
1546621Sbt150084 	nochpoll,		/* cb_chpoll */
1556621Sbt150084 	ddi_prop_op,		/* cb_prop_op */
1566621Sbt150084 	NULL,			/* cb_stream */
1576621Sbt150084 	D_MP | D_HOTPLUG,	/* cb_flag */
1586621Sbt150084 	CB_REV,			/* cb_rev */
1596621Sbt150084 	nodev,			/* cb_aread */
1606621Sbt150084 	nodev			/* cb_awrite */
1616621Sbt150084 };
1626621Sbt150084 
1636621Sbt150084 static struct dev_ops ixgbe_dev_ops = {
1646621Sbt150084 	DEVO_REV,		/* devo_rev */
1656621Sbt150084 	0,			/* devo_refcnt */
1666621Sbt150084 	NULL,			/* devo_getinfo */
1676621Sbt150084 	nulldev,		/* devo_identify */
1686621Sbt150084 	nulldev,		/* devo_probe */
1696621Sbt150084 	ixgbe_attach,		/* devo_attach */
1706621Sbt150084 	ixgbe_detach,		/* devo_detach */
1716621Sbt150084 	nodev,			/* devo_reset */
1726621Sbt150084 	&ixgbe_cb_ops,		/* devo_cb_ops */
1736621Sbt150084 	NULL,			/* devo_bus_ops */
1747656SSherry.Moore@Sun.COM 	ddi_power,		/* devo_power */
1757656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
1766621Sbt150084 };
1776621Sbt150084 
1786621Sbt150084 static struct modldrv ixgbe_modldrv = {
1796621Sbt150084 	&mod_driverops,		/* Type of module.  This one is a driver */
18011486SZhen.W@Sun.COM 	ixgbe_ident,		/* Discription string */
1816621Sbt150084 	&ixgbe_dev_ops		/* driver ops */
1826621Sbt150084 };
1836621Sbt150084 
1846621Sbt150084 static struct modlinkage ixgbe_modlinkage = {
1856621Sbt150084 	MODREV_1, &ixgbe_modldrv, NULL
1866621Sbt150084 };
1876621Sbt150084 
1886621Sbt150084 /*
1896621Sbt150084  * Access attributes for register mapping
1906621Sbt150084  */
1916621Sbt150084 ddi_device_acc_attr_t ixgbe_regs_acc_attr = {
19211236SStephen.Hanson@Sun.COM 	DDI_DEVICE_ATTR_V1,
1936621Sbt150084 	DDI_STRUCTURE_LE_ACC,
1946621Sbt150084 	DDI_STRICTORDER_ACC,
1956621Sbt150084 	DDI_FLAGERR_ACC
1966621Sbt150084 };
1976621Sbt150084 
1986621Sbt150084 /*
1996621Sbt150084  * Loopback property
2006621Sbt150084  */
2016621Sbt150084 static lb_property_t lb_normal = {
2026621Sbt150084 	normal,	"normal", IXGBE_LB_NONE
2036621Sbt150084 };
2046621Sbt150084 
2056621Sbt150084 static lb_property_t lb_mac = {
2066621Sbt150084 	internal, "MAC", IXGBE_LB_INTERNAL_MAC
2076621Sbt150084 };
2086621Sbt150084 
20911150SZhen.W@Sun.COM static lb_property_t lb_external = {
21011150SZhen.W@Sun.COM 	external, "External", IXGBE_LB_EXTERNAL
21111150SZhen.W@Sun.COM };
21211150SZhen.W@Sun.COM 
21310376SChenlu.Chen@Sun.COM #define	IXGBE_M_CALLBACK_FLAGS \
21411878SVenu.Iyer@Sun.COM 	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
2156621Sbt150084 
2166621Sbt150084 static mac_callbacks_t ixgbe_m_callbacks = {
2176621Sbt150084 	IXGBE_M_CALLBACK_FLAGS,
2186621Sbt150084 	ixgbe_m_stat,
2196621Sbt150084 	ixgbe_m_start,
2206621Sbt150084 	ixgbe_m_stop,
2216621Sbt150084 	ixgbe_m_promisc,
2226621Sbt150084 	ixgbe_m_multicst,
2238275SEric Cheng 	NULL,
2246621Sbt150084 	NULL,
22511878SVenu.Iyer@Sun.COM 	NULL,
2266621Sbt150084 	ixgbe_m_ioctl,
22710376SChenlu.Chen@Sun.COM 	ixgbe_m_getcapab,
22810376SChenlu.Chen@Sun.COM 	NULL,
22910376SChenlu.Chen@Sun.COM 	NULL,
23010376SChenlu.Chen@Sun.COM 	ixgbe_m_setprop,
23111878SVenu.Iyer@Sun.COM 	ixgbe_m_getprop,
23211878SVenu.Iyer@Sun.COM 	ixgbe_m_propinfo
2336621Sbt150084 };
2346621Sbt150084 
2356621Sbt150084 /*
2368490SPaul.Guo@Sun.COM  * Initialize capabilities of each supported adapter type
2378490SPaul.Guo@Sun.COM  */
2388490SPaul.Guo@Sun.COM static adapter_info_t ixgbe_82598eb_cap = {
2398490SPaul.Guo@Sun.COM 	64,		/* maximum number of rx queues */
2408490SPaul.Guo@Sun.COM 	1,		/* minimum number of rx queues */
24111878SVenu.Iyer@Sun.COM 	64,		/* default number of rx queues */
24211878SVenu.Iyer@Sun.COM 	16,		/* maximum number of rx groups */
24311878SVenu.Iyer@Sun.COM 	1,		/* minimum number of rx groups */
24411878SVenu.Iyer@Sun.COM 	1,		/* default number of rx groups */
2458490SPaul.Guo@Sun.COM 	32,		/* maximum number of tx queues */
2468490SPaul.Guo@Sun.COM 	1,		/* minimum number of tx queues */
2478490SPaul.Guo@Sun.COM 	8,		/* default number of tx queues */
24811150SZhen.W@Sun.COM 	16366,		/* maximum MTU size */
24910376SChenlu.Chen@Sun.COM 	0xFFFF,		/* maximum interrupt throttle rate */
25010376SChenlu.Chen@Sun.COM 	0,		/* minimum interrupt throttle rate */
25110376SChenlu.Chen@Sun.COM 	200,		/* default interrupt throttle rate */
2528490SPaul.Guo@Sun.COM 	18,		/* maximum total msix vectors */
2538490SPaul.Guo@Sun.COM 	16,		/* maximum number of ring vectors */
2548490SPaul.Guo@Sun.COM 	2,		/* maximum number of other vectors */
2558490SPaul.Guo@Sun.COM 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
2568490SPaul.Guo@Sun.COM 	(IXGBE_FLAG_DCA_CAPABLE	/* capability flags */
2578490SPaul.Guo@Sun.COM 	| IXGBE_FLAG_RSS_CAPABLE
2588490SPaul.Guo@Sun.COM 	| IXGBE_FLAG_VMDQ_CAPABLE)
2598490SPaul.Guo@Sun.COM };
2608490SPaul.Guo@Sun.COM 
2619353SSamuel.Tu@Sun.COM static adapter_info_t ixgbe_82599eb_cap = {
2629353SSamuel.Tu@Sun.COM 	128,		/* maximum number of rx queues */
2639353SSamuel.Tu@Sun.COM 	1,		/* minimum number of rx queues */
26411878SVenu.Iyer@Sun.COM 	128,		/* default number of rx queues */
26511878SVenu.Iyer@Sun.COM 	64,		/* maximum number of rx groups */
26611878SVenu.Iyer@Sun.COM 	1,		/* minimum number of rx groups */
26711878SVenu.Iyer@Sun.COM 	1,		/* default number of rx groups */
2689353SSamuel.Tu@Sun.COM 	128,		/* maximum number of tx queues */
2699353SSamuel.Tu@Sun.COM 	1,		/* minimum number of tx queues */
2709353SSamuel.Tu@Sun.COM 	8,		/* default number of tx queues */
27111150SZhen.W@Sun.COM 	15500,		/* maximum MTU size */
27210376SChenlu.Chen@Sun.COM 	0xFF8,		/* maximum interrupt throttle rate */
27310376SChenlu.Chen@Sun.COM 	0,		/* minimum interrupt throttle rate */
27410376SChenlu.Chen@Sun.COM 	200,		/* default interrupt throttle rate */
2759353SSamuel.Tu@Sun.COM 	64,		/* maximum total msix vectors */
2769353SSamuel.Tu@Sun.COM 	16,		/* maximum number of ring vectors */
2779353SSamuel.Tu@Sun.COM 	2,		/* maximum number of other vectors */
2789353SSamuel.Tu@Sun.COM 	IXGBE_EICR_LSC,	/* "other" interrupt types handled */
2799353SSamuel.Tu@Sun.COM 	(IXGBE_FLAG_DCA_CAPABLE	/* capability flags */
2809353SSamuel.Tu@Sun.COM 	| IXGBE_FLAG_RSS_CAPABLE
28111486SZhen.W@Sun.COM 	| IXGBE_FLAG_VMDQ_CAPABLE
28211486SZhen.W@Sun.COM 	| IXGBE_FLAG_RSC_CAPABLE)
2839353SSamuel.Tu@Sun.COM };
2849353SSamuel.Tu@Sun.COM 
2858490SPaul.Guo@Sun.COM /*
2866621Sbt150084  * Module Initialization Functions.
2876621Sbt150084  */
2886621Sbt150084 
2896621Sbt150084 int
2906621Sbt150084 _init(void)
2916621Sbt150084 {
2926621Sbt150084 	int status;
2936621Sbt150084 
2946621Sbt150084 	mac_init_ops(&ixgbe_dev_ops, MODULE_NAME);
2956621Sbt150084 
2966621Sbt150084 	status = mod_install(&ixgbe_modlinkage);
2976621Sbt150084 
2986621Sbt150084 	if (status != DDI_SUCCESS) {
2996621Sbt150084 		mac_fini_ops(&ixgbe_dev_ops);
3006621Sbt150084 	}
3016621Sbt150084 
3026621Sbt150084 	return (status);
3036621Sbt150084 }
3046621Sbt150084 
3056621Sbt150084 int
3066621Sbt150084 _fini(void)
3076621Sbt150084 {
3086621Sbt150084 	int status;
3096621Sbt150084 
3106621Sbt150084 	status = mod_remove(&ixgbe_modlinkage);
3116621Sbt150084 
3126621Sbt150084 	if (status == DDI_SUCCESS) {
3136621Sbt150084 		mac_fini_ops(&ixgbe_dev_ops);
3146621Sbt150084 	}
3156621Sbt150084 
3166621Sbt150084 	return (status);
3176621Sbt150084 }
3186621Sbt150084 
3196621Sbt150084 int
3206621Sbt150084 _info(struct modinfo *modinfop)
3216621Sbt150084 {
3226621Sbt150084 	int status;
3236621Sbt150084 
3246621Sbt150084 	status = mod_info(&ixgbe_modlinkage, modinfop);
3256621Sbt150084 
3266621Sbt150084 	return (status);
3276621Sbt150084 }
3286621Sbt150084 
3296621Sbt150084 /*
3306621Sbt150084  * ixgbe_attach - Driver attach.
3316621Sbt150084  *
3326621Sbt150084  * This function is the device specific initialization entry
3336621Sbt150084  * point. This entry point is required and must be written.
3346621Sbt150084  * The DDI_ATTACH command must be provided in the attach entry
3356621Sbt150084  * point. When attach() is called with cmd set to DDI_ATTACH,
3366621Sbt150084  * all normal kernel services (such as kmem_alloc(9F)) are
3376621Sbt150084  * available for use by the driver.
3386621Sbt150084  *
3396621Sbt150084  * The attach() function will be called once for each instance
3406621Sbt150084  * of  the  device  on  the  system with cmd set to DDI_ATTACH.
3416621Sbt150084  * Until attach() succeeds, the only driver entry points which
3426621Sbt150084  * may be called are open(9E) and getinfo(9E).
3436621Sbt150084  */
3446621Sbt150084 static int
3456621Sbt150084 ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3466621Sbt150084 {
3476621Sbt150084 	ixgbe_t *ixgbe;
3486621Sbt150084 	struct ixgbe_osdep *osdep;
3496621Sbt150084 	struct ixgbe_hw *hw;
3506621Sbt150084 	int instance;
3518490SPaul.Guo@Sun.COM 	char taskqname[32];
3526621Sbt150084 
3536621Sbt150084 	/*
3546621Sbt150084 	 * Check the command and perform corresponding operations
3556621Sbt150084 	 */
3566621Sbt150084 	switch (cmd) {
3576621Sbt150084 	default:
3586621Sbt150084 		return (DDI_FAILURE);
3596621Sbt150084 
3606621Sbt150084 	case DDI_RESUME:
3616621Sbt150084 		return (ixgbe_resume(devinfo));
3626621Sbt150084 
3636621Sbt150084 	case DDI_ATTACH:
3646621Sbt150084 		break;
3656621Sbt150084 	}
3666621Sbt150084 
3676621Sbt150084 	/* Get the device instance */
3686621Sbt150084 	instance = ddi_get_instance(devinfo);
3696621Sbt150084 
3706621Sbt150084 	/* Allocate memory for the instance data structure */
3716621Sbt150084 	ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP);
3726621Sbt150084 
3736621Sbt150084 	ixgbe->dip = devinfo;
3746621Sbt150084 	ixgbe->instance = instance;
3756621Sbt150084 
3766621Sbt150084 	hw = &ixgbe->hw;
3776621Sbt150084 	osdep = &ixgbe->osdep;
3786621Sbt150084 	hw->back = osdep;
3796621Sbt150084 	osdep->ixgbe = ixgbe;
3806621Sbt150084 
3816621Sbt150084 	/* Attach the instance pointer to the dev_info data structure */
3826621Sbt150084 	ddi_set_driver_private(devinfo, ixgbe);
3836621Sbt150084 
3846621Sbt150084 	/*
3856621Sbt150084 	 * Initialize for fma support
3866621Sbt150084 	 */
3877167Sgg161487 	ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE,
3886621Sbt150084 	    0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
3896621Sbt150084 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
3906621Sbt150084 	ixgbe_fm_init(ixgbe);
3916621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT;
3926621Sbt150084 
3936621Sbt150084 	/*
3946621Sbt150084 	 * Map PCI config space registers
3956621Sbt150084 	 */
3966621Sbt150084 	if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
3976621Sbt150084 		ixgbe_error(ixgbe, "Failed to map PCI configurations");
3986621Sbt150084 		goto attach_fail;
3996621Sbt150084 	}
4006621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
4016621Sbt150084 
4026621Sbt150084 	/*
4036621Sbt150084 	 * Identify the chipset family
4046621Sbt150084 	 */
4056621Sbt150084 	if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) {
4066621Sbt150084 		ixgbe_error(ixgbe, "Failed to identify hardware");
4076621Sbt150084 		goto attach_fail;
4086621Sbt150084 	}
4096621Sbt150084 
4106621Sbt150084 	/*
4116621Sbt150084 	 * Map device registers
4126621Sbt150084 	 */
4136621Sbt150084 	if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) {
4146621Sbt150084 		ixgbe_error(ixgbe, "Failed to map device registers");
4156621Sbt150084 		goto attach_fail;
4166621Sbt150084 	}
4176621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP;
4186621Sbt150084 
4196621Sbt150084 	/*
4206621Sbt150084 	 * Initialize driver parameters
4216621Sbt150084 	 */
4226621Sbt150084 	ixgbe_init_properties(ixgbe);
4236621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS;
4246621Sbt150084 
4256621Sbt150084 	/*
42611878SVenu.Iyer@Sun.COM 	 * Register interrupt callback
42711878SVenu.Iyer@Sun.COM 	 */
42811878SVenu.Iyer@Sun.COM 	if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) {
42911878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe, "Failed to register interrupt callback");
43011878SVenu.Iyer@Sun.COM 		goto attach_fail;
43111878SVenu.Iyer@Sun.COM 	}
43211878SVenu.Iyer@Sun.COM 
43311878SVenu.Iyer@Sun.COM 	/*
4346621Sbt150084 	 * Allocate interrupts
4356621Sbt150084 	 */
4366621Sbt150084 	if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) {
4376621Sbt150084 		ixgbe_error(ixgbe, "Failed to allocate interrupts");
4386621Sbt150084 		goto attach_fail;
4396621Sbt150084 	}
4406621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
4416621Sbt150084 
4426621Sbt150084 	/*
4436621Sbt150084 	 * Allocate rx/tx rings based on the ring numbers.
4446621Sbt150084 	 * The actual numbers of rx/tx rings are decided by the number of
4456621Sbt150084 	 * allocated interrupt vectors, so we should allocate the rings after
4466621Sbt150084 	 * interrupts are allocated.
4476621Sbt150084 	 */
4486621Sbt150084 	if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) {
4496621Sbt150084 		ixgbe_error(ixgbe, "Failed to allocate rx and tx rings");
4506621Sbt150084 		goto attach_fail;
4516621Sbt150084 	}
4526621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS;
4536621Sbt150084 
4546621Sbt150084 	/*
4556621Sbt150084 	 * Map rings to interrupt vectors
4566621Sbt150084 	 */
4579353SSamuel.Tu@Sun.COM 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
4589353SSamuel.Tu@Sun.COM 		ixgbe_error(ixgbe, "Failed to map interrupts to vectors");
4596621Sbt150084 		goto attach_fail;
4606621Sbt150084 	}
4616621Sbt150084 
4626621Sbt150084 	/*
4636621Sbt150084 	 * Add interrupt handlers
4646621Sbt150084 	 */
4656621Sbt150084 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
4666621Sbt150084 		ixgbe_error(ixgbe, "Failed to add interrupt handlers");
4676621Sbt150084 		goto attach_fail;
4686621Sbt150084 	}
4696621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
4706621Sbt150084 
4716621Sbt150084 	/*
47211233SPaul.Guo@Sun.COM 	 * Create a taskq for sfp-change
4738490SPaul.Guo@Sun.COM 	 */
4748490SPaul.Guo@Sun.COM 	(void) sprintf(taskqname, "ixgbe%d_taskq", instance);
47511233SPaul.Guo@Sun.COM 	if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname,
4768490SPaul.Guo@Sun.COM 	    1, TASKQ_DEFAULTPRI, 0)) == NULL) {
4778490SPaul.Guo@Sun.COM 		ixgbe_error(ixgbe, "taskq_create failed");
4788490SPaul.Guo@Sun.COM 		goto attach_fail;
4798490SPaul.Guo@Sun.COM 	}
48011233SPaul.Guo@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ;
4818490SPaul.Guo@Sun.COM 
4828490SPaul.Guo@Sun.COM 	/*
4836621Sbt150084 	 * Initialize driver parameters
4846621Sbt150084 	 */
4856621Sbt150084 	if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) {
4866621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize driver settings");
4876621Sbt150084 		goto attach_fail;
4886621Sbt150084 	}
4896621Sbt150084 
4906621Sbt150084 	/*
4916621Sbt150084 	 * Initialize mutexes for this device.
4926621Sbt150084 	 * Do this before enabling the interrupt handler and
4936621Sbt150084 	 * register the softint to avoid the condition where
4946621Sbt150084 	 * interrupt handler can try using uninitialized mutex.
4956621Sbt150084 	 */
4966621Sbt150084 	ixgbe_init_locks(ixgbe);
4976621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS;
4986621Sbt150084 
4996621Sbt150084 	/*
5006621Sbt150084 	 * Initialize chipset hardware
5016621Sbt150084 	 */
5026621Sbt150084 	if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) {
5036621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize adapter");
5046621Sbt150084 		goto attach_fail;
5056621Sbt150084 	}
50611233SPaul.Guo@Sun.COM 	ixgbe->link_check_complete = B_FALSE;
50711233SPaul.Guo@Sun.COM 	ixgbe->link_check_hrtime = gethrtime() +
50811233SPaul.Guo@Sun.COM 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
5096621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_INIT;
5106621Sbt150084 
5116621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) {
5126621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
5136621Sbt150084 		goto attach_fail;
5146621Sbt150084 	}
5156621Sbt150084 
5166621Sbt150084 	/*
5176621Sbt150084 	 * Initialize statistics
5186621Sbt150084 	 */
5196621Sbt150084 	if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) {
5206621Sbt150084 		ixgbe_error(ixgbe, "Failed to initialize statistics");
5216621Sbt150084 		goto attach_fail;
5226621Sbt150084 	}
5236621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_STATS;
5246621Sbt150084 
5256621Sbt150084 	/*
5266621Sbt150084 	 * Register the driver to the MAC
5276621Sbt150084 	 */
5286621Sbt150084 	if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) {
5296621Sbt150084 		ixgbe_error(ixgbe, "Failed to register MAC");
5306621Sbt150084 		goto attach_fail;
5316621Sbt150084 	}
5328490SPaul.Guo@Sun.COM 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
5336621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_MAC;
5346621Sbt150084 
53511233SPaul.Guo@Sun.COM 	ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe,
53611233SPaul.Guo@Sun.COM 	    IXGBE_CYCLIC_PERIOD, DDI_IPL_0);
53711233SPaul.Guo@Sun.COM 	if (ixgbe->periodic_id == 0) {
53811233SPaul.Guo@Sun.COM 		ixgbe_error(ixgbe, "Failed to add the link check timer");
53911233SPaul.Guo@Sun.COM 		goto attach_fail;
54011233SPaul.Guo@Sun.COM 	}
54111233SPaul.Guo@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER;
54211233SPaul.Guo@Sun.COM 
5436621Sbt150084 	/*
5446621Sbt150084 	 * Now that mutex locks are initialized, and the chip is also
5456621Sbt150084 	 * initialized, enable interrupts.
5466621Sbt150084 	 */
5476621Sbt150084 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
5486621Sbt150084 		ixgbe_error(ixgbe, "Failed to enable DDI interrupts");
5496621Sbt150084 		goto attach_fail;
5506621Sbt150084 	}
5516621Sbt150084 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
5526621Sbt150084 
55311486SZhen.W@Sun.COM 	ixgbe_log(ixgbe, "%s, %s", ixgbe_ident, ixgbe_version);
55411233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED);
5556621Sbt150084 
5566621Sbt150084 	return (DDI_SUCCESS);
5576621Sbt150084 
5586621Sbt150084 attach_fail:
5596621Sbt150084 	ixgbe_unconfigure(devinfo, ixgbe);
5606621Sbt150084 	return (DDI_FAILURE);
5616621Sbt150084 }
5626621Sbt150084 
5636621Sbt150084 /*
5646621Sbt150084  * ixgbe_detach - Driver detach.
5656621Sbt150084  *
5666621Sbt150084  * The detach() function is the complement of the attach routine.
5676621Sbt150084  * If cmd is set to DDI_DETACH, detach() is used to remove  the
5686621Sbt150084  * state  associated  with  a  given  instance of a device node
5696621Sbt150084  * prior to the removal of that instance from the system.
5706621Sbt150084  *
5716621Sbt150084  * The detach() function will be called once for each  instance
5726621Sbt150084  * of the device for which there has been a successful attach()
5736621Sbt150084  * once there are no longer  any  opens  on  the  device.
5746621Sbt150084  *
5756621Sbt150084  * Interrupts routine are disabled, All memory allocated by this
5766621Sbt150084  * driver are freed.
5776621Sbt150084  */
5786621Sbt150084 static int
5796621Sbt150084 ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
5806621Sbt150084 {
5816621Sbt150084 	ixgbe_t *ixgbe;
5826621Sbt150084 
5836621Sbt150084 	/*
5846621Sbt150084 	 * Check detach command
5856621Sbt150084 	 */
5866621Sbt150084 	switch (cmd) {
5876621Sbt150084 	default:
5886621Sbt150084 		return (DDI_FAILURE);
5896621Sbt150084 
5906621Sbt150084 	case DDI_SUSPEND:
5916621Sbt150084 		return (ixgbe_suspend(devinfo));
5926621Sbt150084 
5936621Sbt150084 	case DDI_DETACH:
5946621Sbt150084 		break;
5956621Sbt150084 	}
5966621Sbt150084 
5976621Sbt150084 	/*
5986621Sbt150084 	 * Get the pointer to the driver private data structure
5996621Sbt150084 	 */
6006621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
6016621Sbt150084 	if (ixgbe == NULL)
6026621Sbt150084 		return (DDI_FAILURE);
6036621Sbt150084 
6046621Sbt150084 	/*
6056621Sbt150084 	 * If the device is still running, it needs to be stopped first.
6066621Sbt150084 	 * This check is necessary because under some specific circumstances,
6076621Sbt150084 	 * the detach routine can be called without stopping the interface
6086621Sbt150084 	 * first.
6096621Sbt150084 	 */
6106621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
61111233SPaul.Guo@Sun.COM 		atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
61211233SPaul.Guo@Sun.COM 		mutex_enter(&ixgbe->gen_lock);
61310376SChenlu.Chen@Sun.COM 		ixgbe_stop(ixgbe, B_TRUE);
6146621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
6156621Sbt150084 		/* Disable and stop the watchdog timer */
6166621Sbt150084 		ixgbe_disable_watchdog_timer(ixgbe);
61711233SPaul.Guo@Sun.COM 	}
6186621Sbt150084 
6196621Sbt150084 	/*
6206621Sbt150084 	 * Check if there are still rx buffers held by the upper layer.
6216621Sbt150084 	 * If so, fail the detach.
6226621Sbt150084 	 */
6236621Sbt150084 	if (!ixgbe_rx_drain(ixgbe))
6246621Sbt150084 		return (DDI_FAILURE);
6256621Sbt150084 
6266621Sbt150084 	/*
6276621Sbt150084 	 * Do the remaining unconfigure routines
6286621Sbt150084 	 */
6296621Sbt150084 	ixgbe_unconfigure(devinfo, ixgbe);
6306621Sbt150084 
6316621Sbt150084 	return (DDI_SUCCESS);
6326621Sbt150084 }
6336621Sbt150084 
6346621Sbt150084 static void
6356621Sbt150084 ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe)
6366621Sbt150084 {
6376621Sbt150084 	/*
6386621Sbt150084 	 * Disable interrupt
6396621Sbt150084 	 */
6406621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
6416621Sbt150084 		(void) ixgbe_disable_intrs(ixgbe);
6426621Sbt150084 	}
6436621Sbt150084 
6446621Sbt150084 	/*
64511233SPaul.Guo@Sun.COM 	 * remove the link check timer
64611233SPaul.Guo@Sun.COM 	 */
64711233SPaul.Guo@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) {
64811233SPaul.Guo@Sun.COM 		if (ixgbe->periodic_id != NULL) {
64911233SPaul.Guo@Sun.COM 			ddi_periodic_delete(ixgbe->periodic_id);
65011233SPaul.Guo@Sun.COM 			ixgbe->periodic_id = NULL;
65111233SPaul.Guo@Sun.COM 		}
65211233SPaul.Guo@Sun.COM 	}
65311233SPaul.Guo@Sun.COM 
65411233SPaul.Guo@Sun.COM 	/*
6556621Sbt150084 	 * Unregister MAC
6566621Sbt150084 	 */
6576621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) {
6586621Sbt150084 		(void) mac_unregister(ixgbe->mac_hdl);
6596621Sbt150084 	}
6606621Sbt150084 
6616621Sbt150084 	/*
6626621Sbt150084 	 * Free statistics
6636621Sbt150084 	 */
6646621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) {
6656621Sbt150084 		kstat_delete((kstat_t *)ixgbe->ixgbe_ks);
6666621Sbt150084 	}
6676621Sbt150084 
6686621Sbt150084 	/*
6696621Sbt150084 	 * Remove interrupt handlers
6706621Sbt150084 	 */
6716621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
6726621Sbt150084 		ixgbe_rem_intr_handlers(ixgbe);
6736621Sbt150084 	}
6746621Sbt150084 
6756621Sbt150084 	/*
67611233SPaul.Guo@Sun.COM 	 * Remove taskq for sfp-status-change
6778490SPaul.Guo@Sun.COM 	 */
67811233SPaul.Guo@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) {
67911233SPaul.Guo@Sun.COM 		ddi_taskq_destroy(ixgbe->sfp_taskq);
6808490SPaul.Guo@Sun.COM 	}
6818490SPaul.Guo@Sun.COM 
6828490SPaul.Guo@Sun.COM 	/*
6836621Sbt150084 	 * Remove interrupts
6846621Sbt150084 	 */
6856621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) {
6866621Sbt150084 		ixgbe_rem_intrs(ixgbe);
6876621Sbt150084 	}
6886621Sbt150084 
6896621Sbt150084 	/*
69011878SVenu.Iyer@Sun.COM 	 * Unregister interrupt callback handler
69111878SVenu.Iyer@Sun.COM 	 */
69211878SVenu.Iyer@Sun.COM 	(void) ddi_cb_unregister(ixgbe->cb_hdl);
69311878SVenu.Iyer@Sun.COM 
69411878SVenu.Iyer@Sun.COM 	/*
6956621Sbt150084 	 * Remove driver properties
6966621Sbt150084 	 */
6976621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) {
6986621Sbt150084 		(void) ddi_prop_remove_all(devinfo);
6996621Sbt150084 	}
7006621Sbt150084 
7016621Sbt150084 	/*
7026621Sbt150084 	 * Stop the chipset
7036621Sbt150084 	 */
7046621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) {
7056621Sbt150084 		mutex_enter(&ixgbe->gen_lock);
7066621Sbt150084 		ixgbe_chip_stop(ixgbe);
7076621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
7086621Sbt150084 	}
7096621Sbt150084 
7106621Sbt150084 	/*
7116621Sbt150084 	 * Free register handle
7126621Sbt150084 	 */
7136621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
7146621Sbt150084 		if (ixgbe->osdep.reg_handle != NULL)
7156621Sbt150084 			ddi_regs_map_free(&ixgbe->osdep.reg_handle);
7166621Sbt150084 	}
7176621Sbt150084 
7186621Sbt150084 	/*
7196621Sbt150084 	 * Free PCI config handle
7206621Sbt150084 	 */
7216621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) {
7226621Sbt150084 		if (ixgbe->osdep.cfg_handle != NULL)
7236621Sbt150084 			pci_config_teardown(&ixgbe->osdep.cfg_handle);
7246621Sbt150084 	}
7256621Sbt150084 
7266621Sbt150084 	/*
7276621Sbt150084 	 * Free locks
7286621Sbt150084 	 */
7296621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) {
7306621Sbt150084 		ixgbe_destroy_locks(ixgbe);
7316621Sbt150084 	}
7326621Sbt150084 
7336621Sbt150084 	/*
7346621Sbt150084 	 * Free the rx/tx rings
7356621Sbt150084 	 */
7366621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) {
7376621Sbt150084 		ixgbe_free_rings(ixgbe);
7386621Sbt150084 	}
7396621Sbt150084 
7406621Sbt150084 	/*
7416621Sbt150084 	 * Unregister FMA capabilities
7426621Sbt150084 	 */
7436621Sbt150084 	if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) {
7446621Sbt150084 		ixgbe_fm_fini(ixgbe);
7456621Sbt150084 	}
7466621Sbt150084 
7476621Sbt150084 	/*
7486621Sbt150084 	 * Free the driver data structure
7496621Sbt150084 	 */
7506621Sbt150084 	kmem_free(ixgbe, sizeof (ixgbe_t));
7516621Sbt150084 
7526621Sbt150084 	ddi_set_driver_private(devinfo, NULL);
7536621Sbt150084 }
7546621Sbt150084 
7556621Sbt150084 /*
7566621Sbt150084  * ixgbe_register_mac - Register the driver and its function pointers with
7576621Sbt150084  * the GLD interface.
7586621Sbt150084  */
7596621Sbt150084 static int
7606621Sbt150084 ixgbe_register_mac(ixgbe_t *ixgbe)
7616621Sbt150084 {
7626621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
7636621Sbt150084 	mac_register_t *mac;
7646621Sbt150084 	int status;
7656621Sbt150084 
7666621Sbt150084 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
7676621Sbt150084 		return (IXGBE_FAILURE);
7686621Sbt150084 
7696621Sbt150084 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
7706621Sbt150084 	mac->m_driver = ixgbe;
7716621Sbt150084 	mac->m_dip = ixgbe->dip;
7726621Sbt150084 	mac->m_src_addr = hw->mac.addr;
7736621Sbt150084 	mac->m_callbacks = &ixgbe_m_callbacks;
7746621Sbt150084 	mac->m_min_sdu = 0;
7756621Sbt150084 	mac->m_max_sdu = ixgbe->default_mtu;
7766621Sbt150084 	mac->m_margin = VLAN_TAGSZ;
77710376SChenlu.Chen@Sun.COM 	mac->m_priv_props = ixgbe_priv_props;
7788275SEric Cheng 	mac->m_v12n = MAC_VIRT_LEVEL1;
7796621Sbt150084 
7806621Sbt150084 	status = mac_register(mac, &ixgbe->mac_hdl);
7816621Sbt150084 
7826621Sbt150084 	mac_free(mac);
7836621Sbt150084 
7846621Sbt150084 	return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE);
7856621Sbt150084 }
7866621Sbt150084 
7876621Sbt150084 /*
7886621Sbt150084  * ixgbe_identify_hardware - Identify the type of the chipset.
7896621Sbt150084  */
7906621Sbt150084 static int
7916621Sbt150084 ixgbe_identify_hardware(ixgbe_t *ixgbe)
7926621Sbt150084 {
7936621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
7946621Sbt150084 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
7956621Sbt150084 
7966621Sbt150084 	/*
7976621Sbt150084 	 * Get the device id
7986621Sbt150084 	 */
7996621Sbt150084 	hw->vendor_id =
8006621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
8016621Sbt150084 	hw->device_id =
8026621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
8036621Sbt150084 	hw->revision_id =
8046621Sbt150084 	    pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
8056621Sbt150084 	hw->subsystem_device_id =
8066621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
8076621Sbt150084 	hw->subsystem_vendor_id =
8086621Sbt150084 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
8096621Sbt150084 
8108490SPaul.Guo@Sun.COM 	/*
8118490SPaul.Guo@Sun.COM 	 * Set the mac type of the adapter based on the device id
8128490SPaul.Guo@Sun.COM 	 */
8138490SPaul.Guo@Sun.COM 	if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) {
8148490SPaul.Guo@Sun.COM 		return (IXGBE_FAILURE);
8158490SPaul.Guo@Sun.COM 	}
8168490SPaul.Guo@Sun.COM 
8178490SPaul.Guo@Sun.COM 	/*
8188490SPaul.Guo@Sun.COM 	 * Install adapter capabilities
8198490SPaul.Guo@Sun.COM 	 */
8208490SPaul.Guo@Sun.COM 	switch (hw->mac.type) {
8218490SPaul.Guo@Sun.COM 	case ixgbe_mac_82598EB:
82212003SPaul.Guo@Sun.COM 		IXGBE_DEBUGLOG_0(ixgbe, "identify 82598 adapter\n");
8238490SPaul.Guo@Sun.COM 		ixgbe->capab = &ixgbe_82598eb_cap;
8248490SPaul.Guo@Sun.COM 
8258490SPaul.Guo@Sun.COM 		if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) {
8268490SPaul.Guo@Sun.COM 			ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
8278490SPaul.Guo@Sun.COM 			ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1;
8288490SPaul.Guo@Sun.COM 		}
8299353SSamuel.Tu@Sun.COM 		ixgbe->capab->other_intr |= IXGBE_EICR_LSC;
8309353SSamuel.Tu@Sun.COM 
8319353SSamuel.Tu@Sun.COM 		break;
8329353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
83312003SPaul.Guo@Sun.COM 		IXGBE_DEBUGLOG_0(ixgbe, "identify 82599 adapter\n");
8349353SSamuel.Tu@Sun.COM 		ixgbe->capab = &ixgbe_82599eb_cap;
8359353SSamuel.Tu@Sun.COM 
8369353SSamuel.Tu@Sun.COM 		ixgbe->capab->other_intr = (IXGBE_EICR_GPI_SDP1 |
8379353SSamuel.Tu@Sun.COM 		    IXGBE_EICR_GPI_SDP2 | IXGBE_EICR_LSC);
8388490SPaul.Guo@Sun.COM 
8398490SPaul.Guo@Sun.COM 		break;
8408490SPaul.Guo@Sun.COM 	default:
84112003SPaul.Guo@Sun.COM 		IXGBE_DEBUGLOG_1(ixgbe,
8428490SPaul.Guo@Sun.COM 		    "adapter not supported in ixgbe_identify_hardware(): %d\n",
8438490SPaul.Guo@Sun.COM 		    hw->mac.type);
8448490SPaul.Guo@Sun.COM 		return (IXGBE_FAILURE);
8458490SPaul.Guo@Sun.COM 	}
8468490SPaul.Guo@Sun.COM 
8476621Sbt150084 	return (IXGBE_SUCCESS);
8486621Sbt150084 }
8496621Sbt150084 
8506621Sbt150084 /*
8516621Sbt150084  * ixgbe_regs_map - Map the device registers.
8526621Sbt150084  *
8536621Sbt150084  */
8546621Sbt150084 static int
8556621Sbt150084 ixgbe_regs_map(ixgbe_t *ixgbe)
8566621Sbt150084 {
8576621Sbt150084 	dev_info_t *devinfo = ixgbe->dip;
8586621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
8596621Sbt150084 	struct ixgbe_osdep *osdep = &ixgbe->osdep;
8606621Sbt150084 	off_t mem_size;
8616621Sbt150084 
8626621Sbt150084 	/*
8636621Sbt150084 	 * First get the size of device registers to be mapped.
8646621Sbt150084 	 */
8659353SSamuel.Tu@Sun.COM 	if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size)
8669353SSamuel.Tu@Sun.COM 	    != DDI_SUCCESS) {
8676621Sbt150084 		return (IXGBE_FAILURE);
8686621Sbt150084 	}
8696621Sbt150084 
8706621Sbt150084 	/*
8716621Sbt150084 	 * Call ddi_regs_map_setup() to map registers
8726621Sbt150084 	 */
8739353SSamuel.Tu@Sun.COM 	if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET,
8746621Sbt150084 	    (caddr_t *)&hw->hw_addr, 0,
8756621Sbt150084 	    mem_size, &ixgbe_regs_acc_attr,
8766621Sbt150084 	    &osdep->reg_handle)) != DDI_SUCCESS) {
8776621Sbt150084 		return (IXGBE_FAILURE);
8786621Sbt150084 	}
8796621Sbt150084 
8806621Sbt150084 	return (IXGBE_SUCCESS);
8816621Sbt150084 }
8826621Sbt150084 
8836621Sbt150084 /*
8846621Sbt150084  * ixgbe_init_properties - Initialize driver properties.
8856621Sbt150084  */
8866621Sbt150084 static void
8876621Sbt150084 ixgbe_init_properties(ixgbe_t *ixgbe)
8886621Sbt150084 {
8896621Sbt150084 	/*
8906621Sbt150084 	 * Get conf file properties, including link settings
8916621Sbt150084 	 * jumbo frames, ring number, descriptor number, etc.
8926621Sbt150084 	 */
8936621Sbt150084 	ixgbe_get_conf(ixgbe);
89410376SChenlu.Chen@Sun.COM 
89510376SChenlu.Chen@Sun.COM 	ixgbe_init_params(ixgbe);
8966621Sbt150084 }
8976621Sbt150084 
8986621Sbt150084 /*
8996621Sbt150084  * ixgbe_init_driver_settings - Initialize driver settings.
9006621Sbt150084  *
9016621Sbt150084  * The settings include hardware function pointers, bus information,
9026621Sbt150084  * rx/tx rings settings, link state, and any other parameters that
9036621Sbt150084  * need to be setup during driver initialization.
9046621Sbt150084  */
9056621Sbt150084 static int
9066621Sbt150084 ixgbe_init_driver_settings(ixgbe_t *ixgbe)
9076621Sbt150084 {
9086621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
9098275SEric Cheng 	dev_info_t *devinfo = ixgbe->dip;
9106621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
91111878SVenu.Iyer@Sun.COM 	ixgbe_rx_group_t *rx_group;
9126621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
9136621Sbt150084 	uint32_t rx_size;
9146621Sbt150084 	uint32_t tx_size;
91511878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
9166621Sbt150084 	int i;
9176621Sbt150084 
9186621Sbt150084 	/*
9196621Sbt150084 	 * Initialize chipset specific hardware function pointers
9206621Sbt150084 	 */
9216621Sbt150084 	if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) {
9226621Sbt150084 		return (IXGBE_FAILURE);
9236621Sbt150084 	}
9246621Sbt150084 
9256621Sbt150084 	/*
9268275SEric Cheng 	 * Get the system page size
9278275SEric Cheng 	 */
9288275SEric Cheng 	ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1);
9298275SEric Cheng 
9308275SEric Cheng 	/*
9316621Sbt150084 	 * Set rx buffer size
9326621Sbt150084 	 *
9336621Sbt150084 	 * The IP header alignment room is counted in the calculation.
9346621Sbt150084 	 * The rx buffer size is in unit of 1K that is required by the
9356621Sbt150084 	 * chipset hardware.
9366621Sbt150084 	 */
9376621Sbt150084 	rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
9386621Sbt150084 	ixgbe->rx_buf_size = ((rx_size >> 10) +
9396621Sbt150084 	    ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
9406621Sbt150084 
9416621Sbt150084 	/*
9426621Sbt150084 	 * Set tx buffer size
9436621Sbt150084 	 */
9446621Sbt150084 	tx_size = ixgbe->max_frame_size;
9456621Sbt150084 	ixgbe->tx_buf_size = ((tx_size >> 10) +
9466621Sbt150084 	    ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
9476621Sbt150084 
9486621Sbt150084 	/*
94911878SVenu.Iyer@Sun.COM 	 * Initialize rx/tx rings/groups parameters
95011878SVenu.Iyer@Sun.COM 	 */
95111878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
9526621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
9536621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
9546621Sbt150084 		rx_ring->index = i;
9556621Sbt150084 		rx_ring->ixgbe = ixgbe;
95611878SVenu.Iyer@Sun.COM 		rx_ring->group_index = i / ring_per_group;
95711878SVenu.Iyer@Sun.COM 		rx_ring->hw_index = ixgbe_get_hw_rx_index(ixgbe, i);
95811878SVenu.Iyer@Sun.COM 	}
95911878SVenu.Iyer@Sun.COM 
96011878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_rx_groups; i++) {
96111878SVenu.Iyer@Sun.COM 		rx_group = &ixgbe->rx_groups[i];
96211878SVenu.Iyer@Sun.COM 		rx_group->index = i;
96311878SVenu.Iyer@Sun.COM 		rx_group->ixgbe = ixgbe;
9646621Sbt150084 	}
9656621Sbt150084 
9666621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
9676621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
9686621Sbt150084 		tx_ring->index = i;
9696621Sbt150084 		tx_ring->ixgbe = ixgbe;
9706621Sbt150084 		if (ixgbe->tx_head_wb_enable)
9716621Sbt150084 			tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb;
9726621Sbt150084 		else
9736621Sbt150084 			tx_ring->tx_recycle = ixgbe_tx_recycle_legacy;
9746621Sbt150084 
9756621Sbt150084 		tx_ring->ring_size = ixgbe->tx_ring_size;
9766621Sbt150084 		tx_ring->free_list_size = ixgbe->tx_ring_size +
9776621Sbt150084 		    (ixgbe->tx_ring_size >> 1);
9786621Sbt150084 	}
9796621Sbt150084 
9806621Sbt150084 	/*
9816621Sbt150084 	 * Initialize values of interrupt throttling rate
9826621Sbt150084 	 */
9839353SSamuel.Tu@Sun.COM 	for (i = 1; i < MAX_INTR_VECTOR; i++)
9846621Sbt150084 		ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0];
9856621Sbt150084 
9866621Sbt150084 	/*
9876621Sbt150084 	 * The initial link state should be "unknown"
9886621Sbt150084 	 */
9896621Sbt150084 	ixgbe->link_state = LINK_STATE_UNKNOWN;
9909353SSamuel.Tu@Sun.COM 
9916621Sbt150084 	return (IXGBE_SUCCESS);
9926621Sbt150084 }
9936621Sbt150084 
9946621Sbt150084 /*
9956621Sbt150084  * ixgbe_init_locks - Initialize locks.
9966621Sbt150084  */
9976621Sbt150084 static void
9986621Sbt150084 ixgbe_init_locks(ixgbe_t *ixgbe)
9996621Sbt150084 {
10006621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
10016621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
10026621Sbt150084 	int i;
10036621Sbt150084 
10046621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
10056621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
10066621Sbt150084 		mutex_init(&rx_ring->rx_lock, NULL,
10076621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10086621Sbt150084 	}
10096621Sbt150084 
10106621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
10116621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
10126621Sbt150084 		mutex_init(&tx_ring->tx_lock, NULL,
10136621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10146621Sbt150084 		mutex_init(&tx_ring->recycle_lock, NULL,
10156621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10166621Sbt150084 		mutex_init(&tx_ring->tcb_head_lock, NULL,
10176621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10186621Sbt150084 		mutex_init(&tx_ring->tcb_tail_lock, NULL,
10196621Sbt150084 		    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10206621Sbt150084 	}
10216621Sbt150084 
10226621Sbt150084 	mutex_init(&ixgbe->gen_lock, NULL,
10236621Sbt150084 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10246621Sbt150084 
10256621Sbt150084 	mutex_init(&ixgbe->watchdog_lock, NULL,
10266621Sbt150084 	    MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
10276621Sbt150084 }
10286621Sbt150084 
10296621Sbt150084 /*
10306621Sbt150084  * ixgbe_destroy_locks - Destroy locks.
10316621Sbt150084  */
10326621Sbt150084 static void
10336621Sbt150084 ixgbe_destroy_locks(ixgbe_t *ixgbe)
10346621Sbt150084 {
10356621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
10366621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
10376621Sbt150084 	int i;
10386621Sbt150084 
10396621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
10406621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
10416621Sbt150084 		mutex_destroy(&rx_ring->rx_lock);
10426621Sbt150084 	}
10436621Sbt150084 
10446621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
10456621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
10466621Sbt150084 		mutex_destroy(&tx_ring->tx_lock);
10476621Sbt150084 		mutex_destroy(&tx_ring->recycle_lock);
10486621Sbt150084 		mutex_destroy(&tx_ring->tcb_head_lock);
10496621Sbt150084 		mutex_destroy(&tx_ring->tcb_tail_lock);
10506621Sbt150084 	}
10516621Sbt150084 
10526621Sbt150084 	mutex_destroy(&ixgbe->gen_lock);
10536621Sbt150084 	mutex_destroy(&ixgbe->watchdog_lock);
10546621Sbt150084 }
10556621Sbt150084 
10566621Sbt150084 static int
10576621Sbt150084 ixgbe_resume(dev_info_t *devinfo)
10586621Sbt150084 {
10596621Sbt150084 	ixgbe_t *ixgbe;
106011233SPaul.Guo@Sun.COM 	int i;
10616621Sbt150084 
10626621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
10636621Sbt150084 	if (ixgbe == NULL)
10646621Sbt150084 		return (DDI_FAILURE);
10656621Sbt150084 
10666621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
10676621Sbt150084 
10686621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
106910376SChenlu.Chen@Sun.COM 		if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
10706621Sbt150084 			mutex_exit(&ixgbe->gen_lock);
10716621Sbt150084 			return (DDI_FAILURE);
10726621Sbt150084 		}
10736621Sbt150084 
10746621Sbt150084 		/*
10756621Sbt150084 		 * Enable and start the watchdog timer
10766621Sbt150084 		 */
10776621Sbt150084 		ixgbe_enable_watchdog_timer(ixgbe);
10786621Sbt150084 	}
10796621Sbt150084 
108011233SPaul.Guo@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED);
108111233SPaul.Guo@Sun.COM 
108211233SPaul.Guo@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_STARTED) {
108311233SPaul.Guo@Sun.COM 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
108411233SPaul.Guo@Sun.COM 			mac_tx_ring_update(ixgbe->mac_hdl,
108511233SPaul.Guo@Sun.COM 			    ixgbe->tx_rings[i].ring_handle);
108611233SPaul.Guo@Sun.COM 		}
108711233SPaul.Guo@Sun.COM 	}
10886621Sbt150084 
10896621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
10906621Sbt150084 
10916621Sbt150084 	return (DDI_SUCCESS);
10926621Sbt150084 }
10936621Sbt150084 
10946621Sbt150084 static int
10956621Sbt150084 ixgbe_suspend(dev_info_t *devinfo)
10966621Sbt150084 {
10976621Sbt150084 	ixgbe_t *ixgbe;
10986621Sbt150084 
10996621Sbt150084 	ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
11006621Sbt150084 	if (ixgbe == NULL)
11016621Sbt150084 		return (DDI_FAILURE);
11026621Sbt150084 
11036621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
11046621Sbt150084 
110511233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED);
110610376SChenlu.Chen@Sun.COM 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
110710376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
110810376SChenlu.Chen@Sun.COM 		return (DDI_SUCCESS);
110910376SChenlu.Chen@Sun.COM 	}
111010376SChenlu.Chen@Sun.COM 	ixgbe_stop(ixgbe, B_FALSE);
11116621Sbt150084 
11126621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
11136621Sbt150084 
11146621Sbt150084 	/*
11156621Sbt150084 	 * Disable and stop the watchdog timer
11166621Sbt150084 	 */
11176621Sbt150084 	ixgbe_disable_watchdog_timer(ixgbe);
11186621Sbt150084 
11196621Sbt150084 	return (DDI_SUCCESS);
11206621Sbt150084 }
11216621Sbt150084 
11226621Sbt150084 /*
11236621Sbt150084  * ixgbe_init - Initialize the device.
11246621Sbt150084  */
11256621Sbt150084 static int
11266621Sbt150084 ixgbe_init(ixgbe_t *ixgbe)
11276621Sbt150084 {
11286621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
11296621Sbt150084 
11306621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
11316621Sbt150084 
11326621Sbt150084 	/*
11336621Sbt150084 	 * Reset chipset to put the hardware in a known state
11346621Sbt150084 	 * before we try to do anything with the eeprom.
11356621Sbt150084 	 */
11366621Sbt150084 	if (ixgbe_reset_hw(hw) != IXGBE_SUCCESS) {
11376621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11386621Sbt150084 		goto init_fail;
11396621Sbt150084 	}
11406621Sbt150084 
11416621Sbt150084 	/*
11426621Sbt150084 	 * Need to init eeprom before validating the checksum.
11436621Sbt150084 	 */
11446621Sbt150084 	if (ixgbe_init_eeprom_params(hw) < 0) {
11456621Sbt150084 		ixgbe_error(ixgbe,
11466621Sbt150084 		    "Unable to intitialize the eeprom interface.");
11476621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11486621Sbt150084 		goto init_fail;
11496621Sbt150084 	}
11506621Sbt150084 
11516621Sbt150084 	/*
11526621Sbt150084 	 * NVM validation
11536621Sbt150084 	 */
11546621Sbt150084 	if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
11556621Sbt150084 		/*
11566621Sbt150084 		 * Some PCI-E parts fail the first check due to
11576621Sbt150084 		 * the link being in sleep state.  Call it again,
11586621Sbt150084 		 * if it fails a second time it's a real issue.
11596621Sbt150084 		 */
11606621Sbt150084 		if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
11616621Sbt150084 			ixgbe_error(ixgbe,
11626621Sbt150084 			    "Invalid NVM checksum. Please contact "
11636621Sbt150084 			    "the vendor to update the NVM.");
11646621Sbt150084 			ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11656621Sbt150084 			goto init_fail;
11666621Sbt150084 		}
11676621Sbt150084 	}
11686621Sbt150084 
11696621Sbt150084 	/*
11706621Sbt150084 	 * Setup default flow control thresholds - enable/disable
11716621Sbt150084 	 * & flow control type is controlled by ixgbe.conf
11726621Sbt150084 	 */
11736621Sbt150084 	hw->fc.high_water = DEFAULT_FCRTH;
11746621Sbt150084 	hw->fc.low_water = DEFAULT_FCRTL;
11756621Sbt150084 	hw->fc.pause_time = DEFAULT_FCPAUSE;
11766621Sbt150084 	hw->fc.send_xon = B_TRUE;
11776621Sbt150084 
11786621Sbt150084 	/*
11796621Sbt150084 	 * Initialize link settings
11806621Sbt150084 	 */
11816621Sbt150084 	(void) ixgbe_driver_setup_link(ixgbe, B_FALSE);
11826621Sbt150084 
11836621Sbt150084 	/*
11846621Sbt150084 	 * Initialize the chipset hardware
11856621Sbt150084 	 */
11866621Sbt150084 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
11876621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
11886621Sbt150084 		goto init_fail;
11896621Sbt150084 	}
11906621Sbt150084 
11916621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
11926621Sbt150084 		goto init_fail;
11936621Sbt150084 	}
11946621Sbt150084 
11956621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
11966621Sbt150084 	return (IXGBE_SUCCESS);
11976621Sbt150084 
11986621Sbt150084 init_fail:
11996621Sbt150084 	/*
12006621Sbt150084 	 * Reset PHY
12016621Sbt150084 	 */
12026621Sbt150084 	(void) ixgbe_reset_phy(hw);
12036621Sbt150084 
12046621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
12056621Sbt150084 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
12066621Sbt150084 	return (IXGBE_FAILURE);
12076621Sbt150084 }
12086621Sbt150084 
12096621Sbt150084 /*
12106621Sbt150084  * ixgbe_chip_start - Initialize and start the chipset hardware.
12116621Sbt150084  */
12126621Sbt150084 static int
12136621Sbt150084 ixgbe_chip_start(ixgbe_t *ixgbe)
12146621Sbt150084 {
12156621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
121610305SPaul.Guo@Sun.COM 	int ret_val, i;
12176621Sbt150084 
12186621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
12196621Sbt150084 
12206621Sbt150084 	/*
12216621Sbt150084 	 * Get the mac address
12226621Sbt150084 	 * This function should handle SPARC case correctly.
12236621Sbt150084 	 */
12246621Sbt150084 	if (!ixgbe_find_mac_address(ixgbe)) {
12256621Sbt150084 		ixgbe_error(ixgbe, "Failed to get the mac address");
12266621Sbt150084 		return (IXGBE_FAILURE);
12276621Sbt150084 	}
12286621Sbt150084 
12296621Sbt150084 	/*
12306621Sbt150084 	 * Validate the mac address
12316621Sbt150084 	 */
12326621Sbt150084 	(void) ixgbe_init_rx_addrs(hw);
12336621Sbt150084 	if (!is_valid_mac_addr(hw->mac.addr)) {
12346621Sbt150084 		ixgbe_error(ixgbe, "Invalid mac address");
12356621Sbt150084 		return (IXGBE_FAILURE);
12366621Sbt150084 	}
12376621Sbt150084 
12386621Sbt150084 	/*
12396621Sbt150084 	 * Configure/Initialize hardware
12406621Sbt150084 	 */
124110305SPaul.Guo@Sun.COM 	ret_val = ixgbe_init_hw(hw);
124210305SPaul.Guo@Sun.COM 	if (ret_val != IXGBE_SUCCESS) {
124310305SPaul.Guo@Sun.COM 		if (ret_val == IXGBE_ERR_EEPROM_VERSION) {
124410305SPaul.Guo@Sun.COM 			ixgbe_error(ixgbe,
124510305SPaul.Guo@Sun.COM 			    "This 82599 device is pre-release and contains"
124610305SPaul.Guo@Sun.COM 			    " outdated firmware, please contact your hardware"
124710305SPaul.Guo@Sun.COM 			    " vendor for a replacement.");
124810305SPaul.Guo@Sun.COM 		} else {
124910305SPaul.Guo@Sun.COM 			ixgbe_error(ixgbe, "Failed to initialize hardware");
125010305SPaul.Guo@Sun.COM 			return (IXGBE_FAILURE);
125110305SPaul.Guo@Sun.COM 		}
12526621Sbt150084 	}
12536621Sbt150084 
12546621Sbt150084 	/*
125512003SPaul.Guo@Sun.COM 	 * Re-enable relaxed ordering for performance.  It is disabled
125612003SPaul.Guo@Sun.COM 	 * by default in the hardware init.
125712003SPaul.Guo@Sun.COM 	 */
125812003SPaul.Guo@Sun.COM 	ixgbe_enable_relaxed_ordering(hw);
125912003SPaul.Guo@Sun.COM 
126012003SPaul.Guo@Sun.COM 	/*
12616621Sbt150084 	 * Setup adapter interrupt vectors
12626621Sbt150084 	 */
12636621Sbt150084 	ixgbe_setup_adapter_vector(ixgbe);
12646621Sbt150084 
12656621Sbt150084 	/*
12666621Sbt150084 	 * Initialize unicast addresses.
12676621Sbt150084 	 */
12686621Sbt150084 	ixgbe_init_unicst(ixgbe);
12696621Sbt150084 
12706621Sbt150084 	/*
12716621Sbt150084 	 * Setup and initialize the mctable structures.
12726621Sbt150084 	 */
12736621Sbt150084 	ixgbe_setup_multicst(ixgbe);
12746621Sbt150084 
12756621Sbt150084 	/*
12766621Sbt150084 	 * Set interrupt throttling rate
12776621Sbt150084 	 */
12789353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->intr_cnt; i++) {
12796621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]);
12809353SSamuel.Tu@Sun.COM 	}
12816621Sbt150084 
12826621Sbt150084 	/*
12836621Sbt150084 	 * Save the state of the phy
12846621Sbt150084 	 */
12856621Sbt150084 	ixgbe_get_hw_state(ixgbe);
12866621Sbt150084 
12876621Sbt150084 	/*
12886621Sbt150084 	 * Make sure driver has control
12896621Sbt150084 	 */
12906621Sbt150084 	ixgbe_get_driver_control(hw);
12916621Sbt150084 
12926621Sbt150084 	return (IXGBE_SUCCESS);
12936621Sbt150084 }
12946621Sbt150084 
12956621Sbt150084 /*
12966621Sbt150084  * ixgbe_chip_stop - Stop the chipset hardware
12976621Sbt150084  */
12986621Sbt150084 static void
12996621Sbt150084 ixgbe_chip_stop(ixgbe_t *ixgbe)
13006621Sbt150084 {
13016621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
13026621Sbt150084 
13036621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
13046621Sbt150084 
13056621Sbt150084 	/*
13066621Sbt150084 	 * Tell firmware driver is no longer in control
13076621Sbt150084 	 */
13086621Sbt150084 	ixgbe_release_driver_control(hw);
13096621Sbt150084 
13106621Sbt150084 	/*
13116621Sbt150084 	 * Reset the chipset
13126621Sbt150084 	 */
13136621Sbt150084 	(void) ixgbe_reset_hw(hw);
13146621Sbt150084 
13156621Sbt150084 	/*
13166621Sbt150084 	 * Reset PHY
13176621Sbt150084 	 */
13186621Sbt150084 	(void) ixgbe_reset_phy(hw);
13196621Sbt150084 }
13206621Sbt150084 
13216621Sbt150084 /*
13226621Sbt150084  * ixgbe_reset - Reset the chipset and re-start the driver.
13236621Sbt150084  *
13246621Sbt150084  * It involves stopping and re-starting the chipset,
13256621Sbt150084  * and re-configuring the rx/tx rings.
13266621Sbt150084  */
13276621Sbt150084 static int
13286621Sbt150084 ixgbe_reset(ixgbe_t *ixgbe)
13296621Sbt150084 {
133011233SPaul.Guo@Sun.COM 	int i;
133111233SPaul.Guo@Sun.COM 
133210376SChenlu.Chen@Sun.COM 	/*
133310376SChenlu.Chen@Sun.COM 	 * Disable and stop the watchdog timer
133410376SChenlu.Chen@Sun.COM 	 */
133510376SChenlu.Chen@Sun.COM 	ixgbe_disable_watchdog_timer(ixgbe);
13366621Sbt150084 
13376621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
13386621Sbt150084 
13396621Sbt150084 	ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED);
134011233SPaul.Guo@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
13416621Sbt150084 
134210376SChenlu.Chen@Sun.COM 	ixgbe_stop(ixgbe, B_FALSE);
134310376SChenlu.Chen@Sun.COM 
134410376SChenlu.Chen@Sun.COM 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
134510376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
134610376SChenlu.Chen@Sun.COM 		return (IXGBE_FAILURE);
13476621Sbt150084 	}
13486621Sbt150084 
134911233SPaul.Guo@Sun.COM 	/*
135011233SPaul.Guo@Sun.COM 	 * After resetting, need to recheck the link status.
135111233SPaul.Guo@Sun.COM 	 */
135211233SPaul.Guo@Sun.COM 	ixgbe->link_check_complete = B_FALSE;
135311233SPaul.Guo@Sun.COM 	ixgbe->link_check_hrtime = gethrtime() +
135411233SPaul.Guo@Sun.COM 	    (IXGBE_LINK_UP_TIME * 100000000ULL);
135511233SPaul.Guo@Sun.COM 
135611233SPaul.Guo@Sun.COM 	atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED);
135711233SPaul.Guo@Sun.COM 
135811233SPaul.Guo@Sun.COM 	if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) {
135911233SPaul.Guo@Sun.COM 		for (i = 0; i < ixgbe->num_tx_rings; i++) {
136011233SPaul.Guo@Sun.COM 			mac_tx_ring_update(ixgbe->mac_hdl,
136111233SPaul.Guo@Sun.COM 			    ixgbe->tx_rings[i].ring_handle);
136211233SPaul.Guo@Sun.COM 		}
136311233SPaul.Guo@Sun.COM 	}
136411233SPaul.Guo@Sun.COM 
13656621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
13666621Sbt150084 
136710376SChenlu.Chen@Sun.COM 	/*
136810376SChenlu.Chen@Sun.COM 	 * Enable and start the watchdog timer
136910376SChenlu.Chen@Sun.COM 	 */
137010376SChenlu.Chen@Sun.COM 	ixgbe_enable_watchdog_timer(ixgbe);
137110376SChenlu.Chen@Sun.COM 
13726621Sbt150084 	return (IXGBE_SUCCESS);
13736621Sbt150084 }
13746621Sbt150084 
13756621Sbt150084 /*
13766621Sbt150084  * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources.
13776621Sbt150084  */
13786621Sbt150084 static void
13796621Sbt150084 ixgbe_tx_clean(ixgbe_t *ixgbe)
13806621Sbt150084 {
13816621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
13826621Sbt150084 	tx_control_block_t *tcb;
13836621Sbt150084 	link_list_t pending_list;
13846621Sbt150084 	uint32_t desc_num;
13856621Sbt150084 	int i, j;
13866621Sbt150084 
13876621Sbt150084 	LINK_LIST_INIT(&pending_list);
13886621Sbt150084 
13896621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
13906621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
13916621Sbt150084 
13926621Sbt150084 		mutex_enter(&tx_ring->recycle_lock);
13936621Sbt150084 
13946621Sbt150084 		/*
13956621Sbt150084 		 * Clean the pending tx data - the pending packets in the
13966621Sbt150084 		 * work_list that have no chances to be transmitted again.
13976621Sbt150084 		 *
13986621Sbt150084 		 * We must ensure the chipset is stopped or the link is down
13996621Sbt150084 		 * before cleaning the transmit packets.
14006621Sbt150084 		 */
14016621Sbt150084 		desc_num = 0;
14026621Sbt150084 		for (j = 0; j < tx_ring->ring_size; j++) {
14036621Sbt150084 			tcb = tx_ring->work_list[j];
14046621Sbt150084 			if (tcb != NULL) {
14056621Sbt150084 				desc_num += tcb->desc_num;
14066621Sbt150084 
14076621Sbt150084 				tx_ring->work_list[j] = NULL;
14086621Sbt150084 
14096621Sbt150084 				ixgbe_free_tcb(tcb);
14106621Sbt150084 
14116621Sbt150084 				LIST_PUSH_TAIL(&pending_list, &tcb->link);
14126621Sbt150084 			}
14136621Sbt150084 		}
14146621Sbt150084 
14156621Sbt150084 		if (desc_num > 0) {
14166621Sbt150084 			atomic_add_32(&tx_ring->tbd_free, desc_num);
14176621Sbt150084 			ASSERT(tx_ring->tbd_free == tx_ring->ring_size);
14186621Sbt150084 
14196621Sbt150084 			/*
14206621Sbt150084 			 * Reset the head and tail pointers of the tbd ring;
14216621Sbt150084 			 * Reset the writeback head if it's enable.
14226621Sbt150084 			 */
14236621Sbt150084 			tx_ring->tbd_head = 0;
14246621Sbt150084 			tx_ring->tbd_tail = 0;
14256621Sbt150084 			if (ixgbe->tx_head_wb_enable)
14266621Sbt150084 				*tx_ring->tbd_head_wb = 0;
14276621Sbt150084 
14286621Sbt150084 			IXGBE_WRITE_REG(&ixgbe->hw,
14296621Sbt150084 			    IXGBE_TDH(tx_ring->index), 0);
14306621Sbt150084 			IXGBE_WRITE_REG(&ixgbe->hw,
14316621Sbt150084 			    IXGBE_TDT(tx_ring->index), 0);
14326621Sbt150084 		}
14336621Sbt150084 
14346621Sbt150084 		mutex_exit(&tx_ring->recycle_lock);
14356621Sbt150084 
14366621Sbt150084 		/*
14376621Sbt150084 		 * Add the tx control blocks in the pending list to
14386621Sbt150084 		 * the free list.
14396621Sbt150084 		 */
14406621Sbt150084 		ixgbe_put_free_list(tx_ring, &pending_list);
14416621Sbt150084 	}
14426621Sbt150084 }
14436621Sbt150084 
14446621Sbt150084 /*
14456621Sbt150084  * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be
14466621Sbt150084  * transmitted.
14476621Sbt150084  */
14486621Sbt150084 static boolean_t
14496621Sbt150084 ixgbe_tx_drain(ixgbe_t *ixgbe)
14506621Sbt150084 {
14516621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
14526621Sbt150084 	boolean_t done;
14536621Sbt150084 	int i, j;
14546621Sbt150084 
14556621Sbt150084 	/*
14566621Sbt150084 	 * Wait for a specific time to allow pending tx packets
14576621Sbt150084 	 * to be transmitted.
14586621Sbt150084 	 *
14596621Sbt150084 	 * Check the counter tbd_free to see if transmission is done.
14606621Sbt150084 	 * No lock protection is needed here.
14616621Sbt150084 	 *
14626621Sbt150084 	 * Return B_TRUE if all pending packets have been transmitted;
14636621Sbt150084 	 * Otherwise return B_FALSE;
14646621Sbt150084 	 */
14656621Sbt150084 	for (i = 0; i < TX_DRAIN_TIME; i++) {
14666621Sbt150084 
14676621Sbt150084 		done = B_TRUE;
14686621Sbt150084 		for (j = 0; j < ixgbe->num_tx_rings; j++) {
14696621Sbt150084 			tx_ring = &ixgbe->tx_rings[j];
14706621Sbt150084 			done = done &&
14716621Sbt150084 			    (tx_ring->tbd_free == tx_ring->ring_size);
14726621Sbt150084 		}
14736621Sbt150084 
14746621Sbt150084 		if (done)
14756621Sbt150084 			break;
14766621Sbt150084 
14776621Sbt150084 		msec_delay(1);
14786621Sbt150084 	}
14796621Sbt150084 
14806621Sbt150084 	return (done);
14816621Sbt150084 }
14826621Sbt150084 
14836621Sbt150084 /*
14846621Sbt150084  * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer.
14856621Sbt150084  */
14866621Sbt150084 static boolean_t
14876621Sbt150084 ixgbe_rx_drain(ixgbe_t *ixgbe)
14886621Sbt150084 {
148910376SChenlu.Chen@Sun.COM 	boolean_t done = B_TRUE;
149010376SChenlu.Chen@Sun.COM 	int i;
14916621Sbt150084 
14926621Sbt150084 	/*
14936621Sbt150084 	 * Polling the rx free list to check if those rx buffers held by
14946621Sbt150084 	 * the upper layer are released.
14956621Sbt150084 	 *
14966621Sbt150084 	 * Check the counter rcb_free to see if all pending buffers are
14976621Sbt150084 	 * released. No lock protection is needed here.
14986621Sbt150084 	 *
14996621Sbt150084 	 * Return B_TRUE if all pending buffers have been released;
15006621Sbt150084 	 * Otherwise return B_FALSE;
15016621Sbt150084 	 */
15026621Sbt150084 	for (i = 0; i < RX_DRAIN_TIME; i++) {
150310376SChenlu.Chen@Sun.COM 		done = (ixgbe->rcb_pending == 0);
15046621Sbt150084 
15056621Sbt150084 		if (done)
15066621Sbt150084 			break;
15076621Sbt150084 
15086621Sbt150084 		msec_delay(1);
15096621Sbt150084 	}
15106621Sbt150084 
15116621Sbt150084 	return (done);
15126621Sbt150084 }
15136621Sbt150084 
15146621Sbt150084 /*
15156621Sbt150084  * ixgbe_start - Start the driver/chipset.
15166621Sbt150084  */
15176621Sbt150084 int
151810376SChenlu.Chen@Sun.COM ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer)
15196621Sbt150084 {
15206621Sbt150084 	int i;
15216621Sbt150084 
15226621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
15236621Sbt150084 
152410376SChenlu.Chen@Sun.COM 	if (alloc_buffer) {
152510376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) {
152610376SChenlu.Chen@Sun.COM 			ixgbe_error(ixgbe,
152710376SChenlu.Chen@Sun.COM 			    "Failed to allocate software receive rings");
152810376SChenlu.Chen@Sun.COM 			return (IXGBE_FAILURE);
152910376SChenlu.Chen@Sun.COM 		}
153010376SChenlu.Chen@Sun.COM 
153110376SChenlu.Chen@Sun.COM 		/* Allocate buffers for all the rx/tx rings */
153210376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) {
153310376SChenlu.Chen@Sun.COM 			ixgbe_error(ixgbe, "Failed to allocate DMA resource");
153410376SChenlu.Chen@Sun.COM 			return (IXGBE_FAILURE);
153510376SChenlu.Chen@Sun.COM 		}
153610376SChenlu.Chen@Sun.COM 
153710376SChenlu.Chen@Sun.COM 		ixgbe->tx_ring_init = B_TRUE;
153810376SChenlu.Chen@Sun.COM 	} else {
153910376SChenlu.Chen@Sun.COM 		ixgbe->tx_ring_init = B_FALSE;
154010376SChenlu.Chen@Sun.COM 	}
154110376SChenlu.Chen@Sun.COM 
15426621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++)
15436621Sbt150084 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
15446621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++)
15456621Sbt150084 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
15466621Sbt150084 
15476621Sbt150084 	/*
15486621Sbt150084 	 * Start the chipset hardware
15496621Sbt150084 	 */
15506621Sbt150084 	if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
15516621Sbt150084 		ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
15526621Sbt150084 		goto start_failure;
15536621Sbt150084 	}
15546621Sbt150084 
15556621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
15566621Sbt150084 		goto start_failure;
15576621Sbt150084 	}
15586621Sbt150084 
15596621Sbt150084 	/*
15606621Sbt150084 	 * Setup the rx/tx rings
15616621Sbt150084 	 */
15626621Sbt150084 	ixgbe_setup_rings(ixgbe);
15636621Sbt150084 
15646621Sbt150084 	/*
156511233SPaul.Guo@Sun.COM 	 * ixgbe_start() will be called when resetting, however if reset
156611233SPaul.Guo@Sun.COM 	 * happens, we need to clear the ERROR and STALL flags before
156711233SPaul.Guo@Sun.COM 	 * enabling the interrupts.
156811233SPaul.Guo@Sun.COM 	 */
156911233SPaul.Guo@Sun.COM 	atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR | IXGBE_STALL));
157011233SPaul.Guo@Sun.COM 
157111233SPaul.Guo@Sun.COM 	/*
15726621Sbt150084 	 * Enable adapter interrupts
15736621Sbt150084 	 * The interrupts must be enabled after the driver state is START
15746621Sbt150084 	 */
15756621Sbt150084 	ixgbe_enable_adapter_interrupts(ixgbe);
15766621Sbt150084 
15776621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
15786621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
15796621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
15806621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
15816621Sbt150084 
15826621Sbt150084 	return (IXGBE_SUCCESS);
15836621Sbt150084 
15846621Sbt150084 start_failure:
15856621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
15866621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
15876621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
15886621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
15896621Sbt150084 
15906621Sbt150084 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
15916621Sbt150084 
15926621Sbt150084 	return (IXGBE_FAILURE);
15936621Sbt150084 }
15946621Sbt150084 
15956621Sbt150084 /*
15966621Sbt150084  * ixgbe_stop - Stop the driver/chipset.
15976621Sbt150084  */
15986621Sbt150084 void
159910376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer)
16006621Sbt150084 {
16016621Sbt150084 	int i;
16026621Sbt150084 
16036621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
16046621Sbt150084 
16056621Sbt150084 	/*
16066621Sbt150084 	 * Disable the adapter interrupts
16076621Sbt150084 	 */
16086621Sbt150084 	ixgbe_disable_adapter_interrupts(ixgbe);
16096621Sbt150084 
16106621Sbt150084 	/*
16116621Sbt150084 	 * Drain the pending tx packets
16126621Sbt150084 	 */
16136621Sbt150084 	(void) ixgbe_tx_drain(ixgbe);
16146621Sbt150084 
16156621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++)
16166621Sbt150084 		mutex_enter(&ixgbe->rx_rings[i].rx_lock);
16176621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++)
16186621Sbt150084 		mutex_enter(&ixgbe->tx_rings[i].tx_lock);
16196621Sbt150084 
16206621Sbt150084 	/*
16216621Sbt150084 	 * Stop the chipset hardware
16226621Sbt150084 	 */
16236621Sbt150084 	ixgbe_chip_stop(ixgbe);
16246621Sbt150084 
16256621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
16266621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
16276621Sbt150084 	}
16286621Sbt150084 
16296621Sbt150084 	/*
16306621Sbt150084 	 * Clean the pending tx data/resources
16316621Sbt150084 	 */
16326621Sbt150084 	ixgbe_tx_clean(ixgbe);
16336621Sbt150084 
16346621Sbt150084 	for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
16356621Sbt150084 		mutex_exit(&ixgbe->tx_rings[i].tx_lock);
16366621Sbt150084 	for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
16376621Sbt150084 		mutex_exit(&ixgbe->rx_rings[i].rx_lock);
163810376SChenlu.Chen@Sun.COM 
163910376SChenlu.Chen@Sun.COM 	if (ixgbe->link_state == LINK_STATE_UP) {
164010376SChenlu.Chen@Sun.COM 		ixgbe->link_state = LINK_STATE_UNKNOWN;
164110376SChenlu.Chen@Sun.COM 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
164210376SChenlu.Chen@Sun.COM 	}
164310376SChenlu.Chen@Sun.COM 
164410376SChenlu.Chen@Sun.COM 	if (free_buffer) {
164510376SChenlu.Chen@Sun.COM 		/*
164610376SChenlu.Chen@Sun.COM 		 * Release the DMA/memory resources of rx/tx rings
164710376SChenlu.Chen@Sun.COM 		 */
164810376SChenlu.Chen@Sun.COM 		ixgbe_free_dma(ixgbe);
164910376SChenlu.Chen@Sun.COM 		ixgbe_free_rx_data(ixgbe);
165010376SChenlu.Chen@Sun.COM 	}
16516621Sbt150084 }
16526621Sbt150084 
16536621Sbt150084 /*
165411878SVenu.Iyer@Sun.COM  * ixgbe_cbfunc - Driver interface for generic DDI callbacks
165511878SVenu.Iyer@Sun.COM  */
165611878SVenu.Iyer@Sun.COM /* ARGSUSED */
165711878SVenu.Iyer@Sun.COM static int
165811878SVenu.Iyer@Sun.COM ixgbe_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
165911878SVenu.Iyer@Sun.COM     void *arg1, void *arg2)
166011878SVenu.Iyer@Sun.COM {
166111878SVenu.Iyer@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
166211878SVenu.Iyer@Sun.COM 
166311878SVenu.Iyer@Sun.COM 	switch (cbaction) {
166411878SVenu.Iyer@Sun.COM 	/* IRM callback */
166511878SVenu.Iyer@Sun.COM 	int count;
166611878SVenu.Iyer@Sun.COM 	case DDI_CB_INTR_ADD:
166711878SVenu.Iyer@Sun.COM 	case DDI_CB_INTR_REMOVE:
166811878SVenu.Iyer@Sun.COM 		count = (int)(uintptr_t)cbarg;
166911878SVenu.Iyer@Sun.COM 		ASSERT(ixgbe->intr_type == DDI_INTR_TYPE_MSIX);
167011878SVenu.Iyer@Sun.COM 		DTRACE_PROBE2(ixgbe__irm__callback, int, count,
167111878SVenu.Iyer@Sun.COM 		    int, ixgbe->intr_cnt);
167211878SVenu.Iyer@Sun.COM 		if (ixgbe_intr_adjust(ixgbe, cbaction, count) !=
167311878SVenu.Iyer@Sun.COM 		    DDI_SUCCESS) {
167411878SVenu.Iyer@Sun.COM 			ixgbe_error(ixgbe,
167511878SVenu.Iyer@Sun.COM 			    "IRM CB: Failed to adjust interrupts");
167611878SVenu.Iyer@Sun.COM 			goto cb_fail;
167711878SVenu.Iyer@Sun.COM 		}
167811878SVenu.Iyer@Sun.COM 		break;
167911878SVenu.Iyer@Sun.COM 	default:
168011878SVenu.Iyer@Sun.COM 		IXGBE_DEBUGLOG_1(ixgbe, "DDI CB: action 0x%x NOT supported",
168111878SVenu.Iyer@Sun.COM 		    cbaction);
168211878SVenu.Iyer@Sun.COM 		return (DDI_ENOTSUP);
168311878SVenu.Iyer@Sun.COM 	}
168411878SVenu.Iyer@Sun.COM 	return (DDI_SUCCESS);
168511878SVenu.Iyer@Sun.COM cb_fail:
168611878SVenu.Iyer@Sun.COM 	return (DDI_FAILURE);
168711878SVenu.Iyer@Sun.COM }
168811878SVenu.Iyer@Sun.COM 
168911878SVenu.Iyer@Sun.COM /*
169011878SVenu.Iyer@Sun.COM  * ixgbe_intr_adjust - Adjust interrupt to respond to IRM request.
169111878SVenu.Iyer@Sun.COM  */
169211878SVenu.Iyer@Sun.COM static int
169311878SVenu.Iyer@Sun.COM ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count)
169411878SVenu.Iyer@Sun.COM {
169511878SVenu.Iyer@Sun.COM 	int i, rc, actual;
169611878SVenu.Iyer@Sun.COM 
169711878SVenu.Iyer@Sun.COM 	if (count == 0)
169811878SVenu.Iyer@Sun.COM 		return (DDI_SUCCESS);
169911878SVenu.Iyer@Sun.COM 
170011878SVenu.Iyer@Sun.COM 	if ((cbaction == DDI_CB_INTR_ADD &&
170111878SVenu.Iyer@Sun.COM 	    ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) ||
170211878SVenu.Iyer@Sun.COM 	    (cbaction == DDI_CB_INTR_REMOVE &&
170311878SVenu.Iyer@Sun.COM 	    ixgbe->intr_cnt - count < ixgbe->intr_cnt_min))
170411878SVenu.Iyer@Sun.COM 		return (DDI_FAILURE);
170511878SVenu.Iyer@Sun.COM 
170611878SVenu.Iyer@Sun.COM 	if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
170711878SVenu.Iyer@Sun.COM 		return (DDI_FAILURE);
170811878SVenu.Iyer@Sun.COM 	}
170911878SVenu.Iyer@Sun.COM 
171011878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++)
171111878SVenu.Iyer@Sun.COM 		mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL);
171211878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++)
171311878SVenu.Iyer@Sun.COM 		mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL);
171411878SVenu.Iyer@Sun.COM 
171511878SVenu.Iyer@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
171611878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state &= ~IXGBE_STARTED;
171711878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST;
171811878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state |= IXGBE_SUSPENDED;
171911878SVenu.Iyer@Sun.COM 	mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
172011878SVenu.Iyer@Sun.COM 
172111878SVenu.Iyer@Sun.COM 	ixgbe_stop(ixgbe, B_FALSE);
172211878SVenu.Iyer@Sun.COM 	/*
172311878SVenu.Iyer@Sun.COM 	 * Disable interrupts
172411878SVenu.Iyer@Sun.COM 	 */
172511878SVenu.Iyer@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
172611878SVenu.Iyer@Sun.COM 		rc = ixgbe_disable_intrs(ixgbe);
172711878SVenu.Iyer@Sun.COM 		ASSERT(rc == IXGBE_SUCCESS);
172811878SVenu.Iyer@Sun.COM 	}
172911878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress &= ~ATTACH_PROGRESS_ENABLE_INTR;
173011878SVenu.Iyer@Sun.COM 
173111878SVenu.Iyer@Sun.COM 	/*
173211878SVenu.Iyer@Sun.COM 	 * Remove interrupt handlers
173311878SVenu.Iyer@Sun.COM 	 */
173411878SVenu.Iyer@Sun.COM 	if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
173511878SVenu.Iyer@Sun.COM 		ixgbe_rem_intr_handlers(ixgbe);
173611878SVenu.Iyer@Sun.COM 	}
173711878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress &= ~ATTACH_PROGRESS_ADD_INTR;
173811878SVenu.Iyer@Sun.COM 
173911878SVenu.Iyer@Sun.COM 	/*
174011878SVenu.Iyer@Sun.COM 	 * Clear vect_map
174111878SVenu.Iyer@Sun.COM 	 */
174211878SVenu.Iyer@Sun.COM 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
174311878SVenu.Iyer@Sun.COM 	switch (cbaction) {
174411878SVenu.Iyer@Sun.COM 	case DDI_CB_INTR_ADD:
174511878SVenu.Iyer@Sun.COM 		rc = ddi_intr_alloc(ixgbe->dip, ixgbe->htable,
174611878SVenu.Iyer@Sun.COM 		    DDI_INTR_TYPE_MSIX, ixgbe->intr_cnt, count, &actual,
174711878SVenu.Iyer@Sun.COM 		    DDI_INTR_ALLOC_NORMAL);
174811878SVenu.Iyer@Sun.COM 		if (rc != DDI_SUCCESS || actual != count) {
174911878SVenu.Iyer@Sun.COM 			ixgbe_log(ixgbe, "Adjust interrupts failed."
175011878SVenu.Iyer@Sun.COM 			    "return: %d, irm cb size: %d, actual: %d",
175111878SVenu.Iyer@Sun.COM 			    rc, count, actual);
175211878SVenu.Iyer@Sun.COM 			goto intr_adjust_fail;
175311878SVenu.Iyer@Sun.COM 		}
175411878SVenu.Iyer@Sun.COM 		ixgbe->intr_cnt += count;
175511878SVenu.Iyer@Sun.COM 		break;
175611878SVenu.Iyer@Sun.COM 
175711878SVenu.Iyer@Sun.COM 	case DDI_CB_INTR_REMOVE:
175811878SVenu.Iyer@Sun.COM 		for (i = ixgbe->intr_cnt - count;
175911878SVenu.Iyer@Sun.COM 		    i < ixgbe->intr_cnt; i ++) {
176011878SVenu.Iyer@Sun.COM 			rc = ddi_intr_free(ixgbe->htable[i]);
176111878SVenu.Iyer@Sun.COM 			ixgbe->htable[i] = NULL;
176211878SVenu.Iyer@Sun.COM 			if (rc != DDI_SUCCESS) {
176311878SVenu.Iyer@Sun.COM 				ixgbe_log(ixgbe, "Adjust interrupts failed."
176411878SVenu.Iyer@Sun.COM 				    "return: %d, irm cb size: %d, actual: %d",
176511878SVenu.Iyer@Sun.COM 				    rc, count, actual);
176611878SVenu.Iyer@Sun.COM 				goto intr_adjust_fail;
176711878SVenu.Iyer@Sun.COM 			}
176811878SVenu.Iyer@Sun.COM 		}
176911878SVenu.Iyer@Sun.COM 		ixgbe->intr_cnt -= count;
177011878SVenu.Iyer@Sun.COM 		break;
177111878SVenu.Iyer@Sun.COM 	}
177211878SVenu.Iyer@Sun.COM 
177311878SVenu.Iyer@Sun.COM 	/*
177411878SVenu.Iyer@Sun.COM 	 * Get priority for first vector, assume remaining are all the same
177511878SVenu.Iyer@Sun.COM 	 */
177611878SVenu.Iyer@Sun.COM 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
177711878SVenu.Iyer@Sun.COM 	if (rc != DDI_SUCCESS) {
177811878SVenu.Iyer@Sun.COM 		ixgbe_log(ixgbe,
177911878SVenu.Iyer@Sun.COM 		    "Get interrupt priority failed: %d", rc);
178011878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
178111878SVenu.Iyer@Sun.COM 	}
178211878SVenu.Iyer@Sun.COM 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
178311878SVenu.Iyer@Sun.COM 	if (rc != DDI_SUCCESS) {
178411878SVenu.Iyer@Sun.COM 		ixgbe_log(ixgbe, "Get interrupt cap failed: %d", rc);
178511878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
178611878SVenu.Iyer@Sun.COM 	}
178711878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
178811878SVenu.Iyer@Sun.COM 
178911878SVenu.Iyer@Sun.COM 	/*
179011878SVenu.Iyer@Sun.COM 	 * Map rings to interrupt vectors
179111878SVenu.Iyer@Sun.COM 	 */
179211878SVenu.Iyer@Sun.COM 	if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
179311878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe,
179411878SVenu.Iyer@Sun.COM 		    "IRM CB: Failed to map interrupts to vectors");
179511878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
179611878SVenu.Iyer@Sun.COM 	}
179711878SVenu.Iyer@Sun.COM 
179811878SVenu.Iyer@Sun.COM 	/*
179911878SVenu.Iyer@Sun.COM 	 * Add interrupt handlers
180011878SVenu.Iyer@Sun.COM 	 */
180111878SVenu.Iyer@Sun.COM 	if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
180211878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe, "IRM CB: Failed to add interrupt handlers");
180311878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
180411878SVenu.Iyer@Sun.COM 	}
180511878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
180611878SVenu.Iyer@Sun.COM 
180711878SVenu.Iyer@Sun.COM 	/*
180811878SVenu.Iyer@Sun.COM 	 * Now that mutex locks are initialized, and the chip is also
180911878SVenu.Iyer@Sun.COM 	 * initialized, enable interrupts.
181011878SVenu.Iyer@Sun.COM 	 */
181111878SVenu.Iyer@Sun.COM 	if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
181211878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts");
181311878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
181411878SVenu.Iyer@Sun.COM 	}
181511878SVenu.Iyer@Sun.COM 	ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
181611878SVenu.Iyer@Sun.COM 	if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
181711878SVenu.Iyer@Sun.COM 		ixgbe_error(ixgbe, "IRM CB: Failed to start");
181811878SVenu.Iyer@Sun.COM 		goto intr_adjust_fail;
181911878SVenu.Iyer@Sun.COM 	}
182011878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST;
182111878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED;
182211878SVenu.Iyer@Sun.COM 	ixgbe->ixgbe_state |= IXGBE_STARTED;
182311878SVenu.Iyer@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
182411878SVenu.Iyer@Sun.COM 
182511878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
182611878SVenu.Iyer@Sun.COM 		mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle,
182711878SVenu.Iyer@Sun.COM 		    ixgbe->htable[ixgbe->rx_rings[i].intr_vector]);
182811878SVenu.Iyer@Sun.COM 	}
182911878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
183011878SVenu.Iyer@Sun.COM 		mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle,
183111878SVenu.Iyer@Sun.COM 		    ixgbe->htable[ixgbe->tx_rings[i].intr_vector]);
183211878SVenu.Iyer@Sun.COM 	}
183311878SVenu.Iyer@Sun.COM 
183411878SVenu.Iyer@Sun.COM 	/* Wakeup all Tx rings */
183511878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
183611878SVenu.Iyer@Sun.COM 		mac_tx_ring_update(ixgbe->mac_hdl,
183711878SVenu.Iyer@Sun.COM 		    ixgbe->tx_rings[i].ring_handle);
183811878SVenu.Iyer@Sun.COM 	}
183911878SVenu.Iyer@Sun.COM 
184011878SVenu.Iyer@Sun.COM 	IXGBE_DEBUGLOG_3(ixgbe,
184111878SVenu.Iyer@Sun.COM 	    "IRM CB: interrupts new value: 0x%x(0x%x:0x%x).",
184211878SVenu.Iyer@Sun.COM 	    ixgbe->intr_cnt, ixgbe->intr_cnt_min, ixgbe->intr_cnt_max);
184311878SVenu.Iyer@Sun.COM 	return (DDI_SUCCESS);
184411878SVenu.Iyer@Sun.COM 
184511878SVenu.Iyer@Sun.COM intr_adjust_fail:
184611878SVenu.Iyer@Sun.COM 	ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
184711878SVenu.Iyer@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
184811878SVenu.Iyer@Sun.COM 	return (DDI_FAILURE);
184911878SVenu.Iyer@Sun.COM }
185011878SVenu.Iyer@Sun.COM 
185111878SVenu.Iyer@Sun.COM /*
185211878SVenu.Iyer@Sun.COM  * ixgbe_intr_cb_register - Register interrupt callback function.
185311878SVenu.Iyer@Sun.COM  */
185411878SVenu.Iyer@Sun.COM static int
185511878SVenu.Iyer@Sun.COM ixgbe_intr_cb_register(ixgbe_t *ixgbe)
185611878SVenu.Iyer@Sun.COM {
185711878SVenu.Iyer@Sun.COM 	if (ddi_cb_register(ixgbe->dip, DDI_CB_FLAG_INTR, ixgbe_cbfunc,
185811878SVenu.Iyer@Sun.COM 	    ixgbe, NULL, &ixgbe->cb_hdl) != DDI_SUCCESS) {
185911878SVenu.Iyer@Sun.COM 		return (IXGBE_FAILURE);
186011878SVenu.Iyer@Sun.COM 	}
186111878SVenu.Iyer@Sun.COM 	IXGBE_DEBUGLOG_0(ixgbe, "Interrupt callback function registered.");
186211878SVenu.Iyer@Sun.COM 	return (IXGBE_SUCCESS);
186311878SVenu.Iyer@Sun.COM }
186411878SVenu.Iyer@Sun.COM 
186511878SVenu.Iyer@Sun.COM /*
18666621Sbt150084  * ixgbe_alloc_rings - Allocate memory space for rx/tx rings.
18676621Sbt150084  */
18686621Sbt150084 static int
18696621Sbt150084 ixgbe_alloc_rings(ixgbe_t *ixgbe)
18706621Sbt150084 {
18716621Sbt150084 	/*
18726621Sbt150084 	 * Allocate memory space for rx rings
18736621Sbt150084 	 */
18746621Sbt150084 	ixgbe->rx_rings = kmem_zalloc(
18756621Sbt150084 	    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings,
18766621Sbt150084 	    KM_NOSLEEP);
18776621Sbt150084 
18786621Sbt150084 	if (ixgbe->rx_rings == NULL) {
18796621Sbt150084 		return (IXGBE_FAILURE);
18806621Sbt150084 	}
18816621Sbt150084 
18826621Sbt150084 	/*
18836621Sbt150084 	 * Allocate memory space for tx rings
18846621Sbt150084 	 */
18856621Sbt150084 	ixgbe->tx_rings = kmem_zalloc(
18866621Sbt150084 	    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings,
18876621Sbt150084 	    KM_NOSLEEP);
18886621Sbt150084 
18896621Sbt150084 	if (ixgbe->tx_rings == NULL) {
18906621Sbt150084 		kmem_free(ixgbe->rx_rings,
18916621Sbt150084 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
18926621Sbt150084 		ixgbe->rx_rings = NULL;
18936621Sbt150084 		return (IXGBE_FAILURE);
18946621Sbt150084 	}
18956621Sbt150084 
18968275SEric Cheng 	/*
18978275SEric Cheng 	 * Allocate memory space for rx ring groups
18988275SEric Cheng 	 */
18998275SEric Cheng 	ixgbe->rx_groups = kmem_zalloc(
19008275SEric Cheng 	    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups,
19018275SEric Cheng 	    KM_NOSLEEP);
19028275SEric Cheng 
19038275SEric Cheng 	if (ixgbe->rx_groups == NULL) {
19048275SEric Cheng 		kmem_free(ixgbe->rx_rings,
19058275SEric Cheng 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
19068275SEric Cheng 		kmem_free(ixgbe->tx_rings,
19078275SEric Cheng 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
19088275SEric Cheng 		ixgbe->rx_rings = NULL;
19098275SEric Cheng 		ixgbe->tx_rings = NULL;
19108275SEric Cheng 		return (IXGBE_FAILURE);
19118275SEric Cheng 	}
19128275SEric Cheng 
19136621Sbt150084 	return (IXGBE_SUCCESS);
19146621Sbt150084 }
19156621Sbt150084 
19166621Sbt150084 /*
19176621Sbt150084  * ixgbe_free_rings - Free the memory space of rx/tx rings.
19186621Sbt150084  */
19196621Sbt150084 static void
19206621Sbt150084 ixgbe_free_rings(ixgbe_t *ixgbe)
19216621Sbt150084 {
19226621Sbt150084 	if (ixgbe->rx_rings != NULL) {
19236621Sbt150084 		kmem_free(ixgbe->rx_rings,
19246621Sbt150084 		    sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
19256621Sbt150084 		ixgbe->rx_rings = NULL;
19266621Sbt150084 	}
19276621Sbt150084 
19286621Sbt150084 	if (ixgbe->tx_rings != NULL) {
19296621Sbt150084 		kmem_free(ixgbe->tx_rings,
19306621Sbt150084 		    sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
19316621Sbt150084 		ixgbe->tx_rings = NULL;
19326621Sbt150084 	}
19338275SEric Cheng 
19348275SEric Cheng 	if (ixgbe->rx_groups != NULL) {
19358275SEric Cheng 		kmem_free(ixgbe->rx_groups,
19368275SEric Cheng 		    sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups);
19378275SEric Cheng 		ixgbe->rx_groups = NULL;
19388275SEric Cheng 	}
19396621Sbt150084 }
19406621Sbt150084 
194110376SChenlu.Chen@Sun.COM static int
194210376SChenlu.Chen@Sun.COM ixgbe_alloc_rx_data(ixgbe_t *ixgbe)
194310376SChenlu.Chen@Sun.COM {
194410376SChenlu.Chen@Sun.COM 	ixgbe_rx_ring_t *rx_ring;
194510376SChenlu.Chen@Sun.COM 	int i;
194610376SChenlu.Chen@Sun.COM 
194710376SChenlu.Chen@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
194810376SChenlu.Chen@Sun.COM 		rx_ring = &ixgbe->rx_rings[i];
194910376SChenlu.Chen@Sun.COM 		if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS)
195010376SChenlu.Chen@Sun.COM 			goto alloc_rx_rings_failure;
195110376SChenlu.Chen@Sun.COM 	}
195210376SChenlu.Chen@Sun.COM 	return (IXGBE_SUCCESS);
195310376SChenlu.Chen@Sun.COM 
195410376SChenlu.Chen@Sun.COM alloc_rx_rings_failure:
195510376SChenlu.Chen@Sun.COM 	ixgbe_free_rx_data(ixgbe);
195610376SChenlu.Chen@Sun.COM 	return (IXGBE_FAILURE);
195710376SChenlu.Chen@Sun.COM }
195810376SChenlu.Chen@Sun.COM 
195910376SChenlu.Chen@Sun.COM static void
196010376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe_t *ixgbe)
196110376SChenlu.Chen@Sun.COM {
196210376SChenlu.Chen@Sun.COM 	ixgbe_rx_ring_t *rx_ring;
196310376SChenlu.Chen@Sun.COM 	ixgbe_rx_data_t *rx_data;
196410376SChenlu.Chen@Sun.COM 	int i;
196510376SChenlu.Chen@Sun.COM 
196610376SChenlu.Chen@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
196710376SChenlu.Chen@Sun.COM 		rx_ring = &ixgbe->rx_rings[i];
196810376SChenlu.Chen@Sun.COM 
196910376SChenlu.Chen@Sun.COM 		mutex_enter(&ixgbe->rx_pending_lock);
197010376SChenlu.Chen@Sun.COM 		rx_data = rx_ring->rx_data;
197110376SChenlu.Chen@Sun.COM 
197210376SChenlu.Chen@Sun.COM 		if (rx_data != NULL) {
197310376SChenlu.Chen@Sun.COM 			rx_data->flag |= IXGBE_RX_STOPPED;
197410376SChenlu.Chen@Sun.COM 
197510376SChenlu.Chen@Sun.COM 			if (rx_data->rcb_pending == 0) {
197610376SChenlu.Chen@Sun.COM 				ixgbe_free_rx_ring_data(rx_data);
197710376SChenlu.Chen@Sun.COM 				rx_ring->rx_data = NULL;
197810376SChenlu.Chen@Sun.COM 			}
197910376SChenlu.Chen@Sun.COM 		}
198010376SChenlu.Chen@Sun.COM 
198110376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->rx_pending_lock);
198210376SChenlu.Chen@Sun.COM 	}
198310376SChenlu.Chen@Sun.COM }
198410376SChenlu.Chen@Sun.COM 
19856621Sbt150084 /*
19866621Sbt150084  * ixgbe_setup_rings - Setup rx/tx rings.
19876621Sbt150084  */
19886621Sbt150084 static void
19896621Sbt150084 ixgbe_setup_rings(ixgbe_t *ixgbe)
19906621Sbt150084 {
19916621Sbt150084 	/*
19926621Sbt150084 	 * Setup the rx/tx rings, including the following:
19936621Sbt150084 	 *
19946621Sbt150084 	 * 1. Setup the descriptor ring and the control block buffers;
19956621Sbt150084 	 * 2. Initialize necessary registers for receive/transmit;
19966621Sbt150084 	 * 3. Initialize software pointers/parameters for receive/transmit;
19976621Sbt150084 	 */
19986621Sbt150084 	ixgbe_setup_rx(ixgbe);
19996621Sbt150084 
20006621Sbt150084 	ixgbe_setup_tx(ixgbe);
20016621Sbt150084 }
20026621Sbt150084 
20036621Sbt150084 static void
20046621Sbt150084 ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring)
20056621Sbt150084 {
20066621Sbt150084 	ixgbe_t *ixgbe = rx_ring->ixgbe;
200710376SChenlu.Chen@Sun.COM 	ixgbe_rx_data_t *rx_data = rx_ring->rx_data;
20086621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
20096621Sbt150084 	rx_control_block_t *rcb;
20106621Sbt150084 	union ixgbe_adv_rx_desc	*rbd;
20116621Sbt150084 	uint32_t size;
20126621Sbt150084 	uint32_t buf_low;
20136621Sbt150084 	uint32_t buf_high;
20146621Sbt150084 	uint32_t reg_val;
20156621Sbt150084 	int i;
20166621Sbt150084 
20176621Sbt150084 	ASSERT(mutex_owned(&rx_ring->rx_lock));
20186621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
20196621Sbt150084 
20206621Sbt150084 	for (i = 0; i < ixgbe->rx_ring_size; i++) {
202110376SChenlu.Chen@Sun.COM 		rcb = rx_data->work_list[i];
202210376SChenlu.Chen@Sun.COM 		rbd = &rx_data->rbd_ring[i];
20236621Sbt150084 
20246621Sbt150084 		rbd->read.pkt_addr = rcb->rx_buf.dma_address;
20256621Sbt150084 		rbd->read.hdr_addr = NULL;
20266621Sbt150084 	}
20276621Sbt150084 
20286621Sbt150084 	/*
20296621Sbt150084 	 * Initialize the length register
20306621Sbt150084 	 */
203110376SChenlu.Chen@Sun.COM 	size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc);
203211878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->hw_index), size);
20336621Sbt150084 
20346621Sbt150084 	/*
20356621Sbt150084 	 * Initialize the base address registers
20366621Sbt150084 	 */
203710376SChenlu.Chen@Sun.COM 	buf_low = (uint32_t)rx_data->rbd_area.dma_address;
203810376SChenlu.Chen@Sun.COM 	buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32);
203911878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->hw_index), buf_high);
204011878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->hw_index), buf_low);
20416621Sbt150084 
20426621Sbt150084 	/*
20436621Sbt150084 	 * Setup head & tail pointers
20446621Sbt150084 	 */
204511878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->hw_index),
204611878SVenu.Iyer@Sun.COM 	    rx_data->ring_size - 1);
204711878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->hw_index), 0);
20486621Sbt150084 
204910376SChenlu.Chen@Sun.COM 	rx_data->rbd_next = 0;
205011486SZhen.W@Sun.COM 	rx_data->lro_first = 0;
20516621Sbt150084 
20526621Sbt150084 	/*
20536621Sbt150084 	 * Setup the Receive Descriptor Control Register (RXDCTL)
20546621Sbt150084 	 * PTHRESH=32 descriptors (half the internal cache)
20556621Sbt150084 	 * HTHRESH=0 descriptors (to minimize latency on fetch)
20566621Sbt150084 	 * WTHRESH defaults to 1 (writeback each descriptor)
20576621Sbt150084 	 */
205811878SVenu.Iyer@Sun.COM 	reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index));
20596621Sbt150084 	reg_val |= IXGBE_RXDCTL_ENABLE;	/* enable queue */
20609353SSamuel.Tu@Sun.COM 
20619353SSamuel.Tu@Sun.COM 	/* Not a valid value for 82599 */
20629353SSamuel.Tu@Sun.COM 	if (hw->mac.type < ixgbe_mac_82599EB) {
20639353SSamuel.Tu@Sun.COM 		reg_val |= 0x0020;	/* pthresh */
20649353SSamuel.Tu@Sun.COM 	}
206511878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val);
20666621Sbt150084 
20679353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
20689353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
20699353SSamuel.Tu@Sun.COM 		reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS);
20709353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
20719353SSamuel.Tu@Sun.COM 	}
20729353SSamuel.Tu@Sun.COM 
20736621Sbt150084 	/*
20746621Sbt150084 	 * Setup the Split and Replication Receive Control Register.
20756621Sbt150084 	 * Set the rx buffer size and the advanced descriptor type.
20766621Sbt150084 	 */
20776621Sbt150084 	reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) |
20786621Sbt150084 	    IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
20799353SSamuel.Tu@Sun.COM 	reg_val |= IXGBE_SRRCTL_DROP_EN;
208011878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->hw_index), reg_val);
20816621Sbt150084 }
20826621Sbt150084 
20836621Sbt150084 static void
20846621Sbt150084 ixgbe_setup_rx(ixgbe_t *ixgbe)
20856621Sbt150084 {
20866621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
20876621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
20886621Sbt150084 	uint32_t reg_val;
20898275SEric Cheng 	uint32_t ring_mapping;
209011878SVenu.Iyer@Sun.COM 	uint32_t i, index;
209111878SVenu.Iyer@Sun.COM 	uint32_t psrtype_rss_bit;
20926621Sbt150084 
20939353SSamuel.Tu@Sun.COM 	/* PSRTYPE must be configured for 82599 */
209411878SVenu.Iyer@Sun.COM 	if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ &&
209511878SVenu.Iyer@Sun.COM 	    ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) {
209611878SVenu.Iyer@Sun.COM 		reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
209711878SVenu.Iyer@Sun.COM 		    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
209811878SVenu.Iyer@Sun.COM 		reg_val |= IXGBE_PSRTYPE_L2HDR;
209911878SVenu.Iyer@Sun.COM 		reg_val |= 0x80000000;
210011878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val);
210111878SVenu.Iyer@Sun.COM 	} else {
210211878SVenu.Iyer@Sun.COM 		if (ixgbe->num_rx_groups > 32) {
210311878SVenu.Iyer@Sun.COM 			psrtype_rss_bit = 0x20000000;
210411878SVenu.Iyer@Sun.COM 		} else {
210511878SVenu.Iyer@Sun.COM 			psrtype_rss_bit = 0x40000000;
210611878SVenu.Iyer@Sun.COM 		}
210711878SVenu.Iyer@Sun.COM 		for (i = 0; i < ixgbe->capab->max_rx_grp_num; i++) {
210811878SVenu.Iyer@Sun.COM 			reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
210911878SVenu.Iyer@Sun.COM 			    IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
211011878SVenu.Iyer@Sun.COM 			reg_val |= IXGBE_PSRTYPE_L2HDR;
211111878SVenu.Iyer@Sun.COM 			reg_val |= psrtype_rss_bit;
211211878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val);
211311878SVenu.Iyer@Sun.COM 		}
211411878SVenu.Iyer@Sun.COM 	}
21159353SSamuel.Tu@Sun.COM 
21166621Sbt150084 	/*
21176621Sbt150084 	 * Set filter control in FCTRL to accept broadcast packets and do
21186621Sbt150084 	 * not pass pause frames to host.  Flow control settings are already
21196621Sbt150084 	 * in this register, so preserve them.
21206621Sbt150084 	 */
21216621Sbt150084 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
21226621Sbt150084 	reg_val |= IXGBE_FCTRL_BAM;	/* broadcast accept mode */
21236621Sbt150084 	reg_val |= IXGBE_FCTRL_DPF;	/* discard pause frames */
21246621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val);
21256621Sbt150084 
21266621Sbt150084 	/*
212711878SVenu.Iyer@Sun.COM 	 * Hardware checksum settings
212811878SVenu.Iyer@Sun.COM 	 */
212911878SVenu.Iyer@Sun.COM 	if (ixgbe->rx_hcksum_enable) {
213011878SVenu.Iyer@Sun.COM 		reg_val = IXGBE_RXCSUM_IPPCSE;	/* IP checksum */
213111878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val);
213211878SVenu.Iyer@Sun.COM 	}
213311878SVenu.Iyer@Sun.COM 
213411878SVenu.Iyer@Sun.COM 	/*
213511878SVenu.Iyer@Sun.COM 	 * Setup VMDq and RSS for multiple receive queues
213611878SVenu.Iyer@Sun.COM 	 */
213711878SVenu.Iyer@Sun.COM 	switch (ixgbe->classify_mode) {
213811878SVenu.Iyer@Sun.COM 	case IXGBE_CLASSIFY_RSS:
213911878SVenu.Iyer@Sun.COM 		/*
214011878SVenu.Iyer@Sun.COM 		 * One group, only RSS is needed when more than
214111878SVenu.Iyer@Sun.COM 		 * one ring enabled.
214211878SVenu.Iyer@Sun.COM 		 */
214311878SVenu.Iyer@Sun.COM 		ixgbe_setup_rss(ixgbe);
214411878SVenu.Iyer@Sun.COM 		break;
214511878SVenu.Iyer@Sun.COM 
214611878SVenu.Iyer@Sun.COM 	case IXGBE_CLASSIFY_VMDQ:
214711878SVenu.Iyer@Sun.COM 		/*
214811878SVenu.Iyer@Sun.COM 		 * Multiple groups, each group has one ring,
214911878SVenu.Iyer@Sun.COM 		 * only VMDq is needed.
215011878SVenu.Iyer@Sun.COM 		 */
215111878SVenu.Iyer@Sun.COM 		ixgbe_setup_vmdq(ixgbe);
215211878SVenu.Iyer@Sun.COM 		break;
215311878SVenu.Iyer@Sun.COM 
215411878SVenu.Iyer@Sun.COM 	case IXGBE_CLASSIFY_VMDQ_RSS:
215511878SVenu.Iyer@Sun.COM 		/*
215611878SVenu.Iyer@Sun.COM 		 * Multiple groups and multiple rings, both
215711878SVenu.Iyer@Sun.COM 		 * VMDq and RSS are needed.
215811878SVenu.Iyer@Sun.COM 		 */
215911878SVenu.Iyer@Sun.COM 		ixgbe_setup_vmdq_rss(ixgbe);
216011878SVenu.Iyer@Sun.COM 		break;
216111878SVenu.Iyer@Sun.COM 
216211878SVenu.Iyer@Sun.COM 	default:
216311878SVenu.Iyer@Sun.COM 		break;
216411878SVenu.Iyer@Sun.COM 	}
216511878SVenu.Iyer@Sun.COM 
216611878SVenu.Iyer@Sun.COM 	/*
21676621Sbt150084 	 * Enable the receive unit.  This must be done after filter
21686621Sbt150084 	 * control is set in FCTRL.
21696621Sbt150084 	 */
21706621Sbt150084 	reg_val = (IXGBE_RXCTRL_RXEN	/* Enable Receive Unit */
21716621Sbt150084 	    | IXGBE_RXCTRL_DMBYPS);	/* descriptor monitor bypass */
21726621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
21736621Sbt150084 
21746621Sbt150084 	/*
21756621Sbt150084 	 * ixgbe_setup_rx_ring must be called after configuring RXCTRL
21766621Sbt150084 	 */
21776621Sbt150084 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
21786621Sbt150084 		rx_ring = &ixgbe->rx_rings[i];
21796621Sbt150084 		ixgbe_setup_rx_ring(rx_ring);
21806621Sbt150084 	}
21816621Sbt150084 
21826621Sbt150084 	/*
21838275SEric Cheng 	 * Setup the per-ring statistics mapping.
21848275SEric Cheng 	 */
21858275SEric Cheng 	ring_mapping = 0;
21868275SEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
218711878SVenu.Iyer@Sun.COM 		index = ixgbe->rx_rings[i].hw_index;
218811878SVenu.Iyer@Sun.COM 		ring_mapping = IXGBE_READ_REG(hw, IXGBE_RQSMR(index >> 2));
218911878SVenu.Iyer@Sun.COM 		ring_mapping |= (i & 0xF) << (8 * (index & 0x3));
219011878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RQSMR(index >> 2), ring_mapping);
219111878SVenu.Iyer@Sun.COM 	}
21928275SEric Cheng 
21938275SEric Cheng 	/*
21949353SSamuel.Tu@Sun.COM 	 * The Max Frame Size in MHADD/MAXFRS will be internally increased
21959353SSamuel.Tu@Sun.COM 	 * by four bytes if the packet has a VLAN field, so includes MTU,
21969353SSamuel.Tu@Sun.COM 	 * ethernet header and frame check sequence.
21979353SSamuel.Tu@Sun.COM 	 * Register is MAXFRS in 82599.
21986621Sbt150084 	 */
21996621Sbt150084 	reg_val = (ixgbe->default_mtu + sizeof (struct ether_header)
22006621Sbt150084 	    + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT;
22016621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val);
22026621Sbt150084 
22036621Sbt150084 	/*
22046621Sbt150084 	 * Setup Jumbo Frame enable bit
22056621Sbt150084 	 */
22066621Sbt150084 	if (ixgbe->default_mtu > ETHERMTU) {
22076621Sbt150084 		reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
22086621Sbt150084 		reg_val |= IXGBE_HLREG0_JUMBOEN;
22096621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
22106621Sbt150084 	}
221111891SVenu.Iyer@Sun.COM 
221211891SVenu.Iyer@Sun.COM 	/*
221311891SVenu.Iyer@Sun.COM 	 * Setup RSC for multiple receive queues.
221411891SVenu.Iyer@Sun.COM 	 */
221511891SVenu.Iyer@Sun.COM 	if (ixgbe->lro_enable) {
221611891SVenu.Iyer@Sun.COM 		for (i = 0; i < ixgbe->num_rx_rings; i++) {
221711891SVenu.Iyer@Sun.COM 			/*
221811891SVenu.Iyer@Sun.COM 			 * Make sure rx_buf_size * MAXDESC not greater
221911891SVenu.Iyer@Sun.COM 			 * than 65535.
222011891SVenu.Iyer@Sun.COM 			 * Intel recommends 4 for MAXDESC field value.
222111891SVenu.Iyer@Sun.COM 			 */
222211891SVenu.Iyer@Sun.COM 			reg_val = IXGBE_READ_REG(hw, IXGBE_RSCCTL(i));
222311891SVenu.Iyer@Sun.COM 			reg_val |= IXGBE_RSCCTL_RSCEN;
222411891SVenu.Iyer@Sun.COM 			if (ixgbe->rx_buf_size == IXGBE_PKG_BUF_16k)
222511891SVenu.Iyer@Sun.COM 				reg_val |= IXGBE_RSCCTL_MAXDESC_1;
222611891SVenu.Iyer@Sun.COM 			else
222711891SVenu.Iyer@Sun.COM 				reg_val |= IXGBE_RSCCTL_MAXDESC_4;
222811891SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw,  IXGBE_RSCCTL(i), reg_val);
222911891SVenu.Iyer@Sun.COM 		}
223011891SVenu.Iyer@Sun.COM 
223111891SVenu.Iyer@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_RSCDBU);
223211891SVenu.Iyer@Sun.COM 		reg_val |= IXGBE_RSCDBU_RSCACKDIS;
223311891SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, reg_val);
223411891SVenu.Iyer@Sun.COM 
223511891SVenu.Iyer@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
223611891SVenu.Iyer@Sun.COM 		reg_val |= IXGBE_RDRXCTL_RSCACKC;
223712003SPaul.Guo@Sun.COM 		reg_val |= IXGBE_RDRXCTL_FCOE_WRFIX;
223811891SVenu.Iyer@Sun.COM 		reg_val &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
223911891SVenu.Iyer@Sun.COM 
224011891SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
224111891SVenu.Iyer@Sun.COM 	}
22426621Sbt150084 }
22436621Sbt150084 
22446621Sbt150084 static void
22456621Sbt150084 ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring)
22466621Sbt150084 {
22476621Sbt150084 	ixgbe_t *ixgbe = tx_ring->ixgbe;
22486621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
22496621Sbt150084 	uint32_t size;
22506621Sbt150084 	uint32_t buf_low;
22516621Sbt150084 	uint32_t buf_high;
22526621Sbt150084 	uint32_t reg_val;
22536621Sbt150084 
22546621Sbt150084 	ASSERT(mutex_owned(&tx_ring->tx_lock));
22556621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
22566621Sbt150084 
22576621Sbt150084 	/*
22586621Sbt150084 	 * Initialize the length register
22596621Sbt150084 	 */
22606621Sbt150084 	size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc);
22616621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size);
22626621Sbt150084 
22636621Sbt150084 	/*
22646621Sbt150084 	 * Initialize the base address registers
22656621Sbt150084 	 */
22666621Sbt150084 	buf_low = (uint32_t)tx_ring->tbd_area.dma_address;
22676621Sbt150084 	buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32);
22686621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low);
22696621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high);
22706621Sbt150084 
22716621Sbt150084 	/*
22726621Sbt150084 	 * Setup head & tail pointers
22736621Sbt150084 	 */
22746621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0);
22756621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0);
22766621Sbt150084 
22776621Sbt150084 	/*
22786621Sbt150084 	 * Setup head write-back
22796621Sbt150084 	 */
22806621Sbt150084 	if (ixgbe->tx_head_wb_enable) {
22816621Sbt150084 		/*
22826621Sbt150084 		 * The memory of the head write-back is allocated using
22836621Sbt150084 		 * the extra tbd beyond the tail of the tbd ring.
22846621Sbt150084 		 */
22856621Sbt150084 		tx_ring->tbd_head_wb = (uint32_t *)
22866621Sbt150084 		    ((uintptr_t)tx_ring->tbd_area.address + size);
22876621Sbt150084 		*tx_ring->tbd_head_wb = 0;
22886621Sbt150084 
22896621Sbt150084 		buf_low = (uint32_t)
22906621Sbt150084 		    (tx_ring->tbd_area.dma_address + size);
22916621Sbt150084 		buf_high = (uint32_t)
22926621Sbt150084 		    ((tx_ring->tbd_area.dma_address + size) >> 32);
22936621Sbt150084 
22946621Sbt150084 		/* Set the head write-back enable bit */
22956621Sbt150084 		buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE;
22966621Sbt150084 
22976621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low);
22986621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high);
22996621Sbt150084 
23006621Sbt150084 		/*
23016621Sbt150084 		 * Turn off relaxed ordering for head write back or it will
23026621Sbt150084 		 * cause problems with the tx recycling
23036621Sbt150084 		 */
23046621Sbt150084 		reg_val = IXGBE_READ_REG(hw,
23056621Sbt150084 		    IXGBE_DCA_TXCTRL(tx_ring->index));
23066621Sbt150084 		reg_val &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
23076621Sbt150084 		IXGBE_WRITE_REG(hw,
23086621Sbt150084 		    IXGBE_DCA_TXCTRL(tx_ring->index), reg_val);
23096621Sbt150084 	} else {
23106621Sbt150084 		tx_ring->tbd_head_wb = NULL;
23116621Sbt150084 	}
23126621Sbt150084 
23136621Sbt150084 	tx_ring->tbd_head = 0;
23146621Sbt150084 	tx_ring->tbd_tail = 0;
23156621Sbt150084 	tx_ring->tbd_free = tx_ring->ring_size;
23166621Sbt150084 
231710376SChenlu.Chen@Sun.COM 	if (ixgbe->tx_ring_init == B_TRUE) {
23186621Sbt150084 		tx_ring->tcb_head = 0;
23196621Sbt150084 		tx_ring->tcb_tail = 0;
23206621Sbt150084 		tx_ring->tcb_free = tx_ring->free_list_size;
23216621Sbt150084 	}
23226621Sbt150084 
23236621Sbt150084 	/*
23247245Sgg161487 	 * Initialize the s/w context structure
23256621Sbt150084 	 */
23267245Sgg161487 	bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t));
23276621Sbt150084 }
23286621Sbt150084 
23296621Sbt150084 static void
23306621Sbt150084 ixgbe_setup_tx(ixgbe_t *ixgbe)
23316621Sbt150084 {
23327167Sgg161487 	struct ixgbe_hw *hw = &ixgbe->hw;
23336621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
23347167Sgg161487 	uint32_t reg_val;
23358275SEric Cheng 	uint32_t ring_mapping;
23366621Sbt150084 	int i;
23376621Sbt150084 
23386621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
23396621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
23406621Sbt150084 		ixgbe_setup_tx_ring(tx_ring);
23416621Sbt150084 	}
23427167Sgg161487 
23437167Sgg161487 	/*
23448275SEric Cheng 	 * Setup the per-ring statistics mapping.
23458275SEric Cheng 	 */
23468275SEric Cheng 	ring_mapping = 0;
23478275SEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
23488275SEric Cheng 		ring_mapping |= (i & 0xF) << (8 * (i & 0x3));
23498275SEric Cheng 		if ((i & 0x3) == 0x3) {
23509353SSamuel.Tu@Sun.COM 			if (hw->mac.type >= ixgbe_mac_82599EB) {
23519353SSamuel.Tu@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2),
23529353SSamuel.Tu@Sun.COM 				    ring_mapping);
23539353SSamuel.Tu@Sun.COM 			} else {
23549353SSamuel.Tu@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2),
23559353SSamuel.Tu@Sun.COM 				    ring_mapping);
23569353SSamuel.Tu@Sun.COM 			}
23578275SEric Cheng 			ring_mapping = 0;
23588275SEric Cheng 		}
23598275SEric Cheng 	}
23608275SEric Cheng 	if ((i & 0x3) != 0x3)
23619353SSamuel.Tu@Sun.COM 		if (hw->mac.type >= ixgbe_mac_82599EB) {
23629353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping);
23639353SSamuel.Tu@Sun.COM 		} else {
23649353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping);
23659353SSamuel.Tu@Sun.COM 		}
23668275SEric Cheng 
23678275SEric Cheng 	/*
23687167Sgg161487 	 * Enable CRC appending and TX padding (for short tx frames)
23697167Sgg161487 	 */
23707167Sgg161487 	reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
23717167Sgg161487 	reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN;
23727167Sgg161487 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
23739353SSamuel.Tu@Sun.COM 
23749353SSamuel.Tu@Sun.COM 	/*
23759353SSamuel.Tu@Sun.COM 	 * enable DMA for 82599 parts
23769353SSamuel.Tu@Sun.COM 	 */
23779353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
23789353SSamuel.Tu@Sun.COM 	/* DMATXCTL.TE must be set after all Tx config is complete */
23799353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
23809353SSamuel.Tu@Sun.COM 		reg_val |= IXGBE_DMATXCTL_TE;
23819353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val);
23829353SSamuel.Tu@Sun.COM 	}
23839353SSamuel.Tu@Sun.COM 
23849353SSamuel.Tu@Sun.COM 	/*
23859353SSamuel.Tu@Sun.COM 	 * Enabling tx queues ..
23869353SSamuel.Tu@Sun.COM 	 * For 82599 must be done after DMATXCTL.TE is set
23879353SSamuel.Tu@Sun.COM 	 */
23889353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
23899353SSamuel.Tu@Sun.COM 		tx_ring = &ixgbe->tx_rings[i];
23909353SSamuel.Tu@Sun.COM 		reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index));
23919353SSamuel.Tu@Sun.COM 		reg_val |= IXGBE_TXDCTL_ENABLE;
23929353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val);
23939353SSamuel.Tu@Sun.COM 	}
23946621Sbt150084 }
23956621Sbt150084 
23966621Sbt150084 /*
23976621Sbt150084  * ixgbe_setup_rss - Setup receive-side scaling feature.
23986621Sbt150084  */
23996621Sbt150084 static void
24006621Sbt150084 ixgbe_setup_rss(ixgbe_t *ixgbe)
24016621Sbt150084 {
24026621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
24037167Sgg161487 	uint32_t i, mrqc, rxcsum;
24046621Sbt150084 	uint32_t random;
24056621Sbt150084 	uint32_t reta;
240611878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
24076621Sbt150084 
24086621Sbt150084 	/*
24096621Sbt150084 	 * Fill out redirection table
24106621Sbt150084 	 */
24116621Sbt150084 	reta = 0;
241211878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
241311878SVenu.Iyer@Sun.COM 
24146621Sbt150084 	for (i = 0; i < 128; i++) {
241511878SVenu.Iyer@Sun.COM 		reta = (reta << 8) | (i % ring_per_group) |
241611878SVenu.Iyer@Sun.COM 		    ((i % ring_per_group) << 4);
24177167Sgg161487 		if ((i & 3) == 3)
24186621Sbt150084 			IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
24196621Sbt150084 	}
24206621Sbt150084 
24216621Sbt150084 	/*
24226621Sbt150084 	 * Fill out hash function seeds with a random constant
24236621Sbt150084 	 */
24246621Sbt150084 	for (i = 0; i < 10; i++) {
24256621Sbt150084 		(void) random_get_pseudo_bytes((uint8_t *)&random,
24266621Sbt150084 		    sizeof (uint32_t));
24276621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random);
24286621Sbt150084 	}
24296621Sbt150084 
24306621Sbt150084 	/*
24317167Sgg161487 	 * Enable RSS & perform hash on these packet types
24326621Sbt150084 	 */
24336621Sbt150084 	mrqc = IXGBE_MRQC_RSSEN |
24346621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4 |
24356621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
24366621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
24376621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
24386621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
24396621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6 |
24406621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
24416621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
24426621Sbt150084 	    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
24436621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
24446621Sbt150084 
24456621Sbt150084 	/*
24466621Sbt150084 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
24476621Sbt150084 	 * It is an adapter hardware limitation that Packet Checksum is
24486621Sbt150084 	 * mutually exclusive with RSS.
24496621Sbt150084 	 */
24506621Sbt150084 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
24516621Sbt150084 	rxcsum |= IXGBE_RXCSUM_PCSD;
24526621Sbt150084 	rxcsum &= ~IXGBE_RXCSUM_IPPCSE;
24536621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
24546621Sbt150084 }
24556621Sbt150084 
24566621Sbt150084 /*
245711878SVenu.Iyer@Sun.COM  * ixgbe_setup_vmdq - Setup MAC classification feature
245811878SVenu.Iyer@Sun.COM  */
245911878SVenu.Iyer@Sun.COM static void
246011878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq(ixgbe_t *ixgbe)
246111878SVenu.Iyer@Sun.COM {
246211878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
246311878SVenu.Iyer@Sun.COM 	uint32_t vmdctl, i, vtctl;
246411878SVenu.Iyer@Sun.COM 
246511878SVenu.Iyer@Sun.COM 	/*
246611878SVenu.Iyer@Sun.COM 	 * Setup the VMDq Control register, enable VMDq based on
246711878SVenu.Iyer@Sun.COM 	 * packet destination MAC address:
246811878SVenu.Iyer@Sun.COM 	 */
246911878SVenu.Iyer@Sun.COM 	switch (hw->mac.type) {
247011878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82598EB:
247111878SVenu.Iyer@Sun.COM 		/*
247211878SVenu.Iyer@Sun.COM 		 * VMDq Enable = 1;
247311878SVenu.Iyer@Sun.COM 		 * VMDq Filter = 0; MAC filtering
247411878SVenu.Iyer@Sun.COM 		 * Default VMDq output index = 0;
247511878SVenu.Iyer@Sun.COM 		 */
247611878SVenu.Iyer@Sun.COM 		vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
247711878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
247811878SVenu.Iyer@Sun.COM 		break;
247911878SVenu.Iyer@Sun.COM 
248011878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82599EB:
248111878SVenu.Iyer@Sun.COM 		/*
248211878SVenu.Iyer@Sun.COM 		 * Enable VMDq-only.
248311878SVenu.Iyer@Sun.COM 		 */
248411878SVenu.Iyer@Sun.COM 		vmdctl = IXGBE_MRQC_VMDQEN;
248511878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl);
248611878SVenu.Iyer@Sun.COM 
248711878SVenu.Iyer@Sun.COM 		for (i = 0; i < hw->mac.num_rar_entries; i++) {
248811878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0);
248911878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0);
249011878SVenu.Iyer@Sun.COM 		}
249111878SVenu.Iyer@Sun.COM 
249211878SVenu.Iyer@Sun.COM 		/*
249311878SVenu.Iyer@Sun.COM 		 * Enable Virtualization and Replication.
249411878SVenu.Iyer@Sun.COM 		 */
249511878SVenu.Iyer@Sun.COM 		vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
249611878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
249711878SVenu.Iyer@Sun.COM 
249811878SVenu.Iyer@Sun.COM 		/*
249911878SVenu.Iyer@Sun.COM 		 * Enable receiving packets to all VFs
250011878SVenu.Iyer@Sun.COM 		 */
250111878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL);
250211878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL);
250311878SVenu.Iyer@Sun.COM 
250411878SVenu.Iyer@Sun.COM 		break;
250511878SVenu.Iyer@Sun.COM 
250611878SVenu.Iyer@Sun.COM 	default:
250711878SVenu.Iyer@Sun.COM 		break;
250811878SVenu.Iyer@Sun.COM 	}
250911878SVenu.Iyer@Sun.COM }
251011878SVenu.Iyer@Sun.COM 
251111878SVenu.Iyer@Sun.COM /*
251211878SVenu.Iyer@Sun.COM  * ixgbe_setup_vmdq_rss - Setup both vmdq feature and rss feature.
251311878SVenu.Iyer@Sun.COM  */
251411878SVenu.Iyer@Sun.COM static void
251511878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe)
251611878SVenu.Iyer@Sun.COM {
251711878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
251811878SVenu.Iyer@Sun.COM 	uint32_t i, mrqc, rxcsum;
251911878SVenu.Iyer@Sun.COM 	uint32_t random;
252011878SVenu.Iyer@Sun.COM 	uint32_t reta;
252111878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
252211878SVenu.Iyer@Sun.COM 	uint32_t vmdctl, vtctl;
252311878SVenu.Iyer@Sun.COM 
252411878SVenu.Iyer@Sun.COM 	/*
252511878SVenu.Iyer@Sun.COM 	 * Fill out redirection table
252611878SVenu.Iyer@Sun.COM 	 */
252711878SVenu.Iyer@Sun.COM 	reta = 0;
252811878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
252911878SVenu.Iyer@Sun.COM 	for (i = 0; i < 128; i++) {
253011878SVenu.Iyer@Sun.COM 		reta = (reta << 8) | (i % ring_per_group) |
253111878SVenu.Iyer@Sun.COM 		    ((i % ring_per_group) << 4);
253211878SVenu.Iyer@Sun.COM 		if ((i & 3) == 3)
253311878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
253411878SVenu.Iyer@Sun.COM 	}
253511878SVenu.Iyer@Sun.COM 
253611878SVenu.Iyer@Sun.COM 	/*
253711878SVenu.Iyer@Sun.COM 	 * Fill out hash function seeds with a random constant
253811878SVenu.Iyer@Sun.COM 	 */
253911878SVenu.Iyer@Sun.COM 	for (i = 0; i < 10; i++) {
254011878SVenu.Iyer@Sun.COM 		(void) random_get_pseudo_bytes((uint8_t *)&random,
254111878SVenu.Iyer@Sun.COM 		    sizeof (uint32_t));
254211878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random);
254311878SVenu.Iyer@Sun.COM 	}
254411878SVenu.Iyer@Sun.COM 
254511878SVenu.Iyer@Sun.COM 	/*
254611878SVenu.Iyer@Sun.COM 	 * Enable and setup RSS and VMDq
254711878SVenu.Iyer@Sun.COM 	 */
254811878SVenu.Iyer@Sun.COM 	switch (hw->mac.type) {
254911878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82598EB:
255011878SVenu.Iyer@Sun.COM 		/*
255111878SVenu.Iyer@Sun.COM 		 * Enable RSS & Setup RSS Hash functions
255211878SVenu.Iyer@Sun.COM 		 */
255311878SVenu.Iyer@Sun.COM 		mrqc = IXGBE_MRQC_RSSEN |
255411878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4 |
255511878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
255611878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
255711878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
255811878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
255911878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6 |
256011878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
256111878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
256211878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
256311878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
256411878SVenu.Iyer@Sun.COM 
256511878SVenu.Iyer@Sun.COM 		/*
256611878SVenu.Iyer@Sun.COM 		 * Enable and Setup VMDq
256711878SVenu.Iyer@Sun.COM 		 * VMDq Filter = 0; MAC filtering
256811878SVenu.Iyer@Sun.COM 		 * Default VMDq output index = 0;
256911878SVenu.Iyer@Sun.COM 		 */
257011878SVenu.Iyer@Sun.COM 		vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
257111878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
257211878SVenu.Iyer@Sun.COM 		break;
257311878SVenu.Iyer@Sun.COM 
257411878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82599EB:
257511878SVenu.Iyer@Sun.COM 		/*
257611878SVenu.Iyer@Sun.COM 		 * Enable RSS & Setup RSS Hash functions
257711878SVenu.Iyer@Sun.COM 		 */
257811878SVenu.Iyer@Sun.COM 		mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 |
257911878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
258011878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
258111878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
258211878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX |
258311878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6 |
258411878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
258511878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
258611878SVenu.Iyer@Sun.COM 		    IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
258711878SVenu.Iyer@Sun.COM 
258811878SVenu.Iyer@Sun.COM 		/*
258911878SVenu.Iyer@Sun.COM 		 * Enable VMDq+RSS.
259011878SVenu.Iyer@Sun.COM 		 */
259111878SVenu.Iyer@Sun.COM 		if (ixgbe->num_rx_groups > 32)  {
259211878SVenu.Iyer@Sun.COM 			mrqc = mrqc | IXGBE_MRQC_VMDQRSS64EN;
259311878SVenu.Iyer@Sun.COM 		} else {
259411878SVenu.Iyer@Sun.COM 			mrqc = mrqc | IXGBE_MRQC_VMDQRSS32EN;
259511878SVenu.Iyer@Sun.COM 		}
259611878SVenu.Iyer@Sun.COM 
259711878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
259811878SVenu.Iyer@Sun.COM 
259911878SVenu.Iyer@Sun.COM 		for (i = 0; i < hw->mac.num_rar_entries; i++) {
260011878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0);
260111878SVenu.Iyer@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0);
260211878SVenu.Iyer@Sun.COM 		}
260311878SVenu.Iyer@Sun.COM 		break;
260411878SVenu.Iyer@Sun.COM 
260511878SVenu.Iyer@Sun.COM 	default:
260611878SVenu.Iyer@Sun.COM 		break;
260711878SVenu.Iyer@Sun.COM 
260811878SVenu.Iyer@Sun.COM 	}
260911878SVenu.Iyer@Sun.COM 
261011878SVenu.Iyer@Sun.COM 	/*
261111878SVenu.Iyer@Sun.COM 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
261211878SVenu.Iyer@Sun.COM 	 * It is an adapter hardware limitation that Packet Checksum is
261311878SVenu.Iyer@Sun.COM 	 * mutually exclusive with RSS.
261411878SVenu.Iyer@Sun.COM 	 */
261511878SVenu.Iyer@Sun.COM 	rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
261611878SVenu.Iyer@Sun.COM 	rxcsum |= IXGBE_RXCSUM_PCSD;
261711878SVenu.Iyer@Sun.COM 	rxcsum &= ~IXGBE_RXCSUM_IPPCSE;
261811878SVenu.Iyer@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
261911878SVenu.Iyer@Sun.COM 
262011878SVenu.Iyer@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
262111878SVenu.Iyer@Sun.COM 		/*
262211878SVenu.Iyer@Sun.COM 		 * Enable Virtualization and Replication.
262311878SVenu.Iyer@Sun.COM 		 */
262411878SVenu.Iyer@Sun.COM 		vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
262511878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
262611878SVenu.Iyer@Sun.COM 
262711878SVenu.Iyer@Sun.COM 		/*
262811878SVenu.Iyer@Sun.COM 		 * Enable receiving packets to all VFs
262911878SVenu.Iyer@Sun.COM 		 */
263011878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL);
263111878SVenu.Iyer@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL);
263211878SVenu.Iyer@Sun.COM 	}
263311878SVenu.Iyer@Sun.COM }
263411878SVenu.Iyer@Sun.COM 
263511878SVenu.Iyer@Sun.COM /*
26366621Sbt150084  * ixgbe_init_unicst - Initialize the unicast addresses.
26376621Sbt150084  */
26386621Sbt150084 static void
26396621Sbt150084 ixgbe_init_unicst(ixgbe_t *ixgbe)
26406621Sbt150084 {
26416621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
26428275SEric Cheng 	uint8_t *mac_addr;
26436621Sbt150084 	int slot;
26446621Sbt150084 	/*
26456621Sbt150084 	 * Here we should consider two situations:
26466621Sbt150084 	 *
26478275SEric Cheng 	 * 1. Chipset is initialized at the first time,
26488275SEric Cheng 	 *    Clear all the multiple unicast addresses.
26496621Sbt150084 	 *
26506621Sbt150084 	 * 2. Chipset is reset
26516621Sbt150084 	 *    Recover the multiple unicast addresses from the
26526621Sbt150084 	 *    software data structure to the RAR registers.
26536621Sbt150084 	 */
26546621Sbt150084 	if (!ixgbe->unicst_init) {
26556621Sbt150084 		/*
26566621Sbt150084 		 * Initialize the multiple unicast addresses
26576621Sbt150084 		 */
265811878SVenu.Iyer@Sun.COM 		ixgbe->unicst_total = hw->mac.num_rar_entries;
26598275SEric Cheng 		ixgbe->unicst_avail = ixgbe->unicst_total;
26608275SEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
26618275SEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
26628275SEric Cheng 			bzero(mac_addr, ETHERADDRL);
26638275SEric Cheng 			(void) ixgbe_set_rar(hw, slot, mac_addr, NULL, NULL);
26646621Sbt150084 			ixgbe->unicst_addr[slot].mac.set = 0;
26658275SEric Cheng 		}
26666621Sbt150084 		ixgbe->unicst_init = B_TRUE;
26676621Sbt150084 	} else {
26686621Sbt150084 		/* Re-configure the RAR registers */
26698275SEric Cheng 		for (slot = 0; slot < ixgbe->unicst_total; slot++) {
26708275SEric Cheng 			mac_addr = ixgbe->unicst_addr[slot].mac.addr;
26718275SEric Cheng 			if (ixgbe->unicst_addr[slot].mac.set == 1) {
26728275SEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
267311878SVenu.Iyer@Sun.COM 				    ixgbe->unicst_addr[slot].mac.group_index,
267411878SVenu.Iyer@Sun.COM 				    IXGBE_RAH_AV);
26758275SEric Cheng 			} else {
26768275SEric Cheng 				bzero(mac_addr, ETHERADDRL);
26778275SEric Cheng 				(void) ixgbe_set_rar(hw, slot, mac_addr,
26788275SEric Cheng 				    NULL, NULL);
26798275SEric Cheng 			}
26808275SEric Cheng 		}
26816621Sbt150084 	}
26826621Sbt150084 }
26838275SEric Cheng 
26846621Sbt150084 /*
26858275SEric Cheng  * ixgbe_unicst_find - Find the slot for the specified unicast address
26868275SEric Cheng  */
26878275SEric Cheng int
26888275SEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr)
26898275SEric Cheng {
26908275SEric Cheng 	int slot;
26918275SEric Cheng 
26928275SEric Cheng 	ASSERT(mutex_owned(&ixgbe->gen_lock));
26938275SEric Cheng 
26948275SEric Cheng 	for (slot = 0; slot < ixgbe->unicst_total; slot++) {
26958275SEric Cheng 		if (bcmp(ixgbe->unicst_addr[slot].mac.addr,
26968275SEric Cheng 		    mac_addr, ETHERADDRL) == 0)
26978275SEric Cheng 			return (slot);
26988275SEric Cheng 	}
26998275SEric Cheng 
27008275SEric Cheng 	return (-1);
27018275SEric Cheng }
27028275SEric Cheng 
27038275SEric Cheng /*
27046621Sbt150084  * ixgbe_multicst_add - Add a multicst address.
27056621Sbt150084  */
27066621Sbt150084 int
27076621Sbt150084 ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr)
27086621Sbt150084 {
27096621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
27106621Sbt150084 
27116621Sbt150084 	if ((multiaddr[0] & 01) == 0) {
27126621Sbt150084 		return (EINVAL);
27136621Sbt150084 	}
27146621Sbt150084 
27156621Sbt150084 	if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) {
27166621Sbt150084 		return (ENOENT);
27176621Sbt150084 	}
27186621Sbt150084 
27196621Sbt150084 	bcopy(multiaddr,
27206621Sbt150084 	    &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL);
27216621Sbt150084 	ixgbe->mcast_count++;
27226621Sbt150084 
27236621Sbt150084 	/*
27246621Sbt150084 	 * Update the multicast table in the hardware
27256621Sbt150084 	 */
27266621Sbt150084 	ixgbe_setup_multicst(ixgbe);
27276621Sbt150084 
27286621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
27296621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
27306621Sbt150084 		return (EIO);
27316621Sbt150084 	}
27326621Sbt150084 
27336621Sbt150084 	return (0);
27346621Sbt150084 }
27356621Sbt150084 
27366621Sbt150084 /*
27376621Sbt150084  * ixgbe_multicst_remove - Remove a multicst address.
27386621Sbt150084  */
27396621Sbt150084 int
27406621Sbt150084 ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr)
27416621Sbt150084 {
27426621Sbt150084 	int i;
27436621Sbt150084 
27446621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
27456621Sbt150084 
27466621Sbt150084 	for (i = 0; i < ixgbe->mcast_count; i++) {
27476621Sbt150084 		if (bcmp(multiaddr, &ixgbe->mcast_table[i],
27486621Sbt150084 		    ETHERADDRL) == 0) {
27496621Sbt150084 			for (i++; i < ixgbe->mcast_count; i++) {
27506621Sbt150084 				ixgbe->mcast_table[i - 1] =
27516621Sbt150084 				    ixgbe->mcast_table[i];
27526621Sbt150084 			}
27536621Sbt150084 			ixgbe->mcast_count--;
27546621Sbt150084 			break;
27556621Sbt150084 		}
27566621Sbt150084 	}
27576621Sbt150084 
27586621Sbt150084 	/*
27596621Sbt150084 	 * Update the multicast table in the hardware
27606621Sbt150084 	 */
27616621Sbt150084 	ixgbe_setup_multicst(ixgbe);
27626621Sbt150084 
27636621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
27646621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
27656621Sbt150084 		return (EIO);
27666621Sbt150084 	}
27676621Sbt150084 
27686621Sbt150084 	return (0);
27696621Sbt150084 }
27706621Sbt150084 
27716621Sbt150084 /*
27726621Sbt150084  * ixgbe_setup_multicast - Setup multicast data structures.
27736621Sbt150084  *
27746621Sbt150084  * This routine initializes all of the multicast related structures
27756621Sbt150084  * and save them in the hardware registers.
27766621Sbt150084  */
27776621Sbt150084 static void
27786621Sbt150084 ixgbe_setup_multicst(ixgbe_t *ixgbe)
27796621Sbt150084 {
27806621Sbt150084 	uint8_t *mc_addr_list;
27816621Sbt150084 	uint32_t mc_addr_count;
27826621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
27836621Sbt150084 
27846621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
27856621Sbt150084 
27866621Sbt150084 	ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES);
27876621Sbt150084 
27886621Sbt150084 	mc_addr_list = (uint8_t *)ixgbe->mcast_table;
27896621Sbt150084 	mc_addr_count = ixgbe->mcast_count;
27906621Sbt150084 
27916621Sbt150084 	/*
27926621Sbt150084 	 * Update the multicast addresses to the MTA registers
27936621Sbt150084 	 */
27946621Sbt150084 	(void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
27956621Sbt150084 	    ixgbe_mc_table_itr);
27966621Sbt150084 }
27976621Sbt150084 
27986621Sbt150084 /*
279911878SVenu.Iyer@Sun.COM  * ixgbe_setup_vmdq_rss_conf - Configure vmdq and rss (number and mode).
280011878SVenu.Iyer@Sun.COM  *
280111878SVenu.Iyer@Sun.COM  * Configure the rx classification mode (vmdq & rss) and vmdq & rss numbers.
280211878SVenu.Iyer@Sun.COM  * Different chipsets may have different allowed configuration of vmdq and rss.
280311878SVenu.Iyer@Sun.COM  */
280411878SVenu.Iyer@Sun.COM static void
280511878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe)
280611878SVenu.Iyer@Sun.COM {
280711878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
280811878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
280911878SVenu.Iyer@Sun.COM 
281011878SVenu.Iyer@Sun.COM 	switch (hw->mac.type) {
281111878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82598EB:
281211878SVenu.Iyer@Sun.COM 		/*
281311878SVenu.Iyer@Sun.COM 		 * 82598 supports the following combination:
281411878SVenu.Iyer@Sun.COM 		 * vmdq no. x rss no.
281511878SVenu.Iyer@Sun.COM 		 * [5..16]  x 1
281611878SVenu.Iyer@Sun.COM 		 * [1..4]   x [1..16]
281711878SVenu.Iyer@Sun.COM 		 * However 8 rss queue per pool (vmdq) is sufficient for
281811878SVenu.Iyer@Sun.COM 		 * most cases.
281911878SVenu.Iyer@Sun.COM 		 */
282011878SVenu.Iyer@Sun.COM 		ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
282111878SVenu.Iyer@Sun.COM 		if (ixgbe->num_rx_groups > 4) {
282211878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = ixgbe->num_rx_groups;
282311878SVenu.Iyer@Sun.COM 		} else {
282411878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
282511878SVenu.Iyer@Sun.COM 			    min(8, ring_per_group);
282611878SVenu.Iyer@Sun.COM 		}
282711878SVenu.Iyer@Sun.COM 
282811878SVenu.Iyer@Sun.COM 		break;
282911878SVenu.Iyer@Sun.COM 
283011878SVenu.Iyer@Sun.COM 	case ixgbe_mac_82599EB:
283111878SVenu.Iyer@Sun.COM 		/*
283211878SVenu.Iyer@Sun.COM 		 * 82599 supports the following combination:
283311878SVenu.Iyer@Sun.COM 		 * vmdq no. x rss no.
283411878SVenu.Iyer@Sun.COM 		 * [33..64] x [1..2]
283511878SVenu.Iyer@Sun.COM 		 * [2..32]  x [1..4]
283611878SVenu.Iyer@Sun.COM 		 * 1 x [1..16]
283711878SVenu.Iyer@Sun.COM 		 * However 8 rss queue per pool (vmdq) is sufficient for
283811878SVenu.Iyer@Sun.COM 		 * most cases.
283911878SVenu.Iyer@Sun.COM 		 */
284011878SVenu.Iyer@Sun.COM 		ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
284111878SVenu.Iyer@Sun.COM 		if (ixgbe->num_rx_groups == 1) {
284211878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = min(8, ring_per_group);
284311878SVenu.Iyer@Sun.COM 		} else if (ixgbe->num_rx_groups <= 32) {
284411878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
284511878SVenu.Iyer@Sun.COM 			    min(4, ring_per_group);
284611878SVenu.Iyer@Sun.COM 		} else if (ixgbe->num_rx_groups <= 64) {
284711878SVenu.Iyer@Sun.COM 			ixgbe->num_rx_rings = ixgbe->num_rx_groups *
284811878SVenu.Iyer@Sun.COM 			    min(2, ring_per_group);
284911878SVenu.Iyer@Sun.COM 		}
285011878SVenu.Iyer@Sun.COM 
285111878SVenu.Iyer@Sun.COM 		break;
285211878SVenu.Iyer@Sun.COM 
285311878SVenu.Iyer@Sun.COM 	default:
285411878SVenu.Iyer@Sun.COM 		break;
285511878SVenu.Iyer@Sun.COM 	}
285611878SVenu.Iyer@Sun.COM 
285711878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
285811878SVenu.Iyer@Sun.COM 
285911878SVenu.Iyer@Sun.COM 	if (ixgbe->num_rx_groups == 1 && ring_per_group == 1) {
286011878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
286111878SVenu.Iyer@Sun.COM 	} else if (ixgbe->num_rx_groups != 1 && ring_per_group == 1) {
286211878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ;
286311878SVenu.Iyer@Sun.COM 	} else if (ixgbe->num_rx_groups != 1 && ring_per_group != 1) {
286411878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ_RSS;
286511878SVenu.Iyer@Sun.COM 	} else {
286611878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_RSS;
286711878SVenu.Iyer@Sun.COM 	}
286811878SVenu.Iyer@Sun.COM 
286912003SPaul.Guo@Sun.COM 	IXGBE_DEBUGLOG_2(ixgbe, "rx group number:%d, rx ring number:%d",
287011878SVenu.Iyer@Sun.COM 	    ixgbe->num_rx_groups, ixgbe->num_rx_rings);
287111878SVenu.Iyer@Sun.COM }
287211878SVenu.Iyer@Sun.COM 
287311878SVenu.Iyer@Sun.COM /*
28746621Sbt150084  * ixgbe_get_conf - Get driver configurations set in driver.conf.
28756621Sbt150084  *
28766621Sbt150084  * This routine gets user-configured values out of the configuration
28776621Sbt150084  * file ixgbe.conf.
28786621Sbt150084  *
28796621Sbt150084  * For each configurable value, there is a minimum, a maximum, and a
28806621Sbt150084  * default.
28816621Sbt150084  * If user does not configure a value, use the default.
28826621Sbt150084  * If user configures below the minimum, use the minumum.
28836621Sbt150084  * If user configures above the maximum, use the maxumum.
28846621Sbt150084  */
28856621Sbt150084 static void
28866621Sbt150084 ixgbe_get_conf(ixgbe_t *ixgbe)
28876621Sbt150084 {
28886621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
28896621Sbt150084 	uint32_t flow_control;
28906621Sbt150084 
28916621Sbt150084 	/*
28926621Sbt150084 	 * ixgbe driver supports the following user configurations:
28936621Sbt150084 	 *
28946621Sbt150084 	 * Jumbo frame configuration:
28956621Sbt150084 	 *    default_mtu
28966621Sbt150084 	 *
28976621Sbt150084 	 * Ethernet flow control configuration:
28986621Sbt150084 	 *    flow_control
28996621Sbt150084 	 *
29006621Sbt150084 	 * Multiple rings configurations:
29016621Sbt150084 	 *    tx_queue_number
29026621Sbt150084 	 *    tx_ring_size
29036621Sbt150084 	 *    rx_queue_number
29046621Sbt150084 	 *    rx_ring_size
29056621Sbt150084 	 *
29066621Sbt150084 	 * Call ixgbe_get_prop() to get the value for a specific
29076621Sbt150084 	 * configuration parameter.
29086621Sbt150084 	 */
29096621Sbt150084 
29106621Sbt150084 	/*
29116621Sbt150084 	 * Jumbo frame configuration - max_frame_size controls host buffer
29126621Sbt150084 	 * allocation, so includes MTU, ethernet header, vlan tag and
29136621Sbt150084 	 * frame check sequence.
29146621Sbt150084 	 */
29156621Sbt150084 	ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU,
291611150SZhen.W@Sun.COM 	    MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU);
29176621Sbt150084 
29186621Sbt150084 	ixgbe->max_frame_size = ixgbe->default_mtu +
29196621Sbt150084 	    sizeof (struct ether_vlan_header) + ETHERFCSL;
29206621Sbt150084 
29216621Sbt150084 	/*
29226621Sbt150084 	 * Ethernet flow control configuration
29236621Sbt150084 	 */
29246621Sbt150084 	flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL,
29258275SEric Cheng 	    ixgbe_fc_none, 3, ixgbe_fc_none);
29266621Sbt150084 	if (flow_control == 3)
29276621Sbt150084 		flow_control = ixgbe_fc_default;
29286621Sbt150084 
29299353SSamuel.Tu@Sun.COM 	/*
29309353SSamuel.Tu@Sun.COM 	 * fc.requested mode is what the user requests.  After autoneg,
29319353SSamuel.Tu@Sun.COM 	 * fc.current_mode will be the flow_control mode that was negotiated.
29329353SSamuel.Tu@Sun.COM 	 */
29339353SSamuel.Tu@Sun.COM 	hw->fc.requested_mode = flow_control;
29346621Sbt150084 
29356621Sbt150084 	/*
29366621Sbt150084 	 * Multiple rings configurations
29376621Sbt150084 	 */
29386621Sbt150084 	ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM,
29398490SPaul.Guo@Sun.COM 	    ixgbe->capab->min_tx_que_num,
29408490SPaul.Guo@Sun.COM 	    ixgbe->capab->max_tx_que_num,
29418490SPaul.Guo@Sun.COM 	    ixgbe->capab->def_tx_que_num);
29426621Sbt150084 	ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE,
29436621Sbt150084 	    MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE);
29446621Sbt150084 
29456621Sbt150084 	ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM,
29468490SPaul.Guo@Sun.COM 	    ixgbe->capab->min_rx_que_num,
29478490SPaul.Guo@Sun.COM 	    ixgbe->capab->max_rx_que_num,
29488490SPaul.Guo@Sun.COM 	    ixgbe->capab->def_rx_que_num);
29496621Sbt150084 	ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE,
29506621Sbt150084 	    MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE);
29516621Sbt150084 
29526621Sbt150084 	/*
29538275SEric Cheng 	 * Multiple groups configuration
29548275SEric Cheng 	 */
29558275SEric Cheng 	ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM,
295611878SVenu.Iyer@Sun.COM 	    ixgbe->capab->min_rx_grp_num, ixgbe->capab->max_rx_grp_num,
295711878SVenu.Iyer@Sun.COM 	    ixgbe->capab->def_rx_grp_num);
29588275SEric Cheng 
29598275SEric Cheng 	ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE,
29608275SEric Cheng 	    0, 1, DEFAULT_MR_ENABLE);
29618275SEric Cheng 
29628275SEric Cheng 	if (ixgbe->mr_enable == B_FALSE) {
29638275SEric Cheng 		ixgbe->num_tx_rings = 1;
29648275SEric Cheng 		ixgbe->num_rx_rings = 1;
29658275SEric Cheng 		ixgbe->num_rx_groups = 1;
296611878SVenu.Iyer@Sun.COM 		ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
296711878SVenu.Iyer@Sun.COM 	} else {
296811878SVenu.Iyer@Sun.COM 		ixgbe->num_rx_rings = ixgbe->num_rx_groups *
296911878SVenu.Iyer@Sun.COM 		    max(ixgbe->num_rx_rings / ixgbe->num_rx_groups, 1);
297011878SVenu.Iyer@Sun.COM 		/*
297111878SVenu.Iyer@Sun.COM 		 * The combination of num_rx_rings and num_rx_groups
297211878SVenu.Iyer@Sun.COM 		 * may be not supported by h/w. We need to adjust
297311878SVenu.Iyer@Sun.COM 		 * them to appropriate values.
297411878SVenu.Iyer@Sun.COM 		 */
297511878SVenu.Iyer@Sun.COM 		ixgbe_setup_vmdq_rss_conf(ixgbe);
29768275SEric Cheng 	}
29778275SEric Cheng 
29788275SEric Cheng 	/*
29796621Sbt150084 	 * Tunable used to force an interrupt type. The only use is
29806621Sbt150084 	 * for testing of the lesser interrupt types.
29816621Sbt150084 	 * 0 = don't force interrupt type
29828275SEric Cheng 	 * 1 = force interrupt type MSI-X
29836621Sbt150084 	 * 2 = force interrupt type MSI
29846621Sbt150084 	 * 3 = force interrupt type Legacy
29856621Sbt150084 	 */
29866621Sbt150084 	ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE,
29876621Sbt150084 	    IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE);
29886621Sbt150084 
29896621Sbt150084 	ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE,
29907167Sgg161487 	    0, 1, DEFAULT_TX_HCKSUM_ENABLE);
29916621Sbt150084 	ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE,
29927167Sgg161487 	    0, 1, DEFAULT_RX_HCKSUM_ENABLE);
29936621Sbt150084 	ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE,
29947167Sgg161487 	    0, 1, DEFAULT_LSO_ENABLE);
299511486SZhen.W@Sun.COM 	ixgbe->lro_enable = ixgbe_get_prop(ixgbe, PROP_LRO_ENABLE,
299611486SZhen.W@Sun.COM 	    0, 1, DEFAULT_LRO_ENABLE);
29976621Sbt150084 	ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE,
29987167Sgg161487 	    0, 1, DEFAULT_TX_HEAD_WB_ENABLE);
29997167Sgg161487 
30009353SSamuel.Tu@Sun.COM 	/* Head Write Back not recommended for 82599 */
30019353SSamuel.Tu@Sun.COM 	if (hw->mac.type >= ixgbe_mac_82599EB) {
30029353SSamuel.Tu@Sun.COM 		ixgbe->tx_head_wb_enable = B_FALSE;
30039353SSamuel.Tu@Sun.COM 	}
30049353SSamuel.Tu@Sun.COM 
30057167Sgg161487 	/*
30067167Sgg161487 	 * ixgbe LSO needs the tx h/w checksum support.
30077167Sgg161487 	 * LSO will be disabled if tx h/w checksum is not
30087167Sgg161487 	 * enabled.
30097167Sgg161487 	 */
30107167Sgg161487 	if (ixgbe->tx_hcksum_enable == B_FALSE) {
30117167Sgg161487 		ixgbe->lso_enable = B_FALSE;
30127167Sgg161487 	}
30136621Sbt150084 
301411486SZhen.W@Sun.COM 	/*
301511486SZhen.W@Sun.COM 	 * ixgbe LRO needs the rx h/w checksum support.
301611486SZhen.W@Sun.COM 	 * LRO will be disabled if rx h/w checksum is not
301711486SZhen.W@Sun.COM 	 * enabled.
301811486SZhen.W@Sun.COM 	 */
301911486SZhen.W@Sun.COM 	if (ixgbe->rx_hcksum_enable == B_FALSE) {
302011486SZhen.W@Sun.COM 		ixgbe->lro_enable = B_FALSE;
302111486SZhen.W@Sun.COM 	}
302211486SZhen.W@Sun.COM 
302311486SZhen.W@Sun.COM 	/*
302411486SZhen.W@Sun.COM 	 * ixgbe LRO only been supported by 82599 now
302511486SZhen.W@Sun.COM 	 */
302611486SZhen.W@Sun.COM 	if (hw->mac.type != ixgbe_mac_82599EB) {
302711486SZhen.W@Sun.COM 		ixgbe->lro_enable = B_FALSE;
302811486SZhen.W@Sun.COM 	}
30296621Sbt150084 	ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD,
30306621Sbt150084 	    MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD,
30316621Sbt150084 	    DEFAULT_TX_COPY_THRESHOLD);
30326621Sbt150084 	ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe,
30336621Sbt150084 	    PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD,
30346621Sbt150084 	    MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD);
30356621Sbt150084 	ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe,
30366621Sbt150084 	    PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD,
30376621Sbt150084 	    MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD);
30386621Sbt150084 	ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe,
30396621Sbt150084 	    PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD,
30406621Sbt150084 	    MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD);
30416621Sbt150084 
30426621Sbt150084 	ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD,
30436621Sbt150084 	    MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD,
30446621Sbt150084 	    DEFAULT_RX_COPY_THRESHOLD);
30456621Sbt150084 	ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR,
30466621Sbt150084 	    MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR,
30476621Sbt150084 	    DEFAULT_RX_LIMIT_PER_INTR);
30486621Sbt150084 
304910376SChenlu.Chen@Sun.COM 	ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING,
305010376SChenlu.Chen@Sun.COM 	    ixgbe->capab->min_intr_throttle,
305110376SChenlu.Chen@Sun.COM 	    ixgbe->capab->max_intr_throttle,
305210376SChenlu.Chen@Sun.COM 	    ixgbe->capab->def_intr_throttle);
30539353SSamuel.Tu@Sun.COM 	/*
305410376SChenlu.Chen@Sun.COM 	 * 82599 requires the interupt throttling rate is
305510376SChenlu.Chen@Sun.COM 	 * a multiple of 8. This is enforced by the register
305610376SChenlu.Chen@Sun.COM 	 * definiton.
30579353SSamuel.Tu@Sun.COM 	 */
305810376SChenlu.Chen@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB)
305910376SChenlu.Chen@Sun.COM 		ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8;
306010376SChenlu.Chen@Sun.COM }
306110376SChenlu.Chen@Sun.COM 
306210376SChenlu.Chen@Sun.COM static void
306310376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe_t *ixgbe)
306410376SChenlu.Chen@Sun.COM {
306510376SChenlu.Chen@Sun.COM 	ixgbe->param_en_10000fdx_cap = 1;
306610376SChenlu.Chen@Sun.COM 	ixgbe->param_en_1000fdx_cap = 1;
306710376SChenlu.Chen@Sun.COM 	ixgbe->param_en_100fdx_cap = 1;
306810376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_10000fdx_cap = 1;
306910376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_1000fdx_cap = 1;
307010376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_100fdx_cap = 1;
307110376SChenlu.Chen@Sun.COM 
307210376SChenlu.Chen@Sun.COM 	ixgbe->param_pause_cap = 1;
307310376SChenlu.Chen@Sun.COM 	ixgbe->param_asym_pause_cap = 1;
307410376SChenlu.Chen@Sun.COM 	ixgbe->param_rem_fault = 0;
307510376SChenlu.Chen@Sun.COM 
307610376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_autoneg_cap = 1;
307710376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_pause_cap = 1;
307810376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_asym_pause_cap = 1;
307910376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_rem_fault = 0;
308010376SChenlu.Chen@Sun.COM 
308110376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_10000fdx_cap = 0;
308210376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_1000fdx_cap = 0;
308310376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_100fdx_cap = 0;
308410376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_autoneg_cap = 0;
308510376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_pause_cap = 0;
308610376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_asym_pause_cap = 0;
308710376SChenlu.Chen@Sun.COM 	ixgbe->param_lp_rem_fault = 0;
30886621Sbt150084 }
30896621Sbt150084 
30906621Sbt150084 /*
30916621Sbt150084  * ixgbe_get_prop - Get a property value out of the configuration file
30926621Sbt150084  * ixgbe.conf.
30936621Sbt150084  *
30946621Sbt150084  * Caller provides the name of the property, a default value, a minimum
30956621Sbt150084  * value, and a maximum value.
30966621Sbt150084  *
30976621Sbt150084  * Return configured value of the property, with default, minimum and
30986621Sbt150084  * maximum properly applied.
30996621Sbt150084  */
31006621Sbt150084 static int
31016621Sbt150084 ixgbe_get_prop(ixgbe_t *ixgbe,
31026621Sbt150084     char *propname,	/* name of the property */
31036621Sbt150084     int minval,		/* minimum acceptable value */
31046621Sbt150084     int maxval,		/* maximim acceptable value */
31056621Sbt150084     int defval)		/* default value */
31066621Sbt150084 {
31076621Sbt150084 	int value;
31086621Sbt150084 
31096621Sbt150084 	/*
31106621Sbt150084 	 * Call ddi_prop_get_int() to read the conf settings
31116621Sbt150084 	 */
31126621Sbt150084 	value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip,
31136621Sbt150084 	    DDI_PROP_DONTPASS, propname, defval);
31146621Sbt150084 	if (value > maxval)
31156621Sbt150084 		value = maxval;
31166621Sbt150084 
31176621Sbt150084 	if (value < minval)
31186621Sbt150084 		value = minval;
31196621Sbt150084 
31206621Sbt150084 	return (value);
31216621Sbt150084 }
31226621Sbt150084 
31236621Sbt150084 /*
31246621Sbt150084  * ixgbe_driver_setup_link - Using the link properties to setup the link.
31256621Sbt150084  */
31266621Sbt150084 int
31276621Sbt150084 ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw)
31286621Sbt150084 {
312910998SChenlu.Chen@Sun.COM 	u32 autoneg_advertised = 0;
313010998SChenlu.Chen@Sun.COM 
313110998SChenlu.Chen@Sun.COM 	/*
313210998SChenlu.Chen@Sun.COM 	 * No half duplex support with 10Gb parts
313310998SChenlu.Chen@Sun.COM 	 */
313410998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_10000fdx_cap == 1)
313510998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
313610998SChenlu.Chen@Sun.COM 
313710998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_1000fdx_cap == 1)
313810998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
313910998SChenlu.Chen@Sun.COM 
314010998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_100fdx_cap == 1)
314110998SChenlu.Chen@Sun.COM 		autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
314210998SChenlu.Chen@Sun.COM 
314310998SChenlu.Chen@Sun.COM 	if (ixgbe->param_adv_autoneg_cap == 1 && autoneg_advertised == 0) {
314410998SChenlu.Chen@Sun.COM 		ixgbe_notice(ixgbe, "Invalid link settings. Setup link "
314510998SChenlu.Chen@Sun.COM 		    "to autonegotiation with full link capabilities.");
314610998SChenlu.Chen@Sun.COM 
314710998SChenlu.Chen@Sun.COM 		autoneg_advertised = IXGBE_LINK_SPEED_10GB_FULL |
314810998SChenlu.Chen@Sun.COM 		    IXGBE_LINK_SPEED_1GB_FULL |
314910998SChenlu.Chen@Sun.COM 		    IXGBE_LINK_SPEED_100_FULL;
31506621Sbt150084 	}
31516621Sbt150084 
31526621Sbt150084 	if (setup_hw) {
315310998SChenlu.Chen@Sun.COM 		if (ixgbe_setup_link(&ixgbe->hw, autoneg_advertised,
315410998SChenlu.Chen@Sun.COM 		    ixgbe->param_adv_autoneg_cap, B_TRUE) != IXGBE_SUCCESS) {
31559353SSamuel.Tu@Sun.COM 			ixgbe_notice(ixgbe, "Setup link failed on this "
31569353SSamuel.Tu@Sun.COM 			    "device.");
31576621Sbt150084 			return (IXGBE_FAILURE);
31589353SSamuel.Tu@Sun.COM 		}
31596621Sbt150084 	}
31606621Sbt150084 
31616621Sbt150084 	return (IXGBE_SUCCESS);
31626621Sbt150084 }
31636621Sbt150084 
31646621Sbt150084 /*
316511233SPaul.Guo@Sun.COM  * ixgbe_driver_link_check - Link status processing.
316611233SPaul.Guo@Sun.COM  *
316711233SPaul.Guo@Sun.COM  * This function can be called in both kernel context and interrupt context
31686621Sbt150084  */
31698490SPaul.Guo@Sun.COM static void
317011233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe_t *ixgbe)
31716621Sbt150084 {
31726621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
31736621Sbt150084 	ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
31746621Sbt150084 	boolean_t link_up = B_FALSE;
31756621Sbt150084 	boolean_t link_changed = B_FALSE;
31766621Sbt150084 
317711233SPaul.Guo@Sun.COM 	ASSERT(mutex_owned(&ixgbe->gen_lock));
317811233SPaul.Guo@Sun.COM 
317911233SPaul.Guo@Sun.COM 	(void) ixgbe_check_link(hw, &speed, &link_up, false);
31806621Sbt150084 	if (link_up) {
318111233SPaul.Guo@Sun.COM 		ixgbe->link_check_complete = B_TRUE;
318211233SPaul.Guo@Sun.COM 
31839353SSamuel.Tu@Sun.COM 		/* Link is up, enable flow control settings */
31849353SSamuel.Tu@Sun.COM 		(void) ixgbe_fc_enable(hw, 0);
31859353SSamuel.Tu@Sun.COM 
31866621Sbt150084 		/*
31876621Sbt150084 		 * The Link is up, check whether it was marked as down earlier
31886621Sbt150084 		 */
31896621Sbt150084 		if (ixgbe->link_state != LINK_STATE_UP) {
31906621Sbt150084 			switch (speed) {
31919353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_10GB_FULL:
31929353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_10GB;
31939353SSamuel.Tu@Sun.COM 				break;
31949353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_1GB_FULL:
31959353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_1GB;
31969353SSamuel.Tu@Sun.COM 				break;
31979353SSamuel.Tu@Sun.COM 			case IXGBE_LINK_SPEED_100_FULL:
31989353SSamuel.Tu@Sun.COM 				ixgbe->link_speed = SPEED_100;
31996621Sbt150084 			}
32006621Sbt150084 			ixgbe->link_duplex = LINK_DUPLEX_FULL;
32016621Sbt150084 			ixgbe->link_state = LINK_STATE_UP;
32026621Sbt150084 			link_changed = B_TRUE;
32036621Sbt150084 		}
32046621Sbt150084 	} else {
320511233SPaul.Guo@Sun.COM 		if (ixgbe->link_check_complete == B_TRUE ||
320611233SPaul.Guo@Sun.COM 		    (ixgbe->link_check_complete == B_FALSE &&
320711233SPaul.Guo@Sun.COM 		    gethrtime() >= ixgbe->link_check_hrtime)) {
320811233SPaul.Guo@Sun.COM 			/*
320911233SPaul.Guo@Sun.COM 			 * The link is really down
321011233SPaul.Guo@Sun.COM 			 */
321111233SPaul.Guo@Sun.COM 			ixgbe->link_check_complete = B_TRUE;
321211233SPaul.Guo@Sun.COM 
321311233SPaul.Guo@Sun.COM 			if (ixgbe->link_state != LINK_STATE_DOWN) {
321411233SPaul.Guo@Sun.COM 				ixgbe->link_speed = 0;
321511233SPaul.Guo@Sun.COM 				ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN;
321611233SPaul.Guo@Sun.COM 				ixgbe->link_state = LINK_STATE_DOWN;
321711233SPaul.Guo@Sun.COM 				link_changed = B_TRUE;
321811233SPaul.Guo@Sun.COM 			}
32196621Sbt150084 		}
32206621Sbt150084 	}
32216621Sbt150084 
32228490SPaul.Guo@Sun.COM 	/*
32238490SPaul.Guo@Sun.COM 	 * this is only reached after a link-status-change interrupt
32248490SPaul.Guo@Sun.COM 	 * so always get new phy state
32258490SPaul.Guo@Sun.COM 	 */
32268490SPaul.Guo@Sun.COM 	ixgbe_get_hw_state(ixgbe);
32278490SPaul.Guo@Sun.COM 
322811233SPaul.Guo@Sun.COM 	/*
322911233SPaul.Guo@Sun.COM 	 * If we are in an interrupt context, need to re-enable the
323011233SPaul.Guo@Sun.COM 	 * interrupt, which was automasked
323111233SPaul.Guo@Sun.COM 	 */
323211233SPaul.Guo@Sun.COM 	if (servicing_interrupt() != 0) {
323311233SPaul.Guo@Sun.COM 		ixgbe->eims |= IXGBE_EICR_LSC;
323411233SPaul.Guo@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
323511233SPaul.Guo@Sun.COM 	}
323611233SPaul.Guo@Sun.COM 
32378490SPaul.Guo@Sun.COM 	if (link_changed) {
32388490SPaul.Guo@Sun.COM 		mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
32398490SPaul.Guo@Sun.COM 	}
32406621Sbt150084 }
32416621Sbt150084 
32426621Sbt150084 /*
32439353SSamuel.Tu@Sun.COM  * ixgbe_sfp_check - sfp module processing done in taskq only for 82599.
32449353SSamuel.Tu@Sun.COM  */
32459353SSamuel.Tu@Sun.COM static void
32469353SSamuel.Tu@Sun.COM ixgbe_sfp_check(void *arg)
32479353SSamuel.Tu@Sun.COM {
32489353SSamuel.Tu@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
32499353SSamuel.Tu@Sun.COM 	uint32_t eicr = ixgbe->eicr;
32509353SSamuel.Tu@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
32519353SSamuel.Tu@Sun.COM 
325211233SPaul.Guo@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
32539353SSamuel.Tu@Sun.COM 	if (eicr & IXGBE_EICR_GPI_SDP1) {
32549353SSamuel.Tu@Sun.COM 		/* clear the interrupt */
32559353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
32569353SSamuel.Tu@Sun.COM 
32579353SSamuel.Tu@Sun.COM 		/* if link up, do multispeed fiber setup */
325810998SChenlu.Chen@Sun.COM 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
325910998SChenlu.Chen@Sun.COM 		    B_TRUE, B_TRUE);
32609353SSamuel.Tu@Sun.COM 		ixgbe_driver_link_check(ixgbe);
32619353SSamuel.Tu@Sun.COM 	} else if (eicr & IXGBE_EICR_GPI_SDP2) {
32629353SSamuel.Tu@Sun.COM 		/* clear the interrupt */
32639353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
32649353SSamuel.Tu@Sun.COM 
32659353SSamuel.Tu@Sun.COM 		/* if link up, do sfp module setup */
32669353SSamuel.Tu@Sun.COM 		(void) hw->mac.ops.setup_sfp(hw);
32679353SSamuel.Tu@Sun.COM 
32689353SSamuel.Tu@Sun.COM 		/* do multispeed fiber setup */
326910998SChenlu.Chen@Sun.COM 		(void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
327010998SChenlu.Chen@Sun.COM 		    B_TRUE, B_TRUE);
32719353SSamuel.Tu@Sun.COM 		ixgbe_driver_link_check(ixgbe);
32729353SSamuel.Tu@Sun.COM 	}
327311233SPaul.Guo@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
327411233SPaul.Guo@Sun.COM }
327511233SPaul.Guo@Sun.COM 
327611233SPaul.Guo@Sun.COM /*
327711233SPaul.Guo@Sun.COM  * ixgbe_link_timer - timer for link status detection
327811233SPaul.Guo@Sun.COM  */
327911233SPaul.Guo@Sun.COM static void
328011233SPaul.Guo@Sun.COM ixgbe_link_timer(void *arg)
328111233SPaul.Guo@Sun.COM {
328211233SPaul.Guo@Sun.COM 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
328311233SPaul.Guo@Sun.COM 
328411233SPaul.Guo@Sun.COM 	mutex_enter(&ixgbe->gen_lock);
328511233SPaul.Guo@Sun.COM 	ixgbe_driver_link_check(ixgbe);
328611233SPaul.Guo@Sun.COM 	mutex_exit(&ixgbe->gen_lock);
32879353SSamuel.Tu@Sun.COM }
32889353SSamuel.Tu@Sun.COM 
32899353SSamuel.Tu@Sun.COM /*
32906621Sbt150084  * ixgbe_local_timer - Driver watchdog function.
32916621Sbt150084  *
329211233SPaul.Guo@Sun.COM  * This function will handle the transmit stall check and other routines.
32936621Sbt150084  */
32946621Sbt150084 static void
32956621Sbt150084 ixgbe_local_timer(void *arg)
32966621Sbt150084 {
32976621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
32986621Sbt150084 
329911233SPaul.Guo@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_ERROR) {
33006621Sbt150084 		ixgbe->reset_count++;
33016621Sbt150084 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
33026621Sbt150084 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
330311233SPaul.Guo@Sun.COM 		ixgbe_restart_watchdog_timer(ixgbe);
330411233SPaul.Guo@Sun.COM 		return;
33056621Sbt150084 	}
33066621Sbt150084 
330711233SPaul.Guo@Sun.COM 	if (ixgbe_stall_check(ixgbe)) {
330811233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL);
330911233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
331011233SPaul.Guo@Sun.COM 
331111233SPaul.Guo@Sun.COM 		ixgbe->reset_count++;
331211233SPaul.Guo@Sun.COM 		if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
331311233SPaul.Guo@Sun.COM 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
331411233SPaul.Guo@Sun.COM 	}
331511486SZhen.W@Sun.COM 
331611486SZhen.W@Sun.COM 	ixgbe_restart_watchdog_timer(ixgbe);
33176621Sbt150084 }
33186621Sbt150084 
33196621Sbt150084 /*
33206621Sbt150084  * ixgbe_stall_check - Check for transmit stall.
33216621Sbt150084  *
33226621Sbt150084  * This function checks if the adapter is stalled (in transmit).
33236621Sbt150084  *
33246621Sbt150084  * It is called each time the watchdog timeout is invoked.
33256621Sbt150084  * If the transmit descriptor reclaim continuously fails,
33266621Sbt150084  * the watchdog value will increment by 1. If the watchdog
33276621Sbt150084  * value exceeds the threshold, the ixgbe is assumed to
33286621Sbt150084  * have stalled and need to be reset.
33296621Sbt150084  */
33306621Sbt150084 static boolean_t
33316621Sbt150084 ixgbe_stall_check(ixgbe_t *ixgbe)
33326621Sbt150084 {
33336621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
33346621Sbt150084 	boolean_t result;
33356621Sbt150084 	int i;
33366621Sbt150084 
33376621Sbt150084 	if (ixgbe->link_state != LINK_STATE_UP)
33386621Sbt150084 		return (B_FALSE);
33396621Sbt150084 
33406621Sbt150084 	/*
33416621Sbt150084 	 * If any tx ring is stalled, we'll reset the chipset
33426621Sbt150084 	 */
33436621Sbt150084 	result = B_FALSE;
33446621Sbt150084 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
33456621Sbt150084 		tx_ring = &ixgbe->tx_rings[i];
334610376SChenlu.Chen@Sun.COM 		if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) {
334710305SPaul.Guo@Sun.COM 			tx_ring->tx_recycle(tx_ring);
334810305SPaul.Guo@Sun.COM 		}
33496621Sbt150084 
33506621Sbt150084 		if (tx_ring->recycle_fail > 0)
33516621Sbt150084 			tx_ring->stall_watchdog++;
33526621Sbt150084 		else
33536621Sbt150084 			tx_ring->stall_watchdog = 0;
33546621Sbt150084 
33556621Sbt150084 		if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) {
33566621Sbt150084 			result = B_TRUE;
33576621Sbt150084 			break;
33586621Sbt150084 		}
33596621Sbt150084 	}
33606621Sbt150084 
33616621Sbt150084 	if (result) {
33626621Sbt150084 		tx_ring->stall_watchdog = 0;
33636621Sbt150084 		tx_ring->recycle_fail = 0;
33646621Sbt150084 	}
33656621Sbt150084 
33666621Sbt150084 	return (result);
33676621Sbt150084 }
33686621Sbt150084 
33696621Sbt150084 
33706621Sbt150084 /*
33716621Sbt150084  * is_valid_mac_addr - Check if the mac address is valid.
33726621Sbt150084  */
33736621Sbt150084 static boolean_t
33746621Sbt150084 is_valid_mac_addr(uint8_t *mac_addr)
33756621Sbt150084 {
33766621Sbt150084 	const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 };
33776621Sbt150084 	const uint8_t addr_test2[6] =
33786621Sbt150084 	    { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
33796621Sbt150084 
33806621Sbt150084 	if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) ||
33816621Sbt150084 	    !(bcmp(addr_test2, mac_addr, ETHERADDRL)))
33826621Sbt150084 		return (B_FALSE);
33836621Sbt150084 
33846621Sbt150084 	return (B_TRUE);
33856621Sbt150084 }
33866621Sbt150084 
33876621Sbt150084 static boolean_t
33886621Sbt150084 ixgbe_find_mac_address(ixgbe_t *ixgbe)
33896621Sbt150084 {
33906621Sbt150084 #ifdef __sparc
33916621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
33926621Sbt150084 	uchar_t *bytes;
33936621Sbt150084 	struct ether_addr sysaddr;
33946621Sbt150084 	uint_t nelts;
33956621Sbt150084 	int err;
33966621Sbt150084 	boolean_t found = B_FALSE;
33976621Sbt150084 
33986621Sbt150084 	/*
33996621Sbt150084 	 * The "vendor's factory-set address" may already have
34006621Sbt150084 	 * been extracted from the chip, but if the property
34016621Sbt150084 	 * "local-mac-address" is set we use that instead.
34026621Sbt150084 	 *
34036621Sbt150084 	 * We check whether it looks like an array of 6
34046621Sbt150084 	 * bytes (which it should, if OBP set it).  If we can't
34056621Sbt150084 	 * make sense of it this way, we'll ignore it.
34066621Sbt150084 	 */
34076621Sbt150084 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
34086621Sbt150084 	    DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts);
34096621Sbt150084 	if (err == DDI_PROP_SUCCESS) {
34106621Sbt150084 		if (nelts == ETHERADDRL) {
34116621Sbt150084 			while (nelts--)
34126621Sbt150084 				hw->mac.addr[nelts] = bytes[nelts];
34136621Sbt150084 			found = B_TRUE;
34146621Sbt150084 		}
34156621Sbt150084 		ddi_prop_free(bytes);
34166621Sbt150084 	}
34176621Sbt150084 
34186621Sbt150084 	/*
34196621Sbt150084 	 * Look up the OBP property "local-mac-address?". If the user has set
34206621Sbt150084 	 * 'local-mac-address? = false', use "the system address" instead.
34216621Sbt150084 	 */
34226621Sbt150084 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0,
34236621Sbt150084 	    "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) {
34246621Sbt150084 		if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) {
34256621Sbt150084 			if (localetheraddr(NULL, &sysaddr) != 0) {
34266621Sbt150084 				bcopy(&sysaddr, hw->mac.addr, ETHERADDRL);
34276621Sbt150084 				found = B_TRUE;
34286621Sbt150084 			}
34296621Sbt150084 		}
34306621Sbt150084 		ddi_prop_free(bytes);
34316621Sbt150084 	}
34326621Sbt150084 
34336621Sbt150084 	/*
34346621Sbt150084 	 * Finally(!), if there's a valid "mac-address" property (created
34356621Sbt150084 	 * if we netbooted from this interface), we must use this instead
34366621Sbt150084 	 * of any of the above to ensure that the NFS/install server doesn't
34376621Sbt150084 	 * get confused by the address changing as Solaris takes over!
34386621Sbt150084 	 */
34396621Sbt150084 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
34406621Sbt150084 	    DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts);
34416621Sbt150084 	if (err == DDI_PROP_SUCCESS) {
34426621Sbt150084 		if (nelts == ETHERADDRL) {
34436621Sbt150084 			while (nelts--)
34446621Sbt150084 				hw->mac.addr[nelts] = bytes[nelts];
34456621Sbt150084 			found = B_TRUE;
34466621Sbt150084 		}
34476621Sbt150084 		ddi_prop_free(bytes);
34486621Sbt150084 	}
34496621Sbt150084 
34506621Sbt150084 	if (found) {
34516621Sbt150084 		bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
34526621Sbt150084 		return (B_TRUE);
34536621Sbt150084 	}
34546621Sbt150084 #else
34556621Sbt150084 	_NOTE(ARGUNUSED(ixgbe));
34566621Sbt150084 #endif
34576621Sbt150084 
34586621Sbt150084 	return (B_TRUE);
34596621Sbt150084 }
34606621Sbt150084 
34616621Sbt150084 #pragma inline(ixgbe_arm_watchdog_timer)
34626621Sbt150084 static void
34636621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe)
34646621Sbt150084 {
34656621Sbt150084 	/*
34666621Sbt150084 	 * Fire a watchdog timer
34676621Sbt150084 	 */
34686621Sbt150084 	ixgbe->watchdog_tid =
34696621Sbt150084 	    timeout(ixgbe_local_timer,
34706621Sbt150084 	    (void *)ixgbe, 1 * drv_usectohz(1000000));
34716621Sbt150084 
34726621Sbt150084 }
34736621Sbt150084 
34746621Sbt150084 /*
34756621Sbt150084  * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer.
34766621Sbt150084  */
34776621Sbt150084 void
34786621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe)
34796621Sbt150084 {
34806621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
34816621Sbt150084 
34826621Sbt150084 	if (!ixgbe->watchdog_enable) {
34836621Sbt150084 		ixgbe->watchdog_enable = B_TRUE;
34846621Sbt150084 		ixgbe->watchdog_start = B_TRUE;
34856621Sbt150084 		ixgbe_arm_watchdog_timer(ixgbe);
34866621Sbt150084 	}
34876621Sbt150084 
34886621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
34896621Sbt150084 }
34906621Sbt150084 
34916621Sbt150084 /*
34926621Sbt150084  * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer.
34936621Sbt150084  */
34946621Sbt150084 void
34956621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe)
34966621Sbt150084 {
34976621Sbt150084 	timeout_id_t tid;
34986621Sbt150084 
34996621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
35006621Sbt150084 
35016621Sbt150084 	ixgbe->watchdog_enable = B_FALSE;
35026621Sbt150084 	ixgbe->watchdog_start = B_FALSE;
35036621Sbt150084 	tid = ixgbe->watchdog_tid;
35046621Sbt150084 	ixgbe->watchdog_tid = 0;
35056621Sbt150084 
35066621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
35076621Sbt150084 
35086621Sbt150084 	if (tid != 0)
35096621Sbt150084 		(void) untimeout(tid);
35106621Sbt150084 }
35116621Sbt150084 
35126621Sbt150084 /*
35136621Sbt150084  * ixgbe_start_watchdog_timer - Start the driver watchdog timer.
35146621Sbt150084  */
35158490SPaul.Guo@Sun.COM void
35166621Sbt150084 ixgbe_start_watchdog_timer(ixgbe_t *ixgbe)
35176621Sbt150084 {
35186621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
35196621Sbt150084 
35206621Sbt150084 	if (ixgbe->watchdog_enable) {
35216621Sbt150084 		if (!ixgbe->watchdog_start) {
35226621Sbt150084 			ixgbe->watchdog_start = B_TRUE;
35236621Sbt150084 			ixgbe_arm_watchdog_timer(ixgbe);
35246621Sbt150084 		}
35256621Sbt150084 	}
35266621Sbt150084 
35276621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
35286621Sbt150084 }
35296621Sbt150084 
35306621Sbt150084 /*
35316621Sbt150084  * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer.
35326621Sbt150084  */
35336621Sbt150084 static void
35346621Sbt150084 ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe)
35356621Sbt150084 {
35366621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
35376621Sbt150084 
35386621Sbt150084 	if (ixgbe->watchdog_start)
35396621Sbt150084 		ixgbe_arm_watchdog_timer(ixgbe);
35406621Sbt150084 
35416621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
35426621Sbt150084 }
35436621Sbt150084 
35446621Sbt150084 /*
35456621Sbt150084  * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer.
35466621Sbt150084  */
35478490SPaul.Guo@Sun.COM void
35486621Sbt150084 ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe)
35496621Sbt150084 {
35506621Sbt150084 	timeout_id_t tid;
35516621Sbt150084 
35526621Sbt150084 	mutex_enter(&ixgbe->watchdog_lock);
35536621Sbt150084 
35546621Sbt150084 	ixgbe->watchdog_start = B_FALSE;
35556621Sbt150084 	tid = ixgbe->watchdog_tid;
35566621Sbt150084 	ixgbe->watchdog_tid = 0;
35576621Sbt150084 
35586621Sbt150084 	mutex_exit(&ixgbe->watchdog_lock);
35596621Sbt150084 
35606621Sbt150084 	if (tid != 0)
35616621Sbt150084 		(void) untimeout(tid);
35626621Sbt150084 }
35636621Sbt150084 
35646621Sbt150084 /*
35656621Sbt150084  * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts.
35666621Sbt150084  */
35676621Sbt150084 static void
35686621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe)
35696621Sbt150084 {
35706621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
35716621Sbt150084 
35726621Sbt150084 	/*
35736621Sbt150084 	 * mask all interrupts off
35746621Sbt150084 	 */
35756621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff);
35766621Sbt150084 
35776621Sbt150084 	/*
35786621Sbt150084 	 * for MSI-X, also disable autoclear
35796621Sbt150084 	 */
35806621Sbt150084 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
35816621Sbt150084 		IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0);
35826621Sbt150084 	}
35836621Sbt150084 
35846621Sbt150084 	IXGBE_WRITE_FLUSH(hw);
35856621Sbt150084 }
35866621Sbt150084 
35876621Sbt150084 /*
35886621Sbt150084  * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts.
35896621Sbt150084  */
35906621Sbt150084 static void
35916621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe)
35926621Sbt150084 {
35936621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
35948490SPaul.Guo@Sun.COM 	uint32_t eiac, eiam;
35958490SPaul.Guo@Sun.COM 	uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
35968490SPaul.Guo@Sun.COM 
35978490SPaul.Guo@Sun.COM 	/* interrupt types to enable */
35988490SPaul.Guo@Sun.COM 	ixgbe->eims = IXGBE_EIMS_ENABLE_MASK;	/* shared code default */
35998490SPaul.Guo@Sun.COM 	ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER;	/* minus tcp timer */
36008490SPaul.Guo@Sun.COM 	ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */
36018490SPaul.Guo@Sun.COM 
36028490SPaul.Guo@Sun.COM 	/* enable automask on "other" causes that this adapter can generate */
36038490SPaul.Guo@Sun.COM 	eiam = ixgbe->capab->other_intr;
36046621Sbt150084 
36056621Sbt150084 	/*
36066621Sbt150084 	 * msi-x mode
36076621Sbt150084 	 */
36086621Sbt150084 	if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
36096621Sbt150084 		/* enable autoclear but not on bits 29:20 */
36108490SPaul.Guo@Sun.COM 		eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR);
36116621Sbt150084 
36126621Sbt150084 		/* general purpose interrupt enable */
36138490SPaul.Guo@Sun.COM 		gpie |= (IXGBE_GPIE_MSIX_MODE
36148490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_PBA_SUPPORT
36158490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_OCD
36168490SPaul.Guo@Sun.COM 		    | IXGBE_GPIE_EIAME);
36176621Sbt150084 	/*
36186621Sbt150084 	 * non-msi-x mode
36196621Sbt150084 	 */
36206621Sbt150084 	} else {
36216621Sbt150084 
36226621Sbt150084 		/* disable autoclear, leave gpie at default */
36236621Sbt150084 		eiac = 0;
36248490SPaul.Guo@Sun.COM 
36259353SSamuel.Tu@Sun.COM 		/*
36269353SSamuel.Tu@Sun.COM 		 * General purpose interrupt enable.
36279353SSamuel.Tu@Sun.COM 		 * For 82599, extended interrupt automask enable
36289353SSamuel.Tu@Sun.COM 		 * only in MSI or MSI-X mode
36299353SSamuel.Tu@Sun.COM 		 */
36309353SSamuel.Tu@Sun.COM 		if ((hw->mac.type < ixgbe_mac_82599EB) ||
36319353SSamuel.Tu@Sun.COM 		    (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) {
36329353SSamuel.Tu@Sun.COM 			gpie |= IXGBE_GPIE_EIAME;
36339353SSamuel.Tu@Sun.COM 		}
36349353SSamuel.Tu@Sun.COM 	}
36359353SSamuel.Tu@Sun.COM 	/* Enable specific interrupts for 82599  */
36369353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
36379353SSamuel.Tu@Sun.COM 		gpie |= IXGBE_SDP2_GPIEN; /* pluggable optics intr */
36389353SSamuel.Tu@Sun.COM 		gpie |= IXGBE_SDP1_GPIEN; /* LSC interrupt */
36396621Sbt150084 	}
364011486SZhen.W@Sun.COM 	/* Enable RSC Dealy 8us for 82599  */
364111486SZhen.W@Sun.COM 	if (ixgbe->lro_enable) {
364211486SZhen.W@Sun.COM 		gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT);
364311486SZhen.W@Sun.COM 	}
36448490SPaul.Guo@Sun.COM 	/* write to interrupt control registers */
36458490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
36466621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac);
36478490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam);
36486621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
36496621Sbt150084 	IXGBE_WRITE_FLUSH(hw);
36506621Sbt150084 }
36516621Sbt150084 
36526621Sbt150084 /*
36536621Sbt150084  * ixgbe_loopback_ioctl - Loopback support.
36546621Sbt150084  */
36556621Sbt150084 enum ioc_reply
36566621Sbt150084 ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp)
36576621Sbt150084 {
36586621Sbt150084 	lb_info_sz_t *lbsp;
36596621Sbt150084 	lb_property_t *lbpp;
36606621Sbt150084 	uint32_t *lbmp;
36616621Sbt150084 	uint32_t size;
36626621Sbt150084 	uint32_t value;
36636621Sbt150084 
36646621Sbt150084 	if (mp->b_cont == NULL)
36656621Sbt150084 		return (IOC_INVAL);
36666621Sbt150084 
36676621Sbt150084 	switch (iocp->ioc_cmd) {
36686621Sbt150084 	default:
36696621Sbt150084 		return (IOC_INVAL);
36706621Sbt150084 
36716621Sbt150084 	case LB_GET_INFO_SIZE:
36726621Sbt150084 		size = sizeof (lb_info_sz_t);
36736621Sbt150084 		if (iocp->ioc_count != size)
36746621Sbt150084 			return (IOC_INVAL);
36756621Sbt150084 
36766621Sbt150084 		value = sizeof (lb_normal);
36776621Sbt150084 		value += sizeof (lb_mac);
367811150SZhen.W@Sun.COM 		value += sizeof (lb_external);
36796621Sbt150084 
36806621Sbt150084 		lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr;
36816621Sbt150084 		*lbsp = value;
36826621Sbt150084 		break;
36836621Sbt150084 
36846621Sbt150084 	case LB_GET_INFO:
36856621Sbt150084 		value = sizeof (lb_normal);
36866621Sbt150084 		value += sizeof (lb_mac);
368711150SZhen.W@Sun.COM 		value += sizeof (lb_external);
36886621Sbt150084 
36896621Sbt150084 		size = value;
36906621Sbt150084 		if (iocp->ioc_count != size)
36916621Sbt150084 			return (IOC_INVAL);
36926621Sbt150084 
36936621Sbt150084 		value = 0;
36946621Sbt150084 		lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr;
36956621Sbt150084 
36966621Sbt150084 		lbpp[value++] = lb_normal;
36976621Sbt150084 		lbpp[value++] = lb_mac;
369811150SZhen.W@Sun.COM 		lbpp[value++] = lb_external;
36996621Sbt150084 		break;
37006621Sbt150084 
37016621Sbt150084 	case LB_GET_MODE:
37026621Sbt150084 		size = sizeof (uint32_t);
37036621Sbt150084 		if (iocp->ioc_count != size)
37046621Sbt150084 			return (IOC_INVAL);
37056621Sbt150084 
37066621Sbt150084 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
37076621Sbt150084 		*lbmp = ixgbe->loopback_mode;
37086621Sbt150084 		break;
37096621Sbt150084 
37106621Sbt150084 	case LB_SET_MODE:
37116621Sbt150084 		size = 0;
37126621Sbt150084 		if (iocp->ioc_count != sizeof (uint32_t))
37136621Sbt150084 			return (IOC_INVAL);
37146621Sbt150084 
37156621Sbt150084 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
37166621Sbt150084 		if (!ixgbe_set_loopback_mode(ixgbe, *lbmp))
37176621Sbt150084 			return (IOC_INVAL);
37186621Sbt150084 		break;
37196621Sbt150084 	}
37206621Sbt150084 
37216621Sbt150084 	iocp->ioc_count = size;
37226621Sbt150084 	iocp->ioc_error = 0;
37236621Sbt150084 
37246621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
37256621Sbt150084 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
37266621Sbt150084 		return (IOC_INVAL);
37276621Sbt150084 	}
37286621Sbt150084 
37296621Sbt150084 	return (IOC_REPLY);
37306621Sbt150084 }
37316621Sbt150084 
37326621Sbt150084 /*
37336621Sbt150084  * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode.
37346621Sbt150084  */
37356621Sbt150084 static boolean_t
37366621Sbt150084 ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode)
37376621Sbt150084 {
37386621Sbt150084 	if (mode == ixgbe->loopback_mode)
37396621Sbt150084 		return (B_TRUE);
37406621Sbt150084 
37416621Sbt150084 	ixgbe->loopback_mode = mode;
37426621Sbt150084 
37436621Sbt150084 	if (mode == IXGBE_LB_NONE) {
37446621Sbt150084 		/*
37456621Sbt150084 		 * Reset the chip
37466621Sbt150084 		 */
37476621Sbt150084 		(void) ixgbe_reset(ixgbe);
37486621Sbt150084 		return (B_TRUE);
37496621Sbt150084 	}
37506621Sbt150084 
37516621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
37526621Sbt150084 
37536621Sbt150084 	switch (mode) {
37546621Sbt150084 	default:
37556621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
37566621Sbt150084 		return (B_FALSE);
37576621Sbt150084 
375811150SZhen.W@Sun.COM 	case IXGBE_LB_EXTERNAL:
375911150SZhen.W@Sun.COM 		break;
376011150SZhen.W@Sun.COM 
37616621Sbt150084 	case IXGBE_LB_INTERNAL_MAC:
37626621Sbt150084 		ixgbe_set_internal_mac_loopback(ixgbe);
37636621Sbt150084 		break;
37646621Sbt150084 	}
37656621Sbt150084 
37666621Sbt150084 	mutex_exit(&ixgbe->gen_lock);
37676621Sbt150084 
37686621Sbt150084 	return (B_TRUE);
37696621Sbt150084 }
37706621Sbt150084 
37716621Sbt150084 /*
37726621Sbt150084  * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode.
37736621Sbt150084  */
37746621Sbt150084 static void
37756621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe)
37766621Sbt150084 {
37776621Sbt150084 	struct ixgbe_hw *hw;
37786621Sbt150084 	uint32_t reg;
37796621Sbt150084 	uint8_t atlas;
37806621Sbt150084 
37816621Sbt150084 	hw = &ixgbe->hw;
37826621Sbt150084 
37836621Sbt150084 	/*
37846621Sbt150084 	 * Setup MAC loopback
37856621Sbt150084 	 */
37866621Sbt150084 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0);
37876621Sbt150084 	reg |= IXGBE_HLREG0_LPBK;
37886621Sbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg);
37896621Sbt150084 
37906621Sbt150084 	reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
37916621Sbt150084 	reg &= ~IXGBE_AUTOC_LMS_MASK;
37926621Sbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
37936621Sbt150084 
37946621Sbt150084 	/*
37956621Sbt150084 	 * Disable Atlas Tx lanes to keep packets in loopback and not on wire
37966621Sbt150084 	 */
37976621Sbt150084 	if (hw->mac.type == ixgbe_mac_82598EB) {
37986621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
37996621Sbt150084 		    &atlas);
38006621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_REG_EN;
38016621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
38026621Sbt150084 		    atlas);
38036621Sbt150084 
38046621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
38056621Sbt150084 		    &atlas);
38066621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
38076621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
38086621Sbt150084 		    atlas);
38096621Sbt150084 
38106621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
38116621Sbt150084 		    &atlas);
38126621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
38136621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
38146621Sbt150084 		    atlas);
38156621Sbt150084 
38166621Sbt150084 		(void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
38176621Sbt150084 		    &atlas);
38186621Sbt150084 		atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
38196621Sbt150084 		(void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
38206621Sbt150084 		    atlas);
3821*12280SChenlu.Chen@Sun.COM 	} else if (hw->mac.type == ixgbe_mac_82599EB) {
3822*12280SChenlu.Chen@Sun.COM 		reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
3823*12280SChenlu.Chen@Sun.COM 		reg |= (IXGBE_AUTOC_FLU |
3824*12280SChenlu.Chen@Sun.COM 		    IXGBE_AUTOC_10G_KX4);
3825*12280SChenlu.Chen@Sun.COM 		IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
3826*12280SChenlu.Chen@Sun.COM 
3827*12280SChenlu.Chen@Sun.COM 		(void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL,
3828*12280SChenlu.Chen@Sun.COM 		    B_FALSE, B_TRUE);
38296621Sbt150084 	}
38306621Sbt150084 }
38316621Sbt150084 
38326621Sbt150084 #pragma inline(ixgbe_intr_rx_work)
38336621Sbt150084 /*
38346621Sbt150084  * ixgbe_intr_rx_work - RX processing of ISR.
38356621Sbt150084  */
38366621Sbt150084 static void
38376621Sbt150084 ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring)
38386621Sbt150084 {
38396621Sbt150084 	mblk_t *mp;
38406621Sbt150084 
38416621Sbt150084 	mutex_enter(&rx_ring->rx_lock);
38426621Sbt150084 
38438275SEric Cheng 	mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
38446621Sbt150084 	mutex_exit(&rx_ring->rx_lock);
38456621Sbt150084 
38466621Sbt150084 	if (mp != NULL)
38478275SEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
38488275SEric Cheng 		    rx_ring->ring_gen_num);
38496621Sbt150084 }
38506621Sbt150084 
38516621Sbt150084 #pragma inline(ixgbe_intr_tx_work)
38526621Sbt150084 /*
38536621Sbt150084  * ixgbe_intr_tx_work - TX processing of ISR.
38546621Sbt150084  */
38556621Sbt150084 static void
38566621Sbt150084 ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring)
38576621Sbt150084 {
385810376SChenlu.Chen@Sun.COM 	ixgbe_t *ixgbe = tx_ring->ixgbe;
385910376SChenlu.Chen@Sun.COM 
38606621Sbt150084 	/*
38616621Sbt150084 	 * Recycle the tx descriptors
38626621Sbt150084 	 */
38636621Sbt150084 	tx_ring->tx_recycle(tx_ring);
38646621Sbt150084 
38656621Sbt150084 	/*
38666621Sbt150084 	 * Schedule the re-transmit
38676621Sbt150084 	 */
38686621Sbt150084 	if (tx_ring->reschedule &&
386910376SChenlu.Chen@Sun.COM 	    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) {
38706621Sbt150084 		tx_ring->reschedule = B_FALSE;
38718275SEric Cheng 		mac_tx_ring_update(tx_ring->ixgbe->mac_hdl,
38728275SEric Cheng 		    tx_ring->ring_handle);
38736621Sbt150084 		IXGBE_DEBUG_STAT(tx_ring->stat_reschedule);
38746621Sbt150084 	}
38756621Sbt150084 }
38766621Sbt150084 
38776621Sbt150084 #pragma inline(ixgbe_intr_other_work)
38786621Sbt150084 /*
38798490SPaul.Guo@Sun.COM  * ixgbe_intr_other_work - Process interrupt types other than tx/rx
38806621Sbt150084  */
38816621Sbt150084 static void
38828490SPaul.Guo@Sun.COM ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr)
38836621Sbt150084 {
38849353SSamuel.Tu@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
388511233SPaul.Guo@Sun.COM 
388611233SPaul.Guo@Sun.COM 	ASSERT(mutex_owned(&ixgbe->gen_lock));
388711233SPaul.Guo@Sun.COM 
38888490SPaul.Guo@Sun.COM 	/*
388911233SPaul.Guo@Sun.COM 	 * handle link status change
38908490SPaul.Guo@Sun.COM 	 */
38918490SPaul.Guo@Sun.COM 	if (eicr & IXGBE_EICR_LSC) {
389211233SPaul.Guo@Sun.COM 		ixgbe_driver_link_check(ixgbe);
38938490SPaul.Guo@Sun.COM 	}
38946621Sbt150084 
38956621Sbt150084 	/*
38968490SPaul.Guo@Sun.COM 	 * check for fan failure on adapters with fans
38976621Sbt150084 	 */
38988490SPaul.Guo@Sun.COM 	if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
38998490SPaul.Guo@Sun.COM 	    (eicr & IXGBE_EICR_GPI_SDP1)) {
39009353SSamuel.Tu@Sun.COM 		if (hw->mac.type < ixgbe_mac_82599EB) {
39019353SSamuel.Tu@Sun.COM 			ixgbe_log(ixgbe,
39029353SSamuel.Tu@Sun.COM 			    "Fan has stopped, replace the adapter\n");
39039353SSamuel.Tu@Sun.COM 
39049353SSamuel.Tu@Sun.COM 			/* re-enable the interrupt, which was automasked */
39059353SSamuel.Tu@Sun.COM 			ixgbe->eims |= IXGBE_EICR_GPI_SDP1;
39069353SSamuel.Tu@Sun.COM 		}
39079353SSamuel.Tu@Sun.COM 	}
39089353SSamuel.Tu@Sun.COM 
39099353SSamuel.Tu@Sun.COM 	/*
39109353SSamuel.Tu@Sun.COM 	 * Do SFP check for 82599
39119353SSamuel.Tu@Sun.COM 	 */
39129353SSamuel.Tu@Sun.COM 	if (hw->mac.type == ixgbe_mac_82599EB) {
391311233SPaul.Guo@Sun.COM 		if ((ddi_taskq_dispatch(ixgbe->sfp_taskq,
39149353SSamuel.Tu@Sun.COM 		    ixgbe_sfp_check, (void *)ixgbe,
39159353SSamuel.Tu@Sun.COM 		    DDI_NOSLEEP)) != DDI_SUCCESS) {
391610305SPaul.Guo@Sun.COM 			ixgbe_log(ixgbe, "No memory available to dispatch "
391710305SPaul.Guo@Sun.COM 			    "taskq for SFP check");
39189353SSamuel.Tu@Sun.COM 		}
391911233SPaul.Guo@Sun.COM 
392011233SPaul.Guo@Sun.COM 		/*
392111233SPaul.Guo@Sun.COM 		 * We need to fully re-check the link later.
392211233SPaul.Guo@Sun.COM 		 */
392311233SPaul.Guo@Sun.COM 		ixgbe->link_check_complete = B_FALSE;
392411233SPaul.Guo@Sun.COM 		ixgbe->link_check_hrtime = gethrtime() +
392511233SPaul.Guo@Sun.COM 		    (IXGBE_LINK_UP_TIME * 100000000ULL);
39268490SPaul.Guo@Sun.COM 	}
39276621Sbt150084 }
39286621Sbt150084 
39296621Sbt150084 /*
39306621Sbt150084  * ixgbe_intr_legacy - Interrupt handler for legacy interrupts.
39316621Sbt150084  */
39326621Sbt150084 static uint_t
39336621Sbt150084 ixgbe_intr_legacy(void *arg1, void *arg2)
39346621Sbt150084 {
39356621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
39366621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
39376621Sbt150084 	ixgbe_tx_ring_t *tx_ring;
39388275SEric Cheng 	ixgbe_rx_ring_t *rx_ring;
39396621Sbt150084 	uint32_t eicr;
39406621Sbt150084 	mblk_t *mp;
39416621Sbt150084 	boolean_t tx_reschedule;
39426621Sbt150084 	uint_t result;
39436621Sbt150084 
39448490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
39456621Sbt150084 
39466621Sbt150084 	mutex_enter(&ixgbe->gen_lock);
39476621Sbt150084 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
39486621Sbt150084 		mutex_exit(&ixgbe->gen_lock);
39496621Sbt150084 		return (DDI_INTR_UNCLAIMED);
39506621Sbt150084 	}
39516621Sbt150084 
39526621Sbt150084 	mp = NULL;
39536621Sbt150084 	tx_reschedule = B_FALSE;
39546621Sbt150084 
39556621Sbt150084 	/*
39566621Sbt150084 	 * Any bit set in eicr: claim this interrupt
39576621Sbt150084 	 */
39586621Sbt150084 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
395911233SPaul.Guo@Sun.COM 
396011233SPaul.Guo@Sun.COM 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
396112003SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
396211233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
396311233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
396411233SPaul.Guo@Sun.COM 		return (DDI_INTR_CLAIMED);
396511233SPaul.Guo@Sun.COM 	}
396611233SPaul.Guo@Sun.COM 
39676621Sbt150084 	if (eicr) {
39686621Sbt150084 		/*
39696621Sbt150084 		 * For legacy interrupt, we have only one interrupt,
39706621Sbt150084 		 * so we have only one rx ring and one tx ring enabled.
39716621Sbt150084 		 */
39726621Sbt150084 		ASSERT(ixgbe->num_rx_rings == 1);
39736621Sbt150084 		ASSERT(ixgbe->num_tx_rings == 1);
39746621Sbt150084 
39756621Sbt150084 		/*
39768275SEric Cheng 		 * For legacy interrupt, rx rings[0] will use RTxQ[0].
39776621Sbt150084 		 */
39788275SEric Cheng 		if (eicr & 0x1) {
39799353SSamuel.Tu@Sun.COM 			ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE;
39809353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
39819353SSamuel.Tu@Sun.COM 			ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
39826621Sbt150084 			/*
39836621Sbt150084 			 * Clean the rx descriptors
39846621Sbt150084 			 */
39858275SEric Cheng 			rx_ring = &ixgbe->rx_rings[0];
39868275SEric Cheng 			mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
39878275SEric Cheng 		}
39888275SEric Cheng 
39898275SEric Cheng 		/*
39908275SEric Cheng 		 * For legacy interrupt, tx rings[0] will use RTxQ[1].
39918275SEric Cheng 		 */
39928275SEric Cheng 		if (eicr & 0x2) {
39936621Sbt150084 			/*
39946621Sbt150084 			 * Recycle the tx descriptors
39956621Sbt150084 			 */
39966621Sbt150084 			tx_ring = &ixgbe->tx_rings[0];
39976621Sbt150084 			tx_ring->tx_recycle(tx_ring);
39986621Sbt150084 
39996621Sbt150084 			/*
40006621Sbt150084 			 * Schedule the re-transmit
40016621Sbt150084 			 */
40026621Sbt150084 			tx_reschedule = (tx_ring->reschedule &&
400310376SChenlu.Chen@Sun.COM 			    (tx_ring->tbd_free >= ixgbe->tx_resched_thresh));
40046621Sbt150084 		}
40056621Sbt150084 
40068490SPaul.Guo@Sun.COM 		/* any interrupt type other than tx/rx */
40078490SPaul.Guo@Sun.COM 		if (eicr & ixgbe->capab->other_intr) {
40089353SSamuel.Tu@Sun.COM 			if (hw->mac.type < ixgbe_mac_82599EB) {
40099353SSamuel.Tu@Sun.COM 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
40109353SSamuel.Tu@Sun.COM 			}
40119353SSamuel.Tu@Sun.COM 			if (hw->mac.type == ixgbe_mac_82599EB) {
40129353SSamuel.Tu@Sun.COM 				ixgbe->eimc = IXGBE_82599_OTHER_INTR;
40139353SSamuel.Tu@Sun.COM 				IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
40149353SSamuel.Tu@Sun.COM 			}
40159353SSamuel.Tu@Sun.COM 			ixgbe_intr_other_work(ixgbe, eicr);
40168490SPaul.Guo@Sun.COM 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
40176621Sbt150084 		}
40186621Sbt150084 
40198490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
40208490SPaul.Guo@Sun.COM 
40216621Sbt150084 		result = DDI_INTR_CLAIMED;
40226621Sbt150084 	} else {
40238490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
40248490SPaul.Guo@Sun.COM 
40256621Sbt150084 		/*
40266621Sbt150084 		 * No interrupt cause bits set: don't claim this interrupt.
40276621Sbt150084 		 */
40286621Sbt150084 		result = DDI_INTR_UNCLAIMED;
40296621Sbt150084 	}
40306621Sbt150084 
40318490SPaul.Guo@Sun.COM 	/* re-enable the interrupts which were automasked */
40328490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
40336621Sbt150084 
40346621Sbt150084 	/*
40356621Sbt150084 	 * Do the following work outside of the gen_lock
40366621Sbt150084 	 */
40379353SSamuel.Tu@Sun.COM 	if (mp != NULL) {
40388275SEric Cheng 		mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
40398275SEric Cheng 		    rx_ring->ring_gen_num);
40409353SSamuel.Tu@Sun.COM 	}
40416621Sbt150084 
40426621Sbt150084 	if (tx_reschedule)  {
40436621Sbt150084 		tx_ring->reschedule = B_FALSE;
40448275SEric Cheng 		mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle);
40456621Sbt150084 		IXGBE_DEBUG_STAT(tx_ring->stat_reschedule);
40466621Sbt150084 	}
40476621Sbt150084 
40486621Sbt150084 	return (result);
40496621Sbt150084 }
40506621Sbt150084 
40516621Sbt150084 /*
40526621Sbt150084  * ixgbe_intr_msi - Interrupt handler for MSI.
40536621Sbt150084  */
40546621Sbt150084 static uint_t
40556621Sbt150084 ixgbe_intr_msi(void *arg1, void *arg2)
40566621Sbt150084 {
40576621Sbt150084 	ixgbe_t *ixgbe = (ixgbe_t *)arg1;
40586621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
40596621Sbt150084 	uint32_t eicr;
40606621Sbt150084 
40618490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
40628490SPaul.Guo@Sun.COM 
40636621Sbt150084 	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
40646621Sbt150084 
406511233SPaul.Guo@Sun.COM 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
406611233SPaul.Guo@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
406711233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
406811233SPaul.Guo@Sun.COM 		return (DDI_INTR_CLAIMED);
406911233SPaul.Guo@Sun.COM 	}
407011233SPaul.Guo@Sun.COM 
40716621Sbt150084 	/*
40726621Sbt150084 	 * For MSI interrupt, we have only one vector,
40736621Sbt150084 	 * so we have only one rx ring and one tx ring enabled.
40746621Sbt150084 	 */
40756621Sbt150084 	ASSERT(ixgbe->num_rx_rings == 1);
40766621Sbt150084 	ASSERT(ixgbe->num_tx_rings == 1);
40776621Sbt150084 
40786621Sbt150084 	/*
40798275SEric Cheng 	 * For MSI interrupt, rx rings[0] will use RTxQ[0].
40806621Sbt150084 	 */
40818275SEric Cheng 	if (eicr & 0x1) {
40826621Sbt150084 		ixgbe_intr_rx_work(&ixgbe->rx_rings[0]);
40838275SEric Cheng 	}
40848275SEric Cheng 
40858275SEric Cheng 	/*
40868275SEric Cheng 	 * For MSI interrupt, tx rings[0] will use RTxQ[1].
40878275SEric Cheng 	 */
40888275SEric Cheng 	if (eicr & 0x2) {
40896621Sbt150084 		ixgbe_intr_tx_work(&ixgbe->tx_rings[0]);
40906621Sbt150084 	}
40916621Sbt150084 
40928490SPaul.Guo@Sun.COM 	/* any interrupt type other than tx/rx */
40938490SPaul.Guo@Sun.COM 	if (eicr & ixgbe->capab->other_intr) {
40948490SPaul.Guo@Sun.COM 		mutex_enter(&ixgbe->gen_lock);
40959353SSamuel.Tu@Sun.COM 		if (hw->mac.type < ixgbe_mac_82599EB) {
40969353SSamuel.Tu@Sun.COM 			ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
40979353SSamuel.Tu@Sun.COM 		}
40989353SSamuel.Tu@Sun.COM 		if (hw->mac.type == ixgbe_mac_82599EB) {
40999353SSamuel.Tu@Sun.COM 			ixgbe->eimc = IXGBE_82599_OTHER_INTR;
41009353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
41019353SSamuel.Tu@Sun.COM 		}
41029353SSamuel.Tu@Sun.COM 		ixgbe_intr_other_work(ixgbe, eicr);
41038490SPaul.Guo@Sun.COM 		ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
41048490SPaul.Guo@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
41056621Sbt150084 	}
41066621Sbt150084 
41078490SPaul.Guo@Sun.COM 	/* re-enable the interrupts which were automasked */
41088490SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
41098490SPaul.Guo@Sun.COM 
41106621Sbt150084 	return (DDI_INTR_CLAIMED);
41116621Sbt150084 }
41126621Sbt150084 
41136621Sbt150084 /*
41149353SSamuel.Tu@Sun.COM  * ixgbe_intr_msix - Interrupt handler for MSI-X.
41156621Sbt150084  */
41166621Sbt150084 static uint_t
41179353SSamuel.Tu@Sun.COM ixgbe_intr_msix(void *arg1, void *arg2)
41186621Sbt150084 {
41199353SSamuel.Tu@Sun.COM 	ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1;
41208275SEric Cheng 	ixgbe_t *ixgbe = vect->ixgbe;
41219353SSamuel.Tu@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
41229353SSamuel.Tu@Sun.COM 	uint32_t eicr;
41238275SEric Cheng 	int r_idx = 0;
41246621Sbt150084 
41258490SPaul.Guo@Sun.COM 	_NOTE(ARGUNUSED(arg2));
41268490SPaul.Guo@Sun.COM 
41276621Sbt150084 	/*
41288275SEric Cheng 	 * Clean each rx ring that has its bit set in the map
41296621Sbt150084 	 */
41306621Sbt150084 	r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1));
41316621Sbt150084 	while (r_idx >= 0) {
41326621Sbt150084 		ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]);
41336621Sbt150084 		r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
41346621Sbt150084 		    (ixgbe->num_rx_rings - 1));
41356621Sbt150084 	}
41366621Sbt150084 
41378275SEric Cheng 	/*
41388275SEric Cheng 	 * Clean each tx ring that has its bit set in the map
41398275SEric Cheng 	 */
41408275SEric Cheng 	r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1));
41418275SEric Cheng 	while (r_idx >= 0) {
41428275SEric Cheng 		ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]);
41438275SEric Cheng 		r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
41448275SEric Cheng 		    (ixgbe->num_tx_rings - 1));
41458275SEric Cheng 	}
41468275SEric Cheng 
41476621Sbt150084 
41486621Sbt150084 	/*
41499353SSamuel.Tu@Sun.COM 	 * Clean other interrupt (link change) that has its bit set in the map
41506621Sbt150084 	 */
41519353SSamuel.Tu@Sun.COM 	if (BT_TEST(vect->other_map, 0) == 1) {
41529353SSamuel.Tu@Sun.COM 		eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
41539353SSamuel.Tu@Sun.COM 
415411233SPaul.Guo@Sun.COM 		if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) !=
415511233SPaul.Guo@Sun.COM 		    DDI_FM_OK) {
415611233SPaul.Guo@Sun.COM 			ddi_fm_service_impact(ixgbe->dip,
415711233SPaul.Guo@Sun.COM 			    DDI_SERVICE_DEGRADED);
415811233SPaul.Guo@Sun.COM 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
415911233SPaul.Guo@Sun.COM 			return (DDI_INTR_CLAIMED);
416011233SPaul.Guo@Sun.COM 		}
416111233SPaul.Guo@Sun.COM 
41629353SSamuel.Tu@Sun.COM 		/*
41639353SSamuel.Tu@Sun.COM 		 * Need check cause bits and only other causes will
41649353SSamuel.Tu@Sun.COM 		 * be processed
41659353SSamuel.Tu@Sun.COM 		 */
41669353SSamuel.Tu@Sun.COM 		/* any interrupt type other than tx/rx */
41679353SSamuel.Tu@Sun.COM 		if (eicr & ixgbe->capab->other_intr) {
41689353SSamuel.Tu@Sun.COM 			if (hw->mac.type < ixgbe_mac_82599EB) {
41699353SSamuel.Tu@Sun.COM 				mutex_enter(&ixgbe->gen_lock);
41709353SSamuel.Tu@Sun.COM 				ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
41719353SSamuel.Tu@Sun.COM 				ixgbe_intr_other_work(ixgbe, eicr);
41729353SSamuel.Tu@Sun.COM 				mutex_exit(&ixgbe->gen_lock);
41739353SSamuel.Tu@Sun.COM 			} else {
41749353SSamuel.Tu@Sun.COM 				if (hw->mac.type == ixgbe_mac_82599EB) {
41759353SSamuel.Tu@Sun.COM 					mutex_enter(&ixgbe->gen_lock);
41769353SSamuel.Tu@Sun.COM 					ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
41779353SSamuel.Tu@Sun.COM 					ixgbe_intr_other_work(ixgbe, eicr);
41789353SSamuel.Tu@Sun.COM 					mutex_exit(&ixgbe->gen_lock);
41799353SSamuel.Tu@Sun.COM 				}
41809353SSamuel.Tu@Sun.COM 			}
41819353SSamuel.Tu@Sun.COM 		}
41829353SSamuel.Tu@Sun.COM 
41839353SSamuel.Tu@Sun.COM 		/* re-enable the interrupts which were automasked */
41849353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
41856621Sbt150084 	}
41866621Sbt150084 
41876621Sbt150084 	return (DDI_INTR_CLAIMED);
41886621Sbt150084 }
41896621Sbt150084 
41906621Sbt150084 /*
41916621Sbt150084  * ixgbe_alloc_intrs - Allocate interrupts for the driver.
41926621Sbt150084  *
41936621Sbt150084  * Normal sequence is to try MSI-X; if not sucessful, try MSI;
41946621Sbt150084  * if not successful, try Legacy.
41956621Sbt150084  * ixgbe->intr_force can be used to force sequence to start with
41966621Sbt150084  * any of the 3 types.
41976621Sbt150084  * If MSI-X is not used, number of tx/rx rings is forced to 1.
41986621Sbt150084  */
41996621Sbt150084 static int
42006621Sbt150084 ixgbe_alloc_intrs(ixgbe_t *ixgbe)
42016621Sbt150084 {
42026621Sbt150084 	dev_info_t *devinfo;
42036621Sbt150084 	int intr_types;
42046621Sbt150084 	int rc;
42056621Sbt150084 
42066621Sbt150084 	devinfo = ixgbe->dip;
42076621Sbt150084 
42086621Sbt150084 	/*
42096621Sbt150084 	 * Get supported interrupt types
42106621Sbt150084 	 */
42116621Sbt150084 	rc = ddi_intr_get_supported_types(devinfo, &intr_types);
42126621Sbt150084 
42136621Sbt150084 	if (rc != DDI_SUCCESS) {
42146621Sbt150084 		ixgbe_log(ixgbe,
42156621Sbt150084 		    "Get supported interrupt types failed: %d", rc);
42166621Sbt150084 		return (IXGBE_FAILURE);
42176621Sbt150084 	}
42186621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types);
42196621Sbt150084 
42206621Sbt150084 	ixgbe->intr_type = 0;
42216621Sbt150084 
42226621Sbt150084 	/*
42236621Sbt150084 	 * Install MSI-X interrupts
42246621Sbt150084 	 */
42256621Sbt150084 	if ((intr_types & DDI_INTR_TYPE_MSIX) &&
42266621Sbt150084 	    (ixgbe->intr_force <= IXGBE_INTR_MSIX)) {
42276621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX);
42286621Sbt150084 		if (rc == IXGBE_SUCCESS)
42296621Sbt150084 			return (IXGBE_SUCCESS);
42306621Sbt150084 
42316621Sbt150084 		ixgbe_log(ixgbe,
42326621Sbt150084 		    "Allocate MSI-X failed, trying MSI interrupts...");
42336621Sbt150084 	}
42346621Sbt150084 
42356621Sbt150084 	/*
42368275SEric Cheng 	 * MSI-X not used, force rings and groups to 1
42376621Sbt150084 	 */
42386621Sbt150084 	ixgbe->num_rx_rings = 1;
42398275SEric Cheng 	ixgbe->num_rx_groups = 1;
42406621Sbt150084 	ixgbe->num_tx_rings = 1;
424111878SVenu.Iyer@Sun.COM 	ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
42426621Sbt150084 	ixgbe_log(ixgbe,
42438275SEric Cheng 	    "MSI-X not used, force rings and groups number to 1");
42446621Sbt150084 
42456621Sbt150084 	/*
42466621Sbt150084 	 * Install MSI interrupts
42476621Sbt150084 	 */
42486621Sbt150084 	if ((intr_types & DDI_INTR_TYPE_MSI) &&
42496621Sbt150084 	    (ixgbe->intr_force <= IXGBE_INTR_MSI)) {
42506621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI);
42516621Sbt150084 		if (rc == IXGBE_SUCCESS)
42526621Sbt150084 			return (IXGBE_SUCCESS);
42536621Sbt150084 
42546621Sbt150084 		ixgbe_log(ixgbe,
42556621Sbt150084 		    "Allocate MSI failed, trying Legacy interrupts...");
42566621Sbt150084 	}
42576621Sbt150084 
42586621Sbt150084 	/*
42596621Sbt150084 	 * Install legacy interrupts
42606621Sbt150084 	 */
42616621Sbt150084 	if (intr_types & DDI_INTR_TYPE_FIXED) {
42626621Sbt150084 		rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED);
42636621Sbt150084 		if (rc == IXGBE_SUCCESS)
42646621Sbt150084 			return (IXGBE_SUCCESS);
42656621Sbt150084 
42666621Sbt150084 		ixgbe_log(ixgbe,
42676621Sbt150084 		    "Allocate Legacy interrupts failed");
42686621Sbt150084 	}
42696621Sbt150084 
42706621Sbt150084 	/*
42716621Sbt150084 	 * If none of the 3 types succeeded, return failure
42726621Sbt150084 	 */
42736621Sbt150084 	return (IXGBE_FAILURE);
42746621Sbt150084 }
42756621Sbt150084 
42766621Sbt150084 /*
42776621Sbt150084  * ixgbe_alloc_intr_handles - Allocate interrupt handles.
42786621Sbt150084  *
42796621Sbt150084  * For legacy and MSI, only 1 handle is needed.  For MSI-X,
42806621Sbt150084  * if fewer than 2 handles are available, return failure.
42818275SEric Cheng  * Upon success, this maps the vectors to rx and tx rings for
42828275SEric Cheng  * interrupts.
42836621Sbt150084  */
42846621Sbt150084 static int
42856621Sbt150084 ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type)
42866621Sbt150084 {
42876621Sbt150084 	dev_info_t *devinfo;
428811878SVenu.Iyer@Sun.COM 	int request, count, actual;
42898275SEric Cheng 	int minimum;
42906621Sbt150084 	int rc;
429111878SVenu.Iyer@Sun.COM 	uint32_t ring_per_group;
42926621Sbt150084 
42936621Sbt150084 	devinfo = ixgbe->dip;
42946621Sbt150084 
42956621Sbt150084 	switch (intr_type) {
42966621Sbt150084 	case DDI_INTR_TYPE_FIXED:
42976621Sbt150084 		request = 1;	/* Request 1 legacy interrupt handle */
42986621Sbt150084 		minimum = 1;
42996621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy");
43006621Sbt150084 		break;
43016621Sbt150084 
43026621Sbt150084 	case DDI_INTR_TYPE_MSI:
43036621Sbt150084 		request = 1;	/* Request 1 MSI interrupt handle */
43046621Sbt150084 		minimum = 1;
43056621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI");
43066621Sbt150084 		break;
43076621Sbt150084 
43086621Sbt150084 	case DDI_INTR_TYPE_MSIX:
43096621Sbt150084 		/*
43106621Sbt150084 		 * Best number of vectors for the adapter is
431111878SVenu.Iyer@Sun.COM 		 * (# rx rings + # tx rings), however we will
431211878SVenu.Iyer@Sun.COM 		 * limit the request number.
43136621Sbt150084 		 */
431411878SVenu.Iyer@Sun.COM 		request = min(16, ixgbe->num_rx_rings + ixgbe->num_tx_rings);
43159353SSamuel.Tu@Sun.COM 		if (request > ixgbe->capab->max_ring_vect)
43169353SSamuel.Tu@Sun.COM 			request = ixgbe->capab->max_ring_vect;
431711878SVenu.Iyer@Sun.COM 		minimum = 1;
43186621Sbt150084 		IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X");
43196621Sbt150084 		break;
43206621Sbt150084 
43216621Sbt150084 	default:
43226621Sbt150084 		ixgbe_log(ixgbe,
43236621Sbt150084 		    "invalid call to ixgbe_alloc_intr_handles(): %d\n",
43246621Sbt150084 		    intr_type);
43256621Sbt150084 		return (IXGBE_FAILURE);
43266621Sbt150084 	}
43276621Sbt150084 	IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d  minimum: %d",
43286621Sbt150084 	    request, minimum);
43296621Sbt150084 
43306621Sbt150084 	/*
43316621Sbt150084 	 * Get number of supported interrupts
43326621Sbt150084 	 */
43336621Sbt150084 	rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
43346621Sbt150084 	if ((rc != DDI_SUCCESS) || (count < minimum)) {
43356621Sbt150084 		ixgbe_log(ixgbe,
43366621Sbt150084 		    "Get interrupt number failed. Return: %d, count: %d",
43376621Sbt150084 		    rc, count);
43386621Sbt150084 		return (IXGBE_FAILURE);
43396621Sbt150084 	}
43406621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count);
43416621Sbt150084 
43426621Sbt150084 	actual = 0;
43436621Sbt150084 	ixgbe->intr_cnt = 0;
434411878SVenu.Iyer@Sun.COM 	ixgbe->intr_cnt_max = 0;
434511878SVenu.Iyer@Sun.COM 	ixgbe->intr_cnt_min = 0;
43466621Sbt150084 
43476621Sbt150084 	/*
43486621Sbt150084 	 * Allocate an array of interrupt handles
43496621Sbt150084 	 */
43506621Sbt150084 	ixgbe->intr_size = request * sizeof (ddi_intr_handle_t);
43516621Sbt150084 	ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP);
43526621Sbt150084 
43536621Sbt150084 	rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0,
43546621Sbt150084 	    request, &actual, DDI_INTR_ALLOC_NORMAL);
43556621Sbt150084 	if (rc != DDI_SUCCESS) {
43566621Sbt150084 		ixgbe_log(ixgbe, "Allocate interrupts failed. "
43576621Sbt150084 		    "return: %d, request: %d, actual: %d",
43586621Sbt150084 		    rc, request, actual);
43596621Sbt150084 		goto alloc_handle_fail;
43606621Sbt150084 	}
43616621Sbt150084 	IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual);
43626621Sbt150084 
436311878SVenu.Iyer@Sun.COM 	/*
436411878SVenu.Iyer@Sun.COM 	 * upper/lower limit of interrupts
436511878SVenu.Iyer@Sun.COM 	 */
43666621Sbt150084 	ixgbe->intr_cnt = actual;
436711878SVenu.Iyer@Sun.COM 	ixgbe->intr_cnt_max = request;
436811878SVenu.Iyer@Sun.COM 	ixgbe->intr_cnt_min = minimum;
436911878SVenu.Iyer@Sun.COM 
437011878SVenu.Iyer@Sun.COM 	/*
437111878SVenu.Iyer@Sun.COM 	 * rss number per group should not exceed the rx interrupt number,
437211878SVenu.Iyer@Sun.COM 	 * else need to adjust rx ring number.
437311878SVenu.Iyer@Sun.COM 	 */
437411878SVenu.Iyer@Sun.COM 	ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
437511878SVenu.Iyer@Sun.COM 	ASSERT((ixgbe->num_rx_rings % ixgbe->num_rx_groups) == 0);
437611878SVenu.Iyer@Sun.COM 	if (min(actual, ixgbe->num_rx_rings) < ring_per_group) {
437711878SVenu.Iyer@Sun.COM 		ixgbe->num_rx_rings = ixgbe->num_rx_groups *
437811878SVenu.Iyer@Sun.COM 		    min(actual, ixgbe->num_rx_rings);
437911878SVenu.Iyer@Sun.COM 		ixgbe_setup_vmdq_rss_conf(ixgbe);
438011878SVenu.Iyer@Sun.COM 	}
43816621Sbt150084 
43826621Sbt150084 	/*
43838275SEric Cheng 	 * Now we know the actual number of vectors.  Here we map the vector
43848275SEric Cheng 	 * to other, rx rings and tx ring.
43856621Sbt150084 	 */
43866621Sbt150084 	if (actual < minimum) {
43876621Sbt150084 		ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d",
43886621Sbt150084 		    actual);
43896621Sbt150084 		goto alloc_handle_fail;
43906621Sbt150084 	}
43916621Sbt150084 
43926621Sbt150084 	/*
43936621Sbt150084 	 * Get priority for first vector, assume remaining are all the same
43946621Sbt150084 	 */
43956621Sbt150084 	rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
43966621Sbt150084 	if (rc != DDI_SUCCESS) {
43976621Sbt150084 		ixgbe_log(ixgbe,
43986621Sbt150084 		    "Get interrupt priority failed: %d", rc);
43996621Sbt150084 		goto alloc_handle_fail;
44006621Sbt150084 	}
44016621Sbt150084 
44026621Sbt150084 	rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
44036621Sbt150084 	if (rc != DDI_SUCCESS) {
44046621Sbt150084 		ixgbe_log(ixgbe,
44056621Sbt150084 		    "Get interrupt cap failed: %d", rc);
44066621Sbt150084 		goto alloc_handle_fail;
44076621Sbt150084 	}
44086621Sbt150084 
44096621Sbt150084 	ixgbe->intr_type = intr_type;
44106621Sbt150084 
44116621Sbt150084 	return (IXGBE_SUCCESS);
44126621Sbt150084 
44136621Sbt150084 alloc_handle_fail:
44146621Sbt150084 	ixgbe_rem_intrs(ixgbe);
44156621Sbt150084 
44166621Sbt150084 	return (IXGBE_FAILURE);
44176621Sbt150084 }
44186621Sbt150084 
44196621Sbt150084 /*
44206621Sbt150084  * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type.
44216621Sbt150084  *
44226621Sbt150084  * Before adding the interrupt handlers, the interrupt vectors have
44236621Sbt150084  * been allocated, and the rx/tx rings have also been allocated.
44246621Sbt150084  */
44256621Sbt150084 static int
44266621Sbt150084 ixgbe_add_intr_handlers(ixgbe_t *ixgbe)
44276621Sbt150084 {
44288275SEric Cheng 	int vector = 0;
44296621Sbt150084 	int rc;
44306621Sbt150084 
44316621Sbt150084 	switch (ixgbe->intr_type) {
44326621Sbt150084 	case DDI_INTR_TYPE_MSIX:
44336621Sbt150084 		/*
44349353SSamuel.Tu@Sun.COM 		 * Add interrupt handler for all vectors
44356621Sbt150084 		 */
44369353SSamuel.Tu@Sun.COM 		for (vector = 0; vector < ixgbe->intr_cnt; vector++) {
44376621Sbt150084 			/*
44386621Sbt150084 			 * install pointer to vect_map[vector]
44396621Sbt150084 			 */
44406621Sbt150084 			rc = ddi_intr_add_handler(ixgbe->htable[vector],
44419353SSamuel.Tu@Sun.COM 			    (ddi_intr_handler_t *)ixgbe_intr_msix,
44426621Sbt150084 			    (void *)&ixgbe->vect_map[vector], NULL);
44436621Sbt150084 
44446621Sbt150084 			if (rc != DDI_SUCCESS) {
44456621Sbt150084 				ixgbe_log(ixgbe,
444612003SPaul.Guo@Sun.COM 				    "Add interrupt handler failed. "
44478275SEric Cheng 				    "return: %d, vector: %d", rc, vector);
44486621Sbt150084 				for (vector--; vector >= 0; vector--) {
44496621Sbt150084 					(void) ddi_intr_remove_handler(
44506621Sbt150084 					    ixgbe->htable[vector]);
44516621Sbt150084 				}
44526621Sbt150084 				return (IXGBE_FAILURE);
44536621Sbt150084 			}
44546621Sbt150084 		}
44558275SEric Cheng 
44566621Sbt150084 		break;
44576621Sbt150084 
44586621Sbt150084 	case DDI_INTR_TYPE_MSI:
44596621Sbt150084 		/*
44606621Sbt150084 		 * Add interrupt handlers for the only vector
44616621Sbt150084 		 */
44626621Sbt150084 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
44636621Sbt150084 		    (ddi_intr_handler_t *)ixgbe_intr_msi,
44646621Sbt150084 		    (void *)ixgbe, NULL);
44656621Sbt150084 
44666621Sbt150084 		if (rc != DDI_SUCCESS) {
44676621Sbt150084 			ixgbe_log(ixgbe,
44686621Sbt150084 			    "Add MSI interrupt handler failed: %d", rc);
44696621Sbt150084 			return (IXGBE_FAILURE);
44706621Sbt150084 		}
44716621Sbt150084 
44726621Sbt150084 		break;
44736621Sbt150084 
44746621Sbt150084 	case DDI_INTR_TYPE_FIXED:
44756621Sbt150084 		/*
44766621Sbt150084 		 * Add interrupt handlers for the only vector
44776621Sbt150084 		 */
44786621Sbt150084 		rc = ddi_intr_add_handler(ixgbe->htable[vector],
44796621Sbt150084 		    (ddi_intr_handler_t *)ixgbe_intr_legacy,
44806621Sbt150084 		    (void *)ixgbe, NULL);
44816621Sbt150084 
44826621Sbt150084 		if (rc != DDI_SUCCESS) {
44836621Sbt150084 			ixgbe_log(ixgbe,
44846621Sbt150084 			    "Add legacy interrupt handler failed: %d", rc);
44856621Sbt150084 			return (IXGBE_FAILURE);
44866621Sbt150084 		}
44876621Sbt150084 
44886621Sbt150084 		break;
44896621Sbt150084 
44906621Sbt150084 	default:
44916621Sbt150084 		return (IXGBE_FAILURE);
44926621Sbt150084 	}
44936621Sbt150084 
44946621Sbt150084 	return (IXGBE_SUCCESS);
44956621Sbt150084 }
44966621Sbt150084 
44976621Sbt150084 #pragma inline(ixgbe_map_rxring_to_vector)
44986621Sbt150084 /*
44996621Sbt150084  * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector.
45006621Sbt150084  */
45016621Sbt150084 static void
45026621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx)
45036621Sbt150084 {
45046621Sbt150084 	/*
45056621Sbt150084 	 * Set bit in map
45066621Sbt150084 	 */
45076621Sbt150084 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
45086621Sbt150084 
45096621Sbt150084 	/*
45106621Sbt150084 	 * Count bits set
45116621Sbt150084 	 */
45126621Sbt150084 	ixgbe->vect_map[v_idx].rxr_cnt++;
45136621Sbt150084 
45146621Sbt150084 	/*
45156621Sbt150084 	 * Remember bit position
45166621Sbt150084 	 */
45178275SEric Cheng 	ixgbe->rx_rings[r_idx].intr_vector = v_idx;
45186621Sbt150084 	ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx;
45196621Sbt150084 }
45206621Sbt150084 
45216621Sbt150084 #pragma inline(ixgbe_map_txring_to_vector)
45226621Sbt150084 /*
45236621Sbt150084  * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector.
45246621Sbt150084  */
45256621Sbt150084 static void
45266621Sbt150084 ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx)
45276621Sbt150084 {
45286621Sbt150084 	/*
45296621Sbt150084 	 * Set bit in map
45306621Sbt150084 	 */
45316621Sbt150084 	BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx);
45326621Sbt150084 
45336621Sbt150084 	/*
45346621Sbt150084 	 * Count bits set
45356621Sbt150084 	 */
45366621Sbt150084 	ixgbe->vect_map[v_idx].txr_cnt++;
45376621Sbt150084 
45386621Sbt150084 	/*
45396621Sbt150084 	 * Remember bit position
45406621Sbt150084 	 */
45418275SEric Cheng 	ixgbe->tx_rings[t_idx].intr_vector = v_idx;
45426621Sbt150084 	ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx;
45436621Sbt150084 }
45446621Sbt150084 
45456621Sbt150084 /*
45468275SEric Cheng  * ixgbe_setup_ivar - Set the given entry in the given interrupt vector
45476621Sbt150084  * allocation register (IVAR).
45489353SSamuel.Tu@Sun.COM  * cause:
45499353SSamuel.Tu@Sun.COM  *   -1 : other cause
45509353SSamuel.Tu@Sun.COM  *    0 : rx
45519353SSamuel.Tu@Sun.COM  *    1 : tx
45526621Sbt150084  */
45536621Sbt150084 static void
45549353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector,
45559353SSamuel.Tu@Sun.COM     int8_t cause)
45566621Sbt150084 {
45576621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
45586621Sbt150084 	u32 ivar, index;
45596621Sbt150084 
45609353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
45619353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
45629353SSamuel.Tu@Sun.COM 		msix_vector |= IXGBE_IVAR_ALLOC_VAL;
45639353SSamuel.Tu@Sun.COM 		if (cause == -1) {
45649353SSamuel.Tu@Sun.COM 			cause = 0;
45659353SSamuel.Tu@Sun.COM 		}
45669353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
45679353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
45689353SSamuel.Tu@Sun.COM 		ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3)));
45699353SSamuel.Tu@Sun.COM 		ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3)));
45709353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
45719353SSamuel.Tu@Sun.COM 		break;
45729353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
45739353SSamuel.Tu@Sun.COM 		if (cause == -1) {
45749353SSamuel.Tu@Sun.COM 			/* other causes */
45759353SSamuel.Tu@Sun.COM 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
45769353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
45779353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
45789353SSamuel.Tu@Sun.COM 			ivar &= ~(0xFF << index);
45799353SSamuel.Tu@Sun.COM 			ivar |= (msix_vector << index);
45809353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
45819353SSamuel.Tu@Sun.COM 		} else {
45829353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
45839353SSamuel.Tu@Sun.COM 			msix_vector |= IXGBE_IVAR_ALLOC_VAL;
45849353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
45859353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
45869353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
45879353SSamuel.Tu@Sun.COM 			ivar &= ~(0xFF << index);
45889353SSamuel.Tu@Sun.COM 			ivar |= (msix_vector << index);
45899353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
45909353SSamuel.Tu@Sun.COM 			    ivar);
45919353SSamuel.Tu@Sun.COM 		}
45929353SSamuel.Tu@Sun.COM 		break;
45939353SSamuel.Tu@Sun.COM 	default:
45949353SSamuel.Tu@Sun.COM 		break;
45959353SSamuel.Tu@Sun.COM 	}
45968275SEric Cheng }
45978275SEric Cheng 
45988275SEric Cheng /*
45998275SEric Cheng  * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of
46008275SEric Cheng  * given interrupt vector allocation register (IVAR).
46019353SSamuel.Tu@Sun.COM  * cause:
46029353SSamuel.Tu@Sun.COM  *   -1 : other cause
46039353SSamuel.Tu@Sun.COM  *    0 : rx
46049353SSamuel.Tu@Sun.COM  *    1 : tx
46058275SEric Cheng  */
46068275SEric Cheng static void
46079353SSamuel.Tu@Sun.COM ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
46088275SEric Cheng {
46098275SEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
46108275SEric Cheng 	u32 ivar, index;
46118275SEric Cheng 
46129353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
46139353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
46149353SSamuel.Tu@Sun.COM 		if (cause == -1) {
46159353SSamuel.Tu@Sun.COM 			cause = 0;
46169353SSamuel.Tu@Sun.COM 		}
46179353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
46189353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
46199353SSamuel.Tu@Sun.COM 		ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 *
46209353SSamuel.Tu@Sun.COM 		    (intr_alloc_entry & 0x3)));
46219353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
46229353SSamuel.Tu@Sun.COM 		break;
46239353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
46249353SSamuel.Tu@Sun.COM 		if (cause == -1) {
46259353SSamuel.Tu@Sun.COM 			/* other causes */
46269353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
46279353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
46289353SSamuel.Tu@Sun.COM 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
46299353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
46309353SSamuel.Tu@Sun.COM 		} else {
46319353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
46329353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
46339353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
46349353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
46359353SSamuel.Tu@Sun.COM 			ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
46369353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
46379353SSamuel.Tu@Sun.COM 			    ivar);
46389353SSamuel.Tu@Sun.COM 		}
46399353SSamuel.Tu@Sun.COM 		break;
46409353SSamuel.Tu@Sun.COM 	default:
46419353SSamuel.Tu@Sun.COM 		break;
46429353SSamuel.Tu@Sun.COM 	}
46438275SEric Cheng }
46448275SEric Cheng 
46458275SEric Cheng /*
46469353SSamuel.Tu@Sun.COM  * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of
46478275SEric Cheng  * given interrupt vector allocation register (IVAR).
46489353SSamuel.Tu@Sun.COM  * cause:
46499353SSamuel.Tu@Sun.COM  *   -1 : other cause
46509353SSamuel.Tu@Sun.COM  *    0 : rx
46519353SSamuel.Tu@Sun.COM  *    1 : tx
46528275SEric Cheng  */
46538275SEric Cheng static void
46549353SSamuel.Tu@Sun.COM ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
46558275SEric Cheng {
46568275SEric Cheng 	struct ixgbe_hw *hw = &ixgbe->hw;
46578275SEric Cheng 	u32 ivar, index;
46588275SEric Cheng 
46599353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
46609353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
46619353SSamuel.Tu@Sun.COM 		if (cause == -1) {
46629353SSamuel.Tu@Sun.COM 			cause = 0;
46639353SSamuel.Tu@Sun.COM 		}
46649353SSamuel.Tu@Sun.COM 		index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
46659353SSamuel.Tu@Sun.COM 		ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
46669353SSamuel.Tu@Sun.COM 		ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 *
46679353SSamuel.Tu@Sun.COM 		    (intr_alloc_entry & 0x3)));
46689353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
46699353SSamuel.Tu@Sun.COM 		break;
46709353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
46719353SSamuel.Tu@Sun.COM 		if (cause == -1) {
46729353SSamuel.Tu@Sun.COM 			/* other causes */
46739353SSamuel.Tu@Sun.COM 			index = (intr_alloc_entry & 1) * 8;
46749353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
46759353SSamuel.Tu@Sun.COM 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
46769353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
46779353SSamuel.Tu@Sun.COM 		} else {
46789353SSamuel.Tu@Sun.COM 			/* tx or rx causes */
46799353SSamuel.Tu@Sun.COM 			index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
46809353SSamuel.Tu@Sun.COM 			ivar = IXGBE_READ_REG(hw,
46819353SSamuel.Tu@Sun.COM 			    IXGBE_IVAR(intr_alloc_entry >> 1));
46829353SSamuel.Tu@Sun.COM 			ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
46839353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
46849353SSamuel.Tu@Sun.COM 			    ivar);
46859353SSamuel.Tu@Sun.COM 		}
46869353SSamuel.Tu@Sun.COM 		break;
46879353SSamuel.Tu@Sun.COM 	default:
46889353SSamuel.Tu@Sun.COM 		break;
46899353SSamuel.Tu@Sun.COM 	}
46906621Sbt150084 }
46916621Sbt150084 
46926621Sbt150084 /*
469311878SVenu.Iyer@Sun.COM  * Convert the rx ring index driver maintained to the rx ring index
469411878SVenu.Iyer@Sun.COM  * in h/w.
469511878SVenu.Iyer@Sun.COM  */
469611878SVenu.Iyer@Sun.COM static uint32_t
469711878SVenu.Iyer@Sun.COM ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index)
469811878SVenu.Iyer@Sun.COM {
469911878SVenu.Iyer@Sun.COM 
470011878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
470111878SVenu.Iyer@Sun.COM 	uint32_t rx_ring_per_group, hw_rx_index;
470211878SVenu.Iyer@Sun.COM 
470311878SVenu.Iyer@Sun.COM 	if (ixgbe->classify_mode == IXGBE_CLASSIFY_RSS ||
470411878SVenu.Iyer@Sun.COM 	    ixgbe->classify_mode == IXGBE_CLASSIFY_NONE) {
470511878SVenu.Iyer@Sun.COM 		return (sw_rx_index);
470611878SVenu.Iyer@Sun.COM 	} else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ) {
470711878SVenu.Iyer@Sun.COM 		if (hw->mac.type == ixgbe_mac_82598EB) {
470811878SVenu.Iyer@Sun.COM 			return (sw_rx_index);
470911878SVenu.Iyer@Sun.COM 		} else if (hw->mac.type == ixgbe_mac_82599EB) {
471011878SVenu.Iyer@Sun.COM 			return (sw_rx_index * 2);
471111878SVenu.Iyer@Sun.COM 		}
471211878SVenu.Iyer@Sun.COM 	} else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) {
471311878SVenu.Iyer@Sun.COM 		rx_ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
471411878SVenu.Iyer@Sun.COM 
471511878SVenu.Iyer@Sun.COM 		if (hw->mac.type == ixgbe_mac_82598EB) {
471611878SVenu.Iyer@Sun.COM 			hw_rx_index = (sw_rx_index / rx_ring_per_group) *
471711878SVenu.Iyer@Sun.COM 			    16 + (sw_rx_index % rx_ring_per_group);
471811878SVenu.Iyer@Sun.COM 			return (hw_rx_index);
471911878SVenu.Iyer@Sun.COM 		} else if (hw->mac.type == ixgbe_mac_82599EB) {
472011878SVenu.Iyer@Sun.COM 			if (ixgbe->num_rx_groups > 32) {
472111878SVenu.Iyer@Sun.COM 				hw_rx_index = (sw_rx_index /
472211878SVenu.Iyer@Sun.COM 				    rx_ring_per_group) * 2 +
472311878SVenu.Iyer@Sun.COM 				    (sw_rx_index % rx_ring_per_group);
472411878SVenu.Iyer@Sun.COM 			} else {
472511878SVenu.Iyer@Sun.COM 				hw_rx_index = (sw_rx_index /
472611878SVenu.Iyer@Sun.COM 				    rx_ring_per_group) * 4 +
472711878SVenu.Iyer@Sun.COM 				    (sw_rx_index % rx_ring_per_group);
472811878SVenu.Iyer@Sun.COM 			}
472911878SVenu.Iyer@Sun.COM 			return (hw_rx_index);
473011878SVenu.Iyer@Sun.COM 		}
473111878SVenu.Iyer@Sun.COM 	}
473211878SVenu.Iyer@Sun.COM 
473311878SVenu.Iyer@Sun.COM 	/*
473411878SVenu.Iyer@Sun.COM 	 * Should never reach. Just to make compiler happy.
473511878SVenu.Iyer@Sun.COM 	 */
473611878SVenu.Iyer@Sun.COM 	return (sw_rx_index);
473711878SVenu.Iyer@Sun.COM }
473811878SVenu.Iyer@Sun.COM 
473911878SVenu.Iyer@Sun.COM /*
47409353SSamuel.Tu@Sun.COM  * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors.
47416621Sbt150084  *
47429353SSamuel.Tu@Sun.COM  * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt
47439353SSamuel.Tu@Sun.COM  * to vector[0 - (intr_cnt -1)].
47446621Sbt150084  */
47456621Sbt150084 static int
47469353SSamuel.Tu@Sun.COM ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe)
47476621Sbt150084 {
47486621Sbt150084 	int i, vector = 0;
47496621Sbt150084 
47506621Sbt150084 	/* initialize vector map */
47516621Sbt150084 	bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
47529353SSamuel.Tu@Sun.COM 	for (i = 0; i < ixgbe->intr_cnt; i++) {
47539353SSamuel.Tu@Sun.COM 		ixgbe->vect_map[i].ixgbe = ixgbe;
47549353SSamuel.Tu@Sun.COM 	}
47556621Sbt150084 
47566621Sbt150084 	/*
47578275SEric Cheng 	 * non-MSI-X case is very simple: rx rings[0] on RTxQ[0],
47588275SEric Cheng 	 * tx rings[0] on RTxQ[1].
47596621Sbt150084 	 */
47606621Sbt150084 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
47616621Sbt150084 		ixgbe_map_rxring_to_vector(ixgbe, 0, 0);
47628275SEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, 0, 1);
47636621Sbt150084 		return (IXGBE_SUCCESS);
47646621Sbt150084 	}
47656621Sbt150084 
47666621Sbt150084 	/*
47679353SSamuel.Tu@Sun.COM 	 * Interrupts/vectors mapping for MSI-X
47686621Sbt150084 	 */
47696621Sbt150084 
47706621Sbt150084 	/*
47719353SSamuel.Tu@Sun.COM 	 * Map other interrupt to vector 0,
47729353SSamuel.Tu@Sun.COM 	 * Set bit in map and count the bits set.
47739353SSamuel.Tu@Sun.COM 	 */
47749353SSamuel.Tu@Sun.COM 	BT_SET(ixgbe->vect_map[vector].other_map, 0);
47759353SSamuel.Tu@Sun.COM 	ixgbe->vect_map[vector].other_cnt++;
47769353SSamuel.Tu@Sun.COM 
47779353SSamuel.Tu@Sun.COM 	/*
47789353SSamuel.Tu@Sun.COM 	 * Map rx ring interrupts to vectors
47796621Sbt150084 	 */
47808275SEric Cheng 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
47818275SEric Cheng 		ixgbe_map_rxring_to_vector(ixgbe, i, vector);
47829353SSamuel.Tu@Sun.COM 		vector = (vector +1) % ixgbe->intr_cnt;
47838275SEric Cheng 	}
47846621Sbt150084 
47856621Sbt150084 	/*
47869353SSamuel.Tu@Sun.COM 	 * Map tx ring interrupts to vectors
47876621Sbt150084 	 */
47888275SEric Cheng 	for (i = 0; i < ixgbe->num_tx_rings; i++) {
47898275SEric Cheng 		ixgbe_map_txring_to_vector(ixgbe, i, vector);
47909353SSamuel.Tu@Sun.COM 		vector = (vector +1) % ixgbe->intr_cnt;
47916621Sbt150084 	}
47926621Sbt150084 
47936621Sbt150084 	return (IXGBE_SUCCESS);
47946621Sbt150084 }
47956621Sbt150084 
47966621Sbt150084 /*
47976621Sbt150084  * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s).
47986621Sbt150084  *
47998275SEric Cheng  * This relies on ring/vector mapping already set up in the
48006621Sbt150084  * vect_map[] structures
48016621Sbt150084  */
48026621Sbt150084 static void
48036621Sbt150084 ixgbe_setup_adapter_vector(ixgbe_t *ixgbe)
48046621Sbt150084 {
48056621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
48069353SSamuel.Tu@Sun.COM 	ixgbe_intr_vector_t *vect;	/* vector bitmap */
48078275SEric Cheng 	int r_idx;	/* ring index */
48088275SEric Cheng 	int v_idx;	/* vector index */
480911878SVenu.Iyer@Sun.COM 	uint32_t hw_index;
48106621Sbt150084 
48116621Sbt150084 	/*
48126621Sbt150084 	 * Clear any previous entries
48136621Sbt150084 	 */
48149353SSamuel.Tu@Sun.COM 	switch (hw->mac.type) {
48159353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82598EB:
48169353SSamuel.Tu@Sun.COM 		for (v_idx = 0; v_idx < 25; v_idx++)
48179353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
48189353SSamuel.Tu@Sun.COM 
48199353SSamuel.Tu@Sun.COM 		break;
48209353SSamuel.Tu@Sun.COM 	case ixgbe_mac_82599EB:
48219353SSamuel.Tu@Sun.COM 		for (v_idx = 0; v_idx < 64; v_idx++)
48229353SSamuel.Tu@Sun.COM 			IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
48239353SSamuel.Tu@Sun.COM 		IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0);
48249353SSamuel.Tu@Sun.COM 
48259353SSamuel.Tu@Sun.COM 		break;
48269353SSamuel.Tu@Sun.COM 	default:
48279353SSamuel.Tu@Sun.COM 		break;
48289353SSamuel.Tu@Sun.COM 	}
48296621Sbt150084 
48306621Sbt150084 	/*
48318275SEric Cheng 	 * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and
48328275SEric Cheng 	 * tx rings[0] will use RTxQ[1].
48336621Sbt150084 	 */
48348275SEric Cheng 	if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
48359353SSamuel.Tu@Sun.COM 		ixgbe_setup_ivar(ixgbe, 0, 0, 0);
48369353SSamuel.Tu@Sun.COM 		ixgbe_setup_ivar(ixgbe, 0, 1, 1);
48378275SEric Cheng 		return;
48388275SEric Cheng 	}
48398275SEric Cheng 
48408275SEric Cheng 	/*
48419353SSamuel.Tu@Sun.COM 	 * For MSI-X interrupt, "Other" is always on vector[0].
48428275SEric Cheng 	 */
48439353SSamuel.Tu@Sun.COM 	ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1);
48446621Sbt150084 
48456621Sbt150084 	/*
48466621Sbt150084 	 * For each interrupt vector, populate the IVAR table
48476621Sbt150084 	 */
48486621Sbt150084 	for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) {
48496621Sbt150084 		vect = &ixgbe->vect_map[v_idx];
48506621Sbt150084 
48516621Sbt150084 		/*
48526621Sbt150084 		 * For each rx ring bit set
48536621Sbt150084 		 */
48546621Sbt150084 		r_idx = bt_getlowbit(vect->rx_map, 0,
48556621Sbt150084 		    (ixgbe->num_rx_rings - 1));
48566621Sbt150084 
48576621Sbt150084 		while (r_idx >= 0) {
485811878SVenu.Iyer@Sun.COM 			hw_index = ixgbe->rx_rings[r_idx].hw_index;
485911878SVenu.Iyer@Sun.COM 			ixgbe_setup_ivar(ixgbe, hw_index, v_idx, 0);
48606621Sbt150084 			r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
48616621Sbt150084 			    (ixgbe->num_rx_rings - 1));
48626621Sbt150084 		}
48636621Sbt150084 
48646621Sbt150084 		/*
48656621Sbt150084 		 * For each tx ring bit set
48666621Sbt150084 		 */
48676621Sbt150084 		r_idx = bt_getlowbit(vect->tx_map, 0,
48686621Sbt150084 		    (ixgbe->num_tx_rings - 1));
48696621Sbt150084 
48706621Sbt150084 		while (r_idx >= 0) {
48719353SSamuel.Tu@Sun.COM 			ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1);
48726621Sbt150084 			r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
48736621Sbt150084 			    (ixgbe->num_tx_rings - 1));
48746621Sbt150084 		}
48756621Sbt150084 	}
48766621Sbt150084 }
48776621Sbt150084 
48786621Sbt150084 /*
48796621Sbt150084  * ixgbe_rem_intr_handlers - Remove the interrupt handlers.
48806621Sbt150084  */
48816621Sbt150084 static void
48826621Sbt150084 ixgbe_rem_intr_handlers(ixgbe_t *ixgbe)
48836621Sbt150084 {
48846621Sbt150084 	int i;
48856621Sbt150084 	int rc;
48866621Sbt150084 
48876621Sbt150084 	for (i = 0; i < ixgbe->intr_cnt; i++) {
48886621Sbt150084 		rc = ddi_intr_remove_handler(ixgbe->htable[i]);
48896621Sbt150084 		if (rc != DDI_SUCCESS) {
48906621Sbt150084 			IXGBE_DEBUGLOG_1(ixgbe,
48916621Sbt150084 			    "Remove intr handler failed: %d", rc);
48926621Sbt150084 		}
48936621Sbt150084 	}
48946621Sbt150084 }
48956621Sbt150084 
48966621Sbt150084 /*
48976621Sbt150084  * ixgbe_rem_intrs - Remove the allocated interrupts.
48986621Sbt150084  */
48996621Sbt150084 static void
49006621Sbt150084 ixgbe_rem_intrs(ixgbe_t *ixgbe)
49016621Sbt150084 {
49026621Sbt150084 	int i;
49036621Sbt150084 	int rc;
49046621Sbt150084 
49056621Sbt150084 	for (i = 0; i < ixgbe->intr_cnt; i++) {
49066621Sbt150084 		rc = ddi_intr_free(ixgbe->htable[i]);
49076621Sbt150084 		if (rc != DDI_SUCCESS) {
49086621Sbt150084 			IXGBE_DEBUGLOG_1(ixgbe,
49096621Sbt150084 			    "Free intr failed: %d", rc);
49106621Sbt150084 		}
49116621Sbt150084 	}
49126621Sbt150084 
49136621Sbt150084 	kmem_free(ixgbe->htable, ixgbe->intr_size);
49146621Sbt150084 	ixgbe->htable = NULL;
49156621Sbt150084 }
49166621Sbt150084 
49176621Sbt150084 /*
49186621Sbt150084  * ixgbe_enable_intrs - Enable all the ddi interrupts.
49196621Sbt150084  */
49206621Sbt150084 static int
49216621Sbt150084 ixgbe_enable_intrs(ixgbe_t *ixgbe)
49226621Sbt150084 {
49236621Sbt150084 	int i;
49246621Sbt150084 	int rc;
49256621Sbt150084 
49266621Sbt150084 	/*
49276621Sbt150084 	 * Enable interrupts
49286621Sbt150084 	 */
49296621Sbt150084 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
49306621Sbt150084 		/*
49316621Sbt150084 		 * Call ddi_intr_block_enable() for MSI
49326621Sbt150084 		 */
49336621Sbt150084 		rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt);
49346621Sbt150084 		if (rc != DDI_SUCCESS) {
49356621Sbt150084 			ixgbe_log(ixgbe,
49366621Sbt150084 			    "Enable block intr failed: %d", rc);
49376621Sbt150084 			return (IXGBE_FAILURE);
49386621Sbt150084 		}
49396621Sbt150084 	} else {
49406621Sbt150084 		/*
49416621Sbt150084 		 * Call ddi_intr_enable() for Legacy/MSI non block enable
49426621Sbt150084 		 */
49436621Sbt150084 		for (i = 0; i < ixgbe->intr_cnt; i++) {
49446621Sbt150084 			rc = ddi_intr_enable(ixgbe->htable[i]);
49456621Sbt150084 			if (rc != DDI_SUCCESS) {
49466621Sbt150084 				ixgbe_log(ixgbe,
49476621Sbt150084 				    "Enable intr failed: %d", rc);
49486621Sbt150084 				return (IXGBE_FAILURE);
49496621Sbt150084 			}
49506621Sbt150084 		}
49516621Sbt150084 	}
49526621Sbt150084 
49536621Sbt150084 	return (IXGBE_SUCCESS);
49546621Sbt150084 }
49556621Sbt150084 
49566621Sbt150084 /*
49576621Sbt150084  * ixgbe_disable_intrs - Disable all the interrupts.
49586621Sbt150084  */
49596621Sbt150084 static int
49606621Sbt150084 ixgbe_disable_intrs(ixgbe_t *ixgbe)
49616621Sbt150084 {
49626621Sbt150084 	int i;
49636621Sbt150084 	int rc;
49646621Sbt150084 
49656621Sbt150084 	/*
49666621Sbt150084 	 * Disable all interrupts
49676621Sbt150084 	 */
49686621Sbt150084 	if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
49696621Sbt150084 		rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt);
49706621Sbt150084 		if (rc != DDI_SUCCESS) {
49716621Sbt150084 			ixgbe_log(ixgbe,
49726621Sbt150084 			    "Disable block intr failed: %d", rc);
49736621Sbt150084 			return (IXGBE_FAILURE);
49746621Sbt150084 		}
49756621Sbt150084 	} else {
49766621Sbt150084 		for (i = 0; i < ixgbe->intr_cnt; i++) {
49776621Sbt150084 			rc = ddi_intr_disable(ixgbe->htable[i]);
49786621Sbt150084 			if (rc != DDI_SUCCESS) {
49796621Sbt150084 				ixgbe_log(ixgbe,
49806621Sbt150084 				    "Disable intr failed: %d", rc);
49816621Sbt150084 				return (IXGBE_FAILURE);
49826621Sbt150084 			}
49836621Sbt150084 		}
49846621Sbt150084 	}
49856621Sbt150084 
49866621Sbt150084 	return (IXGBE_SUCCESS);
49876621Sbt150084 }
49886621Sbt150084 
49896621Sbt150084 /*
49906621Sbt150084  * ixgbe_get_hw_state - Get and save parameters related to adapter hardware.
49916621Sbt150084  */
49926621Sbt150084 static void
49936621Sbt150084 ixgbe_get_hw_state(ixgbe_t *ixgbe)
49946621Sbt150084 {
49956621Sbt150084 	struct ixgbe_hw *hw = &ixgbe->hw;
49968490SPaul.Guo@Sun.COM 	ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
49978490SPaul.Guo@Sun.COM 	boolean_t link_up = B_FALSE;
49986621Sbt150084 	uint32_t pcs1g_anlp = 0;
49996621Sbt150084 	uint32_t pcs1g_ana = 0;
50006621Sbt150084 
50016621Sbt150084 	ASSERT(mutex_owned(&ixgbe->gen_lock));
50026621Sbt150084 	ixgbe->param_lp_1000fdx_cap = 0;
50036621Sbt150084 	ixgbe->param_lp_100fdx_cap  = 0;
50046621Sbt150084 
50058490SPaul.Guo@Sun.COM 	/* check for link, don't wait */
50068490SPaul.Guo@Sun.COM 	(void) ixgbe_check_link(hw, &speed, &link_up, false);
50078490SPaul.Guo@Sun.COM 	if (link_up) {
50086621Sbt150084 		pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
50096621Sbt150084 		pcs1g_ana = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
50106621Sbt150084 
50116621Sbt150084 		ixgbe->param_lp_1000fdx_cap =
50126621Sbt150084 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
50136621Sbt150084 		ixgbe->param_lp_100fdx_cap =
50146621Sbt150084 		    (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
50156621Sbt150084 	}
50166621Sbt150084 
501710376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_1000fdx_cap =
501810376SChenlu.Chen@Sun.COM 	    (pcs1g_ana & IXGBE_PCS1GANA_FDC)  ? 1 : 0;
501910376SChenlu.Chen@Sun.COM 	ixgbe->param_adv_100fdx_cap = (pcs1g_ana & IXGBE_PCS1GANA_FDC)  ? 1 : 0;
50206621Sbt150084 }
50216621Sbt150084 
50226621Sbt150084 /*
50236621Sbt150084  * ixgbe_get_driver_control - Notify that driver is in control of device.
50246621Sbt150084  */
50256621Sbt150084 static void
50266621Sbt150084 ixgbe_get_driver_control(struct ixgbe_hw *hw)
50276621Sbt150084 {
50286621Sbt150084 	uint32_t ctrl_ext;
50296621Sbt150084 
50306621Sbt150084 	/*
50316621Sbt150084 	 * Notify firmware that driver is in control of device
50326621Sbt150084 	 */
50336621Sbt150084 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
50346621Sbt150084 	ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
50356621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
50366621Sbt150084 }
50376621Sbt150084 
50386621Sbt150084 /*
50396621Sbt150084  * ixgbe_release_driver_control - Notify that driver is no longer in control
50406621Sbt150084  * of device.
50416621Sbt150084  */
50426621Sbt150084 static void
50436621Sbt150084 ixgbe_release_driver_control(struct ixgbe_hw *hw)
50446621Sbt150084 {
50456621Sbt150084 	uint32_t ctrl_ext;
50466621Sbt150084 
50476621Sbt150084 	/*
50486621Sbt150084 	 * Notify firmware that driver is no longer in control of device
50496621Sbt150084 	 */
50506621Sbt150084 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
50516621Sbt150084 	ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
50526621Sbt150084 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
50536621Sbt150084 }
50546621Sbt150084 
50556621Sbt150084 /*
50566621Sbt150084  * ixgbe_atomic_reserve - Atomic decrease operation.
50576621Sbt150084  */
50586621Sbt150084 int
50596621Sbt150084 ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n)
50606621Sbt150084 {
50616621Sbt150084 	uint32_t oldval;
50626621Sbt150084 	uint32_t newval;
50636621Sbt150084 
50646621Sbt150084 	/*
50656621Sbt150084 	 * ATOMICALLY
50666621Sbt150084 	 */
50676621Sbt150084 	do {
50686621Sbt150084 		oldval = *count_p;
50696621Sbt150084 		if (oldval < n)
50706621Sbt150084 			return (-1);
50716621Sbt150084 		newval = oldval - n;
50726621Sbt150084 	} while (atomic_cas_32(count_p, oldval, newval) != oldval);
50736621Sbt150084 
50746621Sbt150084 	return (newval);
50756621Sbt150084 }
50766621Sbt150084 
50776621Sbt150084 /*
50786621Sbt150084  * ixgbe_mc_table_itr - Traverse the entries in the multicast table.
50796621Sbt150084  */
50806621Sbt150084 static uint8_t *
50816621Sbt150084 ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq)
50826621Sbt150084 {
50838490SPaul.Guo@Sun.COM 	uint8_t *addr = *upd_ptr;
50848490SPaul.Guo@Sun.COM 	uint8_t *new_ptr;
50858490SPaul.Guo@Sun.COM 
50866621Sbt150084 	_NOTE(ARGUNUSED(hw));
50876621Sbt150084 	_NOTE(ARGUNUSED(vmdq));
50886621Sbt150084 
50896621Sbt150084 	new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS;
50906621Sbt150084 	*upd_ptr = new_ptr;
50916621Sbt150084 	return (addr);
50926621Sbt150084 }
50936621Sbt150084 
50946621Sbt150084 /*
50956621Sbt150084  * FMA support
50966621Sbt150084  */
50976621Sbt150084 int
50986621Sbt150084 ixgbe_check_acc_handle(ddi_acc_handle_t handle)
50996621Sbt150084 {
51006621Sbt150084 	ddi_fm_error_t de;
51016621Sbt150084 
51026621Sbt150084 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
51036621Sbt150084 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
51046621Sbt150084 	return (de.fme_status);
51056621Sbt150084 }
51066621Sbt150084 
51076621Sbt150084 int
51086621Sbt150084 ixgbe_check_dma_handle(ddi_dma_handle_t handle)
51096621Sbt150084 {
51106621Sbt150084 	ddi_fm_error_t de;
51116621Sbt150084 
51126621Sbt150084 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
51136621Sbt150084 	return (de.fme_status);
51146621Sbt150084 }
51156621Sbt150084 
51166621Sbt150084 /*
51176621Sbt150084  * ixgbe_fm_error_cb - The IO fault service error handling callback function.
51186621Sbt150084  */
51196621Sbt150084 static int
51206621Sbt150084 ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
51216621Sbt150084 {
51226621Sbt150084 	_NOTE(ARGUNUSED(impl_data));
51236621Sbt150084 	/*
51246621Sbt150084 	 * as the driver can always deal with an error in any dma or
51256621Sbt150084 	 * access handle, we can just return the fme_status value.
51266621Sbt150084 	 */
51276621Sbt150084 	pci_ereport_post(dip, err, NULL);
51286621Sbt150084 	return (err->fme_status);
51296621Sbt150084 }
51306621Sbt150084 
51316621Sbt150084 static void
51326621Sbt150084 ixgbe_fm_init(ixgbe_t *ixgbe)
51336621Sbt150084 {
51346621Sbt150084 	ddi_iblock_cookie_t iblk;
513511236SStephen.Hanson@Sun.COM 	int fma_dma_flag;
51366621Sbt150084 
51376621Sbt150084 	/*
51386621Sbt150084 	 * Only register with IO Fault Services if we have some capability
51396621Sbt150084 	 */
51406621Sbt150084 	if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
51416621Sbt150084 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
51426621Sbt150084 	} else {
51436621Sbt150084 		ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
51446621Sbt150084 	}
51456621Sbt150084 
51466621Sbt150084 	if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
51476621Sbt150084 		fma_dma_flag = 1;
51486621Sbt150084 	} else {
51496621Sbt150084 		fma_dma_flag = 0;
51506621Sbt150084 	}
51516621Sbt150084 
515211236SStephen.Hanson@Sun.COM 	ixgbe_set_fma_flags(fma_dma_flag);
51536621Sbt150084 
51546621Sbt150084 	if (ixgbe->fm_capabilities) {
51556621Sbt150084 
51566621Sbt150084 		/*
51576621Sbt150084 		 * Register capabilities with IO Fault Services
51586621Sbt150084 		 */
51596621Sbt150084 		ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk);
51606621Sbt150084 
51616621Sbt150084 		/*
51626621Sbt150084 		 * Initialize pci ereport capabilities if ereport capable
51636621Sbt150084 		 */
51646621Sbt150084 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
51656621Sbt150084 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
51666621Sbt150084 			pci_ereport_setup(ixgbe->dip);
51676621Sbt150084 
51686621Sbt150084 		/*
51696621Sbt150084 		 * Register error callback if error callback capable
51706621Sbt150084 		 */
51716621Sbt150084 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
51726621Sbt150084 			ddi_fm_handler_register(ixgbe->dip,
51736621Sbt150084 			    ixgbe_fm_error_cb, (void*) ixgbe);
51746621Sbt150084 	}
51756621Sbt150084 }
51766621Sbt150084 
51776621Sbt150084 static void
51786621Sbt150084 ixgbe_fm_fini(ixgbe_t *ixgbe)
51796621Sbt150084 {
51806621Sbt150084 	/*
51816621Sbt150084 	 * Only unregister FMA capabilities if they are registered
51826621Sbt150084 	 */
51836621Sbt150084 	if (ixgbe->fm_capabilities) {
51846621Sbt150084 
51856621Sbt150084 		/*
51866621Sbt150084 		 * Release any resources allocated by pci_ereport_setup()
51876621Sbt150084 		 */
51886621Sbt150084 		if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
51896621Sbt150084 		    DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
51906621Sbt150084 			pci_ereport_teardown(ixgbe->dip);
51916621Sbt150084 
51926621Sbt150084 		/*
51936621Sbt150084 		 * Un-register error callback if error callback capable
51946621Sbt150084 		 */
51956621Sbt150084 		if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
51966621Sbt150084 			ddi_fm_handler_unregister(ixgbe->dip);
51976621Sbt150084 
51986621Sbt150084 		/*
51996621Sbt150084 		 * Unregister from IO Fault Service
52006621Sbt150084 		 */
52016621Sbt150084 		ddi_fm_fini(ixgbe->dip);
52026621Sbt150084 	}
52036621Sbt150084 }
52046621Sbt150084 
52056621Sbt150084 void
52066621Sbt150084 ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail)
52076621Sbt150084 {
52086621Sbt150084 	uint64_t ena;
52096621Sbt150084 	char buf[FM_MAX_CLASS];
52106621Sbt150084 
52116621Sbt150084 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
52126621Sbt150084 	ena = fm_ena_generate(0, FM_ENA_FMT1);
52136621Sbt150084 	if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) {
52146621Sbt150084 		ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP,
52156621Sbt150084 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
52166621Sbt150084 	}
52176621Sbt150084 }
52188275SEric Cheng 
52198275SEric Cheng static int
52208275SEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
52218275SEric Cheng {
52228275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh;
52238275SEric Cheng 
52248275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
52258275SEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
52268275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
52278275SEric Cheng 	return (0);
52288275SEric Cheng }
52298275SEric Cheng 
52308275SEric Cheng /*
523111878SVenu.Iyer@Sun.COM  * Get the global ring index by a ring index within a group.
523211878SVenu.Iyer@Sun.COM  */
523311878SVenu.Iyer@Sun.COM static int
523411878SVenu.Iyer@Sun.COM ixgbe_get_rx_ring_index(ixgbe_t *ixgbe, int gindex, int rindex)
523511878SVenu.Iyer@Sun.COM {
523611878SVenu.Iyer@Sun.COM 	ixgbe_rx_ring_t *rx_ring;
523711878SVenu.Iyer@Sun.COM 	int i;
523811878SVenu.Iyer@Sun.COM 
523911878SVenu.Iyer@Sun.COM 	for (i = 0; i < ixgbe->num_rx_rings; i++) {
524011878SVenu.Iyer@Sun.COM 		rx_ring = &ixgbe->rx_rings[i];
524111878SVenu.Iyer@Sun.COM 		if (rx_ring->group_index == gindex)
524211878SVenu.Iyer@Sun.COM 			rindex--;
524311878SVenu.Iyer@Sun.COM 		if (rindex < 0)
524411878SVenu.Iyer@Sun.COM 			return (i);
524511878SVenu.Iyer@Sun.COM 	}
524611878SVenu.Iyer@Sun.COM 
524711878SVenu.Iyer@Sun.COM 	return (-1);
524811878SVenu.Iyer@Sun.COM }
524911878SVenu.Iyer@Sun.COM 
525011878SVenu.Iyer@Sun.COM /*
52518275SEric Cheng  * Callback funtion for MAC layer to register all rings.
52528275SEric Cheng  */
52538275SEric Cheng /* ARGSUSED */
52548275SEric Cheng void
525511878SVenu.Iyer@Sun.COM ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index,
52568275SEric Cheng     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
52578275SEric Cheng {
52588275SEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
52598275SEric Cheng 	mac_intr_t *mintr = &infop->mri_intr;
52608275SEric Cheng 
52618275SEric Cheng 	switch (rtype) {
52628275SEric Cheng 	case MAC_RING_TYPE_RX: {
526311878SVenu.Iyer@Sun.COM 		/*
526411878SVenu.Iyer@Sun.COM 		 * 'index' is the ring index within the group.
526511878SVenu.Iyer@Sun.COM 		 * Need to get the global ring index by searching in groups.
526611878SVenu.Iyer@Sun.COM 		 */
526711878SVenu.Iyer@Sun.COM 		int global_ring_index = ixgbe_get_rx_ring_index(
526811878SVenu.Iyer@Sun.COM 		    ixgbe, group_index, ring_index);
526911878SVenu.Iyer@Sun.COM 
527011878SVenu.Iyer@Sun.COM 		ASSERT(global_ring_index >= 0);
527111878SVenu.Iyer@Sun.COM 
527211878SVenu.Iyer@Sun.COM 		ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[global_ring_index];
52738275SEric Cheng 		rx_ring->ring_handle = rh;
52748275SEric Cheng 
52758275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)rx_ring;
52768275SEric Cheng 		infop->mri_start = ixgbe_ring_start;
52778275SEric Cheng 		infop->mri_stop = NULL;
52788275SEric Cheng 		infop->mri_poll = ixgbe_ring_rx_poll;
527911878SVenu.Iyer@Sun.COM 		infop->mri_stat = ixgbe_rx_ring_stat;
52808275SEric Cheng 
52818275SEric Cheng 		mintr->mi_handle = (mac_intr_handle_t)rx_ring;
52828275SEric Cheng 		mintr->mi_enable = ixgbe_rx_ring_intr_enable;
52838275SEric Cheng 		mintr->mi_disable = ixgbe_rx_ring_intr_disable;
528411878SVenu.Iyer@Sun.COM 		if (ixgbe->intr_type &
528511878SVenu.Iyer@Sun.COM 		    (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
528611878SVenu.Iyer@Sun.COM 			mintr->mi_ddi_handle =
528711878SVenu.Iyer@Sun.COM 			    ixgbe->htable[rx_ring->intr_vector];
528811878SVenu.Iyer@Sun.COM 		}
52898275SEric Cheng 
52908275SEric Cheng 		break;
52918275SEric Cheng 	}
52928275SEric Cheng 	case MAC_RING_TYPE_TX: {
529311878SVenu.Iyer@Sun.COM 		ASSERT(group_index == -1);
52948275SEric Cheng 		ASSERT(ring_index < ixgbe->num_tx_rings);
52958275SEric Cheng 
52968275SEric Cheng 		ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index];
52978275SEric Cheng 		tx_ring->ring_handle = rh;
52988275SEric Cheng 
52998275SEric Cheng 		infop->mri_driver = (mac_ring_driver_t)tx_ring;
53008275SEric Cheng 		infop->mri_start = NULL;
53018275SEric Cheng 		infop->mri_stop = NULL;
53028275SEric Cheng 		infop->mri_tx = ixgbe_ring_tx;
530311878SVenu.Iyer@Sun.COM 		infop->mri_stat = ixgbe_tx_ring_stat;
530411878SVenu.Iyer@Sun.COM 		if (ixgbe->intr_type &
530511878SVenu.Iyer@Sun.COM 		    (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
530611878SVenu.Iyer@Sun.COM 			mintr->mi_ddi_handle =
530711878SVenu.Iyer@Sun.COM 			    ixgbe->htable[tx_ring->intr_vector];
530811878SVenu.Iyer@Sun.COM 		}
53098275SEric Cheng 		break;
53108275SEric Cheng 	}
53118275SEric Cheng 	default:
53128275SEric Cheng 		break;
53138275SEric Cheng 	}
53148275SEric Cheng }
53158275SEric Cheng 
53168275SEric Cheng /*
53178275SEric Cheng  * Callback funtion for MAC layer to register all groups.
53188275SEric Cheng  */
53198275SEric Cheng void
53208275SEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index,
53218275SEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
53228275SEric Cheng {
53238275SEric Cheng 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
53248275SEric Cheng 
53258275SEric Cheng 	switch (rtype) {
53268275SEric Cheng 	case MAC_RING_TYPE_RX: {
53278275SEric Cheng 		ixgbe_rx_group_t *rx_group;
53288275SEric Cheng 
53298275SEric Cheng 		rx_group = &ixgbe->rx_groups[index];
53308275SEric Cheng 		rx_group->group_handle = gh;
53318275SEric Cheng 
53328275SEric Cheng 		infop->mgi_driver = (mac_group_driver_t)rx_group;
53338275SEric Cheng 		infop->mgi_start = NULL;
53348275SEric Cheng 		infop->mgi_stop = NULL;
53358275SEric Cheng 		infop->mgi_addmac = ixgbe_addmac;
53368275SEric Cheng 		infop->mgi_remmac = ixgbe_remmac;
53378275SEric Cheng 		infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups);
53388275SEric Cheng 
53398275SEric Cheng 		break;
53408275SEric Cheng 	}
53418275SEric Cheng 	case MAC_RING_TYPE_TX:
53428275SEric Cheng 		break;
53438275SEric Cheng 	default:
53448275SEric Cheng 		break;
53458275SEric Cheng 	}
53468275SEric Cheng }
53478275SEric Cheng 
53488275SEric Cheng /*
53498275SEric Cheng  * Enable interrupt on the specificed rx ring.
53508275SEric Cheng  */
53518275SEric Cheng int
53528275SEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)
53538275SEric Cheng {
53548275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
53558275SEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
53568275SEric Cheng 	int r_idx = rx_ring->index;
535711878SVenu.Iyer@Sun.COM 	int hw_r_idx = rx_ring->hw_index;
53588275SEric Cheng 	int v_idx = rx_ring->intr_vector;
53598275SEric Cheng 
53608275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
536111878SVenu.Iyer@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
536211878SVenu.Iyer@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
536311878SVenu.Iyer@Sun.COM 		/*
536411878SVenu.Iyer@Sun.COM 		 * Simply return 0.
536511878SVenu.Iyer@Sun.COM 		 * Interrupts are being adjusted. ixgbe_intr_adjust()
536611878SVenu.Iyer@Sun.COM 		 * will eventually re-enable the interrupt when it's
536711878SVenu.Iyer@Sun.COM 		 * done with the adjustment.
536811878SVenu.Iyer@Sun.COM 		 */
536911878SVenu.Iyer@Sun.COM 		return (0);
537011878SVenu.Iyer@Sun.COM 	}
53718275SEric Cheng 
53728275SEric Cheng 	/*
53738275SEric Cheng 	 * To enable interrupt by setting the VAL bit of given interrupt
53748275SEric Cheng 	 * vector allocation register (IVAR).
53758275SEric Cheng 	 */
537611878SVenu.Iyer@Sun.COM 	ixgbe_enable_ivar(ixgbe, hw_r_idx, 0);
53778275SEric Cheng 
53788275SEric Cheng 	BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
537910305SPaul.Guo@Sun.COM 
538010305SPaul.Guo@Sun.COM 	/*
538112003SPaul.Guo@Sun.COM 	 * Trigger a Rx interrupt on this ring
538210305SPaul.Guo@Sun.COM 	 */
538310305SPaul.Guo@Sun.COM 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx));
538410305SPaul.Guo@Sun.COM 	IXGBE_WRITE_FLUSH(&ixgbe->hw);
538510305SPaul.Guo@Sun.COM 
53868275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
53878275SEric Cheng 
53888275SEric Cheng 	return (0);
53898275SEric Cheng }
53908275SEric Cheng 
53918275SEric Cheng /*
53928275SEric Cheng  * Disable interrupt on the specificed rx ring.
53938275SEric Cheng  */
53948275SEric Cheng int
53958275SEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)
53968275SEric Cheng {
53978275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
53988275SEric Cheng 	ixgbe_t *ixgbe = rx_ring->ixgbe;
53998275SEric Cheng 	int r_idx = rx_ring->index;
540011878SVenu.Iyer@Sun.COM 	int hw_r_idx = rx_ring->hw_index;
54018275SEric Cheng 	int v_idx = rx_ring->intr_vector;
54028275SEric Cheng 
54038275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
540411878SVenu.Iyer@Sun.COM 	if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
540511878SVenu.Iyer@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
540611878SVenu.Iyer@Sun.COM 		/*
540711878SVenu.Iyer@Sun.COM 		 * Simply return 0.
540811878SVenu.Iyer@Sun.COM 		 * In the rare case where an interrupt is being
540911878SVenu.Iyer@Sun.COM 		 * disabled while interrupts are being adjusted,
541011878SVenu.Iyer@Sun.COM 		 * we don't fail the operation. No interrupts will
541111878SVenu.Iyer@Sun.COM 		 * be generated while they are adjusted, and
541211878SVenu.Iyer@Sun.COM 		 * ixgbe_intr_adjust() will cause the interrupts
541311878SVenu.Iyer@Sun.COM 		 * to be re-enabled once it completes. Note that
541411878SVenu.Iyer@Sun.COM 		 * in this case, packets may be delivered to the
541511878SVenu.Iyer@Sun.COM 		 * stack via interrupts before xgbe_rx_ring_intr_enable()
541611878SVenu.Iyer@Sun.COM 		 * is called again. This is acceptable since interrupt
541711878SVenu.Iyer@Sun.COM 		 * adjustment is infrequent, and the stack will be
541811878SVenu.Iyer@Sun.COM 		 * able to handle these packets.
541911878SVenu.Iyer@Sun.COM 		 */
542011878SVenu.Iyer@Sun.COM 		return (0);
542111878SVenu.Iyer@Sun.COM 	}
54228275SEric Cheng 
54238275SEric Cheng 	/*
54248275SEric Cheng 	 * To disable interrupt by clearing the VAL bit of given interrupt
54258275SEric Cheng 	 * vector allocation register (IVAR).
54268275SEric Cheng 	 */
542711878SVenu.Iyer@Sun.COM 	ixgbe_disable_ivar(ixgbe, hw_r_idx, 0);
54288275SEric Cheng 
54298275SEric Cheng 	BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx);
54308275SEric Cheng 
54318275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
54328275SEric Cheng 
54338275SEric Cheng 	return (0);
54348275SEric Cheng }
54358275SEric Cheng 
54368275SEric Cheng /*
54378275SEric Cheng  * Add a mac address.
54388275SEric Cheng  */
54398275SEric Cheng static int
54408275SEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr)
54418275SEric Cheng {
54428275SEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
54438275SEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
544411878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
544511878SVenu.Iyer@Sun.COM 	int slot, i;
54468275SEric Cheng 
54478275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
54488275SEric Cheng 
54498275SEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
54508275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
54518275SEric Cheng 		return (ECANCELED);
54528275SEric Cheng 	}
54538275SEric Cheng 
54548275SEric Cheng 	if (ixgbe->unicst_avail == 0) {
54558275SEric Cheng 		/* no slots available */
54568275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
54578275SEric Cheng 		return (ENOSPC);
54588275SEric Cheng 	}
54598275SEric Cheng 
546011878SVenu.Iyer@Sun.COM 	/*
546111878SVenu.Iyer@Sun.COM 	 * The first ixgbe->num_rx_groups slots are reserved for each respective
546211878SVenu.Iyer@Sun.COM 	 * group. The rest slots are shared by all groups. While adding a
546311878SVenu.Iyer@Sun.COM 	 * MAC address, reserved slots are firstly checked then the shared
546411878SVenu.Iyer@Sun.COM 	 * slots are searched.
546511878SVenu.Iyer@Sun.COM 	 */
546611878SVenu.Iyer@Sun.COM 	slot = -1;
546711878SVenu.Iyer@Sun.COM 	if (ixgbe->unicst_addr[rx_group->index].mac.set == 1) {
546811878SVenu.Iyer@Sun.COM 		for (i = ixgbe->num_rx_groups; i < ixgbe->unicst_total; i++) {
546911878SVenu.Iyer@Sun.COM 			if (ixgbe->unicst_addr[i].mac.set == 0) {
547011878SVenu.Iyer@Sun.COM 				slot = i;
547111878SVenu.Iyer@Sun.COM 				break;
547211878SVenu.Iyer@Sun.COM 			}
547311878SVenu.Iyer@Sun.COM 		}
547411878SVenu.Iyer@Sun.COM 	} else {
547511878SVenu.Iyer@Sun.COM 		slot = rx_group->index;
547611878SVenu.Iyer@Sun.COM 	}
547711878SVenu.Iyer@Sun.COM 
547811878SVenu.Iyer@Sun.COM 	if (slot == -1) {
547911878SVenu.Iyer@Sun.COM 		/* no slots available */
548011878SVenu.Iyer@Sun.COM 		mutex_exit(&ixgbe->gen_lock);
548111878SVenu.Iyer@Sun.COM 		return (ENOSPC);
548211878SVenu.Iyer@Sun.COM 	}
548311878SVenu.Iyer@Sun.COM 
548411878SVenu.Iyer@Sun.COM 	bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
548511878SVenu.Iyer@Sun.COM 	(void) ixgbe_set_rar(hw, slot, ixgbe->unicst_addr[slot].mac.addr,
548611878SVenu.Iyer@Sun.COM 	    rx_group->index, IXGBE_RAH_AV);
548711878SVenu.Iyer@Sun.COM 	ixgbe->unicst_addr[slot].mac.set = 1;
548811878SVenu.Iyer@Sun.COM 	ixgbe->unicst_addr[slot].mac.group_index = rx_group->index;
548911878SVenu.Iyer@Sun.COM 	ixgbe->unicst_avail--;
54908275SEric Cheng 
54918275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
54928275SEric Cheng 
549311878SVenu.Iyer@Sun.COM 	return (0);
54948275SEric Cheng }
54958275SEric Cheng 
54968275SEric Cheng /*
54978275SEric Cheng  * Remove a mac address.
54988275SEric Cheng  */
54998275SEric Cheng static int
55008275SEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr)
55018275SEric Cheng {
55028275SEric Cheng 	ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
55038275SEric Cheng 	ixgbe_t *ixgbe = rx_group->ixgbe;
550411878SVenu.Iyer@Sun.COM 	struct ixgbe_hw *hw = &ixgbe->hw;
55058275SEric Cheng 	int slot;
55068275SEric Cheng 
55078275SEric Cheng 	mutex_enter(&ixgbe->gen_lock);
55088275SEric Cheng 
55098275SEric Cheng 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
55108275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
55118275SEric Cheng 		return (ECANCELED);
55128275SEric Cheng 	}
55138275SEric Cheng 
55148275SEric Cheng 	slot = ixgbe_unicst_find(ixgbe, mac_addr);
55158275SEric Cheng 	if (slot == -1) {
55168275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
55178275SEric Cheng 		return (EINVAL);
55188275SEric Cheng 	}
55198275SEric Cheng 
55208275SEric Cheng 	if (ixgbe->unicst_addr[slot].mac.set == 0) {
55218275SEric Cheng 		mutex_exit(&ixgbe->gen_lock);
55228275SEric Cheng 		return (EINVAL);
55238275SEric Cheng 	}
55248275SEric Cheng 
55258275SEric Cheng 	bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
552611878SVenu.Iyer@Sun.COM 	(void) ixgbe_clear_rar(hw, slot);
552711878SVenu.Iyer@Sun.COM 	ixgbe->unicst_addr[slot].mac.set = 0;
552811878SVenu.Iyer@Sun.COM 	ixgbe->unicst_avail++;
55298275SEric Cheng 
55308275SEric Cheng 	mutex_exit(&ixgbe->gen_lock);
55318275SEric Cheng 
553211878SVenu.Iyer@Sun.COM 	return (0);
55338275SEric Cheng }
5534