xref: /titanic_52/usr/src/uts/common/io/igb/igb_main.c (revision e5513923451d9bed546d16298b8bbb046bd602be)
1c869993eSxy150489 /*
2c869993eSxy150489  * CDDL HEADER START
3c869993eSxy150489  *
4c869993eSxy150489  * The contents of this file are subject to the terms of the
5c869993eSxy150489  * Common Development and Distribution License (the "License").
6c869993eSxy150489  * You may not use this file except in compliance with the License.
7c869993eSxy150489  *
80dc2366fSVenugopal Iyer  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90dc2366fSVenugopal Iyer  * or http://www.opensolaris.org/os/licensing.
10c869993eSxy150489  * See the License for the specific language governing permissions
11c869993eSxy150489  * and limitations under the License.
12c869993eSxy150489  *
130dc2366fSVenugopal Iyer  * When distributing Covered Code, include this CDDL HEADER in each
140dc2366fSVenugopal Iyer  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c869993eSxy150489  * If applicable, add the following below this CDDL HEADER, with the
16c869993eSxy150489  * fields enclosed by brackets "[]" replaced with your own identifying
17c869993eSxy150489  * information: Portions Copyright [yyyy] [name of copyright owner]
18c869993eSxy150489  *
19c869993eSxy150489  * CDDL HEADER END
20c869993eSxy150489  */
21c869993eSxy150489 
22c869993eSxy150489 /*
237e526273SRobert Mustacchi  * Copyright (c) 2007-2012 Intel Corporation. All rights reserved.
246d1cdc09SGuoqing Zhu  */
256d1cdc09SGuoqing Zhu 
266d1cdc09SGuoqing Zhu /*
276d1cdc09SGuoqing Zhu  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2843ae5505SDan McDonald  * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
2942cc51e0SRobert Mustacchi  * Copyright 2016 Joyent, Inc.
30c869993eSxy150489  */
31c869993eSxy150489 
32c869993eSxy150489 #include "igb_sw.h"
33c869993eSxy150489 
3419397407SSherry Moore static char ident[] = "Intel 1Gb Ethernet";
356ed0a5cfSTycho Nightingale static char igb_version[] = "igb 2.3.8-ish";
36c869993eSxy150489 
37c869993eSxy150489 /*
38c869993eSxy150489  * Local function protoypes
39c869993eSxy150489  */
40c869993eSxy150489 static int igb_register_mac(igb_t *);
41c869993eSxy150489 static int igb_identify_hardware(igb_t *);
42c869993eSxy150489 static int igb_regs_map(igb_t *);
43c869993eSxy150489 static void igb_init_properties(igb_t *);
44c869993eSxy150489 static int igb_init_driver_settings(igb_t *);
45c869993eSxy150489 static void igb_init_locks(igb_t *);
46c869993eSxy150489 static void igb_destroy_locks(igb_t *);
47b8d0a377Schenlu chen - Sun Microsystems - Beijing China static int igb_init_mac_address(igb_t *);
48c869993eSxy150489 static int igb_init(igb_t *);
49b8d0a377Schenlu chen - Sun Microsystems - Beijing China static int igb_init_adapter(igb_t *);
50b8d0a377Schenlu chen - Sun Microsystems - Beijing China static void igb_stop_adapter(igb_t *);
51c869993eSxy150489 static int igb_reset(igb_t *);
52c869993eSxy150489 static void igb_tx_clean(igb_t *);
53c869993eSxy150489 static boolean_t igb_tx_drain(igb_t *);
54c869993eSxy150489 static boolean_t igb_rx_drain(igb_t *);
55c869993eSxy150489 static int igb_alloc_rings(igb_t *);
56ac7f5757Schenlu chen - Sun Microsystems - Beijing China static int igb_alloc_rx_data(igb_t *);
57ac7f5757Schenlu chen - Sun Microsystems - Beijing China static void igb_free_rx_data(igb_t *);
58c869993eSxy150489 static void igb_free_rings(igb_t *);
59c869993eSxy150489 static void igb_setup_rings(igb_t *);
60c869993eSxy150489 static void igb_setup_rx(igb_t *);
61c869993eSxy150489 static void igb_setup_tx(igb_t *);
62c869993eSxy150489 static void igb_setup_rx_ring(igb_rx_ring_t *);
63c869993eSxy150489 static void igb_setup_tx_ring(igb_tx_ring_t *);
64c869993eSxy150489 static void igb_setup_rss(igb_t *);
65da14cebeSEric Cheng static void igb_setup_mac_rss_classify(igb_t *);
66da14cebeSEric Cheng static void igb_setup_mac_classify(igb_t *);
67c869993eSxy150489 static void igb_init_unicst(igb_t *);
68c869993eSxy150489 static void igb_setup_multicst(igb_t *);
69c869993eSxy150489 static void igb_get_phy_state(igb_t *);
70ac7f5757Schenlu chen - Sun Microsystems - Beijing China static void igb_param_sync(igb_t *);
71c869993eSxy150489 static void igb_get_conf(igb_t *);
72c869993eSxy150489 static int igb_get_prop(igb_t *, char *, int, int, int);
73c869993eSxy150489 static boolean_t igb_is_link_up(igb_t *);
74c869993eSxy150489 static boolean_t igb_link_check(igb_t *);
75c869993eSxy150489 static void igb_local_timer(void *);
76cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China static void igb_link_timer(void *);
77c869993eSxy150489 static void igb_arm_watchdog_timer(igb_t *);
78c869993eSxy150489 static void igb_start_watchdog_timer(igb_t *);
79c869993eSxy150489 static void igb_restart_watchdog_timer(igb_t *);
80c869993eSxy150489 static void igb_stop_watchdog_timer(igb_t *);
81cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China static void igb_start_link_timer(igb_t *);
82cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China static void igb_stop_link_timer(igb_t *);
83c869993eSxy150489 static void igb_disable_adapter_interrupts(igb_t *);
8480a11ad2Schenlu chen - Sun Microsystems - Beijing China static void igb_enable_adapter_interrupts_82575(igb_t *);
8580a11ad2Schenlu chen - Sun Microsystems - Beijing China static void igb_enable_adapter_interrupts_82576(igb_t *);
863f7e60a6Szhefeng xu - Sun Microsystems - Beijing China static void igb_enable_adapter_interrupts_82580(igb_t *);
87c869993eSxy150489 static boolean_t is_valid_mac_addr(uint8_t *);
88c869993eSxy150489 static boolean_t igb_stall_check(igb_t *);
89c869993eSxy150489 static boolean_t igb_set_loopback_mode(igb_t *, uint32_t);
90c869993eSxy150489 static void igb_set_external_loopback(igb_t *);
91c869993eSxy150489 static void igb_set_internal_phy_loopback(igb_t *);
92c869993eSxy150489 static void igb_set_internal_serdes_loopback(igb_t *);
93c869993eSxy150489 static boolean_t igb_find_mac_address(igb_t *);
94c869993eSxy150489 static int igb_alloc_intrs(igb_t *);
95fa25784cSxy150489 static int igb_alloc_intr_handles(igb_t *, int);
96c869993eSxy150489 static int igb_add_intr_handlers(igb_t *);
97c869993eSxy150489 static void igb_rem_intr_handlers(igb_t *);
98c869993eSxy150489 static void igb_rem_intrs(igb_t *);
99c869993eSxy150489 static int igb_enable_intrs(igb_t *);
100c869993eSxy150489 static int igb_disable_intrs(igb_t *);
10180a11ad2Schenlu chen - Sun Microsystems - Beijing China static void igb_setup_msix_82575(igb_t *);
10280a11ad2Schenlu chen - Sun Microsystems - Beijing China static void igb_setup_msix_82576(igb_t *);
1033f7e60a6Szhefeng xu - Sun Microsystems - Beijing China static void igb_setup_msix_82580(igb_t *);
104c869993eSxy150489 static uint_t igb_intr_legacy(void *, void *);
105c869993eSxy150489 static uint_t igb_intr_msi(void *, void *);
106c869993eSxy150489 static uint_t igb_intr_rx(void *, void *);
107da14cebeSEric Cheng static uint_t igb_intr_tx(void *, void *);
108c869993eSxy150489 static uint_t igb_intr_tx_other(void *, void *);
109c869993eSxy150489 static void igb_intr_rx_work(igb_rx_ring_t *);
110c869993eSxy150489 static void igb_intr_tx_work(igb_tx_ring_t *);
111da14cebeSEric Cheng static void igb_intr_link_work(igb_t *);
112c869993eSxy150489 static void igb_get_driver_control(struct e1000_hw *);
113c869993eSxy150489 static void igb_release_driver_control(struct e1000_hw *);
114c869993eSxy150489 
115c869993eSxy150489 static int igb_attach(dev_info_t *, ddi_attach_cmd_t);
116c869993eSxy150489 static int igb_detach(dev_info_t *, ddi_detach_cmd_t);
117c869993eSxy150489 static int igb_resume(dev_info_t *);
118c869993eSxy150489 static int igb_suspend(dev_info_t *);
11919397407SSherry Moore static int igb_quiesce(dev_info_t *);
120c869993eSxy150489 static void igb_unconfigure(dev_info_t *, igb_t *);
1218bb4b220Sgl147354 static int igb_fm_error_cb(dev_info_t *, ddi_fm_error_t *,
1228bb4b220Sgl147354     const void *);
1238bb4b220Sgl147354 static void igb_fm_init(igb_t *);
1248bb4b220Sgl147354 static void igb_fm_fini(igb_t *);
1256ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic static void igb_release_multicast(igb_t *);
126c869993eSxy150489 
1270dc2366fSVenugopal Iyer char *igb_priv_props[] = {
12843ae5505SDan McDonald 	"_eee_support",
1290dc2366fSVenugopal Iyer 	"_tx_copy_thresh",
1300dc2366fSVenugopal Iyer 	"_tx_recycle_thresh",
1310dc2366fSVenugopal Iyer 	"_tx_overload_thresh",
1320dc2366fSVenugopal Iyer 	"_tx_resched_thresh",
1330dc2366fSVenugopal Iyer 	"_rx_copy_thresh",
1340dc2366fSVenugopal Iyer 	"_rx_limit_per_intr",
1350dc2366fSVenugopal Iyer 	"_intr_throttling",
1360dc2366fSVenugopal Iyer 	"_adv_pause_cap",
1370dc2366fSVenugopal Iyer 	"_adv_asym_pause_cap",
1380dc2366fSVenugopal Iyer 	NULL
139ac7f5757Schenlu chen - Sun Microsystems - Beijing China };
140ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
141c869993eSxy150489 static struct cb_ops igb_cb_ops = {
142c869993eSxy150489 	nulldev,		/* cb_open */
143c869993eSxy150489 	nulldev,		/* cb_close */
144c869993eSxy150489 	nodev,			/* cb_strategy */
145c869993eSxy150489 	nodev,			/* cb_print */
146c869993eSxy150489 	nodev,			/* cb_dump */
147c869993eSxy150489 	nodev,			/* cb_read */
148c869993eSxy150489 	nodev,			/* cb_write */
149c869993eSxy150489 	nodev,			/* cb_ioctl */
150c869993eSxy150489 	nodev,			/* cb_devmap */
151c869993eSxy150489 	nodev,			/* cb_mmap */
152c869993eSxy150489 	nodev,			/* cb_segmap */
153c869993eSxy150489 	nochpoll,		/* cb_chpoll */
154c869993eSxy150489 	ddi_prop_op,		/* cb_prop_op */
155c869993eSxy150489 	NULL,			/* cb_stream */
156c869993eSxy150489 	D_MP | D_HOTPLUG,	/* cb_flag */
157c869993eSxy150489 	CB_REV,			/* cb_rev */
158c869993eSxy150489 	nodev,			/* cb_aread */
159c869993eSxy150489 	nodev			/* cb_awrite */
160c869993eSxy150489 };
161c869993eSxy150489 
162c869993eSxy150489 static struct dev_ops igb_dev_ops = {
163c869993eSxy150489 	DEVO_REV,		/* devo_rev */
164c869993eSxy150489 	0,			/* devo_refcnt */
165c869993eSxy150489 	NULL,			/* devo_getinfo */
166c869993eSxy150489 	nulldev,		/* devo_identify */
167c869993eSxy150489 	nulldev,		/* devo_probe */
168c869993eSxy150489 	igb_attach,		/* devo_attach */
169c869993eSxy150489 	igb_detach,		/* devo_detach */
170c869993eSxy150489 	nodev,			/* devo_reset */
171c869993eSxy150489 	&igb_cb_ops,		/* devo_cb_ops */
172c869993eSxy150489 	NULL,			/* devo_bus_ops */
17319397407SSherry Moore 	ddi_power,		/* devo_power */
17419397407SSherry Moore 	igb_quiesce,	/* devo_quiesce */
175c869993eSxy150489 };
176c869993eSxy150489 
177c869993eSxy150489 static struct modldrv igb_modldrv = {
178c869993eSxy150489 	&mod_driverops,		/* Type of module.  This one is a driver */
179c869993eSxy150489 	ident,			/* Discription string */
180c869993eSxy150489 	&igb_dev_ops,		/* driver ops */
181c869993eSxy150489 };
182c869993eSxy150489 
183c869993eSxy150489 static struct modlinkage igb_modlinkage = {
184c869993eSxy150489 	MODREV_1, &igb_modldrv, NULL
185c869993eSxy150489 };
186c869993eSxy150489 
187c869993eSxy150489 /* Access attributes for register mapping */
188c869993eSxy150489 ddi_device_acc_attr_t igb_regs_acc_attr = {
189837c1ac4SStephen Hanson 	DDI_DEVICE_ATTR_V1,
190c869993eSxy150489 	DDI_STRUCTURE_LE_ACC,
191c869993eSxy150489 	DDI_STRICTORDER_ACC,
1928bb4b220Sgl147354 	DDI_FLAGERR_ACC
193c869993eSxy150489 };
194c869993eSxy150489 
195ac7f5757Schenlu chen - Sun Microsystems - Beijing China #define	IGB_M_CALLBACK_FLAGS \
1960dc2366fSVenugopal Iyer 	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
197c869993eSxy150489 
198c869993eSxy150489 static mac_callbacks_t igb_m_callbacks = {
199c869993eSxy150489 	IGB_M_CALLBACK_FLAGS,
200c869993eSxy150489 	igb_m_stat,
201c869993eSxy150489 	igb_m_start,
202c869993eSxy150489 	igb_m_stop,
203c869993eSxy150489 	igb_m_promisc,
204c869993eSxy150489 	igb_m_multicst,
205da14cebeSEric Cheng 	NULL,
206c869993eSxy150489 	NULL,
2070dc2366fSVenugopal Iyer 	NULL,
208c869993eSxy150489 	igb_m_ioctl,
209ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_m_getcapab,
210ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	NULL,
211ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	NULL,
212ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_m_setprop,
2130dc2366fSVenugopal Iyer 	igb_m_getprop,
2140dc2366fSVenugopal Iyer 	igb_m_propinfo
215c869993eSxy150489 };
216c869993eSxy150489 
217c869993eSxy150489 /*
21880a11ad2Schenlu chen - Sun Microsystems - Beijing China  * Initialize capabilities of each supported adapter type
21980a11ad2Schenlu chen - Sun Microsystems - Beijing China  */
22080a11ad2Schenlu chen - Sun Microsystems - Beijing China static adapter_info_t igb_82575_cap = {
22180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* limits */
22280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	4,		/* maximum number of rx queues */
22380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	1,		/* minimum number of rx queues */
22480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	4,		/* default number of rx queues */
22580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	4,		/* maximum number of tx queues */
22680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	1,		/* minimum number of tx queues */
22780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	4,		/* default number of tx queues */
22880a11ad2Schenlu chen - Sun Microsystems - Beijing China 	65535,		/* maximum interrupt throttle rate */
22980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	0,		/* minimum interrupt throttle rate */
23080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	200,		/* default interrupt throttle rate */
23180a11ad2Schenlu chen - Sun Microsystems - Beijing China 
23280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* function pointers */
23380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	igb_enable_adapter_interrupts_82575,
23480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	igb_setup_msix_82575,
23580a11ad2Schenlu chen - Sun Microsystems - Beijing China 
23680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* capabilities */
23780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	(IGB_FLAG_HAS_DCA |	/* capability flags */
238b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	IGB_FLAG_VMDQ_POOL),
239b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
240b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	0xffc00000		/* mask for RXDCTL register */
24180a11ad2Schenlu chen - Sun Microsystems - Beijing China };
24280a11ad2Schenlu chen - Sun Microsystems - Beijing China 
24380a11ad2Schenlu chen - Sun Microsystems - Beijing China static adapter_info_t igb_82576_cap = {
24480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* limits */
245b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	16,		/* maximum number of rx queues */
24680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	1,		/* minimum number of rx queues */
24780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	4,		/* default number of rx queues */
248b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	16,		/* maximum number of tx queues */
24980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	1,		/* minimum number of tx queues */
25080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	4,		/* default number of tx queues */
25180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	65535,		/* maximum interrupt throttle rate */
25280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	0,		/* minimum interrupt throttle rate */
25380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	200,		/* default interrupt throttle rate */
25480a11ad2Schenlu chen - Sun Microsystems - Beijing China 
25580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* function pointers */
25680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	igb_enable_adapter_interrupts_82576,
25780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	igb_setup_msix_82576,
25880a11ad2Schenlu chen - Sun Microsystems - Beijing China 
25980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* capabilities */
26080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	(IGB_FLAG_HAS_DCA |	/* capability flags */
26180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	IGB_FLAG_VMDQ_POOL |
262b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	IGB_FLAG_NEED_CTX_IDX),
263b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
264b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	0xffe00000		/* mask for RXDCTL register */
26580a11ad2Schenlu chen - Sun Microsystems - Beijing China };
26680a11ad2Schenlu chen - Sun Microsystems - Beijing China 
2673f7e60a6Szhefeng xu - Sun Microsystems - Beijing China static adapter_info_t igb_82580_cap = {
2683f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* limits */
2693f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	8,		/* maximum number of rx queues */
2703f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	1,		/* minimum number of rx queues */
2713f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	4,		/* default number of rx queues */
2723f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	8,		/* maximum number of tx queues */
2733f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	1,		/* minimum number of tx queues */
2743f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	4,		/* default number of tx queues */
2753f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	65535,		/* maximum interrupt throttle rate */
2763f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	0,		/* minimum interrupt throttle rate */
2773f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	200,		/* default interrupt throttle rate */
2783f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
2793f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* function pointers */
2803f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	igb_enable_adapter_interrupts_82580,
2813f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	igb_setup_msix_82580,
2823f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
2833f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* capabilities */
2843f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	(IGB_FLAG_HAS_DCA |	/* capability flags */
2853f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	IGB_FLAG_VMDQ_POOL |
2863f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	IGB_FLAG_NEED_CTX_IDX),
2873f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
2883f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	0xffe00000		/* mask for RXDCTL register */
2893f7e60a6Szhefeng xu - Sun Microsystems - Beijing China };
2903f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
2917e526273SRobert Mustacchi static adapter_info_t igb_i350_cap = {
2927e526273SRobert Mustacchi 	/* limits */
2937e526273SRobert Mustacchi 	8,		/* maximum number of rx queues */
2947e526273SRobert Mustacchi 	1,		/* minimum number of rx queues */
2957e526273SRobert Mustacchi 	4,		/* default number of rx queues */
2967e526273SRobert Mustacchi 	8,		/* maximum number of tx queues */
2977e526273SRobert Mustacchi 	1,		/* minimum number of tx queues */
2987e526273SRobert Mustacchi 	4,		/* default number of tx queues */
2997e526273SRobert Mustacchi 	65535,		/* maximum interrupt throttle rate */
3007e526273SRobert Mustacchi 	0,		/* minimum interrupt throttle rate */
3017e526273SRobert Mustacchi 	200,		/* default interrupt throttle rate */
3027e526273SRobert Mustacchi 
3037e526273SRobert Mustacchi 	/* function pointers */
3047e526273SRobert Mustacchi 	igb_enable_adapter_interrupts_82580,
3057e526273SRobert Mustacchi 	igb_setup_msix_82580,
3067e526273SRobert Mustacchi 
3077e526273SRobert Mustacchi 	/* capabilities */
3087e526273SRobert Mustacchi 	(IGB_FLAG_HAS_DCA |	/* capability flags */
3097e526273SRobert Mustacchi 	IGB_FLAG_VMDQ_POOL |
3107e526273SRobert Mustacchi 	IGB_FLAG_NEED_CTX_IDX),
3117e526273SRobert Mustacchi 
3127e526273SRobert Mustacchi 	0xffe00000		/* mask for RXDCTL register */
3137e526273SRobert Mustacchi };
3147e526273SRobert Mustacchi 
3156ed0a5cfSTycho Nightingale static adapter_info_t igb_i210_cap = {
3166ed0a5cfSTycho Nightingale 	/* limits */
3176ed0a5cfSTycho Nightingale 	4,		/* maximum number of rx queues */
3186ed0a5cfSTycho Nightingale 	1,		/* minimum number of rx queues */
3196ed0a5cfSTycho Nightingale 	4,		/* default number of rx queues */
3206ed0a5cfSTycho Nightingale 	4,		/* maximum number of tx queues */
3216ed0a5cfSTycho Nightingale 	1,		/* minimum number of tx queues */
3226ed0a5cfSTycho Nightingale 	4,		/* default number of tx queues */
3236ed0a5cfSTycho Nightingale 	65535,		/* maximum interrupt throttle rate */
3246ed0a5cfSTycho Nightingale 	0,		/* minimum interrupt throttle rate */
3256ed0a5cfSTycho Nightingale 	200,		/* default interrupt throttle rate */
3266ed0a5cfSTycho Nightingale 
3276ed0a5cfSTycho Nightingale 	/* function pointers */
3286ed0a5cfSTycho Nightingale 	igb_enable_adapter_interrupts_82580,
3296ed0a5cfSTycho Nightingale 	igb_setup_msix_82580,
3306ed0a5cfSTycho Nightingale 
3316ed0a5cfSTycho Nightingale 	/* capabilities */
3326ed0a5cfSTycho Nightingale 	(IGB_FLAG_HAS_DCA |	/* capability flags */
3336ed0a5cfSTycho Nightingale 	IGB_FLAG_VMDQ_POOL |
3346ed0a5cfSTycho Nightingale 	IGB_FLAG_NEED_CTX_IDX),
3356ed0a5cfSTycho Nightingale 
3366ed0a5cfSTycho Nightingale 	0xfff00000		/* mask for RXDCTL register */
3376ed0a5cfSTycho Nightingale };
3386ed0a5cfSTycho Nightingale 
33913485e69SGarrett D'Amore static adapter_info_t igb_i354_cap = {
34013485e69SGarrett D'Amore 	/* limits */
34113485e69SGarrett D'Amore 	8,		/* maximum number of rx queues */
34213485e69SGarrett D'Amore 	1,		/* minimum number of rx queues */
34313485e69SGarrett D'Amore 	4,		/* default number of rx queues */
34413485e69SGarrett D'Amore 	8,		/* maximum number of tx queues */
34513485e69SGarrett D'Amore 	1,		/* minimum number of tx queues */
34613485e69SGarrett D'Amore 	4,		/* default number of tx queues */
34713485e69SGarrett D'Amore 	65535,		/* maximum interrupt throttle rate */
34813485e69SGarrett D'Amore 	0,		/* minimum interrupt throttle rate */
34913485e69SGarrett D'Amore 	200,		/* default interrupt throttle rate */
35013485e69SGarrett D'Amore 
35113485e69SGarrett D'Amore 	/* function pointers */
35213485e69SGarrett D'Amore 	igb_enable_adapter_interrupts_82580,
35313485e69SGarrett D'Amore 	igb_setup_msix_82580,
35413485e69SGarrett D'Amore 
35513485e69SGarrett D'Amore 	/* capabilities */
35613485e69SGarrett D'Amore 	(IGB_FLAG_HAS_DCA |	/* capability flags */
35713485e69SGarrett D'Amore 	IGB_FLAG_VMDQ_POOL |
35813485e69SGarrett D'Amore 	IGB_FLAG_NEED_CTX_IDX),
35913485e69SGarrett D'Amore 
36013485e69SGarrett D'Amore 	0xfff00000		/* mask for RXDCTL register */
36113485e69SGarrett D'Amore };
36213485e69SGarrett D'Amore 
36380a11ad2Schenlu chen - Sun Microsystems - Beijing China /*
364c869993eSxy150489  * Module Initialization Functions
365c869993eSxy150489  */
366c869993eSxy150489 
367c869993eSxy150489 int
368c869993eSxy150489 _init(void)
369c869993eSxy150489 {
370c869993eSxy150489 	int status;
371c869993eSxy150489 
372c869993eSxy150489 	mac_init_ops(&igb_dev_ops, MODULE_NAME);
373c869993eSxy150489 
374c869993eSxy150489 	status = mod_install(&igb_modlinkage);
375c869993eSxy150489 
376c869993eSxy150489 	if (status != DDI_SUCCESS) {
377c869993eSxy150489 		mac_fini_ops(&igb_dev_ops);
378c869993eSxy150489 	}
379c869993eSxy150489 
380c869993eSxy150489 	return (status);
381c869993eSxy150489 }
382c869993eSxy150489 
383c869993eSxy150489 int
384c869993eSxy150489 _fini(void)
385c869993eSxy150489 {
386c869993eSxy150489 	int status;
387c869993eSxy150489 
388c869993eSxy150489 	status = mod_remove(&igb_modlinkage);
389c869993eSxy150489 
390c869993eSxy150489 	if (status == DDI_SUCCESS) {
391c869993eSxy150489 		mac_fini_ops(&igb_dev_ops);
392c869993eSxy150489 	}
393c869993eSxy150489 
394c869993eSxy150489 	return (status);
395c869993eSxy150489 
396c869993eSxy150489 }
397c869993eSxy150489 
398c869993eSxy150489 int
399c869993eSxy150489 _info(struct modinfo *modinfop)
400c869993eSxy150489 {
401c869993eSxy150489 	int status;
402c869993eSxy150489 
403c869993eSxy150489 	status = mod_info(&igb_modlinkage, modinfop);
404c869993eSxy150489 
405c869993eSxy150489 	return (status);
406c869993eSxy150489 }
407c869993eSxy150489 
408c869993eSxy150489 /*
409c869993eSxy150489  * igb_attach - driver attach
410c869993eSxy150489  *
411c869993eSxy150489  * This function is the device specific initialization entry
412c869993eSxy150489  * point. This entry point is required and must be written.
413c869993eSxy150489  * The DDI_ATTACH command must be provided in the attach entry
414c869993eSxy150489  * point. When attach() is called with cmd set to DDI_ATTACH,
415c869993eSxy150489  * all normal kernel services (such as kmem_alloc(9F)) are
416c869993eSxy150489  * available for use by the driver.
417c869993eSxy150489  *
418c869993eSxy150489  * The attach() function will be called once for each instance
419c869993eSxy150489  * of  the  device  on  the  system with cmd set to DDI_ATTACH.
420c869993eSxy150489  * Until attach() succeeds, the only driver entry points which
421c869993eSxy150489  * may be called are open(9E) and getinfo(9E).
422c869993eSxy150489  */
423c869993eSxy150489 static int
424c869993eSxy150489 igb_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
425c869993eSxy150489 {
426c869993eSxy150489 	igb_t *igb;
427c869993eSxy150489 	struct igb_osdep *osdep;
428c869993eSxy150489 	struct e1000_hw *hw;
429c869993eSxy150489 	int instance;
430c869993eSxy150489 
431c869993eSxy150489 	/*
432c869993eSxy150489 	 * Check the command and perform corresponding operations
433c869993eSxy150489 	 */
434c869993eSxy150489 	switch (cmd) {
435c869993eSxy150489 	default:
436c869993eSxy150489 		return (DDI_FAILURE);
437c869993eSxy150489 
438c869993eSxy150489 	case DDI_RESUME:
439c869993eSxy150489 		return (igb_resume(devinfo));
440c869993eSxy150489 
441c869993eSxy150489 	case DDI_ATTACH:
442c869993eSxy150489 		break;
443c869993eSxy150489 	}
444c869993eSxy150489 
445c869993eSxy150489 	/* Get the device instance */
446c869993eSxy150489 	instance = ddi_get_instance(devinfo);
447c869993eSxy150489 
448c869993eSxy150489 	/* Allocate memory for the instance data structure */
449c869993eSxy150489 	igb = kmem_zalloc(sizeof (igb_t), KM_SLEEP);
450c869993eSxy150489 
451c869993eSxy150489 	igb->dip = devinfo;
452c869993eSxy150489 	igb->instance = instance;
453c869993eSxy150489 
454c869993eSxy150489 	hw = &igb->hw;
455c869993eSxy150489 	osdep = &igb->osdep;
456c869993eSxy150489 	hw->back = osdep;
457c869993eSxy150489 	osdep->igb = igb;
458c869993eSxy150489 
459c869993eSxy150489 	/* Attach the instance pointer to the dev_info data structure */
460c869993eSxy150489 	ddi_set_driver_private(devinfo, igb);
461c869993eSxy150489 
4628bb4b220Sgl147354 
4638bb4b220Sgl147354 	/* Initialize for fma support */
4648bb4b220Sgl147354 	igb->fm_capabilities = igb_get_prop(igb, "fm-capable",
4658bb4b220Sgl147354 	    0, 0x0f,
4668bb4b220Sgl147354 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
4678bb4b220Sgl147354 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
4688bb4b220Sgl147354 	igb_fm_init(igb);
4698bb4b220Sgl147354 	igb->attach_progress |= ATTACH_PROGRESS_FMINIT;
4708bb4b220Sgl147354 
471c869993eSxy150489 	/*
472c869993eSxy150489 	 * Map PCI config space registers
473c869993eSxy150489 	 */
474c869993eSxy150489 	if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
475*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to map PCI configurations");
476c869993eSxy150489 		goto attach_fail;
477c869993eSxy150489 	}
478c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
479c869993eSxy150489 
480c869993eSxy150489 	/*
481c869993eSxy150489 	 * Identify the chipset family
482c869993eSxy150489 	 */
483c869993eSxy150489 	if (igb_identify_hardware(igb) != IGB_SUCCESS) {
484*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to identify hardware");
485c869993eSxy150489 		goto attach_fail;
486c869993eSxy150489 	}
487c869993eSxy150489 
488c869993eSxy150489 	/*
489c869993eSxy150489 	 * Map device registers
490c869993eSxy150489 	 */
491c869993eSxy150489 	if (igb_regs_map(igb) != IGB_SUCCESS) {
492*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to map device registers");
493c869993eSxy150489 		goto attach_fail;
494c869993eSxy150489 	}
495c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_REGS_MAP;
496c869993eSxy150489 
497c869993eSxy150489 	/*
498c869993eSxy150489 	 * Initialize driver parameters
499c869993eSxy150489 	 */
500c869993eSxy150489 	igb_init_properties(igb);
501c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_PROPS;
502c869993eSxy150489 
503c869993eSxy150489 	/*
504c869993eSxy150489 	 * Allocate interrupts
505c869993eSxy150489 	 */
506c869993eSxy150489 	if (igb_alloc_intrs(igb) != IGB_SUCCESS) {
507*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to allocate interrupts");
508c869993eSxy150489 		goto attach_fail;
509c869993eSxy150489 	}
510c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
511c869993eSxy150489 
512c869993eSxy150489 	/*
513c869993eSxy150489 	 * Allocate rx/tx rings based on the ring numbers.
514c869993eSxy150489 	 * The actual numbers of rx/tx rings are decided by the number of
515c869993eSxy150489 	 * allocated interrupt vectors, so we should allocate the rings after
516c869993eSxy150489 	 * interrupts are allocated.
517c869993eSxy150489 	 */
518c869993eSxy150489 	if (igb_alloc_rings(igb) != IGB_SUCCESS) {
519*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
520*e5513923SYuri Pankov 		    "Failed to allocate rx/tx rings or groups");
521c869993eSxy150489 		goto attach_fail;
522c869993eSxy150489 	}
523c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS;
524c869993eSxy150489 
525c869993eSxy150489 	/*
526c869993eSxy150489 	 * Add interrupt handlers
527c869993eSxy150489 	 */
528c869993eSxy150489 	if (igb_add_intr_handlers(igb) != IGB_SUCCESS) {
529*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to add interrupt handlers");
530c869993eSxy150489 		goto attach_fail;
531c869993eSxy150489 	}
532c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
533c869993eSxy150489 
534c869993eSxy150489 	/*
535c869993eSxy150489 	 * Initialize driver parameters
536c869993eSxy150489 	 */
537c869993eSxy150489 	if (igb_init_driver_settings(igb) != IGB_SUCCESS) {
538*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
539*e5513923SYuri Pankov 		    "Failed to initialize driver settings");
540c869993eSxy150489 		goto attach_fail;
541c869993eSxy150489 	}
542c869993eSxy150489 
5438bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.cfg_handle) != DDI_FM_OK) {
5448bb4b220Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
5458bb4b220Sgl147354 		goto attach_fail;
5468bb4b220Sgl147354 	}
5478bb4b220Sgl147354 
548c869993eSxy150489 	/*
549c869993eSxy150489 	 * Initialize mutexes for this device.
550c869993eSxy150489 	 * Do this before enabling the interrupt handler and
551c869993eSxy150489 	 * register the softint to avoid the condition where
552c869993eSxy150489 	 * interrupt handler can try using uninitialized mutex
553c869993eSxy150489 	 */
554c869993eSxy150489 	igb_init_locks(igb);
555c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_LOCKS;
556c869993eSxy150489 
557c869993eSxy150489 	/*
558ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 * Initialize the adapter
559b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
560c869993eSxy150489 	if (igb_init(igb) != IGB_SUCCESS) {
561*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to initialize adapter");
562c869993eSxy150489 		goto attach_fail;
563c869993eSxy150489 	}
564b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	igb->attach_progress |= ATTACH_PROGRESS_INIT_ADAPTER;
565c869993eSxy150489 
566c869993eSxy150489 	/*
567c869993eSxy150489 	 * Initialize statistics
568c869993eSxy150489 	 */
569c869993eSxy150489 	if (igb_init_stats(igb) != IGB_SUCCESS) {
570*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to initialize statistics");
571c869993eSxy150489 		goto attach_fail;
572c869993eSxy150489 	}
573c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_STATS;
574c869993eSxy150489 
575c869993eSxy150489 	/*
576c869993eSxy150489 	 * Register the driver to the MAC
577c869993eSxy150489 	 */
578c869993eSxy150489 	if (igb_register_mac(igb) != IGB_SUCCESS) {
579*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to register MAC");
580c869993eSxy150489 		goto attach_fail;
581c869993eSxy150489 	}
582c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_MAC;
583c869993eSxy150489 
584c869993eSxy150489 	/*
585c869993eSxy150489 	 * Now that mutex locks are initialized, and the chip is also
586c869993eSxy150489 	 * initialized, enable interrupts.
587c869993eSxy150489 	 */
588c869993eSxy150489 	if (igb_enable_intrs(igb) != IGB_SUCCESS) {
589*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to enable DDI interrupts");
590c869993eSxy150489 		goto attach_fail;
591c869993eSxy150489 	}
592c869993eSxy150489 	igb->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
593c869993eSxy150489 
594*e5513923SYuri Pankov 	igb_log(igb, IGB_LOG_INFO, "%s", igb_version);
595cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	atomic_or_32(&igb->igb_state, IGB_INITIALIZED);
596c869993eSxy150489 
5977e526273SRobert Mustacchi 	/*
5987e526273SRobert Mustacchi 	 * Newer models have Energy Efficient Ethernet, let's disable this by
5997e526273SRobert Mustacchi 	 * default.
6007e526273SRobert Mustacchi 	 */
6017e526273SRobert Mustacchi 	if (igb->hw.mac.type == e1000_i350)
60242cc51e0SRobert Mustacchi 		(void) e1000_set_eee_i350(&igb->hw, B_FALSE, B_FALSE);
60313485e69SGarrett D'Amore 	else if (igb->hw.mac.type == e1000_i354)
60442cc51e0SRobert Mustacchi 		(void) e1000_set_eee_i354(&igb->hw, B_FALSE, B_FALSE);
6057e526273SRobert Mustacchi 
606c869993eSxy150489 	return (DDI_SUCCESS);
607c869993eSxy150489 
608c869993eSxy150489 attach_fail:
609c869993eSxy150489 	igb_unconfigure(devinfo, igb);
610c869993eSxy150489 	return (DDI_FAILURE);
611c869993eSxy150489 }
612c869993eSxy150489 
613c869993eSxy150489 /*
614c869993eSxy150489  * igb_detach - driver detach
615c869993eSxy150489  *
616c869993eSxy150489  * The detach() function is the complement of the attach routine.
617c869993eSxy150489  * If cmd is set to DDI_DETACH, detach() is used to remove  the
618c869993eSxy150489  * state  associated  with  a  given  instance of a device node
619c869993eSxy150489  * prior to the removal of that instance from the system.
620c869993eSxy150489  *
621c869993eSxy150489  * The detach() function will be called once for each  instance
622c869993eSxy150489  * of the device for which there has been a successful attach()
623c869993eSxy150489  * once there are no longer  any  opens  on  the  device.
624c869993eSxy150489  *
625c869993eSxy150489  * Interrupts routine are disabled, All memory allocated by this
626c869993eSxy150489  * driver are freed.
627c869993eSxy150489  */
628c869993eSxy150489 static int
629c869993eSxy150489 igb_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
630c869993eSxy150489 {
631c869993eSxy150489 	igb_t *igb;
632c869993eSxy150489 
633c869993eSxy150489 	/*
634c869993eSxy150489 	 * Check detach command
635c869993eSxy150489 	 */
636c869993eSxy150489 	switch (cmd) {
637c869993eSxy150489 	default:
638c869993eSxy150489 		return (DDI_FAILURE);
639c869993eSxy150489 
640c869993eSxy150489 	case DDI_SUSPEND:
641c869993eSxy150489 		return (igb_suspend(devinfo));
642c869993eSxy150489 
643c869993eSxy150489 	case DDI_DETACH:
644c869993eSxy150489 		break;
645c869993eSxy150489 	}
646c869993eSxy150489 
647c869993eSxy150489 
648c869993eSxy150489 	/*
649c869993eSxy150489 	 * Get the pointer to the driver private data structure
650c869993eSxy150489 	 */
651c869993eSxy150489 	igb = (igb_t *)ddi_get_driver_private(devinfo);
652c869993eSxy150489 	if (igb == NULL)
653c869993eSxy150489 		return (DDI_FAILURE);
654c869993eSxy150489 
655c869993eSxy150489 	/*
656c869993eSxy150489 	 * Unregister MAC. If failed, we have to fail the detach
657c869993eSxy150489 	 */
658c869993eSxy150489 	if (mac_unregister(igb->mac_hdl) != 0) {
659*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to unregister MAC");
660c869993eSxy150489 		return (DDI_FAILURE);
661c869993eSxy150489 	}
662c869993eSxy150489 	igb->attach_progress &= ~ATTACH_PROGRESS_MAC;
663c869993eSxy150489 
664c869993eSxy150489 	/*
665c869993eSxy150489 	 * If the device is still running, it needs to be stopped first.
666c869993eSxy150489 	 * This check is necessary because under some specific circumstances,
667c869993eSxy150489 	 * the detach routine can be called without stopping the interface
668c869993eSxy150489 	 * first.
669c869993eSxy150489 	 */
670c869993eSxy150489 	mutex_enter(&igb->gen_lock);
671c869993eSxy150489 	if (igb->igb_state & IGB_STARTED) {
672cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		atomic_and_32(&igb->igb_state, ~IGB_STARTED);
673ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb_stop(igb, B_TRUE);
674c869993eSxy150489 		mutex_exit(&igb->gen_lock);
675c869993eSxy150489 		/* Disable and stop the watchdog timer */
676c869993eSxy150489 		igb_disable_watchdog_timer(igb);
677c869993eSxy150489 	} else
678c869993eSxy150489 		mutex_exit(&igb->gen_lock);
679c869993eSxy150489 
680c869993eSxy150489 	/*
681c869993eSxy150489 	 * Check if there are still rx buffers held by the upper layer.
682c869993eSxy150489 	 * If so, fail the detach.
683c869993eSxy150489 	 */
684c869993eSxy150489 	if (!igb_rx_drain(igb))
685c869993eSxy150489 		return (DDI_FAILURE);
686c869993eSxy150489 
687c869993eSxy150489 	/*
688c869993eSxy150489 	 * Do the remaining unconfigure routines
689c869993eSxy150489 	 */
690c869993eSxy150489 	igb_unconfigure(devinfo, igb);
691c869993eSxy150489 
692c869993eSxy150489 	return (DDI_SUCCESS);
693c869993eSxy150489 }
694c869993eSxy150489 
69519397407SSherry Moore /*
69619397407SSherry Moore  * quiesce(9E) entry point.
69719397407SSherry Moore  *
69819397407SSherry Moore  * This function is called when the system is single-threaded at high
69919397407SSherry Moore  * PIL with preemption disabled. Therefore, this function must not be
70019397407SSherry Moore  * blocked.
70119397407SSherry Moore  *
70219397407SSherry Moore  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
70319397407SSherry Moore  * DDI_FAILURE indicates an error condition and should almost never happen.
70419397407SSherry Moore  */
70519397407SSherry Moore static int
70619397407SSherry Moore igb_quiesce(dev_info_t *devinfo)
70719397407SSherry Moore {
70819397407SSherry Moore 	igb_t *igb;
70919397407SSherry Moore 	struct e1000_hw *hw;
71019397407SSherry Moore 
71119397407SSherry Moore 	igb = (igb_t *)ddi_get_driver_private(devinfo);
71219397407SSherry Moore 
71319397407SSherry Moore 	if (igb == NULL)
71419397407SSherry Moore 		return (DDI_FAILURE);
71519397407SSherry Moore 
71619397407SSherry Moore 	hw = &igb->hw;
71719397407SSherry Moore 
71819397407SSherry Moore 	/*
71919397407SSherry Moore 	 * Disable the adapter interrupts
72019397407SSherry Moore 	 */
72119397407SSherry Moore 	igb_disable_adapter_interrupts(igb);
72219397407SSherry Moore 
72319397407SSherry Moore 	/* Tell firmware driver is no longer in control */
72419397407SSherry Moore 	igb_release_driver_control(hw);
72519397407SSherry Moore 
72619397407SSherry Moore 	/*
72719397407SSherry Moore 	 * Reset the chipset
72819397407SSherry Moore 	 */
72919397407SSherry Moore 	(void) e1000_reset_hw(hw);
73019397407SSherry Moore 
73119397407SSherry Moore 	/*
73219397407SSherry Moore 	 * Reset PHY if possible
73319397407SSherry Moore 	 */
73419397407SSherry Moore 	if (e1000_check_reset_block(hw) == E1000_SUCCESS)
73519397407SSherry Moore 		(void) e1000_phy_hw_reset(hw);
73619397407SSherry Moore 
73719397407SSherry Moore 	return (DDI_SUCCESS);
73819397407SSherry Moore }
73919397407SSherry Moore 
740b8d0a377Schenlu chen - Sun Microsystems - Beijing China /*
741b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * igb_unconfigure - release all resources held by this instance
742b8d0a377Schenlu chen - Sun Microsystems - Beijing China  */
743c869993eSxy150489 static void
744c869993eSxy150489 igb_unconfigure(dev_info_t *devinfo, igb_t *igb)
745c869993eSxy150489 {
746c869993eSxy150489 	/*
747c869993eSxy150489 	 * Disable interrupt
748c869993eSxy150489 	 */
749c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
750c869993eSxy150489 		(void) igb_disable_intrs(igb);
751c869993eSxy150489 	}
752c869993eSxy150489 
753c869993eSxy150489 	/*
754c869993eSxy150489 	 * Unregister MAC
755c869993eSxy150489 	 */
756c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_MAC) {
757c869993eSxy150489 		(void) mac_unregister(igb->mac_hdl);
758c869993eSxy150489 	}
759c869993eSxy150489 
760c869993eSxy150489 	/*
761c869993eSxy150489 	 * Free statistics
762c869993eSxy150489 	 */
763c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_STATS) {
764c869993eSxy150489 		kstat_delete((kstat_t *)igb->igb_ks);
765c869993eSxy150489 	}
766c869993eSxy150489 
767c869993eSxy150489 	/*
768c869993eSxy150489 	 * Remove interrupt handlers
769c869993eSxy150489 	 */
770c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
771c869993eSxy150489 		igb_rem_intr_handlers(igb);
772c869993eSxy150489 	}
773c869993eSxy150489 
774c869993eSxy150489 	/*
775c869993eSxy150489 	 * Remove interrupts
776c869993eSxy150489 	 */
777c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) {
778c869993eSxy150489 		igb_rem_intrs(igb);
779c869993eSxy150489 	}
780c869993eSxy150489 
781c869993eSxy150489 	/*
782c869993eSxy150489 	 * Remove driver properties
783c869993eSxy150489 	 */
784c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_PROPS) {
785c869993eSxy150489 		(void) ddi_prop_remove_all(devinfo);
786c869993eSxy150489 	}
787c869993eSxy150489 
788c869993eSxy150489 	/*
789b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Stop the adapter
790c869993eSxy150489 	 */
791b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (igb->attach_progress & ATTACH_PROGRESS_INIT_ADAPTER) {
792c869993eSxy150489 		mutex_enter(&igb->gen_lock);
793b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		igb_stop_adapter(igb);
794c869993eSxy150489 		mutex_exit(&igb->gen_lock);
7958bb4b220Sgl147354 		if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
7968bb4b220Sgl147354 			ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
797c869993eSxy150489 	}
798c869993eSxy150489 
799c869993eSxy150489 	/*
8006ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	 * Free multicast table
8016ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	 */
8026ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	igb_release_multicast(igb);
8036ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
8046ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	/*
805c869993eSxy150489 	 * Free register handle
806c869993eSxy150489 	 */
807c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
808c869993eSxy150489 		if (igb->osdep.reg_handle != NULL)
809c869993eSxy150489 			ddi_regs_map_free(&igb->osdep.reg_handle);
810c869993eSxy150489 	}
811c869993eSxy150489 
812c869993eSxy150489 	/*
813c869993eSxy150489 	 * Free PCI config handle
814c869993eSxy150489 	 */
815c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) {
816c869993eSxy150489 		if (igb->osdep.cfg_handle != NULL)
817c869993eSxy150489 			pci_config_teardown(&igb->osdep.cfg_handle);
818c869993eSxy150489 	}
819c869993eSxy150489 
820c869993eSxy150489 	/*
821c869993eSxy150489 	 * Free locks
822c869993eSxy150489 	 */
823c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_LOCKS) {
824c869993eSxy150489 		igb_destroy_locks(igb);
825c869993eSxy150489 	}
826c869993eSxy150489 
827c869993eSxy150489 	/*
828c869993eSxy150489 	 * Free the rx/tx rings
829c869993eSxy150489 	 */
830c869993eSxy150489 	if (igb->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) {
831c869993eSxy150489 		igb_free_rings(igb);
832c869993eSxy150489 	}
833c869993eSxy150489 
834c869993eSxy150489 	/*
8358bb4b220Sgl147354 	 * Remove FMA
8368bb4b220Sgl147354 	 */
8378bb4b220Sgl147354 	if (igb->attach_progress & ATTACH_PROGRESS_FMINIT) {
8388bb4b220Sgl147354 		igb_fm_fini(igb);
8398bb4b220Sgl147354 	}
8408bb4b220Sgl147354 
8418bb4b220Sgl147354 	/*
842c869993eSxy150489 	 * Free the driver data structure
843c869993eSxy150489 	 */
844c869993eSxy150489 	kmem_free(igb, sizeof (igb_t));
845c869993eSxy150489 
846c869993eSxy150489 	ddi_set_driver_private(devinfo, NULL);
847c869993eSxy150489 }
848c869993eSxy150489 
849c869993eSxy150489 /*
850c869993eSxy150489  * igb_register_mac - Register the driver and its function pointers with
851c869993eSxy150489  * the GLD interface
852c869993eSxy150489  */
853c869993eSxy150489 static int
854c869993eSxy150489 igb_register_mac(igb_t *igb)
855c869993eSxy150489 {
856c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
857c869993eSxy150489 	mac_register_t *mac;
858c869993eSxy150489 	int status;
859c869993eSxy150489 
860c869993eSxy150489 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
861c869993eSxy150489 		return (IGB_FAILURE);
862c869993eSxy150489 
863c869993eSxy150489 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
864c869993eSxy150489 	mac->m_driver = igb;
865c869993eSxy150489 	mac->m_dip = igb->dip;
866c869993eSxy150489 	mac->m_src_addr = hw->mac.addr;
867c869993eSxy150489 	mac->m_callbacks = &igb_m_callbacks;
868c869993eSxy150489 	mac->m_min_sdu = 0;
869c869993eSxy150489 	mac->m_max_sdu = igb->max_frame_size -
870c869993eSxy150489 	    sizeof (struct ether_vlan_header) - ETHERFCSL;
871d62bc4baSyz147064 	mac->m_margin = VLAN_TAGSZ;
872ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	mac->m_priv_props = igb_priv_props;
873da14cebeSEric Cheng 	mac->m_v12n = MAC_VIRT_LEVEL1;
874c869993eSxy150489 
875c869993eSxy150489 	status = mac_register(mac, &igb->mac_hdl);
876c869993eSxy150489 
877c869993eSxy150489 	mac_free(mac);
878c869993eSxy150489 
879c869993eSxy150489 	return ((status == 0) ? IGB_SUCCESS : IGB_FAILURE);
880c869993eSxy150489 }
881c869993eSxy150489 
882c869993eSxy150489 /*
883c869993eSxy150489  * igb_identify_hardware - Identify the type of the chipset
884c869993eSxy150489  */
885c869993eSxy150489 static int
886c869993eSxy150489 igb_identify_hardware(igb_t *igb)
887c869993eSxy150489 {
888c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
889c869993eSxy150489 	struct igb_osdep *osdep = &igb->osdep;
890c869993eSxy150489 
891c869993eSxy150489 	/*
892c869993eSxy150489 	 * Get the device id
893c869993eSxy150489 	 */
894c869993eSxy150489 	hw->vendor_id =
895c869993eSxy150489 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
896c869993eSxy150489 	hw->device_id =
897c869993eSxy150489 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
898c869993eSxy150489 	hw->revision_id =
899c869993eSxy150489 	    pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
900c869993eSxy150489 	hw->subsystem_device_id =
901c869993eSxy150489 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
902c869993eSxy150489 	hw->subsystem_vendor_id =
903c869993eSxy150489 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
904c869993eSxy150489 
905c869993eSxy150489 	/*
906c869993eSxy150489 	 * Set the mac type of the adapter based on the device id
907c869993eSxy150489 	 */
908c869993eSxy150489 	if (e1000_set_mac_type(hw) != E1000_SUCCESS) {
909c869993eSxy150489 		return (IGB_FAILURE);
910c869993eSxy150489 	}
911c869993eSxy150489 
91280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/*
91380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * Install adapter capabilities based on mac type
91480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 */
91580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	switch (hw->mac.type) {
91680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	case e1000_82575:
91780a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->capab = &igb_82575_cap;
91880a11ad2Schenlu chen - Sun Microsystems - Beijing China 		break;
91980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	case e1000_82576:
92080a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->capab = &igb_82576_cap;
92180a11ad2Schenlu chen - Sun Microsystems - Beijing China 		break;
9223f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	case e1000_82580:
9233f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		igb->capab = &igb_82580_cap;
9243f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		break;
9257e526273SRobert Mustacchi 	case e1000_i350:
9267e526273SRobert Mustacchi 		igb->capab = &igb_i350_cap;
9277e526273SRobert Mustacchi 		break;
9286ed0a5cfSTycho Nightingale 	case e1000_i210:
9296ed0a5cfSTycho Nightingale 	case e1000_i211:
9306ed0a5cfSTycho Nightingale 		igb->capab = &igb_i210_cap;
9316ed0a5cfSTycho Nightingale 		break;
93213485e69SGarrett D'Amore 	case e1000_i354:
93313485e69SGarrett D'Amore 		igb->capab = &igb_i354_cap;
93413485e69SGarrett D'Amore 		break;
93580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	default:
93680a11ad2Schenlu chen - Sun Microsystems - Beijing China 		return (IGB_FAILURE);
93780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	}
93880a11ad2Schenlu chen - Sun Microsystems - Beijing China 
939c869993eSxy150489 	return (IGB_SUCCESS);
940c869993eSxy150489 }
941c869993eSxy150489 
942c869993eSxy150489 /*
943c869993eSxy150489  * igb_regs_map - Map the device registers
944c869993eSxy150489  */
945c869993eSxy150489 static int
946c869993eSxy150489 igb_regs_map(igb_t *igb)
947c869993eSxy150489 {
948c869993eSxy150489 	dev_info_t *devinfo = igb->dip;
949c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
950c869993eSxy150489 	struct igb_osdep *osdep = &igb->osdep;
951c869993eSxy150489 	off_t mem_size;
952c869993eSxy150489 
953c869993eSxy150489 	/*
954c869993eSxy150489 	 * First get the size of device registers to be mapped.
955c869993eSxy150489 	 */
95680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	if (ddi_dev_regsize(devinfo, IGB_ADAPTER_REGSET, &mem_size) !=
95780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	    DDI_SUCCESS) {
958c869993eSxy150489 		return (IGB_FAILURE);
959c869993eSxy150489 	}
960c869993eSxy150489 
961c869993eSxy150489 	/*
962c869993eSxy150489 	 * Call ddi_regs_map_setup() to map registers
963c869993eSxy150489 	 */
96480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	if ((ddi_regs_map_setup(devinfo, IGB_ADAPTER_REGSET,
965c869993eSxy150489 	    (caddr_t *)&hw->hw_addr, 0,
966c869993eSxy150489 	    mem_size, &igb_regs_acc_attr,
967c869993eSxy150489 	    &osdep->reg_handle)) != DDI_SUCCESS) {
968c869993eSxy150489 		return (IGB_FAILURE);
969c869993eSxy150489 	}
970c869993eSxy150489 
971c869993eSxy150489 	return (IGB_SUCCESS);
972c869993eSxy150489 }
973c869993eSxy150489 
974c869993eSxy150489 /*
975c869993eSxy150489  * igb_init_properties - Initialize driver properties
976c869993eSxy150489  */
977c869993eSxy150489 static void
978c869993eSxy150489 igb_init_properties(igb_t *igb)
979c869993eSxy150489 {
980c869993eSxy150489 	/*
981c869993eSxy150489 	 * Get conf file properties, including link settings
982c869993eSxy150489 	 * jumbo frames, ring number, descriptor number, etc.
983c869993eSxy150489 	 */
984c869993eSxy150489 	igb_get_conf(igb);
985c869993eSxy150489 }
986c869993eSxy150489 
987c869993eSxy150489 /*
988c869993eSxy150489  * igb_init_driver_settings - Initialize driver settings
989c869993eSxy150489  *
990c869993eSxy150489  * The settings include hardware function pointers, bus information,
991c869993eSxy150489  * rx/tx rings settings, link state, and any other parameters that
992c869993eSxy150489  * need to be setup during driver initialization.
993c869993eSxy150489  */
994c869993eSxy150489 static int
995c869993eSxy150489 igb_init_driver_settings(igb_t *igb)
996c869993eSxy150489 {
997c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
998c869993eSxy150489 	igb_rx_ring_t *rx_ring;
999c869993eSxy150489 	igb_tx_ring_t *tx_ring;
1000c869993eSxy150489 	uint32_t rx_size;
1001c869993eSxy150489 	uint32_t tx_size;
1002c869993eSxy150489 	int i;
1003c869993eSxy150489 
1004c869993eSxy150489 	/*
1005c869993eSxy150489 	 * Initialize chipset specific hardware function pointers
1006c869993eSxy150489 	 */
1007c869993eSxy150489 	if (e1000_setup_init_funcs(hw, B_TRUE) != E1000_SUCCESS) {
1008c869993eSxy150489 		return (IGB_FAILURE);
1009c869993eSxy150489 	}
1010c869993eSxy150489 
1011c869993eSxy150489 	/*
1012c869993eSxy150489 	 * Get bus information
1013c869993eSxy150489 	 */
1014c869993eSxy150489 	if (e1000_get_bus_info(hw) != E1000_SUCCESS) {
1015c869993eSxy150489 		return (IGB_FAILURE);
1016c869993eSxy150489 	}
1017c869993eSxy150489 
1018c869993eSxy150489 	/*
1019d11274aaSPaul Guo 	 * Get the system page size
1020d11274aaSPaul Guo 	 */
1021d11274aaSPaul Guo 	igb->page_size = ddi_ptob(igb->dip, (ulong_t)1);
1022d11274aaSPaul Guo 
1023d11274aaSPaul Guo 	/*
1024c869993eSxy150489 	 * Set rx buffer size
1025c869993eSxy150489 	 * The IP header alignment room is counted in the calculation.
1026c869993eSxy150489 	 * The rx buffer size is in unit of 1K that is required by the
1027c869993eSxy150489 	 * chipset hardware.
1028c869993eSxy150489 	 */
1029c869993eSxy150489 	rx_size = igb->max_frame_size + IPHDR_ALIGN_ROOM;
1030c869993eSxy150489 	igb->rx_buf_size = ((rx_size >> 10) +
1031c869993eSxy150489 	    ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
1032c869993eSxy150489 
1033c869993eSxy150489 	/*
1034c869993eSxy150489 	 * Set tx buffer size
1035c869993eSxy150489 	 */
1036c869993eSxy150489 	tx_size = igb->max_frame_size;
1037c869993eSxy150489 	igb->tx_buf_size = ((tx_size >> 10) +
1038c869993eSxy150489 	    ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
1039c869993eSxy150489 
1040c869993eSxy150489 	/*
1041c869993eSxy150489 	 * Initialize rx/tx rings parameters
1042c869993eSxy150489 	 */
1043c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
1044c869993eSxy150489 		rx_ring = &igb->rx_rings[i];
1045c869993eSxy150489 		rx_ring->index = i;
1046c869993eSxy150489 		rx_ring->igb = igb;
1047c869993eSxy150489 	}
1048c869993eSxy150489 
1049c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
1050c869993eSxy150489 		tx_ring = &igb->tx_rings[i];
1051c869993eSxy150489 		tx_ring->index = i;
1052c869993eSxy150489 		tx_ring->igb = igb;
1053c869993eSxy150489 		if (igb->tx_head_wb_enable)
1054c869993eSxy150489 			tx_ring->tx_recycle = igb_tx_recycle_head_wb;
1055c869993eSxy150489 		else
1056c869993eSxy150489 			tx_ring->tx_recycle = igb_tx_recycle_legacy;
1057c869993eSxy150489 
1058c869993eSxy150489 		tx_ring->ring_size = igb->tx_ring_size;
1059c869993eSxy150489 		tx_ring->free_list_size = igb->tx_ring_size +
1060c869993eSxy150489 		    (igb->tx_ring_size >> 1);
1061c869993eSxy150489 	}
1062c869993eSxy150489 
1063c869993eSxy150489 	/*
106480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * Initialize values of interrupt throttling rates
1065c869993eSxy150489 	 */
1066c869993eSxy150489 	for (i = 1; i < MAX_NUM_EITR; i++)
1067c869993eSxy150489 		igb->intr_throttling[i] = igb->intr_throttling[0];
1068c869993eSxy150489 
1069c869993eSxy150489 	/*
1070c869993eSxy150489 	 * The initial link state should be "unknown"
1071c869993eSxy150489 	 */
1072c869993eSxy150489 	igb->link_state = LINK_STATE_UNKNOWN;
1073c869993eSxy150489 
1074c869993eSxy150489 	return (IGB_SUCCESS);
1075c869993eSxy150489 }
1076c869993eSxy150489 
1077c869993eSxy150489 /*
1078c869993eSxy150489  * igb_init_locks - Initialize locks
1079c869993eSxy150489  */
1080c869993eSxy150489 static void
1081c869993eSxy150489 igb_init_locks(igb_t *igb)
1082c869993eSxy150489 {
1083c869993eSxy150489 	igb_rx_ring_t *rx_ring;
1084c869993eSxy150489 	igb_tx_ring_t *tx_ring;
1085c869993eSxy150489 	int i;
1086c869993eSxy150489 
1087c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
1088c869993eSxy150489 		rx_ring = &igb->rx_rings[i];
1089c869993eSxy150489 		mutex_init(&rx_ring->rx_lock, NULL,
1090c869993eSxy150489 		    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
1091c869993eSxy150489 	}
1092c869993eSxy150489 
1093c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
1094c869993eSxy150489 		tx_ring = &igb->tx_rings[i];
1095c869993eSxy150489 		mutex_init(&tx_ring->tx_lock, NULL,
1096c869993eSxy150489 		    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
1097c869993eSxy150489 		mutex_init(&tx_ring->recycle_lock, NULL,
1098c869993eSxy150489 		    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
1099c869993eSxy150489 		mutex_init(&tx_ring->tcb_head_lock, NULL,
1100c869993eSxy150489 		    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
1101c869993eSxy150489 		mutex_init(&tx_ring->tcb_tail_lock, NULL,
1102c869993eSxy150489 		    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
1103c869993eSxy150489 	}
1104c869993eSxy150489 
1105c869993eSxy150489 	mutex_init(&igb->gen_lock, NULL,
1106c869993eSxy150489 	    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
1107c869993eSxy150489 
1108c869993eSxy150489 	mutex_init(&igb->watchdog_lock, NULL,
1109c869993eSxy150489 	    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
1110cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
1111cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	mutex_init(&igb->link_lock, NULL,
1112cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	    MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
1113c869993eSxy150489 }
1114c869993eSxy150489 
1115c869993eSxy150489 /*
1116c869993eSxy150489  * igb_destroy_locks - Destroy locks
1117c869993eSxy150489  */
1118c869993eSxy150489 static void
1119c869993eSxy150489 igb_destroy_locks(igb_t *igb)
1120c869993eSxy150489 {
1121c869993eSxy150489 	igb_rx_ring_t *rx_ring;
1122c869993eSxy150489 	igb_tx_ring_t *tx_ring;
1123c869993eSxy150489 	int i;
1124c869993eSxy150489 
1125c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
1126c869993eSxy150489 		rx_ring = &igb->rx_rings[i];
1127c869993eSxy150489 		mutex_destroy(&rx_ring->rx_lock);
1128c869993eSxy150489 	}
1129c869993eSxy150489 
1130c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
1131c869993eSxy150489 		tx_ring = &igb->tx_rings[i];
1132c869993eSxy150489 		mutex_destroy(&tx_ring->tx_lock);
1133c869993eSxy150489 		mutex_destroy(&tx_ring->recycle_lock);
1134c869993eSxy150489 		mutex_destroy(&tx_ring->tcb_head_lock);
1135c869993eSxy150489 		mutex_destroy(&tx_ring->tcb_tail_lock);
1136c869993eSxy150489 	}
1137c869993eSxy150489 
1138c869993eSxy150489 	mutex_destroy(&igb->gen_lock);
1139c869993eSxy150489 	mutex_destroy(&igb->watchdog_lock);
1140cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	mutex_destroy(&igb->link_lock);
1141c869993eSxy150489 }
1142c869993eSxy150489 
1143c869993eSxy150489 static int
1144c869993eSxy150489 igb_resume(dev_info_t *devinfo)
1145c869993eSxy150489 {
1146c869993eSxy150489 	igb_t *igb;
1147c869993eSxy150489 
1148c869993eSxy150489 	igb = (igb_t *)ddi_get_driver_private(devinfo);
1149c869993eSxy150489 	if (igb == NULL)
1150c869993eSxy150489 		return (DDI_FAILURE);
1151c869993eSxy150489 
1152c869993eSxy150489 	mutex_enter(&igb->gen_lock);
1153c869993eSxy150489 
115482722020SCrisson Guanghao Hu 	/*
115582722020SCrisson Guanghao Hu 	 * Enable interrupts
115682722020SCrisson Guanghao Hu 	 */
115782722020SCrisson Guanghao Hu 	if (igb->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
115882722020SCrisson Guanghao Hu 		if (igb_enable_intrs(igb) != IGB_SUCCESS) {
1159*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
1160*e5513923SYuri Pankov 			    "Failed to enable DDI interrupts");
116182722020SCrisson Guanghao Hu 			mutex_exit(&igb->gen_lock);
116282722020SCrisson Guanghao Hu 			return (DDI_FAILURE);
116382722020SCrisson Guanghao Hu 		}
116482722020SCrisson Guanghao Hu 	}
116582722020SCrisson Guanghao Hu 
1166c869993eSxy150489 	if (igb->igb_state & IGB_STARTED) {
1167ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (igb_start(igb, B_FALSE) != IGB_SUCCESS) {
1168c869993eSxy150489 			mutex_exit(&igb->gen_lock);
1169c869993eSxy150489 			return (DDI_FAILURE);
1170c869993eSxy150489 		}
1171c869993eSxy150489 
1172c869993eSxy150489 		/*
1173c869993eSxy150489 		 * Enable and start the watchdog timer
1174c869993eSxy150489 		 */
1175c869993eSxy150489 		igb_enable_watchdog_timer(igb);
1176c869993eSxy150489 	}
1177c869993eSxy150489 
1178cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	atomic_and_32(&igb->igb_state, ~IGB_SUSPENDED);
1179c869993eSxy150489 
1180c869993eSxy150489 	mutex_exit(&igb->gen_lock);
1181c869993eSxy150489 
1182c869993eSxy150489 	return (DDI_SUCCESS);
1183c869993eSxy150489 }
1184c869993eSxy150489 
1185c869993eSxy150489 static int
1186c869993eSxy150489 igb_suspend(dev_info_t *devinfo)
1187c869993eSxy150489 {
1188c869993eSxy150489 	igb_t *igb;
1189c869993eSxy150489 
1190c869993eSxy150489 	igb = (igb_t *)ddi_get_driver_private(devinfo);
1191c869993eSxy150489 	if (igb == NULL)
1192c869993eSxy150489 		return (DDI_FAILURE);
1193c869993eSxy150489 
1194c869993eSxy150489 	mutex_enter(&igb->gen_lock);
1195c869993eSxy150489 
1196cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	atomic_or_32(&igb->igb_state, IGB_SUSPENDED);
1197c869993eSxy150489 
119882722020SCrisson Guanghao Hu 	/*
119982722020SCrisson Guanghao Hu 	 * Disable interrupts
120082722020SCrisson Guanghao Hu 	 */
120182722020SCrisson Guanghao Hu 	if (igb->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
120282722020SCrisson Guanghao Hu 		(void) igb_disable_intrs(igb);
120382722020SCrisson Guanghao Hu 	}
120482722020SCrisson Guanghao Hu 
1205b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (!(igb->igb_state & IGB_STARTED)) {
1206b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&igb->gen_lock);
1207b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		return (DDI_SUCCESS);
1208b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	}
1209b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1210ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_stop(igb, B_FALSE);
1211c869993eSxy150489 
1212c869993eSxy150489 	mutex_exit(&igb->gen_lock);
1213c869993eSxy150489 
1214c869993eSxy150489 	/*
1215c869993eSxy150489 	 * Disable and stop the watchdog timer
1216c869993eSxy150489 	 */
1217c869993eSxy150489 	igb_disable_watchdog_timer(igb);
1218c869993eSxy150489 
1219c869993eSxy150489 	return (DDI_SUCCESS);
1220c869993eSxy150489 }
1221c869993eSxy150489 
1222c869993eSxy150489 static int
1223c869993eSxy150489 igb_init(igb_t *igb)
1224c869993eSxy150489 {
1225b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	mutex_enter(&igb->gen_lock);
1226b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1227b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
1228b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Initilize the adapter
1229b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
1230b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (igb_init_adapter(igb) != IGB_SUCCESS) {
1231b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&igb->gen_lock);
1232b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
1233b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
1234b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		return (IGB_FAILURE);
1235b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	}
1236b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1237b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	mutex_exit(&igb->gen_lock);
1238b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1239b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	return (IGB_SUCCESS);
1240b8d0a377Schenlu chen - Sun Microsystems - Beijing China }
1241b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1242b8d0a377Schenlu chen - Sun Microsystems - Beijing China /*
1243b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * igb_init_mac_address - Initialize the default MAC address
1244b8d0a377Schenlu chen - Sun Microsystems - Beijing China  *
1245b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * On success, the MAC address is entered in the igb->hw.mac.addr
1246b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * and hw->mac.perm_addr fields and the adapter's RAR(0) receive
1247b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * address register.
1248b8d0a377Schenlu chen - Sun Microsystems - Beijing China  *
1249b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * Important side effects:
1250b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * 1. adapter is reset - this is required to put it in a known state.
1251b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * 2. all of non-volatile memory (NVM) is read & checksummed - NVM is where
1252b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * MAC address and all default settings are stored, so a valid checksum
1253b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * is required.
1254b8d0a377Schenlu chen - Sun Microsystems - Beijing China  */
1255b8d0a377Schenlu chen - Sun Microsystems - Beijing China static int
1256b8d0a377Schenlu chen - Sun Microsystems - Beijing China igb_init_mac_address(igb_t *igb)
1257b8d0a377Schenlu chen - Sun Microsystems - Beijing China {
1258c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
1259c869993eSxy150489 
1260da14cebeSEric Cheng 	ASSERT(mutex_owned(&igb->gen_lock));
1261c869993eSxy150489 
1262c869993eSxy150489 	/*
1263c869993eSxy150489 	 * Reset chipset to put the hardware in a known state
1264b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * before we try to get MAC address from NVM.
1265c869993eSxy150489 	 */
12668bb4b220Sgl147354 	if (e1000_reset_hw(hw) != E1000_SUCCESS) {
1267*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Adapter reset failed.");
1268b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		goto init_mac_fail;
12698bb4b220Sgl147354 	}
1270c869993eSxy150489 
1271c869993eSxy150489 	/*
1272c869993eSxy150489 	 * NVM validation
1273c869993eSxy150489 	 */
12746ed0a5cfSTycho Nightingale 	if (((igb->hw.mac.type != e1000_i210) &&
12756ed0a5cfSTycho Nightingale 	    (igb->hw.mac.type != e1000_i211)) &&
12766ed0a5cfSTycho Nightingale 	    (e1000_validate_nvm_checksum(hw) < 0)) {
1277c869993eSxy150489 		/*
1278c869993eSxy150489 		 * Some PCI-E parts fail the first check due to
1279c869993eSxy150489 		 * the link being in sleep state.  Call it again,
1280c869993eSxy150489 		 * if it fails a second time its a real issue.
1281c869993eSxy150489 		 */
1282c869993eSxy150489 		if (e1000_validate_nvm_checksum(hw) < 0) {
1283*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
1284c869993eSxy150489 			    "Invalid NVM checksum. Please contact "
1285c869993eSxy150489 			    "the vendor to update the NVM.");
1286b8d0a377Schenlu chen - Sun Microsystems - Beijing China 			goto init_mac_fail;
1287c869993eSxy150489 		}
1288c869993eSxy150489 	}
1289c869993eSxy150489 
1290c869993eSxy150489 	/*
1291b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Get the mac address
1292b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * This function should handle SPARC case correctly.
1293b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
1294b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (!igb_find_mac_address(igb)) {
1295*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to get the mac address");
1296b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		goto init_mac_fail;
1297b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	}
1298b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1299b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/* Validate mac address */
1300b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (!is_valid_mac_addr(hw->mac.addr)) {
1301*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Invalid mac address");
1302b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		goto init_mac_fail;
1303b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	}
1304b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1305b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	return (IGB_SUCCESS);
1306b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1307b8d0a377Schenlu chen - Sun Microsystems - Beijing China init_mac_fail:
1308b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	return (IGB_FAILURE);
1309b8d0a377Schenlu chen - Sun Microsystems - Beijing China }
1310b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1311b8d0a377Schenlu chen - Sun Microsystems - Beijing China /*
1312b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * igb_init_adapter - Initialize the adapter
1313b8d0a377Schenlu chen - Sun Microsystems - Beijing China  */
1314b8d0a377Schenlu chen - Sun Microsystems - Beijing China static int
1315b8d0a377Schenlu chen - Sun Microsystems - Beijing China igb_init_adapter(igb_t *igb)
1316b8d0a377Schenlu chen - Sun Microsystems - Beijing China {
1317b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	struct e1000_hw *hw = &igb->hw;
1318b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	uint32_t pba;
131969c76190SKeith M Wesolowski 	int oemid[2];
132069c76190SKeith M Wesolowski 	uint16_t nvmword;
13216ed0a5cfSTycho Nightingale 	uint32_t hwm;
13226ed0a5cfSTycho Nightingale 	uint32_t default_mtu;
132369c76190SKeith M Wesolowski 	u8 pbanum[E1000_PBANUM_LENGTH];
132469c76190SKeith M Wesolowski 	char eepromver[5];	/* f.ff */
1325b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	int i;
1326b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1327b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	ASSERT(mutex_owned(&igb->gen_lock));
1328b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1329b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
1330b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * In order to obtain the default MAC address, this will reset the
1331b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * adapter and validate the NVM that the address and many other
1332b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * default settings come from.
1333b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
1334b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (igb_init_mac_address(igb) != IGB_SUCCESS) {
1335*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to initialize MAC address");
1336b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		goto init_adapter_fail;
1337b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	}
1338b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1339b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
13406ed0a5cfSTycho Nightingale 	 * Packet Buffer Allocation (PBA)
13416ed0a5cfSTycho Nightingale 	 * Writing PBA sets the receive portion of the buffer
13426ed0a5cfSTycho Nightingale 	 * the remainder is used for the transmit buffer.
1343c869993eSxy150489 	 */
13446ed0a5cfSTycho Nightingale 	switch (hw->mac.type) {
13456ed0a5cfSTycho Nightingale 	case e1000_82575:
13466ed0a5cfSTycho Nightingale 		pba = E1000_PBA_32K;
13476ed0a5cfSTycho Nightingale 		break;
13486ed0a5cfSTycho Nightingale 	case e1000_82576:
13496ed0a5cfSTycho Nightingale 		pba = E1000_READ_REG(hw, E1000_RXPBS);
13506ed0a5cfSTycho Nightingale 		pba &= E1000_RXPBS_SIZE_MASK_82576;
13516ed0a5cfSTycho Nightingale 		break;
13526ed0a5cfSTycho Nightingale 	case e1000_82580:
13536ed0a5cfSTycho Nightingale 	case e1000_i350:
135413485e69SGarrett D'Amore 	case e1000_i354:
13556ed0a5cfSTycho Nightingale 		pba = E1000_READ_REG(hw, E1000_RXPBS);
13566ed0a5cfSTycho Nightingale 		pba = e1000_rxpbs_adjust_82580(pba);
13576ed0a5cfSTycho Nightingale 		break;
13586ed0a5cfSTycho Nightingale 	case e1000_i210:
13596ed0a5cfSTycho Nightingale 	case e1000_i211:
136080a11ad2Schenlu chen - Sun Microsystems - Beijing China 		pba = E1000_PBA_34K;
13616ed0a5cfSTycho Nightingale 	default:
13626ed0a5cfSTycho Nightingale 		break;
136380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	}
136480a11ad2Schenlu chen - Sun Microsystems - Beijing China 
13656ed0a5cfSTycho Nightingale 	/* Special needs in case of Jumbo frames */
13666ed0a5cfSTycho Nightingale 	default_mtu = igb_get_prop(igb, PROP_DEFAULT_MTU,
13676ed0a5cfSTycho Nightingale 	    MIN_MTU, MAX_MTU, DEFAULT_MTU);
13686ed0a5cfSTycho Nightingale 	if ((hw->mac.type == e1000_82575) && (default_mtu > ETHERMTU)) {
13696ed0a5cfSTycho Nightingale 		u32 tx_space, min_tx, min_rx;
13706ed0a5cfSTycho Nightingale 		pba = E1000_READ_REG(hw, E1000_PBA);
13716ed0a5cfSTycho Nightingale 		tx_space = pba >> 16;
13726ed0a5cfSTycho Nightingale 		pba &= 0xffff;
13736ed0a5cfSTycho Nightingale 		min_tx = (igb->max_frame_size +
13746ed0a5cfSTycho Nightingale 		    sizeof (struct e1000_tx_desc) - ETHERNET_FCS_SIZE) * 2;
13756ed0a5cfSTycho Nightingale 		min_tx = roundup(min_tx, 1024);
13766ed0a5cfSTycho Nightingale 		min_tx >>= 10;
13776ed0a5cfSTycho Nightingale 		min_rx = igb->max_frame_size;
13786ed0a5cfSTycho Nightingale 		min_rx = roundup(min_rx, 1024);
13796ed0a5cfSTycho Nightingale 		min_rx >>= 10;
13806ed0a5cfSTycho Nightingale 		if (tx_space < min_tx &&
13816ed0a5cfSTycho Nightingale 		    ((min_tx - tx_space) < pba)) {
13826ed0a5cfSTycho Nightingale 			pba = pba - (min_tx - tx_space);
13836ed0a5cfSTycho Nightingale 			/*
13846ed0a5cfSTycho Nightingale 			 * if short on rx space, rx wins
13856ed0a5cfSTycho Nightingale 			 * and must trump tx adjustment
13866ed0a5cfSTycho Nightingale 			 */
13876ed0a5cfSTycho Nightingale 			if (pba < min_rx)
13886ed0a5cfSTycho Nightingale 				pba = min_rx;
13896ed0a5cfSTycho Nightingale 		}
13906ed0a5cfSTycho Nightingale 		E1000_WRITE_REG(hw, E1000_PBA, pba);
13916ed0a5cfSTycho Nightingale 	}
1392c869993eSxy150489 
13936ed0a5cfSTycho Nightingale 	DEBUGOUT1("igb_init: pba=%dK", pba);
13946ed0a5cfSTycho Nightingale 
13956ed0a5cfSTycho Nightingale 	/*
13966ed0a5cfSTycho Nightingale 	 * These parameters control the automatic generation (Tx) and
13976ed0a5cfSTycho Nightingale 	 * response (Rx) to Ethernet PAUSE frames.
13986ed0a5cfSTycho Nightingale 	 * - High water mark should allow for at least two frames to be
13996ed0a5cfSTycho Nightingale 	 *   received after sending an XOFF.
14006ed0a5cfSTycho Nightingale 	 * - Low water mark works best when it is very near the high water mark.
14016ed0a5cfSTycho Nightingale 	 *   This allows the receiver to restart by sending XON when it has
14026ed0a5cfSTycho Nightingale 	 *   drained a bit.
14036ed0a5cfSTycho Nightingale 	 */
14046ed0a5cfSTycho Nightingale 	hwm = min(((pba << 10) * 9 / 10),
14056ed0a5cfSTycho Nightingale 	    ((pba << 10) - 2 * igb->max_frame_size));
14066ed0a5cfSTycho Nightingale 
14076ed0a5cfSTycho Nightingale 	if (hw->mac.type < e1000_82576) {
14086ed0a5cfSTycho Nightingale 		hw->fc.high_water = hwm & 0xFFF8;  /* 8-byte granularity */
1409c869993eSxy150489 		hw->fc.low_water = hw->fc.high_water - 8;
141080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	} else {
14116ed0a5cfSTycho Nightingale 		hw->fc.high_water = hwm & 0xFFF0;  /* 16-byte granularity */
141280a11ad2Schenlu chen - Sun Microsystems - Beijing China 		hw->fc.low_water = hw->fc.high_water - 16;
141380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	}
141480a11ad2Schenlu chen - Sun Microsystems - Beijing China 
1415c869993eSxy150489 	hw->fc.pause_time = E1000_FC_PAUSE_TIME;
1416c869993eSxy150489 	hw->fc.send_xon = B_TRUE;
1417c869993eSxy150489 
14183f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	(void) e1000_validate_mdi_setting(hw);
1419b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1420c869993eSxy150489 	/*
1421b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Reset the chipset hardware the second time to put PBA settings
1422b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * into effect.
1423c869993eSxy150489 	 */
14248bb4b220Sgl147354 	if (e1000_reset_hw(hw) != E1000_SUCCESS) {
1425*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Second reset failed");
1426b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		goto init_adapter_fail;
14278bb4b220Sgl147354 	}
1428c869993eSxy150489 
1429c869993eSxy150489 	/*
1430c869993eSxy150489 	 * Don't wait for auto-negotiation to complete
1431c869993eSxy150489 	 */
1432c869993eSxy150489 	hw->phy.autoneg_wait_to_complete = B_FALSE;
1433c869993eSxy150489 
1434c869993eSxy150489 	/*
1435c869993eSxy150489 	 * Copper options
1436c869993eSxy150489 	 */
1437c869993eSxy150489 	if (hw->phy.media_type == e1000_media_type_copper) {
1438c869993eSxy150489 		hw->phy.mdix = 0;	/* AUTO_ALL_MODES */
1439c869993eSxy150489 		hw->phy.disable_polarity_correction = B_FALSE;
1440c869993eSxy150489 		hw->phy.ms_type = e1000_ms_hw_default; /* E1000_MASTER_SLAVE */
1441c869993eSxy150489 	}
1442c869993eSxy150489 
1443c869993eSxy150489 	/*
1444c869993eSxy150489 	 * Initialize link settings
1445c869993eSxy150489 	 */
1446c869993eSxy150489 	(void) igb_setup_link(igb, B_FALSE);
1447c869993eSxy150489 
1448c869993eSxy150489 	/*
1449c869993eSxy150489 	 * Configure/Initialize hardware
1450c869993eSxy150489 	 */
1451c869993eSxy150489 	if (e1000_init_hw(hw) != E1000_SUCCESS) {
1452*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Failed to initialize hardware");
1453b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		goto init_adapter_fail;
1454c869993eSxy150489 	}
1455c869993eSxy150489 
1456c869993eSxy150489 	/*
1457cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	 *  Start the link setup timer
1458cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	 */
1459cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	igb_start_link_timer(igb);
1460cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
1461cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	/*
1462b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Disable wakeup control by default
1463b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
1464b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_WUC, 0);
1465b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1466b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
1467b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Record phy info in hw struct
1468b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
1469b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	(void) e1000_get_phy_info(hw);
1470b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1471b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
1472c869993eSxy150489 	 * Make sure driver has control
1473c869993eSxy150489 	 */
1474c869993eSxy150489 	igb_get_driver_control(hw);
1475c869993eSxy150489 
1476c869993eSxy150489 	/*
1477b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Restore LED settings to the default from EEPROM
1478b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * to meet the standard for Sun platforms.
1479b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
1480b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	(void) e1000_cleanup_led(hw);
1481b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1482b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
1483c869993eSxy150489 	 * Setup MSI-X interrupts
1484c869993eSxy150489 	 */
1485c869993eSxy150489 	if (igb->intr_type == DDI_INTR_TYPE_MSIX)
148680a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->capab->setup_msix(igb);
1487c869993eSxy150489 
1488c869993eSxy150489 	/*
1489c869993eSxy150489 	 * Initialize unicast addresses.
1490c869993eSxy150489 	 */
1491c869993eSxy150489 	igb_init_unicst(igb);
1492c869993eSxy150489 
1493c869993eSxy150489 	/*
1494c869993eSxy150489 	 * Setup and initialize the mctable structures.
1495c869993eSxy150489 	 */
1496c869993eSxy150489 	igb_setup_multicst(igb);
1497c869993eSxy150489 
1498c869993eSxy150489 	/*
1499c869993eSxy150489 	 * Set interrupt throttling rate
1500c869993eSxy150489 	 */
1501c869993eSxy150489 	for (i = 0; i < igb->intr_cnt; i++)
1502c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_EITR(i), igb->intr_throttling[i]);
1503c869993eSxy150489 
1504c869993eSxy150489 	/*
150569c76190SKeith M Wesolowski 	 * Read identifying information and place in devinfo.
150669c76190SKeith M Wesolowski 	 */
150769c76190SKeith M Wesolowski 	nvmword = 0xffff;
150869c76190SKeith M Wesolowski 	(void) e1000_read_nvm(&igb->hw, NVM_OEM_OFFSET_0, 1, &nvmword);
150969c76190SKeith M Wesolowski 	oemid[0] = (int)nvmword;
151069c76190SKeith M Wesolowski 	(void) e1000_read_nvm(&igb->hw, NVM_OEM_OFFSET_1, 1, &nvmword);
151169c76190SKeith M Wesolowski 	oemid[1] = (int)nvmword;
151269c76190SKeith M Wesolowski 	(void) ddi_prop_update_int_array(DDI_DEV_T_NONE, igb->dip,
151369c76190SKeith M Wesolowski 	    "oem-identifier", oemid, 2);
151469c76190SKeith M Wesolowski 
151569c76190SKeith M Wesolowski 	pbanum[0] = '\0';
151669c76190SKeith M Wesolowski 	(void) e1000_read_pba_string(&igb->hw, pbanum, sizeof (pbanum));
151769c76190SKeith M Wesolowski 	if (*pbanum != '\0') {
151869c76190SKeith M Wesolowski 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, igb->dip,
151969c76190SKeith M Wesolowski 		    "printed-board-assembly", (char *)pbanum);
152069c76190SKeith M Wesolowski 	}
152169c76190SKeith M Wesolowski 
152269c76190SKeith M Wesolowski 	nvmword = 0xffff;
152369c76190SKeith M Wesolowski 	(void) e1000_read_nvm(&igb->hw, NVM_VERSION, 1, &nvmword);
152469c76190SKeith M Wesolowski 	if ((nvmword & 0xf00) == 0) {
152569c76190SKeith M Wesolowski 		(void) snprintf(eepromver, sizeof (eepromver), "%x.%x",
152669c76190SKeith M Wesolowski 		    (nvmword & 0xf000) >> 12, (nvmword & 0xff));
152769c76190SKeith M Wesolowski 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, igb->dip,
152869c76190SKeith M Wesolowski 		    "nvm-version", eepromver);
152969c76190SKeith M Wesolowski 	}
153069c76190SKeith M Wesolowski 
153169c76190SKeith M Wesolowski 	/*
1532c869993eSxy150489 	 * Save the state of the phy
1533c869993eSxy150489 	 */
1534c869993eSxy150489 	igb_get_phy_state(igb);
1535c869993eSxy150489 
1536ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_param_sync(igb);
1537ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
1538c869993eSxy150489 	return (IGB_SUCCESS);
1539b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1540b8d0a377Schenlu chen - Sun Microsystems - Beijing China init_adapter_fail:
1541b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
1542b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Reset PHY if possible
1543b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
1544b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (e1000_check_reset_block(hw) == E1000_SUCCESS)
1545b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		(void) e1000_phy_hw_reset(hw);
1546b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
1547b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	return (IGB_FAILURE);
1548c869993eSxy150489 }
1549c869993eSxy150489 
1550c869993eSxy150489 /*
1551b8d0a377Schenlu chen - Sun Microsystems - Beijing China  * igb_stop_adapter - Stop the adapter
1552c869993eSxy150489  */
1553c869993eSxy150489 static void
1554b8d0a377Schenlu chen - Sun Microsystems - Beijing China igb_stop_adapter(igb_t *igb)
1555c869993eSxy150489 {
1556c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
1557c869993eSxy150489 
1558c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
1559c869993eSxy150489 
1560cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	/* Stop the link setup timer */
1561cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	igb_stop_link_timer(igb);
1562cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
1563c869993eSxy150489 	/* Tell firmware driver is no longer in control */
1564c869993eSxy150489 	igb_release_driver_control(hw);
1565c869993eSxy150489 
1566c869993eSxy150489 	/*
1567c869993eSxy150489 	 * Reset the chipset
1568c869993eSxy150489 	 */
15698bb4b220Sgl147354 	if (e1000_reset_hw(hw) != E1000_SUCCESS) {
15708bb4b220Sgl147354 		igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
15718bb4b220Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
15728bb4b220Sgl147354 	}
1573c869993eSxy150489 
1574c869993eSxy150489 	/*
1575b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * e1000_phy_hw_reset is not needed here, MAC reset above is sufficient
1576c869993eSxy150489 	 */
1577c869993eSxy150489 }
1578c869993eSxy150489 
1579c869993eSxy150489 /*
1580c869993eSxy150489  * igb_reset - Reset the chipset and restart the driver.
1581c869993eSxy150489  *
1582c869993eSxy150489  * It involves stopping and re-starting the chipset,
1583c869993eSxy150489  * and re-configuring the rx/tx rings.
1584c869993eSxy150489  */
1585c869993eSxy150489 static int
1586c869993eSxy150489 igb_reset(igb_t *igb)
1587c869993eSxy150489 {
1588c869993eSxy150489 	int i;
1589c869993eSxy150489 
1590c869993eSxy150489 	mutex_enter(&igb->gen_lock);
1591c869993eSxy150489 
1592c869993eSxy150489 	ASSERT(igb->igb_state & IGB_STARTED);
1593cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	atomic_and_32(&igb->igb_state, ~IGB_STARTED);
1594c869993eSxy150489 
1595c869993eSxy150489 	/*
1596c869993eSxy150489 	 * Disable the adapter interrupts to stop any rx/tx activities
1597c869993eSxy150489 	 * before draining pending data and resetting hardware.
1598c869993eSxy150489 	 */
1599c869993eSxy150489 	igb_disable_adapter_interrupts(igb);
1600c869993eSxy150489 
1601c869993eSxy150489 	/*
1602c869993eSxy150489 	 * Drain the pending transmit packets
1603c869993eSxy150489 	 */
1604c869993eSxy150489 	(void) igb_tx_drain(igb);
1605c869993eSxy150489 
1606c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++)
1607c869993eSxy150489 		mutex_enter(&igb->rx_rings[i].rx_lock);
1608c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++)
1609c869993eSxy150489 		mutex_enter(&igb->tx_rings[i].tx_lock);
1610c869993eSxy150489 
1611c869993eSxy150489 	/*
1612b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Stop the adapter
1613c869993eSxy150489 	 */
1614b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	igb_stop_adapter(igb);
1615c869993eSxy150489 
1616c869993eSxy150489 	/*
1617c869993eSxy150489 	 * Clean the pending tx data/resources
1618c869993eSxy150489 	 */
1619c869993eSxy150489 	igb_tx_clean(igb);
1620c869993eSxy150489 
1621c869993eSxy150489 	/*
1622b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Start the adapter
1623c869993eSxy150489 	 */
1624b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (igb_init_adapter(igb) != IGB_SUCCESS) {
16258bb4b220Sgl147354 		igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
1626c869993eSxy150489 		goto reset_failure;
1627c869993eSxy150489 	}
1628c869993eSxy150489 
1629c869993eSxy150489 	/*
1630c869993eSxy150489 	 * Setup the rx/tx rings
1631c869993eSxy150489 	 */
1632ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb->tx_ring_init = B_FALSE;
1633c869993eSxy150489 	igb_setup_rings(igb);
1634c869993eSxy150489 
1635cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	atomic_and_32(&igb->igb_state, ~(IGB_ERROR | IGB_STALL));
1636cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
1637c869993eSxy150489 	/*
1638c869993eSxy150489 	 * Enable adapter interrupts
1639c869993eSxy150489 	 * The interrupts must be enabled after the driver state is START
1640c869993eSxy150489 	 */
164180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	igb->capab->enable_intr(igb);
1642c869993eSxy150489 
16438bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.cfg_handle) != DDI_FM_OK)
16448bb4b220Sgl147354 		goto reset_failure;
16458bb4b220Sgl147354 
16468bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
16478bb4b220Sgl147354 		goto reset_failure;
16488bb4b220Sgl147354 
1649c869993eSxy150489 	for (i = igb->num_tx_rings - 1; i >= 0; i--)
1650c869993eSxy150489 		mutex_exit(&igb->tx_rings[i].tx_lock);
1651c869993eSxy150489 	for (i = igb->num_rx_rings - 1; i >= 0; i--)
1652c869993eSxy150489 		mutex_exit(&igb->rx_rings[i].rx_lock);
1653c869993eSxy150489 
1654cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	atomic_or_32(&igb->igb_state, IGB_STARTED);
1655cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
1656c869993eSxy150489 	mutex_exit(&igb->gen_lock);
1657c869993eSxy150489 
1658c869993eSxy150489 	return (IGB_SUCCESS);
1659c869993eSxy150489 
1660c869993eSxy150489 reset_failure:
1661c869993eSxy150489 	for (i = igb->num_tx_rings - 1; i >= 0; i--)
1662c869993eSxy150489 		mutex_exit(&igb->tx_rings[i].tx_lock);
1663c869993eSxy150489 	for (i = igb->num_rx_rings - 1; i >= 0; i--)
1664c869993eSxy150489 		mutex_exit(&igb->rx_rings[i].rx_lock);
1665c869993eSxy150489 
1666c869993eSxy150489 	mutex_exit(&igb->gen_lock);
1667c869993eSxy150489 
16688bb4b220Sgl147354 	ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
16698bb4b220Sgl147354 
1670c869993eSxy150489 	return (IGB_FAILURE);
1671c869993eSxy150489 }
1672c869993eSxy150489 
1673c869993eSxy150489 /*
1674c869993eSxy150489  * igb_tx_clean - Clean the pending transmit packets and DMA resources
1675c869993eSxy150489  */
1676c869993eSxy150489 static void
1677c869993eSxy150489 igb_tx_clean(igb_t *igb)
1678c869993eSxy150489 {
1679c869993eSxy150489 	igb_tx_ring_t *tx_ring;
1680c869993eSxy150489 	tx_control_block_t *tcb;
1681c869993eSxy150489 	link_list_t pending_list;
1682c869993eSxy150489 	uint32_t desc_num;
1683c869993eSxy150489 	int i, j;
1684c869993eSxy150489 
1685c869993eSxy150489 	LINK_LIST_INIT(&pending_list);
1686c869993eSxy150489 
1687c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
1688c869993eSxy150489 		tx_ring = &igb->tx_rings[i];
1689c869993eSxy150489 
1690c869993eSxy150489 		mutex_enter(&tx_ring->recycle_lock);
1691c869993eSxy150489 
1692c869993eSxy150489 		/*
1693c869993eSxy150489 		 * Clean the pending tx data - the pending packets in the
1694c869993eSxy150489 		 * work_list that have no chances to be transmitted again.
1695c869993eSxy150489 		 *
1696c869993eSxy150489 		 * We must ensure the chipset is stopped or the link is down
1697c869993eSxy150489 		 * before cleaning the transmit packets.
1698c869993eSxy150489 		 */
1699c869993eSxy150489 		desc_num = 0;
1700c869993eSxy150489 		for (j = 0; j < tx_ring->ring_size; j++) {
1701c869993eSxy150489 			tcb = tx_ring->work_list[j];
1702c869993eSxy150489 			if (tcb != NULL) {
1703c869993eSxy150489 				desc_num += tcb->desc_num;
1704c869993eSxy150489 
1705c869993eSxy150489 				tx_ring->work_list[j] = NULL;
1706c869993eSxy150489 
1707c869993eSxy150489 				igb_free_tcb(tcb);
1708c869993eSxy150489 
1709c869993eSxy150489 				LIST_PUSH_TAIL(&pending_list, &tcb->link);
1710c869993eSxy150489 			}
1711c869993eSxy150489 		}
1712c869993eSxy150489 
1713c869993eSxy150489 		if (desc_num > 0) {
1714c869993eSxy150489 			atomic_add_32(&tx_ring->tbd_free, desc_num);
1715c869993eSxy150489 			ASSERT(tx_ring->tbd_free == tx_ring->ring_size);
1716c869993eSxy150489 
1717c869993eSxy150489 			/*
1718fa25784cSxy150489 			 * Reset the head and tail pointers of the tbd ring;
1719fa25784cSxy150489 			 * Reset the head write-back if it is enabled.
1720c869993eSxy150489 			 */
1721c869993eSxy150489 			tx_ring->tbd_head = 0;
1722c869993eSxy150489 			tx_ring->tbd_tail = 0;
1723fa25784cSxy150489 			if (igb->tx_head_wb_enable)
1724fa25784cSxy150489 				*tx_ring->tbd_head_wb = 0;
1725c869993eSxy150489 
1726c869993eSxy150489 			E1000_WRITE_REG(&igb->hw, E1000_TDH(tx_ring->index), 0);
1727c869993eSxy150489 			E1000_WRITE_REG(&igb->hw, E1000_TDT(tx_ring->index), 0);
1728c869993eSxy150489 		}
1729c869993eSxy150489 
1730c869993eSxy150489 		mutex_exit(&tx_ring->recycle_lock);
1731c869993eSxy150489 
1732c869993eSxy150489 		/*
1733c869993eSxy150489 		 * Add the tx control blocks in the pending list to
1734c869993eSxy150489 		 * the free list.
1735c869993eSxy150489 		 */
1736c869993eSxy150489 		igb_put_free_list(tx_ring, &pending_list);
1737c869993eSxy150489 	}
1738c869993eSxy150489 }
1739c869993eSxy150489 
1740c869993eSxy150489 /*
1741c869993eSxy150489  * igb_tx_drain - Drain the tx rings to allow pending packets to be transmitted
1742c869993eSxy150489  */
1743c869993eSxy150489 static boolean_t
1744c869993eSxy150489 igb_tx_drain(igb_t *igb)
1745c869993eSxy150489 {
1746c869993eSxy150489 	igb_tx_ring_t *tx_ring;
1747c869993eSxy150489 	boolean_t done;
1748c869993eSxy150489 	int i, j;
1749c869993eSxy150489 
1750c869993eSxy150489 	/*
1751c869993eSxy150489 	 * Wait for a specific time to allow pending tx packets
1752c869993eSxy150489 	 * to be transmitted.
1753c869993eSxy150489 	 *
1754c869993eSxy150489 	 * Check the counter tbd_free to see if transmission is done.
1755c869993eSxy150489 	 * No lock protection is needed here.
1756c869993eSxy150489 	 *
1757c869993eSxy150489 	 * Return B_TRUE if all pending packets have been transmitted;
1758c869993eSxy150489 	 * Otherwise return B_FALSE;
1759c869993eSxy150489 	 */
1760c869993eSxy150489 	for (i = 0; i < TX_DRAIN_TIME; i++) {
1761c869993eSxy150489 
1762c869993eSxy150489 		done = B_TRUE;
1763c869993eSxy150489 		for (j = 0; j < igb->num_tx_rings; j++) {
1764c869993eSxy150489 			tx_ring = &igb->tx_rings[j];
1765c869993eSxy150489 			done = done &&
1766c869993eSxy150489 			    (tx_ring->tbd_free == tx_ring->ring_size);
1767c869993eSxy150489 		}
1768c869993eSxy150489 
1769c869993eSxy150489 		if (done)
1770c869993eSxy150489 			break;
1771c869993eSxy150489 
1772c869993eSxy150489 		msec_delay(1);
1773c869993eSxy150489 	}
1774c869993eSxy150489 
1775c869993eSxy150489 	return (done);
1776c869993eSxy150489 }
1777c869993eSxy150489 
1778c869993eSxy150489 /*
1779c869993eSxy150489  * igb_rx_drain - Wait for all rx buffers to be released by upper layer
1780c869993eSxy150489  */
1781c869993eSxy150489 static boolean_t
1782c869993eSxy150489 igb_rx_drain(igb_t *igb)
1783c869993eSxy150489 {
1784c869993eSxy150489 	boolean_t done;
1785ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	int i;
1786c869993eSxy150489 
1787c869993eSxy150489 	/*
1788c869993eSxy150489 	 * Polling the rx free list to check if those rx buffers held by
1789c869993eSxy150489 	 * the upper layer are released.
1790c869993eSxy150489 	 *
1791c869993eSxy150489 	 * Check the counter rcb_free to see if all pending buffers are
1792c869993eSxy150489 	 * released. No lock protection is needed here.
1793c869993eSxy150489 	 *
1794c869993eSxy150489 	 * Return B_TRUE if all pending buffers have been released;
1795c869993eSxy150489 	 * Otherwise return B_FALSE;
1796c869993eSxy150489 	 */
1797c869993eSxy150489 	for (i = 0; i < RX_DRAIN_TIME; i++) {
1798ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		done = (igb->rcb_pending == 0);
1799c869993eSxy150489 
1800c869993eSxy150489 		if (done)
1801c869993eSxy150489 			break;
1802c869993eSxy150489 
1803c869993eSxy150489 		msec_delay(1);
1804c869993eSxy150489 	}
1805c869993eSxy150489 
1806c869993eSxy150489 	return (done);
1807c869993eSxy150489 }
1808c869993eSxy150489 
1809c869993eSxy150489 /*
1810c869993eSxy150489  * igb_start - Start the driver/chipset
1811c869993eSxy150489  */
1812c869993eSxy150489 int
1813ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_start(igb_t *igb, boolean_t alloc_buffer)
1814c869993eSxy150489 {
1815c869993eSxy150489 	int i;
1816c869993eSxy150489 
1817c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
1818c869993eSxy150489 
1819ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (alloc_buffer) {
1820ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (igb_alloc_rx_data(igb) != IGB_SUCCESS) {
1821*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
1822ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			    "Failed to allocate software receive rings");
1823ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			return (IGB_FAILURE);
1824ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		}
1825ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
1826ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		/* Allocate buffers for all the rx/tx rings */
1827ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (igb_alloc_dma(igb) != IGB_SUCCESS) {
1828*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
1829*e5513923SYuri Pankov 			    "Failed to allocate DMA resource");
1830ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			return (IGB_FAILURE);
1831ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		}
1832ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
1833ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->tx_ring_init = B_TRUE;
1834ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	} else {
1835ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->tx_ring_init = B_FALSE;
1836ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
1837ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
1838c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++)
1839c869993eSxy150489 		mutex_enter(&igb->rx_rings[i].rx_lock);
1840c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++)
1841c869993eSxy150489 		mutex_enter(&igb->tx_rings[i].tx_lock);
1842c869993eSxy150489 
1843c869993eSxy150489 	/*
1844b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Start the adapter
1845c869993eSxy150489 	 */
1846b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if ((igb->attach_progress & ATTACH_PROGRESS_INIT_ADAPTER) == 0) {
1847b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		if (igb_init_adapter(igb) != IGB_SUCCESS) {
18488bb4b220Sgl147354 			igb_fm_ereport(igb, DDI_FM_DEVICE_INVAL_STATE);
1849c869993eSxy150489 			goto start_failure;
1850c869993eSxy150489 		}
1851b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		igb->attach_progress |= ATTACH_PROGRESS_INIT_ADAPTER;
1852ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
1853c869993eSxy150489 
1854c869993eSxy150489 	/*
1855c869993eSxy150489 	 * Setup the rx/tx rings
1856c869993eSxy150489 	 */
1857c869993eSxy150489 	igb_setup_rings(igb);
1858c869993eSxy150489 
1859c869993eSxy150489 	/*
1860c869993eSxy150489 	 * Enable adapter interrupts
1861c869993eSxy150489 	 * The interrupts must be enabled after the driver state is START
1862c869993eSxy150489 	 */
186380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	igb->capab->enable_intr(igb);
1864c869993eSxy150489 
18658bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.cfg_handle) != DDI_FM_OK)
18668bb4b220Sgl147354 		goto start_failure;
18678bb4b220Sgl147354 
18688bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
18698bb4b220Sgl147354 		goto start_failure;
18708bb4b220Sgl147354 
18717e526273SRobert Mustacchi 	if (igb->hw.mac.type == e1000_i350)
187242cc51e0SRobert Mustacchi 		(void) e1000_set_eee_i350(&igb->hw, B_FALSE, B_FALSE);
187313485e69SGarrett D'Amore 	else if (igb->hw.mac.type == e1000_i354)
187442cc51e0SRobert Mustacchi 		(void) e1000_set_eee_i354(&igb->hw, B_FALSE, B_FALSE);
18757e526273SRobert Mustacchi 
1876c869993eSxy150489 	for (i = igb->num_tx_rings - 1; i >= 0; i--)
1877c869993eSxy150489 		mutex_exit(&igb->tx_rings[i].tx_lock);
1878c869993eSxy150489 	for (i = igb->num_rx_rings - 1; i >= 0; i--)
1879c869993eSxy150489 		mutex_exit(&igb->rx_rings[i].rx_lock);
1880c869993eSxy150489 
1881c869993eSxy150489 	return (IGB_SUCCESS);
1882c869993eSxy150489 
1883c869993eSxy150489 start_failure:
1884c869993eSxy150489 	for (i = igb->num_tx_rings - 1; i >= 0; i--)
1885c869993eSxy150489 		mutex_exit(&igb->tx_rings[i].tx_lock);
1886c869993eSxy150489 	for (i = igb->num_rx_rings - 1; i >= 0; i--)
1887c869993eSxy150489 		mutex_exit(&igb->rx_rings[i].rx_lock);
1888c869993eSxy150489 
18898bb4b220Sgl147354 	ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
18908bb4b220Sgl147354 
1891c869993eSxy150489 	return (IGB_FAILURE);
1892c869993eSxy150489 }
1893c869993eSxy150489 
1894c869993eSxy150489 /*
1895c869993eSxy150489  * igb_stop - Stop the driver/chipset
1896c869993eSxy150489  */
1897c869993eSxy150489 void
1898ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_stop(igb_t *igb, boolean_t free_buffer)
1899c869993eSxy150489 {
1900c869993eSxy150489 	int i;
1901c869993eSxy150489 
1902c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
1903c869993eSxy150489 
1904b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	igb->attach_progress &= ~ATTACH_PROGRESS_INIT_ADAPTER;
1905da14cebeSEric Cheng 
1906c869993eSxy150489 	/*
1907c869993eSxy150489 	 * Disable the adapter interrupts
1908c869993eSxy150489 	 */
1909c869993eSxy150489 	igb_disable_adapter_interrupts(igb);
1910c869993eSxy150489 
1911c869993eSxy150489 	/*
1912c869993eSxy150489 	 * Drain the pending tx packets
1913c869993eSxy150489 	 */
1914c869993eSxy150489 	(void) igb_tx_drain(igb);
1915c869993eSxy150489 
1916c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++)
1917c869993eSxy150489 		mutex_enter(&igb->rx_rings[i].rx_lock);
1918c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++)
1919c869993eSxy150489 		mutex_enter(&igb->tx_rings[i].tx_lock);
1920c869993eSxy150489 
1921c869993eSxy150489 	/*
1922b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Stop the adapter
1923c869993eSxy150489 	 */
1924b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	igb_stop_adapter(igb);
1925c869993eSxy150489 
1926c869993eSxy150489 	/*
1927c869993eSxy150489 	 * Clean the pending tx data/resources
1928c869993eSxy150489 	 */
1929c869993eSxy150489 	igb_tx_clean(igb);
1930c869993eSxy150489 
1931c869993eSxy150489 	for (i = igb->num_tx_rings - 1; i >= 0; i--)
1932c869993eSxy150489 		mutex_exit(&igb->tx_rings[i].tx_lock);
1933c869993eSxy150489 	for (i = igb->num_rx_rings - 1; i >= 0; i--)
1934c869993eSxy150489 		mutex_exit(&igb->rx_rings[i].rx_lock);
19358bb4b220Sgl147354 
19368bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
19378bb4b220Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
1938ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
1939ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (igb->link_state == LINK_STATE_UP) {
1940ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->link_state = LINK_STATE_UNKNOWN;
1941ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		mac_link_update(igb->mac_hdl, igb->link_state);
1942ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
1943ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
1944ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (free_buffer) {
1945ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		/*
1946ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		 * Release the DMA/memory resources of rx/tx rings
1947ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		 */
1948ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb_free_dma(igb);
1949ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb_free_rx_data(igb);
1950ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
1951c869993eSxy150489 }
1952c869993eSxy150489 
1953c869993eSxy150489 /*
1954c869993eSxy150489  * igb_alloc_rings - Allocate memory space for rx/tx rings
1955c869993eSxy150489  */
1956c869993eSxy150489 static int
1957c869993eSxy150489 igb_alloc_rings(igb_t *igb)
1958c869993eSxy150489 {
1959c869993eSxy150489 	/*
1960c869993eSxy150489 	 * Allocate memory space for rx rings
1961c869993eSxy150489 	 */
1962c869993eSxy150489 	igb->rx_rings = kmem_zalloc(
1963c869993eSxy150489 	    sizeof (igb_rx_ring_t) * igb->num_rx_rings,
1964c869993eSxy150489 	    KM_NOSLEEP);
1965c869993eSxy150489 
1966c869993eSxy150489 	if (igb->rx_rings == NULL) {
1967c869993eSxy150489 		return (IGB_FAILURE);
1968c869993eSxy150489 	}
1969c869993eSxy150489 
1970c869993eSxy150489 	/*
1971c869993eSxy150489 	 * Allocate memory space for tx rings
1972c869993eSxy150489 	 */
1973c869993eSxy150489 	igb->tx_rings = kmem_zalloc(
1974c869993eSxy150489 	    sizeof (igb_tx_ring_t) * igb->num_tx_rings,
1975c869993eSxy150489 	    KM_NOSLEEP);
1976c869993eSxy150489 
1977c869993eSxy150489 	if (igb->tx_rings == NULL) {
1978c869993eSxy150489 		kmem_free(igb->rx_rings,
1979c869993eSxy150489 		    sizeof (igb_rx_ring_t) * igb->num_rx_rings);
1980c869993eSxy150489 		igb->rx_rings = NULL;
1981c869993eSxy150489 		return (IGB_FAILURE);
1982c869993eSxy150489 	}
1983c869993eSxy150489 
1984da14cebeSEric Cheng 	/*
1985da14cebeSEric Cheng 	 * Allocate memory space for rx ring groups
1986da14cebeSEric Cheng 	 */
1987da14cebeSEric Cheng 	igb->rx_groups = kmem_zalloc(
1988da14cebeSEric Cheng 	    sizeof (igb_rx_group_t) * igb->num_rx_groups,
1989da14cebeSEric Cheng 	    KM_NOSLEEP);
1990da14cebeSEric Cheng 
1991da14cebeSEric Cheng 	if (igb->rx_groups == NULL) {
1992da14cebeSEric Cheng 		kmem_free(igb->rx_rings,
1993da14cebeSEric Cheng 		    sizeof (igb_rx_ring_t) * igb->num_rx_rings);
1994da14cebeSEric Cheng 		kmem_free(igb->tx_rings,
1995da14cebeSEric Cheng 		    sizeof (igb_tx_ring_t) * igb->num_tx_rings);
1996da14cebeSEric Cheng 		igb->rx_rings = NULL;
1997da14cebeSEric Cheng 		igb->tx_rings = NULL;
1998da14cebeSEric Cheng 		return (IGB_FAILURE);
1999da14cebeSEric Cheng 	}
2000da14cebeSEric Cheng 
2001c869993eSxy150489 	return (IGB_SUCCESS);
2002c869993eSxy150489 }
2003c869993eSxy150489 
2004c869993eSxy150489 /*
2005c869993eSxy150489  * igb_free_rings - Free the memory space of rx/tx rings.
2006c869993eSxy150489  */
2007c869993eSxy150489 static void
2008c869993eSxy150489 igb_free_rings(igb_t *igb)
2009c869993eSxy150489 {
2010c869993eSxy150489 	if (igb->rx_rings != NULL) {
2011c869993eSxy150489 		kmem_free(igb->rx_rings,
2012c869993eSxy150489 		    sizeof (igb_rx_ring_t) * igb->num_rx_rings);
2013c869993eSxy150489 		igb->rx_rings = NULL;
2014c869993eSxy150489 	}
2015c869993eSxy150489 
2016c869993eSxy150489 	if (igb->tx_rings != NULL) {
2017c869993eSxy150489 		kmem_free(igb->tx_rings,
2018c869993eSxy150489 		    sizeof (igb_tx_ring_t) * igb->num_tx_rings);
2019c869993eSxy150489 		igb->tx_rings = NULL;
2020c869993eSxy150489 	}
2021da14cebeSEric Cheng 
2022da14cebeSEric Cheng 	if (igb->rx_groups != NULL) {
2023da14cebeSEric Cheng 		kmem_free(igb->rx_groups,
2024da14cebeSEric Cheng 		    sizeof (igb_rx_group_t) * igb->num_rx_groups);
2025da14cebeSEric Cheng 		igb->rx_groups = NULL;
2026da14cebeSEric Cheng 	}
2027c869993eSxy150489 }
2028c869993eSxy150489 
2029ac7f5757Schenlu chen - Sun Microsystems - Beijing China static int
2030ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_alloc_rx_data(igb_t *igb)
2031ac7f5757Schenlu chen - Sun Microsystems - Beijing China {
2032ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_rx_ring_t *rx_ring;
2033ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	int i;
2034ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2035ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < igb->num_rx_rings; i++) {
2036ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_ring = &igb->rx_rings[i];
2037ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (igb_alloc_rx_ring_data(rx_ring) != IGB_SUCCESS)
2038ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			goto alloc_rx_rings_failure;
2039ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
2040ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	return (IGB_SUCCESS);
2041ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2042ac7f5757Schenlu chen - Sun Microsystems - Beijing China alloc_rx_rings_failure:
2043ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_free_rx_data(igb);
2044ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	return (IGB_FAILURE);
2045ac7f5757Schenlu chen - Sun Microsystems - Beijing China }
2046ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2047ac7f5757Schenlu chen - Sun Microsystems - Beijing China static void
2048ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_free_rx_data(igb_t *igb)
2049ac7f5757Schenlu chen - Sun Microsystems - Beijing China {
2050ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_rx_ring_t *rx_ring;
2051ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_rx_data_t *rx_data;
2052ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	int i;
2053ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2054ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < igb->num_rx_rings; i++) {
2055ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_ring = &igb->rx_rings[i];
2056ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2057ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		mutex_enter(&igb->rx_pending_lock);
2058ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data = rx_ring->rx_data;
2059ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2060ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (rx_data != NULL) {
2061ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			rx_data->flag |= IGB_RX_STOPPED;
2062ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2063ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			if (rx_data->rcb_pending == 0) {
2064ac7f5757Schenlu chen - Sun Microsystems - Beijing China 				igb_free_rx_ring_data(rx_data);
2065ac7f5757Schenlu chen - Sun Microsystems - Beijing China 				rx_ring->rx_data = NULL;
2066ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			}
2067ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		}
2068ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2069ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&igb->rx_pending_lock);
2070ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
2071ac7f5757Schenlu chen - Sun Microsystems - Beijing China }
2072ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
2073c869993eSxy150489 /*
2074c869993eSxy150489  * igb_setup_rings - Setup rx/tx rings
2075c869993eSxy150489  */
2076c869993eSxy150489 static void
2077c869993eSxy150489 igb_setup_rings(igb_t *igb)
2078c869993eSxy150489 {
2079c869993eSxy150489 	/*
2080c869993eSxy150489 	 * Setup the rx/tx rings, including the following:
2081c869993eSxy150489 	 *
2082c869993eSxy150489 	 * 1. Setup the descriptor ring and the control block buffers;
2083c869993eSxy150489 	 * 2. Initialize necessary registers for receive/transmit;
2084c869993eSxy150489 	 * 3. Initialize software pointers/parameters for receive/transmit;
2085c869993eSxy150489 	 */
2086c869993eSxy150489 	igb_setup_rx(igb);
2087c869993eSxy150489 
2088c869993eSxy150489 	igb_setup_tx(igb);
2089c869993eSxy150489 }
2090c869993eSxy150489 
2091c869993eSxy150489 static void
2092c869993eSxy150489 igb_setup_rx_ring(igb_rx_ring_t *rx_ring)
2093c869993eSxy150489 {
2094c869993eSxy150489 	igb_t *igb = rx_ring->igb;
2095ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_rx_data_t *rx_data = rx_ring->rx_data;
2096c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2097c869993eSxy150489 	rx_control_block_t *rcb;
2098c869993eSxy150489 	union e1000_adv_rx_desc	*rbd;
2099c869993eSxy150489 	uint32_t size;
2100c869993eSxy150489 	uint32_t buf_low;
2101c869993eSxy150489 	uint32_t buf_high;
2102b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	uint32_t rxdctl;
2103c869993eSxy150489 	int i;
2104c869993eSxy150489 
2105c869993eSxy150489 	ASSERT(mutex_owned(&rx_ring->rx_lock));
2106c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
2107c869993eSxy150489 
2108b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
2109b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Initialize descriptor ring with buffer addresses
2110b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
2111c869993eSxy150489 	for (i = 0; i < igb->rx_ring_size; i++) {
2112ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rcb = rx_data->work_list[i];
2113ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rbd = &rx_data->rbd_ring[i];
2114c869993eSxy150489 
2115c869993eSxy150489 		rbd->read.pkt_addr = rcb->rx_buf.dma_address;
2116c869993eSxy150489 		rbd->read.hdr_addr = NULL;
2117c869993eSxy150489 	}
2118c869993eSxy150489 
2119c869993eSxy150489 	/*
2120c869993eSxy150489 	 * Initialize the base address registers
2121c869993eSxy150489 	 */
2122ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	buf_low = (uint32_t)rx_data->rbd_area.dma_address;
2123ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32);
2124c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_RDBAH(rx_ring->index), buf_high);
2125c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_RDBAL(rx_ring->index), buf_low);
2126c869993eSxy150489 
2127c869993eSxy150489 	/*
2128b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Initialize the length register
2129c869993eSxy150489 	 */
2130ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	size = rx_data->ring_size * sizeof (union e1000_adv_rx_desc);
2131b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_RDLEN(rx_ring->index), size);
2132b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
2133b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
2134b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Initialize buffer size & descriptor type
2135b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
2136b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_SRRCTL(rx_ring->index),
2137b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	    ((igb->rx_buf_size >> E1000_SRRCTL_BSIZEPKT_SHIFT) |
2138b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	    E1000_SRRCTL_DESCTYPE_ADV_ONEBUF));
2139b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
2140b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
2141b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Setup the Receive Descriptor Control Register (RXDCTL)
2142b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
2143b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(rx_ring->index));
2144b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	rxdctl &= igb->capab->rxdctl_mask;
2145b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
2146b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	rxdctl |= 16;		/* pthresh */
2147b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	rxdctl |= 8 << 8;	/* hthresh */
2148b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	rxdctl |= 1 << 16;	/* wthresh */
2149b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_RXDCTL(rx_ring->index), rxdctl);
2150c869993eSxy150489 
2151ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	rx_data->rbd_next = 0;
2152c869993eSxy150489 }
2153c869993eSxy150489 
2154c869993eSxy150489 static void
2155c869993eSxy150489 igb_setup_rx(igb_t *igb)
2156c869993eSxy150489 {
2157c869993eSxy150489 	igb_rx_ring_t *rx_ring;
2158ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_rx_data_t *rx_data;
2159da14cebeSEric Cheng 	igb_rx_group_t *rx_group;
2160c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2161b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	uint32_t rctl, rxcsum;
2162da14cebeSEric Cheng 	uint32_t ring_per_group;
2163c869993eSxy150489 	int i;
2164c869993eSxy150489 
2165c869993eSxy150489 	/*
2166b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Setup the Receive Control Register (RCTL), and enable the
2167b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * receiver. The initial configuration is to: enable the receiver,
2168b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * accept broadcasts, discard bad packets, accept long packets,
2169b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * disable VLAN filter checking, and set receive buffer size to
2170b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * 2k.  For 82575, also set the receive descriptor minimum
2171b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * threshold size to 1/2 the ring.
2172c869993eSxy150489 	 */
217380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	rctl = E1000_READ_REG(hw, E1000_RCTL);
217480a11ad2Schenlu chen - Sun Microsystems - Beijing China 
217580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/*
2176b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Clear the field used for wakeup control.  This driver doesn't do
2177b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * wakeup but leave this here for completeness.
217880a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 */
217980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
21803f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
218180a11ad2Schenlu chen - Sun Microsystems - Beijing China 
2182b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	rctl |= (E1000_RCTL_EN |	/* Enable Receive Unit */
2183c869993eSxy150489 	    E1000_RCTL_BAM |		/* Accept Broadcast Packets */
2184b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	    E1000_RCTL_LPE |		/* Large Packet Enable */
2185b8d0a377Schenlu chen - Sun Microsystems - Beijing China 					/* Multicast filter offset */
2186c869993eSxy150489 	    (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
2187b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	    E1000_RCTL_RDMTS_HALF |	/* rx descriptor threshold */
2188b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	    E1000_RCTL_SECRC);		/* Strip Ethernet CRC */
2189c869993eSxy150489 
2190da14cebeSEric Cheng 	for (i = 0; i < igb->num_rx_groups; i++) {
2191da14cebeSEric Cheng 		rx_group = &igb->rx_groups[i];
2192da14cebeSEric Cheng 		rx_group->index = i;
2193da14cebeSEric Cheng 		rx_group->igb = igb;
2194da14cebeSEric Cheng 	}
2195da14cebeSEric Cheng 
2196c869993eSxy150489 	/*
2197b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Set up all rx descriptor rings - must be called before receive unit
2198b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * enabled.
2199d556530cSxy150489 	 */
2200da14cebeSEric Cheng 	ring_per_group = igb->num_rx_rings / igb->num_rx_groups;
2201d556530cSxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
2202d556530cSxy150489 		rx_ring = &igb->rx_rings[i];
2203d556530cSxy150489 		igb_setup_rx_ring(rx_ring);
2204da14cebeSEric Cheng 
2205da14cebeSEric Cheng 		/*
2206da14cebeSEric Cheng 		 * Map a ring to a group by assigning a group index
2207da14cebeSEric Cheng 		 */
2208da14cebeSEric Cheng 		rx_ring->group_index = i / ring_per_group;
2209d556530cSxy150489 	}
2210d556530cSxy150489 
2211d556530cSxy150489 	/*
2212c869993eSxy150489 	 * Setup the Rx Long Packet Max Length register
2213c869993eSxy150489 	 */
2214c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_RLPML, igb->max_frame_size);
2215c869993eSxy150489 
2216c869993eSxy150489 	/*
2217c869993eSxy150489 	 * Hardware checksum settings
2218c869993eSxy150489 	 */
2219c869993eSxy150489 	if (igb->rx_hcksum_enable) {
2220b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		rxcsum =
2221c869993eSxy150489 		    E1000_RXCSUM_TUOFL |	/* TCP/UDP checksum */
2222c869993eSxy150489 		    E1000_RXCSUM_IPOFL;		/* IP checksum */
2223c869993eSxy150489 
2224b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum);
2225c869993eSxy150489 	}
2226c869993eSxy150489 
2227c869993eSxy150489 	/*
2228da14cebeSEric Cheng 	 * Setup classify and RSS for multiple receive queues
2229da14cebeSEric Cheng 	 */
2230da14cebeSEric Cheng 	switch (igb->vmdq_mode) {
2231da14cebeSEric Cheng 	case E1000_VMDQ_OFF:
2232da14cebeSEric Cheng 		/*
2233da14cebeSEric Cheng 		 * One ring group, only RSS is needed when more than
2234da14cebeSEric Cheng 		 * one ring enabled.
2235c869993eSxy150489 		 */
2236c869993eSxy150489 		if (igb->num_rx_rings > 1)
2237c869993eSxy150489 			igb_setup_rss(igb);
2238da14cebeSEric Cheng 		break;
2239da14cebeSEric Cheng 	case E1000_VMDQ_MAC:
2240da14cebeSEric Cheng 		/*
2241da14cebeSEric Cheng 		 * Multiple groups, each group has one ring,
2242da14cebeSEric Cheng 		 * only the MAC classification is needed.
2243da14cebeSEric Cheng 		 */
2244da14cebeSEric Cheng 		igb_setup_mac_classify(igb);
2245da14cebeSEric Cheng 		break;
2246da14cebeSEric Cheng 	case E1000_VMDQ_MAC_RSS:
2247da14cebeSEric Cheng 		/*
2248da14cebeSEric Cheng 		 * Multiple groups and multiple rings, both
2249da14cebeSEric Cheng 		 * MAC classification and RSS are needed.
2250da14cebeSEric Cheng 		 */
2251da14cebeSEric Cheng 		igb_setup_mac_rss_classify(igb);
2252da14cebeSEric Cheng 		break;
2253da14cebeSEric Cheng 	}
2254b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
2255b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
2256b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Enable the receive unit - must be done after all
2257b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * the rx setup above.
2258b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
2259b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
2260b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
2261b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
2262b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Initialize all adapter ring head & tail pointers - must
2263b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * be done after receive unit is enabled
2264b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
2265b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < igb->num_rx_rings; i++) {
2266b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		rx_ring = &igb->rx_rings[i];
2267ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		rx_data = rx_ring->rx_data;
2268b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_RDH(i), 0);
2269ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_RDT(i), rx_data->ring_size - 1);
2270b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	}
2271b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
2272b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
2273b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * 82575 with manageability enabled needs a special flush to make
2274b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * sure the fifos start clean.
2275b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
2276b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if ((hw->mac.type == e1000_82575) &&
2277b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	    (E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN)) {
2278b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		e1000_rx_fifo_flush_82575(hw);
2279b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	}
2280c869993eSxy150489 }
2281c869993eSxy150489 
2282c869993eSxy150489 static void
2283c869993eSxy150489 igb_setup_tx_ring(igb_tx_ring_t *tx_ring)
2284c869993eSxy150489 {
2285c869993eSxy150489 	igb_t *igb = tx_ring->igb;
2286c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2287c869993eSxy150489 	uint32_t size;
2288c869993eSxy150489 	uint32_t buf_low;
2289c869993eSxy150489 	uint32_t buf_high;
2290c869993eSxy150489 	uint32_t reg_val;
2291c869993eSxy150489 
2292c869993eSxy150489 	ASSERT(mutex_owned(&tx_ring->tx_lock));
2293c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
2294c869993eSxy150489 
2295da14cebeSEric Cheng 
2296c869993eSxy150489 	/*
2297c869993eSxy150489 	 * Initialize the length register
2298c869993eSxy150489 	 */
2299c869993eSxy150489 	size = tx_ring->ring_size * sizeof (union e1000_adv_tx_desc);
2300c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_TDLEN(tx_ring->index), size);
2301c869993eSxy150489 
2302c869993eSxy150489 	/*
2303c869993eSxy150489 	 * Initialize the base address registers
2304c869993eSxy150489 	 */
2305c869993eSxy150489 	buf_low = (uint32_t)tx_ring->tbd_area.dma_address;
2306c869993eSxy150489 	buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32);
2307c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_TDBAL(tx_ring->index), buf_low);
2308c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_TDBAH(tx_ring->index), buf_high);
2309c869993eSxy150489 
2310c869993eSxy150489 	/*
2311c869993eSxy150489 	 * Setup head & tail pointers
2312c869993eSxy150489 	 */
2313c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_TDH(tx_ring->index), 0);
2314c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_TDT(tx_ring->index), 0);
2315c869993eSxy150489 
2316c869993eSxy150489 	/*
2317c869993eSxy150489 	 * Setup head write-back
2318c869993eSxy150489 	 */
2319c869993eSxy150489 	if (igb->tx_head_wb_enable) {
2320c869993eSxy150489 		/*
2321c869993eSxy150489 		 * The memory of the head write-back is allocated using
2322c869993eSxy150489 		 * the extra tbd beyond the tail of the tbd ring.
2323c869993eSxy150489 		 */
2324c869993eSxy150489 		tx_ring->tbd_head_wb = (uint32_t *)
2325c869993eSxy150489 		    ((uintptr_t)tx_ring->tbd_area.address + size);
2326fa25784cSxy150489 		*tx_ring->tbd_head_wb = 0;
2327c869993eSxy150489 
2328c869993eSxy150489 		buf_low = (uint32_t)
2329c869993eSxy150489 		    (tx_ring->tbd_area.dma_address + size);
2330c869993eSxy150489 		buf_high = (uint32_t)
2331c869993eSxy150489 		    ((tx_ring->tbd_area.dma_address + size) >> 32);
2332c869993eSxy150489 
2333c869993eSxy150489 		/* Set the head write-back enable bit */
2334c869993eSxy150489 		buf_low |= E1000_TX_HEAD_WB_ENABLE;
2335c869993eSxy150489 
2336c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_TDWBAL(tx_ring->index), buf_low);
2337c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_TDWBAH(tx_ring->index), buf_high);
2338c869993eSxy150489 
2339c869993eSxy150489 		/*
2340c869993eSxy150489 		 * Turn off relaxed ordering for head write back or it will
2341c869993eSxy150489 		 * cause problems with the tx recycling
2342c869993eSxy150489 		 */
2343c869993eSxy150489 		reg_val = E1000_READ_REG(hw,
2344c869993eSxy150489 		    E1000_DCA_TXCTRL(tx_ring->index));
2345c869993eSxy150489 		reg_val &= ~E1000_DCA_TXCTRL_TX_WB_RO_EN;
2346c869993eSxy150489 		E1000_WRITE_REG(hw,
2347c869993eSxy150489 		    E1000_DCA_TXCTRL(tx_ring->index), reg_val);
2348c869993eSxy150489 	} else {
2349c869993eSxy150489 		tx_ring->tbd_head_wb = NULL;
2350c869993eSxy150489 	}
2351c869993eSxy150489 
2352c869993eSxy150489 	tx_ring->tbd_head = 0;
2353c869993eSxy150489 	tx_ring->tbd_tail = 0;
2354c869993eSxy150489 	tx_ring->tbd_free = tx_ring->ring_size;
2355c869993eSxy150489 
2356ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (igb->tx_ring_init == B_TRUE) {
2357c869993eSxy150489 		tx_ring->tcb_head = 0;
2358c869993eSxy150489 		tx_ring->tcb_tail = 0;
2359c869993eSxy150489 		tx_ring->tcb_free = tx_ring->free_list_size;
2360c869993eSxy150489 	}
2361c869993eSxy150489 
2362c869993eSxy150489 	/*
236380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * Enable TXDCTL per queue
236480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 */
236580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	reg_val = E1000_READ_REG(hw, E1000_TXDCTL(tx_ring->index));
236680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	reg_val |= E1000_TXDCTL_QUEUE_ENABLE;
236780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_TXDCTL(tx_ring->index), reg_val);
2368d11274aaSPaul Guo 
2369d11274aaSPaul Guo 	/*
2370d11274aaSPaul Guo 	 * Initialize hardware checksum offload settings
2371d11274aaSPaul Guo 	 */
2372d11274aaSPaul Guo 	bzero(&tx_ring->tx_context, sizeof (tx_context_t));
2373c869993eSxy150489 }
2374c869993eSxy150489 
2375c869993eSxy150489 static void
2376c869993eSxy150489 igb_setup_tx(igb_t *igb)
2377c869993eSxy150489 {
2378c869993eSxy150489 	igb_tx_ring_t *tx_ring;
2379c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2380c869993eSxy150489 	uint32_t reg_val;
2381c869993eSxy150489 	int i;
2382c869993eSxy150489 
2383c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
2384c869993eSxy150489 		tx_ring = &igb->tx_rings[i];
2385c869993eSxy150489 		igb_setup_tx_ring(tx_ring);
2386c869993eSxy150489 	}
2387c869993eSxy150489 
2388c869993eSxy150489 	/*
2389c869993eSxy150489 	 * Setup the Transmit Control Register (TCTL)
2390c869993eSxy150489 	 */
239180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	reg_val = E1000_READ_REG(hw, E1000_TCTL);
239280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	reg_val &= ~E1000_TCTL_CT;
239380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	reg_val |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
239480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	    (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
2395c869993eSxy150489 
239680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* Enable transmits */
239780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	reg_val |= E1000_TCTL_EN;
2398c869993eSxy150489 
2399c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_TCTL, reg_val);
2400c869993eSxy150489 }
2401c869993eSxy150489 
2402c869993eSxy150489 /*
2403c869993eSxy150489  * igb_setup_rss - Setup receive-side scaling feature
2404c869993eSxy150489  */
2405c869993eSxy150489 static void
2406c869993eSxy150489 igb_setup_rss(igb_t *igb)
2407c869993eSxy150489 {
2408c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2409c869993eSxy150489 	uint32_t i, mrqc, rxcsum;
241080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	int shift = 0;
2411c869993eSxy150489 	uint32_t random;
2412c869993eSxy150489 	union e1000_reta {
2413c869993eSxy150489 		uint32_t	dword;
2414c869993eSxy150489 		uint8_t		bytes[4];
2415c869993eSxy150489 	} reta;
2416c869993eSxy150489 
2417c869993eSxy150489 	/* Setup the Redirection Table */
241880a11ad2Schenlu chen - Sun Microsystems - Beijing China 	if (hw->mac.type == e1000_82576) {
24193f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		shift = 3;
242080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	} else if (hw->mac.type == e1000_82575) {
2421c869993eSxy150489 		shift = 6;
242280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	}
2423c869993eSxy150489 	for (i = 0; i < (32 * 4); i++) {
2424c869993eSxy150489 		reta.bytes[i & 3] = (i % igb->num_rx_rings) << shift;
2425c869993eSxy150489 		if ((i & 3) == 3) {
2426c869993eSxy150489 			E1000_WRITE_REG(hw,
2427c869993eSxy150489 			    (E1000_RETA(0) + (i & ~3)), reta.dword);
2428c869993eSxy150489 		}
2429c869993eSxy150489 	}
2430c869993eSxy150489 
2431c869993eSxy150489 	/* Fill out hash function seeds */
2432c869993eSxy150489 	for (i = 0; i < 10; i++) {
2433c869993eSxy150489 		(void) random_get_pseudo_bytes((uint8_t *)&random,
2434c869993eSxy150489 		    sizeof (uint32_t));
2435c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_RSSRK(i), random);
2436c869993eSxy150489 	}
2437c869993eSxy150489 
2438c869993eSxy150489 	/* Setup the Multiple Receive Queue Control register */
2439c869993eSxy150489 	mrqc = E1000_MRQC_ENABLE_RSS_4Q;
2440c869993eSxy150489 	mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 |
2441c869993eSxy150489 	    E1000_MRQC_RSS_FIELD_IPV4_TCP |
2442c869993eSxy150489 	    E1000_MRQC_RSS_FIELD_IPV6 |
2443c869993eSxy150489 	    E1000_MRQC_RSS_FIELD_IPV6_TCP |
2444c869993eSxy150489 	    E1000_MRQC_RSS_FIELD_IPV4_UDP |
2445c869993eSxy150489 	    E1000_MRQC_RSS_FIELD_IPV6_UDP |
2446c869993eSxy150489 	    E1000_MRQC_RSS_FIELD_IPV6_UDP_EX |
2447c869993eSxy150489 	    E1000_MRQC_RSS_FIELD_IPV6_TCP_EX);
2448c869993eSxy150489 
2449c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_MRQC, mrqc);
2450c869993eSxy150489 
2451c869993eSxy150489 	/*
2452c869993eSxy150489 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
2453c869993eSxy150489 	 *
2454c869993eSxy150489 	 * The Packet Checksum is not ethernet CRC. It is another kind of
2455c869993eSxy150489 	 * checksum offloading provided by the 82575 chipset besides the IP
2456c869993eSxy150489 	 * header checksum offloading and the TCP/UDP checksum offloading.
2457c869993eSxy150489 	 * The Packet Checksum is by default computed over the entire packet
2458c869993eSxy150489 	 * from the first byte of the DA through the last byte of the CRC,
2459c869993eSxy150489 	 * including the Ethernet and IP headers.
2460c869993eSxy150489 	 *
2461c869993eSxy150489 	 * It is a hardware limitation that Packet Checksum is mutually
2462c869993eSxy150489 	 * exclusive with RSS.
2463c869993eSxy150489 	 */
2464c869993eSxy150489 	rxcsum = E1000_READ_REG(hw, E1000_RXCSUM);
2465c869993eSxy150489 	rxcsum |= E1000_RXCSUM_PCSD;
2466c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum);
2467c869993eSxy150489 }
2468c869993eSxy150489 
2469c869993eSxy150489 /*
2470da14cebeSEric Cheng  * igb_setup_mac_rss_classify - Setup MAC classification and rss
2471da14cebeSEric Cheng  */
2472da14cebeSEric Cheng static void
2473da14cebeSEric Cheng igb_setup_mac_rss_classify(igb_t *igb)
2474da14cebeSEric Cheng {
2475da14cebeSEric Cheng 	struct e1000_hw *hw = &igb->hw;
2476da14cebeSEric Cheng 	uint32_t i, mrqc, vmdctl, rxcsum;
2477da14cebeSEric Cheng 	uint32_t ring_per_group;
2478da14cebeSEric Cheng 	int shift_group0, shift_group1;
2479da14cebeSEric Cheng 	uint32_t random;
2480da14cebeSEric Cheng 	union e1000_reta {
2481da14cebeSEric Cheng 		uint32_t	dword;
2482da14cebeSEric Cheng 		uint8_t		bytes[4];
2483da14cebeSEric Cheng 	} reta;
2484da14cebeSEric Cheng 
2485da14cebeSEric Cheng 	ring_per_group = igb->num_rx_rings / igb->num_rx_groups;
2486da14cebeSEric Cheng 
2487da14cebeSEric Cheng 	/* Setup the Redirection Table, it is shared between two groups */
2488da14cebeSEric Cheng 	shift_group0 = 2;
2489da14cebeSEric Cheng 	shift_group1 = 6;
2490da14cebeSEric Cheng 	for (i = 0; i < (32 * 4); i++) {
2491da14cebeSEric Cheng 		reta.bytes[i & 3] = ((i % ring_per_group) << shift_group0) |
2492da14cebeSEric Cheng 		    ((ring_per_group + (i % ring_per_group)) << shift_group1);
2493da14cebeSEric Cheng 		if ((i & 3) == 3) {
2494da14cebeSEric Cheng 			E1000_WRITE_REG(hw,
2495da14cebeSEric Cheng 			    (E1000_RETA(0) + (i & ~3)), reta.dword);
2496da14cebeSEric Cheng 		}
2497da14cebeSEric Cheng 	}
2498da14cebeSEric Cheng 
2499da14cebeSEric Cheng 	/* Fill out hash function seeds */
2500da14cebeSEric Cheng 	for (i = 0; i < 10; i++) {
2501da14cebeSEric Cheng 		(void) random_get_pseudo_bytes((uint8_t *)&random,
2502da14cebeSEric Cheng 		    sizeof (uint32_t));
2503da14cebeSEric Cheng 		E1000_WRITE_REG(hw, E1000_RSSRK(i), random);
2504da14cebeSEric Cheng 	}
2505da14cebeSEric Cheng 
2506da14cebeSEric Cheng 	/*
2507da14cebeSEric Cheng 	 * Setup the Multiple Receive Queue Control register,
2508da14cebeSEric Cheng 	 * enable VMDq based on packet destination MAC address and RSS.
2509da14cebeSEric Cheng 	 */
2510da14cebeSEric Cheng 	mrqc = E1000_MRQC_ENABLE_VMDQ_MAC_RSS_GROUP;
2511da14cebeSEric Cheng 	mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 |
2512da14cebeSEric Cheng 	    E1000_MRQC_RSS_FIELD_IPV4_TCP |
2513da14cebeSEric Cheng 	    E1000_MRQC_RSS_FIELD_IPV6 |
2514da14cebeSEric Cheng 	    E1000_MRQC_RSS_FIELD_IPV6_TCP |
2515da14cebeSEric Cheng 	    E1000_MRQC_RSS_FIELD_IPV4_UDP |
2516da14cebeSEric Cheng 	    E1000_MRQC_RSS_FIELD_IPV6_UDP |
2517da14cebeSEric Cheng 	    E1000_MRQC_RSS_FIELD_IPV6_UDP_EX |
2518da14cebeSEric Cheng 	    E1000_MRQC_RSS_FIELD_IPV6_TCP_EX);
2519da14cebeSEric Cheng 
2520da14cebeSEric Cheng 	E1000_WRITE_REG(hw, E1000_MRQC, mrqc);
2521da14cebeSEric Cheng 
2522da14cebeSEric Cheng 
2523da14cebeSEric Cheng 	/* Define the default group and default queues */
2524da14cebeSEric Cheng 	vmdctl = E1000_VMDQ_MAC_GROUP_DEFAULT_QUEUE;
252580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_VT_CTL, vmdctl);
2526da14cebeSEric Cheng 
2527da14cebeSEric Cheng 	/*
2528da14cebeSEric Cheng 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
2529da14cebeSEric Cheng 	 *
2530da14cebeSEric Cheng 	 * The Packet Checksum is not ethernet CRC. It is another kind of
2531da14cebeSEric Cheng 	 * checksum offloading provided by the 82575 chipset besides the IP
2532da14cebeSEric Cheng 	 * header checksum offloading and the TCP/UDP checksum offloading.
2533da14cebeSEric Cheng 	 * The Packet Checksum is by default computed over the entire packet
2534da14cebeSEric Cheng 	 * from the first byte of the DA through the last byte of the CRC,
2535da14cebeSEric Cheng 	 * including the Ethernet and IP headers.
2536da14cebeSEric Cheng 	 *
2537da14cebeSEric Cheng 	 * It is a hardware limitation that Packet Checksum is mutually
2538da14cebeSEric Cheng 	 * exclusive with RSS.
2539da14cebeSEric Cheng 	 */
2540da14cebeSEric Cheng 	rxcsum = E1000_READ_REG(hw, E1000_RXCSUM);
2541da14cebeSEric Cheng 	rxcsum |= E1000_RXCSUM_PCSD;
2542da14cebeSEric Cheng 	E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum);
2543da14cebeSEric Cheng }
2544da14cebeSEric Cheng 
2545da14cebeSEric Cheng /*
2546da14cebeSEric Cheng  * igb_setup_mac_classify - Setup MAC classification feature
2547da14cebeSEric Cheng  */
2548da14cebeSEric Cheng static void
2549da14cebeSEric Cheng igb_setup_mac_classify(igb_t *igb)
2550da14cebeSEric Cheng {
2551da14cebeSEric Cheng 	struct e1000_hw *hw = &igb->hw;
2552da14cebeSEric Cheng 	uint32_t mrqc, rxcsum;
2553da14cebeSEric Cheng 
2554da14cebeSEric Cheng 	/*
2555da14cebeSEric Cheng 	 * Setup the Multiple Receive Queue Control register,
2556da14cebeSEric Cheng 	 * enable VMDq based on packet destination MAC address.
2557da14cebeSEric Cheng 	 */
2558da14cebeSEric Cheng 	mrqc = E1000_MRQC_ENABLE_VMDQ_MAC_GROUP;
2559da14cebeSEric Cheng 	E1000_WRITE_REG(hw, E1000_MRQC, mrqc);
2560da14cebeSEric Cheng 
2561da14cebeSEric Cheng 	/*
2562da14cebeSEric Cheng 	 * Disable Packet Checksum to enable RSS for multiple receive queues.
2563da14cebeSEric Cheng 	 *
2564da14cebeSEric Cheng 	 * The Packet Checksum is not ethernet CRC. It is another kind of
2565da14cebeSEric Cheng 	 * checksum offloading provided by the 82575 chipset besides the IP
2566da14cebeSEric Cheng 	 * header checksum offloading and the TCP/UDP checksum offloading.
2567da14cebeSEric Cheng 	 * The Packet Checksum is by default computed over the entire packet
2568da14cebeSEric Cheng 	 * from the first byte of the DA through the last byte of the CRC,
2569da14cebeSEric Cheng 	 * including the Ethernet and IP headers.
2570da14cebeSEric Cheng 	 *
2571da14cebeSEric Cheng 	 * It is a hardware limitation that Packet Checksum is mutually
2572da14cebeSEric Cheng 	 * exclusive with RSS.
2573da14cebeSEric Cheng 	 */
2574da14cebeSEric Cheng 	rxcsum = E1000_READ_REG(hw, E1000_RXCSUM);
2575da14cebeSEric Cheng 	rxcsum |= E1000_RXCSUM_PCSD;
2576da14cebeSEric Cheng 	E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum);
2577da14cebeSEric Cheng 
2578da14cebeSEric Cheng }
2579da14cebeSEric Cheng 
2580da14cebeSEric Cheng /*
2581c869993eSxy150489  * igb_init_unicst - Initialize the unicast addresses
2582c869993eSxy150489  */
2583c869993eSxy150489 static void
2584c869993eSxy150489 igb_init_unicst(igb_t *igb)
2585c869993eSxy150489 {
2586c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2587c869993eSxy150489 	int slot;
2588c869993eSxy150489 
2589c869993eSxy150489 	/*
2590c869993eSxy150489 	 * Here we should consider two situations:
2591c869993eSxy150489 	 *
2592c869993eSxy150489 	 * 1. Chipset is initialized the first time
2593c869993eSxy150489 	 *    Initialize the multiple unicast addresses, and
2594da14cebeSEric Cheng 	 *    save the default MAC address.
2595c869993eSxy150489 	 *
2596c869993eSxy150489 	 * 2. Chipset is reset
2597c869993eSxy150489 	 *    Recover the multiple unicast addresses from the
2598c869993eSxy150489 	 *    software data structure to the RAR registers.
2599c869993eSxy150489 	 */
2600da14cebeSEric Cheng 
2601da14cebeSEric Cheng 	/*
2602da14cebeSEric Cheng 	 * Clear the default MAC address in the RAR0 rgister,
2603da14cebeSEric Cheng 	 * which is loaded from EEPROM when system boot or chipreset,
2604da14cebeSEric Cheng 	 * this will cause the conficts with add_mac/rem_mac entry
2605da14cebeSEric Cheng 	 * points when VMDq is enabled. For this reason, the RAR0
2606da14cebeSEric Cheng 	 * must be cleared for both cases mentioned above.
2607da14cebeSEric Cheng 	 */
2608da14cebeSEric Cheng 	e1000_rar_clear(hw, 0);
2609da14cebeSEric Cheng 
2610c869993eSxy150489 	if (!igb->unicst_init) {
2611da14cebeSEric Cheng 
2612c869993eSxy150489 		/* Initialize the multiple unicast addresses */
2613c869993eSxy150489 		igb->unicst_total = MAX_NUM_UNICAST_ADDRESSES;
2614da14cebeSEric Cheng 		igb->unicst_avail = igb->unicst_total;
2615c869993eSxy150489 
2616da14cebeSEric Cheng 		for (slot = 0; slot < igb->unicst_total; slot++)
2617c869993eSxy150489 			igb->unicst_addr[slot].mac.set = 0;
2618c869993eSxy150489 
2619c869993eSxy150489 		igb->unicst_init = B_TRUE;
2620c869993eSxy150489 	} else {
2621c869993eSxy150489 		/* Re-configure the RAR registers */
2622da14cebeSEric Cheng 		for (slot = 0; slot < igb->unicst_total; slot++) {
2623c124a83eSRobert Mustacchi 			(void) e1000_rar_set_vmdq(hw,
2624c124a83eSRobert Mustacchi 			    igb->unicst_addr[slot].mac.addr,
2625da14cebeSEric Cheng 			    slot, igb->vmdq_mode,
2626da14cebeSEric Cheng 			    igb->unicst_addr[slot].mac.group_index);
2627da14cebeSEric Cheng 		}
2628c869993eSxy150489 	}
2629c869993eSxy150489 }
2630c869993eSxy150489 
2631c869993eSxy150489 /*
2632da14cebeSEric Cheng  * igb_unicst_find - Find the slot for the specified unicast address
2633da14cebeSEric Cheng  */
2634da14cebeSEric Cheng int
2635da14cebeSEric Cheng igb_unicst_find(igb_t *igb, const uint8_t *mac_addr)
2636da14cebeSEric Cheng {
2637da14cebeSEric Cheng 	int slot;
2638da14cebeSEric Cheng 
2639da14cebeSEric Cheng 	ASSERT(mutex_owned(&igb->gen_lock));
2640da14cebeSEric Cheng 
2641da14cebeSEric Cheng 	for (slot = 0; slot < igb->unicst_total; slot++) {
2642da14cebeSEric Cheng 		if (bcmp(igb->unicst_addr[slot].mac.addr,
2643da14cebeSEric Cheng 		    mac_addr, ETHERADDRL) == 0)
2644da14cebeSEric Cheng 			return (slot);
2645da14cebeSEric Cheng 	}
2646da14cebeSEric Cheng 
2647da14cebeSEric Cheng 	return (-1);
2648da14cebeSEric Cheng }
2649da14cebeSEric Cheng 
2650da14cebeSEric Cheng /*
2651c869993eSxy150489  * igb_unicst_set - Set the unicast address to the specified slot
2652c869993eSxy150489  */
2653c869993eSxy150489 int
2654c869993eSxy150489 igb_unicst_set(igb_t *igb, const uint8_t *mac_addr,
2655da14cebeSEric Cheng     int slot)
2656c869993eSxy150489 {
2657c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2658c869993eSxy150489 
2659c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
2660c869993eSxy150489 
2661c869993eSxy150489 	/*
2662c869993eSxy150489 	 * Save the unicast address in the software data structure
2663c869993eSxy150489 	 */
2664c869993eSxy150489 	bcopy(mac_addr, igb->unicst_addr[slot].mac.addr, ETHERADDRL);
2665c869993eSxy150489 
2666c869993eSxy150489 	/*
2667c869993eSxy150489 	 * Set the unicast address to the RAR register
2668c869993eSxy150489 	 */
2669c124a83eSRobert Mustacchi 	(void) e1000_rar_set(hw, (uint8_t *)mac_addr, slot);
2670c869993eSxy150489 
26718bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
26728bb4b220Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
26738bb4b220Sgl147354 		return (EIO);
26748bb4b220Sgl147354 	}
26758bb4b220Sgl147354 
2676c869993eSxy150489 	return (0);
2677c869993eSxy150489 }
2678c869993eSxy150489 
2679c869993eSxy150489 /*
2680c869993eSxy150489  * igb_multicst_add - Add a multicst address
2681c869993eSxy150489  */
2682c869993eSxy150489 int
2683c869993eSxy150489 igb_multicst_add(igb_t *igb, const uint8_t *multiaddr)
2684c869993eSxy150489 {
26856ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	struct ether_addr *new_table;
26866ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	size_t new_len;
26876ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	size_t old_len;
26886ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
2689c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
2690c869993eSxy150489 
2691c869993eSxy150489 	if ((multiaddr[0] & 01) == 0) {
2692*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR, "Illegal multicast address");
2693c869993eSxy150489 		return (EINVAL);
2694c869993eSxy150489 	}
2695c869993eSxy150489 
26966ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	if (igb->mcast_count >= igb->mcast_max_num) {
2697*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
2698*e5513923SYuri Pankov 		    "Adapter requested more than %d mcast addresses",
26996ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    igb->mcast_max_num);
2700c869993eSxy150489 		return (ENOENT);
2701c869993eSxy150489 	}
2702c869993eSxy150489 
27036ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	if (igb->mcast_count == igb->mcast_alloc_count) {
27046ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		old_len = igb->mcast_alloc_count *
27056ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    sizeof (struct ether_addr);
27066ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		new_len = (igb->mcast_alloc_count + MCAST_ALLOC_COUNT) *
27076ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    sizeof (struct ether_addr);
27086ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
27096ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		new_table = kmem_alloc(new_len, KM_NOSLEEP);
27106ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		if (new_table == NULL) {
2711*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
27126ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			    "Not enough memory to alloc mcast table");
27136ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			return (ENOMEM);
27146ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		}
27156ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
27166ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		if (igb->mcast_table != NULL) {
27176ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			bcopy(igb->mcast_table, new_table, old_len);
27186ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			kmem_free(igb->mcast_table, old_len);
27196ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		}
27206ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		igb->mcast_alloc_count += MCAST_ALLOC_COUNT;
27216ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		igb->mcast_table = new_table;
27226ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	}
27236ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
2724c869993eSxy150489 	bcopy(multiaddr,
2725c869993eSxy150489 	    &igb->mcast_table[igb->mcast_count], ETHERADDRL);
2726c869993eSxy150489 	igb->mcast_count++;
2727c869993eSxy150489 
2728c869993eSxy150489 	/*
2729c869993eSxy150489 	 * Update the multicast table in the hardware
2730c869993eSxy150489 	 */
2731c869993eSxy150489 	igb_setup_multicst(igb);
2732c869993eSxy150489 
27338bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
27348bb4b220Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
27358bb4b220Sgl147354 		return (EIO);
27368bb4b220Sgl147354 	}
27378bb4b220Sgl147354 
2738c869993eSxy150489 	return (0);
2739c869993eSxy150489 }
2740c869993eSxy150489 
2741c869993eSxy150489 /*
2742c869993eSxy150489  * igb_multicst_remove - Remove a multicst address
2743c869993eSxy150489  */
2744c869993eSxy150489 int
2745c869993eSxy150489 igb_multicst_remove(igb_t *igb, const uint8_t *multiaddr)
2746c869993eSxy150489 {
27476ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	struct ether_addr *new_table;
27486ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	size_t new_len;
27496ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	size_t old_len;
2750c869993eSxy150489 	int i;
2751c869993eSxy150489 
2752c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
2753c869993eSxy150489 
2754c869993eSxy150489 	for (i = 0; i < igb->mcast_count; i++) {
2755c869993eSxy150489 		if (bcmp(multiaddr, &igb->mcast_table[i],
2756c869993eSxy150489 		    ETHERADDRL) == 0) {
2757c869993eSxy150489 			for (i++; i < igb->mcast_count; i++) {
2758c869993eSxy150489 				igb->mcast_table[i - 1] =
2759c869993eSxy150489 				    igb->mcast_table[i];
2760c869993eSxy150489 			}
2761c869993eSxy150489 			igb->mcast_count--;
2762c869993eSxy150489 			break;
2763c869993eSxy150489 		}
2764c869993eSxy150489 	}
2765c869993eSxy150489 
27666ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	if ((igb->mcast_alloc_count - igb->mcast_count) >
27676ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	    MCAST_ALLOC_COUNT) {
27686ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		old_len = igb->mcast_alloc_count *
27696ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    sizeof (struct ether_addr);
27706ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		new_len = (igb->mcast_alloc_count - MCAST_ALLOC_COUNT) *
27716ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    sizeof (struct ether_addr);
27726ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
27736ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		new_table = kmem_alloc(new_len, KM_NOSLEEP);
27746ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		if (new_table != NULL) {
27756ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			bcopy(igb->mcast_table, new_table, new_len);
27766ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			kmem_free(igb->mcast_table, old_len);
27776ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			igb->mcast_alloc_count -= MCAST_ALLOC_COUNT;
27786ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			igb->mcast_table = new_table;
27796ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		}
27806ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	}
27816ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
2782c869993eSxy150489 	/*
2783c869993eSxy150489 	 * Update the multicast table in the hardware
2784c869993eSxy150489 	 */
2785c869993eSxy150489 	igb_setup_multicst(igb);
2786c869993eSxy150489 
27878bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
27888bb4b220Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
27898bb4b220Sgl147354 		return (EIO);
27908bb4b220Sgl147354 	}
27918bb4b220Sgl147354 
2792c869993eSxy150489 	return (0);
2793c869993eSxy150489 }
2794c869993eSxy150489 
27956ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic static void
27966ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic igb_release_multicast(igb_t *igb)
27976ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic {
27986ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	if (igb->mcast_table != NULL) {
27996ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		kmem_free(igb->mcast_table,
28006ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		    igb->mcast_alloc_count * sizeof (struct ether_addr));
28016ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		igb->mcast_table = NULL;
28026ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	}
28036ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic }
28046ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
2805c869993eSxy150489 /*
2806c869993eSxy150489  * igb_setup_multicast - setup multicast data structures
2807c869993eSxy150489  *
2808c869993eSxy150489  * This routine initializes all of the multicast related structures
2809c869993eSxy150489  * and save them in the hardware registers.
2810c869993eSxy150489  */
2811c869993eSxy150489 static void
2812c869993eSxy150489 igb_setup_multicst(igb_t *igb)
2813c869993eSxy150489 {
2814c869993eSxy150489 	uint8_t *mc_addr_list;
2815c869993eSxy150489 	uint32_t mc_addr_count;
2816c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2817c869993eSxy150489 
2818c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
28196ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	ASSERT(igb->mcast_count <= igb->mcast_max_num);
2820c869993eSxy150489 
2821c869993eSxy150489 	mc_addr_list = (uint8_t *)igb->mcast_table;
2822c869993eSxy150489 	mc_addr_count = igb->mcast_count;
2823c869993eSxy150489 
2824c869993eSxy150489 	/*
2825c869993eSxy150489 	 * Update the multicase addresses to the MTA registers
2826c869993eSxy150489 	 */
28277d46e7adSzhefeng xu - Sun Microsystems - Beijing China 	e1000_update_mc_addr_list(hw, mc_addr_list, mc_addr_count);
2828c869993eSxy150489 }
2829c869993eSxy150489 
2830c869993eSxy150489 /*
2831c869993eSxy150489  * igb_get_conf - Get driver configurations set in driver.conf
2832c869993eSxy150489  *
2833c869993eSxy150489  * This routine gets user-configured values out of the configuration
2834c869993eSxy150489  * file igb.conf.
2835c869993eSxy150489  *
2836c869993eSxy150489  * For each configurable value, there is a minimum, a maximum, and a
2837c869993eSxy150489  * default.
2838c869993eSxy150489  * If user does not configure a value, use the default.
2839c869993eSxy150489  * If user configures below the minimum, use the minumum.
2840c869993eSxy150489  * If user configures above the maximum, use the maxumum.
2841c869993eSxy150489  */
2842c869993eSxy150489 static void
2843c869993eSxy150489 igb_get_conf(igb_t *igb)
2844c869993eSxy150489 {
2845c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
2846c869993eSxy150489 	uint32_t default_mtu;
2847c869993eSxy150489 	uint32_t flow_control;
2848da14cebeSEric Cheng 	uint32_t ring_per_group;
2849da14cebeSEric Cheng 	int i;
2850c869993eSxy150489 
2851c869993eSxy150489 	/*
2852c869993eSxy150489 	 * igb driver supports the following user configurations:
2853c869993eSxy150489 	 *
2854c869993eSxy150489 	 * Link configurations:
2855c869993eSxy150489 	 *    adv_autoneg_cap
2856c869993eSxy150489 	 *    adv_1000fdx_cap
2857c869993eSxy150489 	 *    adv_100fdx_cap
2858c869993eSxy150489 	 *    adv_100hdx_cap
2859c869993eSxy150489 	 *    adv_10fdx_cap
2860c869993eSxy150489 	 *    adv_10hdx_cap
2861c869993eSxy150489 	 * Note: 1000hdx is not supported.
2862c869993eSxy150489 	 *
2863c869993eSxy150489 	 * Jumbo frame configuration:
2864c869993eSxy150489 	 *    default_mtu
2865c869993eSxy150489 	 *
2866c869993eSxy150489 	 * Ethernet flow control configuration:
2867c869993eSxy150489 	 *    flow_control
2868c869993eSxy150489 	 *
2869c869993eSxy150489 	 * Multiple rings configurations:
2870c869993eSxy150489 	 *    tx_queue_number
2871c869993eSxy150489 	 *    tx_ring_size
2872c869993eSxy150489 	 *    rx_queue_number
2873c869993eSxy150489 	 *    rx_ring_size
2874c869993eSxy150489 	 *
2875c869993eSxy150489 	 * Call igb_get_prop() to get the value for a specific
2876c869993eSxy150489 	 * configuration parameter.
2877c869993eSxy150489 	 */
2878c869993eSxy150489 
2879c869993eSxy150489 	/*
2880c869993eSxy150489 	 * Link configurations
2881c869993eSxy150489 	 */
2882c869993eSxy150489 	igb->param_adv_autoneg_cap = igb_get_prop(igb,
2883c869993eSxy150489 	    PROP_ADV_AUTONEG_CAP, 0, 1, 1);
2884c869993eSxy150489 	igb->param_adv_1000fdx_cap = igb_get_prop(igb,
2885c869993eSxy150489 	    PROP_ADV_1000FDX_CAP, 0, 1, 1);
2886c869993eSxy150489 	igb->param_adv_100fdx_cap = igb_get_prop(igb,
2887c869993eSxy150489 	    PROP_ADV_100FDX_CAP, 0, 1, 1);
2888c869993eSxy150489 	igb->param_adv_100hdx_cap = igb_get_prop(igb,
2889c869993eSxy150489 	    PROP_ADV_100HDX_CAP, 0, 1, 1);
2890c869993eSxy150489 	igb->param_adv_10fdx_cap = igb_get_prop(igb,
2891c869993eSxy150489 	    PROP_ADV_10FDX_CAP, 0, 1, 1);
2892c869993eSxy150489 	igb->param_adv_10hdx_cap = igb_get_prop(igb,
2893c869993eSxy150489 	    PROP_ADV_10HDX_CAP, 0, 1, 1);
2894c869993eSxy150489 
2895c869993eSxy150489 	/*
2896c869993eSxy150489 	 * Jumbo frame configurations
2897c869993eSxy150489 	 */
2898c869993eSxy150489 	default_mtu = igb_get_prop(igb, PROP_DEFAULT_MTU,
2899c869993eSxy150489 	    MIN_MTU, MAX_MTU, DEFAULT_MTU);
2900c869993eSxy150489 
2901c869993eSxy150489 	igb->max_frame_size = default_mtu +
2902c869993eSxy150489 	    sizeof (struct ether_vlan_header) + ETHERFCSL;
2903c869993eSxy150489 
2904c869993eSxy150489 	/*
2905c869993eSxy150489 	 * Ethernet flow control configuration
2906c869993eSxy150489 	 */
2907c869993eSxy150489 	flow_control = igb_get_prop(igb, PROP_FLOW_CONTROL,
2908c869993eSxy150489 	    e1000_fc_none, 4, e1000_fc_full);
2909c869993eSxy150489 	if (flow_control == 4)
2910c869993eSxy150489 		flow_control = e1000_fc_default;
2911c869993eSxy150489 
291280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	hw->fc.requested_mode = flow_control;
2913c869993eSxy150489 
2914c869993eSxy150489 	/*
2915c869993eSxy150489 	 * Multiple rings configurations
2916c869993eSxy150489 	 */
2917c869993eSxy150489 	igb->tx_ring_size = igb_get_prop(igb, PROP_TX_RING_SIZE,
2918c869993eSxy150489 	    MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE);
2919c869993eSxy150489 	igb->rx_ring_size = igb_get_prop(igb, PROP_RX_RING_SIZE,
2920c869993eSxy150489 	    MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE);
2921c869993eSxy150489 
29227d46e7adSzhefeng xu - Sun Microsystems - Beijing China 	igb->mr_enable = igb_get_prop(igb, PROP_MR_ENABLE, 0, 1, 0);
2923da14cebeSEric Cheng 	igb->num_rx_groups = igb_get_prop(igb, PROP_RX_GROUP_NUM,
2924da14cebeSEric Cheng 	    MIN_RX_GROUP_NUM, MAX_RX_GROUP_NUM, DEFAULT_RX_GROUP_NUM);
292580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/*
29263f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	 * Currently we do not support VMDq for 82576 and 82580.
292780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * If it is e1000_82576, set num_rx_groups to 1.
292880a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 */
29293f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	if (hw->mac.type >= e1000_82576)
293080a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->num_rx_groups = 1;
2931da14cebeSEric Cheng 
2932da14cebeSEric Cheng 	if (igb->mr_enable) {
293380a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->num_tx_rings = igb->capab->def_tx_que_num;
293480a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->num_rx_rings = igb->capab->def_rx_que_num;
2935da14cebeSEric Cheng 	} else {
2936da14cebeSEric Cheng 		igb->num_tx_rings = 1;
2937da14cebeSEric Cheng 		igb->num_rx_rings = 1;
2938da14cebeSEric Cheng 
2939da14cebeSEric Cheng 		if (igb->num_rx_groups > 1) {
2940*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
2941da14cebeSEric Cheng 			    "Invalid rx groups number. Please enable multiple "
2942da14cebeSEric Cheng 			    "rings first");
2943da14cebeSEric Cheng 			igb->num_rx_groups = 1;
2944da14cebeSEric Cheng 		}
2945da14cebeSEric Cheng 	}
2946da14cebeSEric Cheng 
2947da14cebeSEric Cheng 	/*
2948da14cebeSEric Cheng 	 * Check the divisibility between rx rings and rx groups.
2949da14cebeSEric Cheng 	 */
2950da14cebeSEric Cheng 	for (i = igb->num_rx_groups; i > 0; i--) {
2951da14cebeSEric Cheng 		if ((igb->num_rx_rings % i) == 0)
2952da14cebeSEric Cheng 			break;
2953da14cebeSEric Cheng 	}
2954da14cebeSEric Cheng 	if (i != igb->num_rx_groups) {
2955*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
2956da14cebeSEric Cheng 		    "Invalid rx groups number. Downgrade the rx group "
2957da14cebeSEric Cheng 		    "number to %d.", i);
2958da14cebeSEric Cheng 		igb->num_rx_groups = i;
2959da14cebeSEric Cheng 	}
2960da14cebeSEric Cheng 
2961da14cebeSEric Cheng 	/*
2962da14cebeSEric Cheng 	 * Get the ring number per group.
2963da14cebeSEric Cheng 	 */
2964da14cebeSEric Cheng 	ring_per_group = igb->num_rx_rings / igb->num_rx_groups;
2965da14cebeSEric Cheng 
2966da14cebeSEric Cheng 	if (igb->num_rx_groups == 1) {
2967da14cebeSEric Cheng 		/*
2968da14cebeSEric Cheng 		 * One rx ring group, the rx ring number is num_rx_rings.
2969da14cebeSEric Cheng 		 */
2970da14cebeSEric Cheng 		igb->vmdq_mode = E1000_VMDQ_OFF;
2971da14cebeSEric Cheng 	} else if (ring_per_group == 1) {
2972da14cebeSEric Cheng 		/*
2973da14cebeSEric Cheng 		 * Multiple rx groups, each group has one rx ring.
2974da14cebeSEric Cheng 		 */
2975da14cebeSEric Cheng 		igb->vmdq_mode = E1000_VMDQ_MAC;
2976da14cebeSEric Cheng 	} else {
2977da14cebeSEric Cheng 		/*
2978da14cebeSEric Cheng 		 * Multiple groups and multiple rings.
2979da14cebeSEric Cheng 		 */
2980da14cebeSEric Cheng 		igb->vmdq_mode = E1000_VMDQ_MAC_RSS;
2981da14cebeSEric Cheng 	}
2982da14cebeSEric Cheng 
2983c869993eSxy150489 	/*
2984c869993eSxy150489 	 * Tunable used to force an interrupt type. The only use is
2985c869993eSxy150489 	 * for testing of the lesser interrupt types.
2986c869993eSxy150489 	 * 0 = don't force interrupt type
2987c869993eSxy150489 	 * 1 = force interrupt type MSIX
2988c869993eSxy150489 	 * 2 = force interrupt type MSI
2989c869993eSxy150489 	 * 3 = force interrupt type Legacy
2990c869993eSxy150489 	 */
2991c869993eSxy150489 	igb->intr_force = igb_get_prop(igb, PROP_INTR_FORCE,
2992d556530cSxy150489 	    IGB_INTR_NONE, IGB_INTR_LEGACY, IGB_INTR_NONE);
2993c869993eSxy150489 
2994c869993eSxy150489 	igb->tx_hcksum_enable = igb_get_prop(igb, PROP_TX_HCKSUM_ENABLE,
2995c869993eSxy150489 	    0, 1, 1);
2996c869993eSxy150489 	igb->rx_hcksum_enable = igb_get_prop(igb, PROP_RX_HCKSUM_ENABLE,
2997c869993eSxy150489 	    0, 1, 1);
2998c869993eSxy150489 	igb->lso_enable = igb_get_prop(igb, PROP_LSO_ENABLE,
2999d11274aaSPaul Guo 	    0, 1, 1);
3000c869993eSxy150489 	igb->tx_head_wb_enable = igb_get_prop(igb, PROP_TX_HEAD_WB_ENABLE,
3001c869993eSxy150489 	    0, 1, 1);
3002c869993eSxy150489 
3003d11274aaSPaul Guo 	/*
3004d11274aaSPaul Guo 	 * igb LSO needs the tx h/w checksum support.
3005d11274aaSPaul Guo 	 * Here LSO will be disabled if tx h/w checksum has been disabled.
3006d11274aaSPaul Guo 	 */
3007d11274aaSPaul Guo 	if (igb->tx_hcksum_enable == B_FALSE)
3008d11274aaSPaul Guo 		igb->lso_enable = B_FALSE;
3009d11274aaSPaul Guo 
3010c869993eSxy150489 	igb->tx_copy_thresh = igb_get_prop(igb, PROP_TX_COPY_THRESHOLD,
3011c869993eSxy150489 	    MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD,
3012c869993eSxy150489 	    DEFAULT_TX_COPY_THRESHOLD);
3013c869993eSxy150489 	igb->tx_recycle_thresh = igb_get_prop(igb, PROP_TX_RECYCLE_THRESHOLD,
3014c869993eSxy150489 	    MIN_TX_RECYCLE_THRESHOLD, MAX_TX_RECYCLE_THRESHOLD,
3015c869993eSxy150489 	    DEFAULT_TX_RECYCLE_THRESHOLD);
3016c869993eSxy150489 	igb->tx_overload_thresh = igb_get_prop(igb, PROP_TX_OVERLOAD_THRESHOLD,
3017c869993eSxy150489 	    MIN_TX_OVERLOAD_THRESHOLD, MAX_TX_OVERLOAD_THRESHOLD,
3018c869993eSxy150489 	    DEFAULT_TX_OVERLOAD_THRESHOLD);
3019c869993eSxy150489 	igb->tx_resched_thresh = igb_get_prop(igb, PROP_TX_RESCHED_THRESHOLD,
302069b2d733SGuoqing Zhu 	    MIN_TX_RESCHED_THRESHOLD,
302169b2d733SGuoqing Zhu 	    MIN(igb->tx_ring_size, MAX_TX_RESCHED_THRESHOLD),
302269b2d733SGuoqing Zhu 	    igb->tx_ring_size > DEFAULT_TX_RESCHED_THRESHOLD ?
302369b2d733SGuoqing Zhu 	    DEFAULT_TX_RESCHED_THRESHOLD : DEFAULT_TX_RESCHED_THRESHOLD_LOW);
3024c869993eSxy150489 
3025c869993eSxy150489 	igb->rx_copy_thresh = igb_get_prop(igb, PROP_RX_COPY_THRESHOLD,
3026c869993eSxy150489 	    MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD,
3027c869993eSxy150489 	    DEFAULT_RX_COPY_THRESHOLD);
3028c869993eSxy150489 	igb->rx_limit_per_intr = igb_get_prop(igb, PROP_RX_LIMIT_PER_INTR,
3029c869993eSxy150489 	    MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR,
3030c869993eSxy150489 	    DEFAULT_RX_LIMIT_PER_INTR);
3031c869993eSxy150489 
3032c869993eSxy150489 	igb->intr_throttling[0] = igb_get_prop(igb, PROP_INTR_THROTTLING,
303380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	    igb->capab->min_intr_throttle,
303480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	    igb->capab->max_intr_throttle,
303580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	    igb->capab->def_intr_throttle);
30366ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 
30376ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	/*
30386ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	 * Max number of multicast addresses
30396ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	 */
30406ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	igb->mcast_max_num =
30416ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	    igb_get_prop(igb, PROP_MCAST_MAX_NUM,
30426ca163a1Svitezslav batrla - Sun Microsystems - Prague Czech Republic 	    MIN_MCAST_NUM, MAX_MCAST_NUM, DEFAULT_MCAST_NUM);
3043c869993eSxy150489 }
3044c869993eSxy150489 
3045c869993eSxy150489 /*
3046c869993eSxy150489  * igb_get_prop - Get a property value out of the configuration file igb.conf
3047c869993eSxy150489  *
3048c869993eSxy150489  * Caller provides the name of the property, a default value, a minimum
3049c869993eSxy150489  * value, and a maximum value.
3050c869993eSxy150489  *
3051c869993eSxy150489  * Return configured value of the property, with default, minimum and
3052c869993eSxy150489  * maximum properly applied.
3053c869993eSxy150489  */
3054c869993eSxy150489 static int
3055c869993eSxy150489 igb_get_prop(igb_t *igb,
3056c869993eSxy150489     char *propname,	/* name of the property */
3057c869993eSxy150489     int minval,		/* minimum acceptable value */
3058c869993eSxy150489     int maxval,		/* maximim acceptable value */
3059c869993eSxy150489     int defval)		/* default value */
3060c869993eSxy150489 {
3061c869993eSxy150489 	int value;
3062c869993eSxy150489 
3063c869993eSxy150489 	/*
3064c869993eSxy150489 	 * Call ddi_prop_get_int() to read the conf settings
3065c869993eSxy150489 	 */
3066c869993eSxy150489 	value = ddi_prop_get_int(DDI_DEV_T_ANY, igb->dip,
3067c869993eSxy150489 	    DDI_PROP_DONTPASS, propname, defval);
3068c869993eSxy150489 
3069c869993eSxy150489 	if (value > maxval)
3070c869993eSxy150489 		value = maxval;
3071c869993eSxy150489 
3072c869993eSxy150489 	if (value < minval)
3073c869993eSxy150489 		value = minval;
3074c869993eSxy150489 
3075c869993eSxy150489 	return (value);
3076c869993eSxy150489 }
3077c869993eSxy150489 
3078c869993eSxy150489 /*
3079c869993eSxy150489  * igb_setup_link - Using the link properties to setup the link
3080c869993eSxy150489  */
3081c869993eSxy150489 int
3082c869993eSxy150489 igb_setup_link(igb_t *igb, boolean_t setup_hw)
3083c869993eSxy150489 {
3084c869993eSxy150489 	struct e1000_mac_info *mac;
3085c869993eSxy150489 	struct e1000_phy_info *phy;
3086c869993eSxy150489 	boolean_t invalid;
3087c869993eSxy150489 
3088c869993eSxy150489 	mac = &igb->hw.mac;
3089c869993eSxy150489 	phy = &igb->hw.phy;
3090c869993eSxy150489 	invalid = B_FALSE;
3091c869993eSxy150489 
3092c869993eSxy150489 	if (igb->param_adv_autoneg_cap == 1) {
3093c869993eSxy150489 		mac->autoneg = B_TRUE;
3094c869993eSxy150489 		phy->autoneg_advertised = 0;
3095c869993eSxy150489 
3096c869993eSxy150489 		/*
3097c869993eSxy150489 		 * 1000hdx is not supported for autonegotiation
3098c869993eSxy150489 		 */
3099c869993eSxy150489 		if (igb->param_adv_1000fdx_cap == 1)
3100c869993eSxy150489 			phy->autoneg_advertised |= ADVERTISE_1000_FULL;
3101c869993eSxy150489 
3102c869993eSxy150489 		if (igb->param_adv_100fdx_cap == 1)
3103c869993eSxy150489 			phy->autoneg_advertised |= ADVERTISE_100_FULL;
3104c869993eSxy150489 
3105c869993eSxy150489 		if (igb->param_adv_100hdx_cap == 1)
3106c869993eSxy150489 			phy->autoneg_advertised |= ADVERTISE_100_HALF;
3107c869993eSxy150489 
3108c869993eSxy150489 		if (igb->param_adv_10fdx_cap == 1)
3109c869993eSxy150489 			phy->autoneg_advertised |= ADVERTISE_10_FULL;
3110c869993eSxy150489 
3111c869993eSxy150489 		if (igb->param_adv_10hdx_cap == 1)
3112c869993eSxy150489 			phy->autoneg_advertised |= ADVERTISE_10_HALF;
3113c869993eSxy150489 
3114c869993eSxy150489 		if (phy->autoneg_advertised == 0)
3115c869993eSxy150489 			invalid = B_TRUE;
3116c869993eSxy150489 	} else {
3117c869993eSxy150489 		mac->autoneg = B_FALSE;
3118c869993eSxy150489 
3119c869993eSxy150489 		/*
3120c869993eSxy150489 		 * 1000fdx and 1000hdx are not supported for forced link
3121c869993eSxy150489 		 */
3122c869993eSxy150489 		if (igb->param_adv_100fdx_cap == 1)
3123c869993eSxy150489 			mac->forced_speed_duplex = ADVERTISE_100_FULL;
3124c869993eSxy150489 		else if (igb->param_adv_100hdx_cap == 1)
3125c869993eSxy150489 			mac->forced_speed_duplex = ADVERTISE_100_HALF;
3126c869993eSxy150489 		else if (igb->param_adv_10fdx_cap == 1)
3127c869993eSxy150489 			mac->forced_speed_duplex = ADVERTISE_10_FULL;
3128c869993eSxy150489 		else if (igb->param_adv_10hdx_cap == 1)
3129c869993eSxy150489 			mac->forced_speed_duplex = ADVERTISE_10_HALF;
3130c869993eSxy150489 		else
3131c869993eSxy150489 			invalid = B_TRUE;
3132c869993eSxy150489 	}
3133c869993eSxy150489 
3134c869993eSxy150489 	if (invalid) {
3135*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO, "Invalid link settings. Setup "
3136*e5513923SYuri Pankov 		    "link to autonegotiation with full link capabilities.");
3137c869993eSxy150489 		mac->autoneg = B_TRUE;
3138c869993eSxy150489 		phy->autoneg_advertised = ADVERTISE_1000_FULL |
3139c869993eSxy150489 		    ADVERTISE_100_FULL | ADVERTISE_100_HALF |
3140c869993eSxy150489 		    ADVERTISE_10_FULL | ADVERTISE_10_HALF;
3141c869993eSxy150489 	}
3142c869993eSxy150489 
3143c869993eSxy150489 	if (setup_hw) {
3144c869993eSxy150489 		if (e1000_setup_link(&igb->hw) != E1000_SUCCESS)
3145c869993eSxy150489 			return (IGB_FAILURE);
3146c869993eSxy150489 	}
3147c869993eSxy150489 
3148c869993eSxy150489 	return (IGB_SUCCESS);
3149c869993eSxy150489 }
3150c869993eSxy150489 
3151c869993eSxy150489 
3152c869993eSxy150489 /*
3153c869993eSxy150489  * igb_is_link_up - Check if the link is up
3154c869993eSxy150489  */
3155c869993eSxy150489 static boolean_t
3156c869993eSxy150489 igb_is_link_up(igb_t *igb)
3157c869993eSxy150489 {
3158c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
3159b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	boolean_t link_up = B_FALSE;
3160c869993eSxy150489 
3161c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
3162c869993eSxy150489 
3163b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
3164b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * get_link_status is set in the interrupt handler on link-status-change
3165b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * or rx sequence error interrupt.  get_link_status will stay
3166b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * false until the e1000_check_for_link establishes link only
3167b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * for copper adapters.
3168b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
3169b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	switch (hw->phy.media_type) {
3170b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	case e1000_media_type_copper:
3171b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		if (hw->mac.get_link_status) {
3172c869993eSxy150489 			(void) e1000_check_for_link(hw);
3173b8d0a377Schenlu chen - Sun Microsystems - Beijing China 			link_up = !hw->mac.get_link_status;
3174c869993eSxy150489 		} else {
3175b8d0a377Schenlu chen - Sun Microsystems - Beijing China 			link_up = B_TRUE;
3176b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		}
3177b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		break;
3178b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	case e1000_media_type_fiber:
3179b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		(void) e1000_check_for_link(hw);
3180b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		link_up = (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU);
3181b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		break;
3182b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	case e1000_media_type_internal_serdes:
3183b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		(void) e1000_check_for_link(hw);
3184b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		link_up = hw->mac.serdes_has_link;
3185b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		break;
3186c869993eSxy150489 	}
3187c869993eSxy150489 
3188c869993eSxy150489 	return (link_up);
3189c869993eSxy150489 }
3190c869993eSxy150489 
3191c869993eSxy150489 /*
3192c869993eSxy150489  * igb_link_check - Link status processing
3193c869993eSxy150489  */
3194c869993eSxy150489 static boolean_t
3195c869993eSxy150489 igb_link_check(igb_t *igb)
3196c869993eSxy150489 {
3197c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
3198c869993eSxy150489 	uint16_t speed = 0, duplex = 0;
3199c869993eSxy150489 	boolean_t link_changed = B_FALSE;
3200c869993eSxy150489 
3201c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
3202c869993eSxy150489 
3203c869993eSxy150489 	if (igb_is_link_up(igb)) {
3204c869993eSxy150489 		/*
3205c869993eSxy150489 		 * The Link is up, check whether it was marked as down earlier
3206c869993eSxy150489 		 */
3207c869993eSxy150489 		if (igb->link_state != LINK_STATE_UP) {
3208c869993eSxy150489 			(void) e1000_get_speed_and_duplex(hw, &speed, &duplex);
3209c869993eSxy150489 			igb->link_speed = speed;
3210c869993eSxy150489 			igb->link_duplex = duplex;
3211c869993eSxy150489 			igb->link_state = LINK_STATE_UP;
3212c869993eSxy150489 			link_changed = B_TRUE;
3213cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 			if (!igb->link_complete)
3214cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 				igb_stop_link_timer(igb);
3215c869993eSxy150489 		}
3216cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	} else if (igb->link_complete) {
3217c869993eSxy150489 		if (igb->link_state != LINK_STATE_DOWN) {
3218c869993eSxy150489 			igb->link_speed = 0;
3219c869993eSxy150489 			igb->link_duplex = 0;
3220c869993eSxy150489 			igb->link_state = LINK_STATE_DOWN;
3221c869993eSxy150489 			link_changed = B_TRUE;
3222c869993eSxy150489 		}
3223c869993eSxy150489 	}
3224c869993eSxy150489 
3225cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
32268bb4b220Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
3227cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		return (B_FALSE);
3228cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	}
32298bb4b220Sgl147354 
3230c869993eSxy150489 	return (link_changed);
3231c869993eSxy150489 }
3232c869993eSxy150489 
3233c869993eSxy150489 /*
3234c869993eSxy150489  * igb_local_timer - driver watchdog function
3235c869993eSxy150489  *
32363f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  * This function will handle the hardware stall check, link status
32373f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  * check and other routines.
3238c869993eSxy150489  */
3239c869993eSxy150489 static void
3240c869993eSxy150489 igb_local_timer(void *arg)
3241c869993eSxy150489 {
3242c869993eSxy150489 	igb_t *igb = (igb_t *)arg;
3243b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	boolean_t link_changed = B_FALSE;
3244c869993eSxy150489 
3245cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (igb->igb_state & IGB_ERROR) {
3246cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		igb->reset_count++;
3247cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		if (igb_reset(igb) == IGB_SUCCESS)
3248cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 			ddi_fm_service_impact(igb->dip, DDI_SERVICE_RESTORED);
32493f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
3250cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		igb_restart_watchdog_timer(igb);
3251cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		return;
3252cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	}
3253cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3254cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (igb_stall_check(igb) || (igb->igb_state & IGB_STALL)) {
32558bb4b220Sgl147354 		igb_fm_ereport(igb, DDI_FM_DEVICE_STALL);
3256b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
3257c869993eSxy150489 		igb->reset_count++;
32588bb4b220Sgl147354 		if (igb_reset(igb) == IGB_SUCCESS)
3259cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 			ddi_fm_service_impact(igb->dip, DDI_SERVICE_RESTORED);
3260cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3261cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		igb_restart_watchdog_timer(igb);
3262cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		return;
3263c869993eSxy150489 	}
3264c869993eSxy150489 
3265c869993eSxy150489 	mutex_enter(&igb->gen_lock);
3266b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (!(igb->igb_state & IGB_SUSPENDED) && (igb->igb_state & IGB_STARTED))
3267c869993eSxy150489 		link_changed = igb_link_check(igb);
3268c869993eSxy150489 	mutex_exit(&igb->gen_lock);
3269c869993eSxy150489 
3270c869993eSxy150489 	if (link_changed)
3271c869993eSxy150489 		mac_link_update(igb->mac_hdl, igb->link_state);
3272c869993eSxy150489 
3273c869993eSxy150489 	igb_restart_watchdog_timer(igb);
3274c869993eSxy150489 }
3275c869993eSxy150489 
3276c869993eSxy150489 /*
3277cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * igb_link_timer - link setup timer function
3278cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  *
3279cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * It is called when the timer for link setup is expired, which indicates
3280cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * the completion of the link setup. The link state will not be updated
3281cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * until the link setup is completed. And the link state will not be sent
3282cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * to the upper layer through mac_link_update() in this function. It will
3283cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * be updated in the local timer routine or the interrupts service routine
3284cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * after the interface is started (plumbed).
3285cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  */
3286cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China static void
3287cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China igb_link_timer(void *arg)
3288cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China {
3289cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	igb_t *igb = (igb_t *)arg;
3290cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3291cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	mutex_enter(&igb->link_lock);
3292cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	igb->link_complete = B_TRUE;
3293cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	igb->link_tid = 0;
3294cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	mutex_exit(&igb->link_lock);
3295cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China }
3296cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China /*
3297c869993eSxy150489  * igb_stall_check - check for transmit stall
3298c869993eSxy150489  *
3299c869993eSxy150489  * This function checks if the adapter is stalled (in transmit).
3300c869993eSxy150489  *
3301c869993eSxy150489  * It is called each time the watchdog timeout is invoked.
3302c869993eSxy150489  * If the transmit descriptor reclaim continuously fails,
3303c869993eSxy150489  * the watchdog value will increment by 1. If the watchdog
3304c869993eSxy150489  * value exceeds the threshold, the igb is assumed to
3305c869993eSxy150489  * have stalled and need to be reset.
3306c869993eSxy150489  */
3307c869993eSxy150489 static boolean_t
3308c869993eSxy150489 igb_stall_check(igb_t *igb)
3309c869993eSxy150489 {
3310c869993eSxy150489 	igb_tx_ring_t *tx_ring;
33113f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	struct e1000_hw *hw = &igb->hw;
3312c869993eSxy150489 	boolean_t result;
3313c869993eSxy150489 	int i;
3314c869993eSxy150489 
3315c869993eSxy150489 	if (igb->link_state != LINK_STATE_UP)
3316c869993eSxy150489 		return (B_FALSE);
3317c869993eSxy150489 
3318c869993eSxy150489 	/*
3319c869993eSxy150489 	 * If any tx ring is stalled, we'll reset the chipset
3320c869993eSxy150489 	 */
3321c869993eSxy150489 	result = B_FALSE;
3322c869993eSxy150489 	for (i = 0; i < igb->num_tx_rings; i++) {
3323c869993eSxy150489 		tx_ring = &igb->tx_rings[i];
3324c869993eSxy150489 
3325c869993eSxy150489 		if (tx_ring->recycle_fail > 0)
3326c869993eSxy150489 			tx_ring->stall_watchdog++;
3327c869993eSxy150489 		else
3328c869993eSxy150489 			tx_ring->stall_watchdog = 0;
3329c869993eSxy150489 
3330c869993eSxy150489 		if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) {
3331c869993eSxy150489 			result = B_TRUE;
33323f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			if (hw->mac.type == e1000_82580) {
33333f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 				hw->dev_spec._82575.global_device_reset
33343f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 				    = B_TRUE;
33353f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			}
3336c869993eSxy150489 			break;
3337c869993eSxy150489 		}
3338c869993eSxy150489 	}
3339c869993eSxy150489 
3340c869993eSxy150489 	if (result) {
3341c869993eSxy150489 		tx_ring->stall_watchdog = 0;
3342c869993eSxy150489 		tx_ring->recycle_fail = 0;
3343c869993eSxy150489 	}
3344c869993eSxy150489 
3345c869993eSxy150489 	return (result);
3346c869993eSxy150489 }
3347c869993eSxy150489 
3348c869993eSxy150489 
3349c869993eSxy150489 /*
3350c869993eSxy150489  * is_valid_mac_addr - Check if the mac address is valid
3351c869993eSxy150489  */
3352c869993eSxy150489 static boolean_t
3353c869993eSxy150489 is_valid_mac_addr(uint8_t *mac_addr)
3354c869993eSxy150489 {
3355c869993eSxy150489 	const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 };
3356c869993eSxy150489 	const uint8_t addr_test2[6] =
3357c869993eSxy150489 	    { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
3358c869993eSxy150489 
3359c869993eSxy150489 	if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) ||
3360c869993eSxy150489 	    !(bcmp(addr_test2, mac_addr, ETHERADDRL)))
3361c869993eSxy150489 		return (B_FALSE);
3362c869993eSxy150489 
3363c869993eSxy150489 	return (B_TRUE);
3364c869993eSxy150489 }
3365c869993eSxy150489 
3366c869993eSxy150489 static boolean_t
3367c869993eSxy150489 igb_find_mac_address(igb_t *igb)
3368c869993eSxy150489 {
3369c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
3370c869993eSxy150489 #ifdef __sparc
3371c869993eSxy150489 	uchar_t *bytes;
3372c869993eSxy150489 	struct ether_addr sysaddr;
3373c869993eSxy150489 	uint_t nelts;
3374c869993eSxy150489 	int err;
3375c869993eSxy150489 	boolean_t found = B_FALSE;
3376c869993eSxy150489 
3377c869993eSxy150489 	/*
3378c869993eSxy150489 	 * The "vendor's factory-set address" may already have
3379c869993eSxy150489 	 * been extracted from the chip, but if the property
3380c869993eSxy150489 	 * "local-mac-address" is set we use that instead.
3381c869993eSxy150489 	 *
3382c869993eSxy150489 	 * We check whether it looks like an array of 6
3383c869993eSxy150489 	 * bytes (which it should, if OBP set it).  If we can't
3384c869993eSxy150489 	 * make sense of it this way, we'll ignore it.
3385c869993eSxy150489 	 */
3386c869993eSxy150489 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, igb->dip,
3387c869993eSxy150489 	    DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts);
3388c869993eSxy150489 	if (err == DDI_PROP_SUCCESS) {
3389c869993eSxy150489 		if (nelts == ETHERADDRL) {
3390c869993eSxy150489 			while (nelts--)
3391c869993eSxy150489 				hw->mac.addr[nelts] = bytes[nelts];
3392c869993eSxy150489 			found = B_TRUE;
3393c869993eSxy150489 		}
3394c869993eSxy150489 		ddi_prop_free(bytes);
3395c869993eSxy150489 	}
3396c869993eSxy150489 
3397c869993eSxy150489 	/*
3398c869993eSxy150489 	 * Look up the OBP property "local-mac-address?". If the user has set
3399c869993eSxy150489 	 * 'local-mac-address? = false', use "the system address" instead.
3400c869993eSxy150489 	 */
3401c869993eSxy150489 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, igb->dip, 0,
3402c869993eSxy150489 	    "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) {
3403c869993eSxy150489 		if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) {
3404c869993eSxy150489 			if (localetheraddr(NULL, &sysaddr) != 0) {
3405c869993eSxy150489 				bcopy(&sysaddr, hw->mac.addr, ETHERADDRL);
3406c869993eSxy150489 				found = B_TRUE;
3407c869993eSxy150489 			}
3408c869993eSxy150489 		}
3409c869993eSxy150489 		ddi_prop_free(bytes);
3410c869993eSxy150489 	}
3411c869993eSxy150489 
3412c869993eSxy150489 	/*
3413c869993eSxy150489 	 * Finally(!), if there's a valid "mac-address" property (created
3414c869993eSxy150489 	 * if we netbooted from this interface), we must use this instead
3415c869993eSxy150489 	 * of any of the above to ensure that the NFS/install server doesn't
3416c869993eSxy150489 	 * get confused by the address changing as Solaris takes over!
3417c869993eSxy150489 	 */
3418c869993eSxy150489 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, igb->dip,
3419c869993eSxy150489 	    DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts);
3420c869993eSxy150489 	if (err == DDI_PROP_SUCCESS) {
3421c869993eSxy150489 		if (nelts == ETHERADDRL) {
3422c869993eSxy150489 			while (nelts--)
3423c869993eSxy150489 				hw->mac.addr[nelts] = bytes[nelts];
3424c869993eSxy150489 			found = B_TRUE;
3425c869993eSxy150489 		}
3426c869993eSxy150489 		ddi_prop_free(bytes);
3427c869993eSxy150489 	}
3428c869993eSxy150489 
3429c869993eSxy150489 	if (found) {
3430c869993eSxy150489 		bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
3431c869993eSxy150489 		return (B_TRUE);
3432c869993eSxy150489 	}
3433c869993eSxy150489 #endif
3434c869993eSxy150489 
3435c869993eSxy150489 	/*
3436c869993eSxy150489 	 * Read the device MAC address from the EEPROM
3437c869993eSxy150489 	 */
3438c869993eSxy150489 	if (e1000_read_mac_addr(hw) != E1000_SUCCESS)
3439c869993eSxy150489 		return (B_FALSE);
3440c869993eSxy150489 
3441c869993eSxy150489 	return (B_TRUE);
3442c869993eSxy150489 }
3443c869993eSxy150489 
3444c869993eSxy150489 #pragma inline(igb_arm_watchdog_timer)
3445c869993eSxy150489 
3446c869993eSxy150489 static void
3447c869993eSxy150489 igb_arm_watchdog_timer(igb_t *igb)
3448c869993eSxy150489 {
3449c869993eSxy150489 	/*
3450c869993eSxy150489 	 * Fire a watchdog timer
3451c869993eSxy150489 	 */
3452c869993eSxy150489 	igb->watchdog_tid =
3453c869993eSxy150489 	    timeout(igb_local_timer,
3454c869993eSxy150489 	    (void *)igb, 1 * drv_usectohz(1000000));
3455c869993eSxy150489 
3456c869993eSxy150489 }
3457c869993eSxy150489 
3458c869993eSxy150489 /*
3459c869993eSxy150489  * igb_enable_watchdog_timer - Enable and start the driver watchdog timer
3460c869993eSxy150489  */
3461c869993eSxy150489 void
3462c869993eSxy150489 igb_enable_watchdog_timer(igb_t *igb)
3463c869993eSxy150489 {
3464c869993eSxy150489 	mutex_enter(&igb->watchdog_lock);
3465c869993eSxy150489 
3466c869993eSxy150489 	if (!igb->watchdog_enable) {
3467c869993eSxy150489 		igb->watchdog_enable = B_TRUE;
3468c869993eSxy150489 		igb->watchdog_start = B_TRUE;
3469c869993eSxy150489 		igb_arm_watchdog_timer(igb);
3470c869993eSxy150489 	}
3471c869993eSxy150489 
3472c869993eSxy150489 	mutex_exit(&igb->watchdog_lock);
3473c869993eSxy150489 
3474c869993eSxy150489 }
3475c869993eSxy150489 
3476c869993eSxy150489 /*
3477c869993eSxy150489  * igb_disable_watchdog_timer - Disable and stop the driver watchdog timer
3478c869993eSxy150489  */
3479c869993eSxy150489 void
3480c869993eSxy150489 igb_disable_watchdog_timer(igb_t *igb)
3481c869993eSxy150489 {
3482c869993eSxy150489 	timeout_id_t tid;
3483c869993eSxy150489 
3484c869993eSxy150489 	mutex_enter(&igb->watchdog_lock);
3485c869993eSxy150489 
3486c869993eSxy150489 	igb->watchdog_enable = B_FALSE;
3487c869993eSxy150489 	igb->watchdog_start = B_FALSE;
3488c869993eSxy150489 	tid = igb->watchdog_tid;
3489c869993eSxy150489 	igb->watchdog_tid = 0;
3490c869993eSxy150489 
3491c869993eSxy150489 	mutex_exit(&igb->watchdog_lock);
3492c869993eSxy150489 
3493c869993eSxy150489 	if (tid != 0)
3494c869993eSxy150489 		(void) untimeout(tid);
3495c869993eSxy150489 
3496c869993eSxy150489 }
3497c869993eSxy150489 
3498c869993eSxy150489 /*
3499c869993eSxy150489  * igb_start_watchdog_timer - Start the driver watchdog timer
3500c869993eSxy150489  */
3501c869993eSxy150489 static void
3502c869993eSxy150489 igb_start_watchdog_timer(igb_t *igb)
3503c869993eSxy150489 {
3504c869993eSxy150489 	mutex_enter(&igb->watchdog_lock);
3505c869993eSxy150489 
3506c869993eSxy150489 	if (igb->watchdog_enable) {
3507c869993eSxy150489 		if (!igb->watchdog_start) {
3508c869993eSxy150489 			igb->watchdog_start = B_TRUE;
3509c869993eSxy150489 			igb_arm_watchdog_timer(igb);
3510c869993eSxy150489 		}
3511c869993eSxy150489 	}
3512c869993eSxy150489 
3513c869993eSxy150489 	mutex_exit(&igb->watchdog_lock);
3514c869993eSxy150489 }
3515c869993eSxy150489 
3516c869993eSxy150489 /*
3517c869993eSxy150489  * igb_restart_watchdog_timer - Restart the driver watchdog timer
3518c869993eSxy150489  */
3519c869993eSxy150489 static void
3520c869993eSxy150489 igb_restart_watchdog_timer(igb_t *igb)
3521c869993eSxy150489 {
3522c869993eSxy150489 	mutex_enter(&igb->watchdog_lock);
3523c869993eSxy150489 
3524c869993eSxy150489 	if (igb->watchdog_start)
3525c869993eSxy150489 		igb_arm_watchdog_timer(igb);
3526c869993eSxy150489 
3527c869993eSxy150489 	mutex_exit(&igb->watchdog_lock);
3528c869993eSxy150489 }
3529c869993eSxy150489 
3530c869993eSxy150489 /*
3531c869993eSxy150489  * igb_stop_watchdog_timer - Stop the driver watchdog timer
3532c869993eSxy150489  */
3533c869993eSxy150489 static void
3534c869993eSxy150489 igb_stop_watchdog_timer(igb_t *igb)
3535c869993eSxy150489 {
3536c869993eSxy150489 	timeout_id_t tid;
3537c869993eSxy150489 
3538c869993eSxy150489 	mutex_enter(&igb->watchdog_lock);
3539c869993eSxy150489 
3540c869993eSxy150489 	igb->watchdog_start = B_FALSE;
3541c869993eSxy150489 	tid = igb->watchdog_tid;
3542c869993eSxy150489 	igb->watchdog_tid = 0;
3543c869993eSxy150489 
3544c869993eSxy150489 	mutex_exit(&igb->watchdog_lock);
3545c869993eSxy150489 
3546c869993eSxy150489 	if (tid != 0)
3547c869993eSxy150489 		(void) untimeout(tid);
3548c869993eSxy150489 }
3549c869993eSxy150489 
3550c869993eSxy150489 /*
3551cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * igb_start_link_timer - Start the link setup timer
3552cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  */
3553cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China static void
3554cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China igb_start_link_timer(struct igb *igb)
3555cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China {
3556cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	struct e1000_hw *hw = &igb->hw;
3557cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	clock_t link_timeout;
3558cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3559cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (hw->mac.autoneg)
3560cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		link_timeout = PHY_AUTO_NEG_LIMIT *
3561cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		    drv_usectohz(100000);
3562cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	else
3563cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		link_timeout = PHY_FORCE_LIMIT * drv_usectohz(100000);
3564cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3565cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	mutex_enter(&igb->link_lock);
3566cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (hw->phy.autoneg_wait_to_complete) {
3567cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		igb->link_complete = B_TRUE;
3568cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	} else {
3569cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		igb->link_complete = B_FALSE;
3570cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		igb->link_tid = timeout(igb_link_timer, (void *)igb,
3571cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		    link_timeout);
3572cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	}
3573cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	mutex_exit(&igb->link_lock);
3574cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China }
3575cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3576cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China /*
3577cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  * igb_stop_link_timer - Stop the link setup timer
3578cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China  */
3579cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China static void
3580cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China igb_stop_link_timer(struct igb *igb)
3581cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China {
3582cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	timeout_id_t tid;
3583cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3584cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	mutex_enter(&igb->link_lock);
3585cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	igb->link_complete = B_TRUE;
3586cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	tid = igb->link_tid;
3587cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	igb->link_tid = 0;
3588cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	mutex_exit(&igb->link_lock);
3589cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3590cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (tid != 0)
3591cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		(void) untimeout(tid);
3592cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China }
3593cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
3594cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China /*
3595c869993eSxy150489  * igb_disable_adapter_interrupts - Clear/disable all hardware interrupts
3596c869993eSxy150489  */
3597c869993eSxy150489 static void
3598c869993eSxy150489 igb_disable_adapter_interrupts(igb_t *igb)
3599c869993eSxy150489 {
3600c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
3601c869993eSxy150489 
3602c869993eSxy150489 	/*
3603c869993eSxy150489 	 * Set the IMC register to mask all the interrupts,
3604c869993eSxy150489 	 * including the tx interrupts.
3605c869993eSxy150489 	 */
360680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_IMC, ~0);
360780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_IAM, 0);
3608c869993eSxy150489 
3609c869993eSxy150489 	/*
3610c869993eSxy150489 	 * Additional disabling for MSI-X
3611c869993eSxy150489 	 */
3612c869993eSxy150489 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
361380a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_EIMC, ~0);
361480a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_EIAC, 0);
361580a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_EIAM, 0);
3616c869993eSxy150489 	}
3617c869993eSxy150489 
3618c869993eSxy150489 	E1000_WRITE_FLUSH(hw);
3619c869993eSxy150489 }
3620c869993eSxy150489 
3621c869993eSxy150489 /*
36223f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  * igb_enable_adapter_interrupts_82580 - Enable NIC interrupts for 82580
36233f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  */
36243f7e60a6Szhefeng xu - Sun Microsystems - Beijing China static void
36253f7e60a6Szhefeng xu - Sun Microsystems - Beijing China igb_enable_adapter_interrupts_82580(igb_t *igb)
36263f7e60a6Szhefeng xu - Sun Microsystems - Beijing China {
36273f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	struct e1000_hw *hw = &igb->hw;
36283f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
36293f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* Clear any pending interrupts */
36303f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	(void) E1000_READ_REG(hw, E1000_ICR);
36313f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	igb->ims_mask |= E1000_IMS_DRSTA;
36323f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
36333f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
36343f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
36353f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		/* Interrupt enabling for MSI-X */
36363f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
36373f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
36383f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		igb->ims_mask = (E1000_IMS_LSC | E1000_IMS_DRSTA);
36393f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_IMS, igb->ims_mask);
36403f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	} else { /* Interrupt enabling for MSI and legacy */
36413f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_IVAR0, E1000_IVAR_VALID);
36423f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		igb->ims_mask = IMS_ENABLE_MASK | E1000_IMS_TXQE;
36433f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		igb->ims_mask |= E1000_IMS_DRSTA;
36443f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_IMS, igb->ims_mask);
36453f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	}
36463f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
36473f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* Disable auto-mask for ICR interrupt bits */
36483f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_IAM, 0);
36493f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
36503f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	E1000_WRITE_FLUSH(hw);
36513f7e60a6Szhefeng xu - Sun Microsystems - Beijing China }
36523f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
36533f7e60a6Szhefeng xu - Sun Microsystems - Beijing China /*
365480a11ad2Schenlu chen - Sun Microsystems - Beijing China  * igb_enable_adapter_interrupts_82576 - Enable NIC interrupts for 82576
3655c869993eSxy150489  */
3656c869993eSxy150489 static void
365780a11ad2Schenlu chen - Sun Microsystems - Beijing China igb_enable_adapter_interrupts_82576(igb_t *igb)
365880a11ad2Schenlu chen - Sun Microsystems - Beijing China {
365980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	struct e1000_hw *hw = &igb->hw;
366080a11ad2Schenlu chen - Sun Microsystems - Beijing China 
3661b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/* Clear any pending interrupts */
3662b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	(void) E1000_READ_REG(hw, E1000_ICR);
3663b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
366480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
366580a11ad2Schenlu chen - Sun Microsystems - Beijing China 
366680a11ad2Schenlu chen - Sun Microsystems - Beijing China 		/* Interrupt enabling for MSI-X */
366780a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
366880a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
366980a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->ims_mask = E1000_IMS_LSC;
367080a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_LSC);
367180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	} else {
367280a11ad2Schenlu chen - Sun Microsystems - Beijing China 		/* Interrupt enabling for MSI and legacy */
367380a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_IVAR0, E1000_IVAR_VALID);
367480a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->ims_mask = IMS_ENABLE_MASK | E1000_IMS_TXQE;
367580a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG(hw, E1000_IMS,
367680a11ad2Schenlu chen - Sun Microsystems - Beijing China 		    (IMS_ENABLE_MASK | E1000_IMS_TXQE));
367780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	}
367880a11ad2Schenlu chen - Sun Microsystems - Beijing China 
367980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* Disable auto-mask for ICR interrupt bits */
368080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_IAM, 0);
368180a11ad2Schenlu chen - Sun Microsystems - Beijing China 
368280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_FLUSH(hw);
368380a11ad2Schenlu chen - Sun Microsystems - Beijing China }
368480a11ad2Schenlu chen - Sun Microsystems - Beijing China 
368580a11ad2Schenlu chen - Sun Microsystems - Beijing China /*
368680a11ad2Schenlu chen - Sun Microsystems - Beijing China  * igb_enable_adapter_interrupts_82575 - Enable NIC interrupts for 82575
368780a11ad2Schenlu chen - Sun Microsystems - Beijing China  */
368880a11ad2Schenlu chen - Sun Microsystems - Beijing China static void
368980a11ad2Schenlu chen - Sun Microsystems - Beijing China igb_enable_adapter_interrupts_82575(igb_t *igb)
3690c869993eSxy150489 {
3691c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
3692c869993eSxy150489 	uint32_t reg;
3693c869993eSxy150489 
3694b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/* Clear any pending interrupts */
3695b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	(void) E1000_READ_REG(hw, E1000_ICR);
3696b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
3697c869993eSxy150489 	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
3698c869993eSxy150489 		/* Interrupt enabling for MSI-X */
3699c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
3700c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
3701da14cebeSEric Cheng 		igb->ims_mask = E1000_IMS_LSC;
3702c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_LSC);
3703c869993eSxy150489 
3704c869993eSxy150489 		/* Enable MSI-X PBA support */
3705c869993eSxy150489 		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3706c869993eSxy150489 		reg |= E1000_CTRL_EXT_PBA_CLR;
3707c869993eSxy150489 
3708c869993eSxy150489 		/* Non-selective interrupt clear-on-read */
3709c869993eSxy150489 		reg |= E1000_CTRL_EXT_IRCA;	/* Called NSICR in the EAS */
3710c869993eSxy150489 
3711c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
3712c869993eSxy150489 	} else {
3713c869993eSxy150489 		/* Interrupt enabling for MSI and legacy */
3714da14cebeSEric Cheng 		igb->ims_mask = IMS_ENABLE_MASK;
3715c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK);
3716c869993eSxy150489 	}
3717c869993eSxy150489 
3718c869993eSxy150489 	E1000_WRITE_FLUSH(hw);
3719c869993eSxy150489 }
3720c869993eSxy150489 
3721c869993eSxy150489 /*
3722c869993eSxy150489  * Loopback Support
3723c869993eSxy150489  */
3724c869993eSxy150489 static lb_property_t lb_normal =
3725c869993eSxy150489 	{ normal,	"normal",	IGB_LB_NONE		};
3726c869993eSxy150489 static lb_property_t lb_external =
3727c869993eSxy150489 	{ external,	"External",	IGB_LB_EXTERNAL		};
3728c869993eSxy150489 static lb_property_t lb_phy =
3729c869993eSxy150489 	{ internal,	"PHY",		IGB_LB_INTERNAL_PHY	};
3730c869993eSxy150489 static lb_property_t lb_serdes =
3731c869993eSxy150489 	{ internal,	"SerDes",	IGB_LB_INTERNAL_SERDES	};
3732c869993eSxy150489 
3733c869993eSxy150489 enum ioc_reply
3734c869993eSxy150489 igb_loopback_ioctl(igb_t *igb, struct iocblk *iocp, mblk_t *mp)
3735c869993eSxy150489 {
3736c869993eSxy150489 	lb_info_sz_t *lbsp;
3737c869993eSxy150489 	lb_property_t *lbpp;
3738c869993eSxy150489 	struct e1000_hw *hw;
3739c869993eSxy150489 	uint32_t *lbmp;
3740c869993eSxy150489 	uint32_t size;
3741c869993eSxy150489 	uint32_t value;
3742c869993eSxy150489 
3743c869993eSxy150489 	hw = &igb->hw;
3744c869993eSxy150489 
3745c869993eSxy150489 	if (mp->b_cont == NULL)
3746c869993eSxy150489 		return (IOC_INVAL);
3747c869993eSxy150489 
3748c869993eSxy150489 	switch (iocp->ioc_cmd) {
3749c869993eSxy150489 	default:
3750c869993eSxy150489 		return (IOC_INVAL);
3751c869993eSxy150489 
3752c869993eSxy150489 	case LB_GET_INFO_SIZE:
3753c869993eSxy150489 		size = sizeof (lb_info_sz_t);
3754c869993eSxy150489 		if (iocp->ioc_count != size)
3755c869993eSxy150489 			return (IOC_INVAL);
3756c869993eSxy150489 
3757c869993eSxy150489 		value = sizeof (lb_normal);
3758c869993eSxy150489 		if (hw->phy.media_type == e1000_media_type_copper)
3759c869993eSxy150489 			value += sizeof (lb_phy);
3760c869993eSxy150489 		else
3761c869993eSxy150489 			value += sizeof (lb_serdes);
3762c869993eSxy150489 		value += sizeof (lb_external);
3763c869993eSxy150489 
3764c869993eSxy150489 		lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr;
3765c869993eSxy150489 		*lbsp = value;
3766c869993eSxy150489 		break;
3767c869993eSxy150489 
3768c869993eSxy150489 	case LB_GET_INFO:
3769c869993eSxy150489 		value = sizeof (lb_normal);
3770c869993eSxy150489 		if (hw->phy.media_type == e1000_media_type_copper)
3771c869993eSxy150489 			value += sizeof (lb_phy);
3772c869993eSxy150489 		else
3773c869993eSxy150489 			value += sizeof (lb_serdes);
3774c869993eSxy150489 		value += sizeof (lb_external);
3775c869993eSxy150489 
3776c869993eSxy150489 		size = value;
3777c869993eSxy150489 		if (iocp->ioc_count != size)
3778c869993eSxy150489 			return (IOC_INVAL);
3779c869993eSxy150489 
3780c869993eSxy150489 		value = 0;
3781c869993eSxy150489 		lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr;
3782c869993eSxy150489 
3783c869993eSxy150489 		lbpp[value++] = lb_normal;
3784c869993eSxy150489 		if (hw->phy.media_type == e1000_media_type_copper)
3785c869993eSxy150489 			lbpp[value++] = lb_phy;
3786c869993eSxy150489 		else
3787c869993eSxy150489 			lbpp[value++] = lb_serdes;
3788c869993eSxy150489 		lbpp[value++] = lb_external;
3789c869993eSxy150489 		break;
3790c869993eSxy150489 
3791c869993eSxy150489 	case LB_GET_MODE:
3792c869993eSxy150489 		size = sizeof (uint32_t);
3793c869993eSxy150489 		if (iocp->ioc_count != size)
3794c869993eSxy150489 			return (IOC_INVAL);
3795c869993eSxy150489 
3796c869993eSxy150489 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
3797c869993eSxy150489 		*lbmp = igb->loopback_mode;
3798c869993eSxy150489 		break;
3799c869993eSxy150489 
3800c869993eSxy150489 	case LB_SET_MODE:
3801c869993eSxy150489 		size = 0;
3802c869993eSxy150489 		if (iocp->ioc_count != sizeof (uint32_t))
3803c869993eSxy150489 			return (IOC_INVAL);
3804c869993eSxy150489 
3805c869993eSxy150489 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
3806c869993eSxy150489 		if (!igb_set_loopback_mode(igb, *lbmp))
3807c869993eSxy150489 			return (IOC_INVAL);
3808c869993eSxy150489 		break;
3809c869993eSxy150489 	}
3810c869993eSxy150489 
3811c869993eSxy150489 	iocp->ioc_count = size;
3812c869993eSxy150489 	iocp->ioc_error = 0;
3813c869993eSxy150489 
38148bb4b220Sgl147354 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
38158bb4b220Sgl147354 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
38168bb4b220Sgl147354 		return (IOC_INVAL);
38178bb4b220Sgl147354 	}
38188bb4b220Sgl147354 
3819c869993eSxy150489 	return (IOC_REPLY);
3820c869993eSxy150489 }
3821c869993eSxy150489 
3822c869993eSxy150489 /*
3823c869993eSxy150489  * igb_set_loopback_mode - Setup loopback based on the loopback mode
3824c869993eSxy150489  */
3825c869993eSxy150489 static boolean_t
3826c869993eSxy150489 igb_set_loopback_mode(igb_t *igb, uint32_t mode)
3827c869993eSxy150489 {
3828c869993eSxy150489 	struct e1000_hw *hw;
3829ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	int i;
3830c869993eSxy150489 
3831c869993eSxy150489 	if (mode == igb->loopback_mode)
3832c869993eSxy150489 		return (B_TRUE);
3833c869993eSxy150489 
3834c869993eSxy150489 	hw = &igb->hw;
3835c869993eSxy150489 
3836c869993eSxy150489 	igb->loopback_mode = mode;
3837c869993eSxy150489 
3838c869993eSxy150489 	if (mode == IGB_LB_NONE) {
3839c869993eSxy150489 		/* Reset the chip */
3840c869993eSxy150489 		hw->phy.autoneg_wait_to_complete = B_TRUE;
3841c869993eSxy150489 		(void) igb_reset(igb);
3842c869993eSxy150489 		hw->phy.autoneg_wait_to_complete = B_FALSE;
3843c869993eSxy150489 		return (B_TRUE);
3844c869993eSxy150489 	}
3845c869993eSxy150489 
3846c869993eSxy150489 	mutex_enter(&igb->gen_lock);
3847c869993eSxy150489 
3848c869993eSxy150489 	switch (mode) {
3849c869993eSxy150489 	default:
3850c869993eSxy150489 		mutex_exit(&igb->gen_lock);
3851c869993eSxy150489 		return (B_FALSE);
3852c869993eSxy150489 
3853c869993eSxy150489 	case IGB_LB_EXTERNAL:
3854c869993eSxy150489 		igb_set_external_loopback(igb);
3855c869993eSxy150489 		break;
3856c869993eSxy150489 
3857c869993eSxy150489 	case IGB_LB_INTERNAL_PHY:
3858c869993eSxy150489 		igb_set_internal_phy_loopback(igb);
3859c869993eSxy150489 		break;
3860c869993eSxy150489 
3861c869993eSxy150489 	case IGB_LB_INTERNAL_SERDES:
3862c869993eSxy150489 		igb_set_internal_serdes_loopback(igb);
3863c869993eSxy150489 		break;
3864c869993eSxy150489 	}
3865c869993eSxy150489 
3866c869993eSxy150489 	mutex_exit(&igb->gen_lock);
3867c869993eSxy150489 
3868ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	/*
3869ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 * When external loopback is set, wait up to 1000ms to get the link up.
3870ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 * According to test, 1000ms can work and it's an experimental value.
3871ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	 */
3872ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (mode == IGB_LB_EXTERNAL) {
3873ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		for (i = 0; i <= 10; i++) {
3874ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			mutex_enter(&igb->gen_lock);
3875ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			(void) igb_link_check(igb);
3876ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			mutex_exit(&igb->gen_lock);
3877ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
3878ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			if (igb->link_state == LINK_STATE_UP)
3879ac7f5757Schenlu chen - Sun Microsystems - Beijing China 				break;
3880ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
3881ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			msec_delay(100);
3882ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		}
3883ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
3884ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		if (igb->link_state != LINK_STATE_UP) {
3885ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			/*
3886ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			 * Does not support external loopback.
3887ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			 * Reset driver to loopback none.
3888ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			 */
3889ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			igb->loopback_mode = IGB_LB_NONE;
3890ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
3891ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			/* Reset the chip */
3892ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			hw->phy.autoneg_wait_to_complete = B_TRUE;
3893ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			(void) igb_reset(igb);
3894ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			hw->phy.autoneg_wait_to_complete = B_FALSE;
3895ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
3896*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO, "Set external loopback "
3897*e5513923SYuri Pankov 			    "failed, reset to loopback none.");
3898ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
3899ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			return (B_FALSE);
3900ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		}
3901ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
3902ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
3903c869993eSxy150489 	return (B_TRUE);
3904c869993eSxy150489 }
3905c869993eSxy150489 
3906c869993eSxy150489 /*
3907c869993eSxy150489  * igb_set_external_loopback - Set the external loopback mode
3908c869993eSxy150489  */
3909c869993eSxy150489 static void
3910c869993eSxy150489 igb_set_external_loopback(igb_t *igb)
3911c869993eSxy150489 {
3912c869993eSxy150489 	struct e1000_hw *hw;
391369b2d733SGuoqing Zhu 	uint32_t ctrl_ext;
3914c869993eSxy150489 
3915c869993eSxy150489 	hw = &igb->hw;
3916c869993eSxy150489 
391769b2d733SGuoqing Zhu 	/* Set link mode to PHY (00b) in the Extended Control register */
391869b2d733SGuoqing Zhu 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
391969b2d733SGuoqing Zhu 	ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
392069b2d733SGuoqing Zhu 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
3921c869993eSxy150489 
3922c869993eSxy150489 	(void) e1000_write_phy_reg(hw, 0x0, 0x0140);
392369b2d733SGuoqing Zhu 	(void) e1000_write_phy_reg(hw, 0x9, 0x1a00);
3924c869993eSxy150489 	(void) e1000_write_phy_reg(hw, 0x12, 0x1610);
3925c869993eSxy150489 	(void) e1000_write_phy_reg(hw, 0x1f37, 0x3f1c);
3926c869993eSxy150489 }
3927c869993eSxy150489 
3928c869993eSxy150489 /*
3929c869993eSxy150489  * igb_set_internal_phy_loopback - Set the internal PHY loopback mode
3930c869993eSxy150489  */
3931c869993eSxy150489 static void
3932c869993eSxy150489 igb_set_internal_phy_loopback(igb_t *igb)
3933c869993eSxy150489 {
3934c869993eSxy150489 	struct e1000_hw *hw;
3935c869993eSxy150489 	uint32_t ctrl_ext;
3936c869993eSxy150489 	uint16_t phy_ctrl;
3937c869993eSxy150489 	uint16_t phy_pconf;
3938c869993eSxy150489 
3939c869993eSxy150489 	hw = &igb->hw;
3940c869993eSxy150489 
3941c869993eSxy150489 	/* Set link mode to PHY (00b) in the Extended Control register */
3942c869993eSxy150489 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
3943c869993eSxy150489 	ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
3944c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
3945c869993eSxy150489 
3946c869993eSxy150489 	/*
3947c869993eSxy150489 	 * Set PHY control register (0x4140):
3948c869993eSxy150489 	 *    Set full duplex mode
3949c869993eSxy150489 	 *    Set loopback bit
3950c869993eSxy150489 	 *    Clear auto-neg enable bit
3951c869993eSxy150489 	 *    Set PHY speed
3952c869993eSxy150489 	 */
3953c869993eSxy150489 	phy_ctrl = MII_CR_FULL_DUPLEX | MII_CR_SPEED_1000 | MII_CR_LOOPBACK;
3954c869993eSxy150489 	(void) e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl);
3955c869993eSxy150489 
3956c869993eSxy150489 	/* Set the link disable bit in the Port Configuration register */
3957c869993eSxy150489 	(void) e1000_read_phy_reg(hw, 0x10, &phy_pconf);
3958c869993eSxy150489 	phy_pconf |= (uint16_t)1 << 14;
3959c869993eSxy150489 	(void) e1000_write_phy_reg(hw, 0x10, phy_pconf);
3960c869993eSxy150489 }
3961c869993eSxy150489 
3962c869993eSxy150489 /*
3963c869993eSxy150489  * igb_set_internal_serdes_loopback - Set the internal SerDes loopback mode
3964c869993eSxy150489  */
3965c869993eSxy150489 static void
3966c869993eSxy150489 igb_set_internal_serdes_loopback(igb_t *igb)
3967c869993eSxy150489 {
3968c869993eSxy150489 	struct e1000_hw *hw;
3969c869993eSxy150489 	uint32_t ctrl_ext;
3970c869993eSxy150489 	uint32_t ctrl;
3971c869993eSxy150489 	uint32_t pcs_lctl;
3972c869993eSxy150489 	uint32_t connsw;
3973c869993eSxy150489 
3974c869993eSxy150489 	hw = &igb->hw;
3975c869993eSxy150489 
3976c869993eSxy150489 	/* Set link mode to SerDes (11b) in the Extended Control register */
3977c869993eSxy150489 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
3978c869993eSxy150489 	ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
3979c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
3980c869993eSxy150489 
3981c869993eSxy150489 	/* Configure the SerDes to loopback */
3982c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_SCTL, 0x410);
3983c869993eSxy150489 
3984c869993eSxy150489 	/* Set Device Control register */
3985c869993eSxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
3986c869993eSxy150489 	ctrl |= (E1000_CTRL_FD |	/* Force full duplex */
3987c869993eSxy150489 	    E1000_CTRL_SLU);		/* Force link up */
3988c869993eSxy150489 	ctrl &= ~(E1000_CTRL_RFCE |	/* Disable receive flow control */
3989c869993eSxy150489 	    E1000_CTRL_TFCE |		/* Disable transmit flow control */
3990c869993eSxy150489 	    E1000_CTRL_LRST);		/* Clear link reset */
3991c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
3992c869993eSxy150489 
3993c869993eSxy150489 	/* Set PCS Link Control register */
3994c869993eSxy150489 	pcs_lctl = E1000_READ_REG(hw, E1000_PCS_LCTL);
3995c869993eSxy150489 	pcs_lctl |= (E1000_PCS_LCTL_FORCE_LINK |
3996c869993eSxy150489 	    E1000_PCS_LCTL_FSD |
3997c869993eSxy150489 	    E1000_PCS_LCTL_FDV_FULL |
3998c869993eSxy150489 	    E1000_PCS_LCTL_FLV_LINK_UP);
3999c869993eSxy150489 	pcs_lctl &= ~E1000_PCS_LCTL_AN_ENABLE;
4000c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_PCS_LCTL, pcs_lctl);
4001c869993eSxy150489 
4002c869993eSxy150489 	/* Set the Copper/Fiber Switch Control - CONNSW register */
4003c869993eSxy150489 	connsw = E1000_READ_REG(hw, E1000_CONNSW);
4004c869993eSxy150489 	connsw &= ~E1000_CONNSW_ENRGSRC;
4005c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_CONNSW, connsw);
4006c869993eSxy150489 }
4007c869993eSxy150489 
4008c869993eSxy150489 #pragma inline(igb_intr_rx_work)
4009c869993eSxy150489 /*
4010c869993eSxy150489  * igb_intr_rx_work - rx processing of ISR
4011c869993eSxy150489  */
4012c869993eSxy150489 static void
4013c869993eSxy150489 igb_intr_rx_work(igb_rx_ring_t *rx_ring)
4014c869993eSxy150489 {
4015c869993eSxy150489 	mblk_t *mp;
4016c869993eSxy150489 
4017c869993eSxy150489 	mutex_enter(&rx_ring->rx_lock);
4018da14cebeSEric Cheng 	mp = igb_rx(rx_ring, IGB_NO_POLL);
4019c869993eSxy150489 	mutex_exit(&rx_ring->rx_lock);
4020c869993eSxy150489 
4021c869993eSxy150489 	if (mp != NULL)
4022da14cebeSEric Cheng 		mac_rx_ring(rx_ring->igb->mac_hdl, rx_ring->ring_handle, mp,
4023da14cebeSEric Cheng 		    rx_ring->ring_gen_num);
4024c869993eSxy150489 }
4025c869993eSxy150489 
4026c869993eSxy150489 #pragma inline(igb_intr_tx_work)
4027c869993eSxy150489 /*
4028c869993eSxy150489  * igb_intr_tx_work - tx processing of ISR
4029c869993eSxy150489  */
4030c869993eSxy150489 static void
4031c869993eSxy150489 igb_intr_tx_work(igb_tx_ring_t *tx_ring)
4032c869993eSxy150489 {
4033ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb_t *igb = tx_ring->igb;
4034ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
4035c869993eSxy150489 	/* Recycle the tx descriptors */
4036c869993eSxy150489 	tx_ring->tx_recycle(tx_ring);
4037c869993eSxy150489 
4038c869993eSxy150489 	/* Schedule the re-transmit */
4039c869993eSxy150489 	if (tx_ring->reschedule &&
4040ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	    (tx_ring->tbd_free >= igb->tx_resched_thresh)) {
4041c869993eSxy150489 		tx_ring->reschedule = B_FALSE;
4042da14cebeSEric Cheng 		mac_tx_ring_update(tx_ring->igb->mac_hdl, tx_ring->ring_handle);
4043c869993eSxy150489 		IGB_DEBUG_STAT(tx_ring->stat_reschedule);
4044c869993eSxy150489 	}
4045c869993eSxy150489 }
4046c869993eSxy150489 
4047da14cebeSEric Cheng #pragma inline(igb_intr_link_work)
4048c869993eSxy150489 /*
4049da14cebeSEric Cheng  * igb_intr_link_work - link-status-change processing of ISR
4050c869993eSxy150489  */
4051c869993eSxy150489 static void
4052da14cebeSEric Cheng igb_intr_link_work(igb_t *igb)
4053c869993eSxy150489 {
4054c869993eSxy150489 	boolean_t link_changed;
4055c869993eSxy150489 
4056c869993eSxy150489 	igb_stop_watchdog_timer(igb);
4057c869993eSxy150489 
4058c869993eSxy150489 	mutex_enter(&igb->gen_lock);
4059c869993eSxy150489 
4060c869993eSxy150489 	/*
4061c869993eSxy150489 	 * Because we got a link-status-change interrupt, force
4062c869993eSxy150489 	 * e1000_check_for_link() to look at phy
4063c869993eSxy150489 	 */
4064c869993eSxy150489 	igb->hw.mac.get_link_status = B_TRUE;
4065c869993eSxy150489 
4066c869993eSxy150489 	/* igb_link_check takes care of link status change */
4067c869993eSxy150489 	link_changed = igb_link_check(igb);
4068c869993eSxy150489 
4069c869993eSxy150489 	/* Get new phy state */
4070c869993eSxy150489 	igb_get_phy_state(igb);
4071c869993eSxy150489 
4072c869993eSxy150489 	mutex_exit(&igb->gen_lock);
4073c869993eSxy150489 
4074c869993eSxy150489 	if (link_changed)
4075c869993eSxy150489 		mac_link_update(igb->mac_hdl, igb->link_state);
4076c869993eSxy150489 
4077c869993eSxy150489 	igb_start_watchdog_timer(igb);
4078c869993eSxy150489 }
4079c869993eSxy150489 
4080c869993eSxy150489 /*
4081c869993eSxy150489  * igb_intr_legacy - Interrupt handler for legacy interrupts
4082c869993eSxy150489  */
4083c869993eSxy150489 static uint_t
4084c869993eSxy150489 igb_intr_legacy(void *arg1, void *arg2)
4085c869993eSxy150489 {
4086c869993eSxy150489 	igb_t *igb = (igb_t *)arg1;
4087c869993eSxy150489 	igb_tx_ring_t *tx_ring;
4088c869993eSxy150489 	uint32_t icr;
4089c869993eSxy150489 	mblk_t *mp;
4090c869993eSxy150489 	boolean_t tx_reschedule;
4091c869993eSxy150489 	boolean_t link_changed;
4092c869993eSxy150489 	uint_t result;
4093c869993eSxy150489 
4094c869993eSxy150489 	_NOTE(ARGUNUSED(arg2));
4095c869993eSxy150489 
4096c869993eSxy150489 	mutex_enter(&igb->gen_lock);
4097c869993eSxy150489 
4098c869993eSxy150489 	if (igb->igb_state & IGB_SUSPENDED) {
4099c869993eSxy150489 		mutex_exit(&igb->gen_lock);
4100c869993eSxy150489 		return (DDI_INTR_UNCLAIMED);
4101c869993eSxy150489 	}
4102c869993eSxy150489 
4103c869993eSxy150489 	mp = NULL;
4104c869993eSxy150489 	tx_reschedule = B_FALSE;
4105c869993eSxy150489 	link_changed = B_FALSE;
4106c869993eSxy150489 	icr = E1000_READ_REG(&igb->hw, E1000_ICR);
4107c869993eSxy150489 
4108cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
4109b227c420Schenlu chen - Sun Microsystems - Beijing China 		mutex_exit(&igb->gen_lock);
4110cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
4111cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		atomic_or_32(&igb->igb_state, IGB_ERROR);
4112cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		return (DDI_INTR_UNCLAIMED);
4113cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	}
4114cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
4115c869993eSxy150489 	if (icr & E1000_ICR_INT_ASSERTED) {
4116c869993eSxy150489 		/*
4117c869993eSxy150489 		 * E1000_ICR_INT_ASSERTED bit was set:
4118c869993eSxy150489 		 * Read(Clear) the ICR, claim this interrupt,
4119c869993eSxy150489 		 * look for work to do.
4120c869993eSxy150489 		 */
4121c869993eSxy150489 		ASSERT(igb->num_rx_rings == 1);
4122c869993eSxy150489 		ASSERT(igb->num_tx_rings == 1);
4123c869993eSxy150489 
412480a11ad2Schenlu chen - Sun Microsystems - Beijing China 		/* Make sure all interrupt causes cleared */
412580a11ad2Schenlu chen - Sun Microsystems - Beijing China 		(void) E1000_READ_REG(&igb->hw, E1000_EICR);
412680a11ad2Schenlu chen - Sun Microsystems - Beijing China 
4127c869993eSxy150489 		if (icr & E1000_ICR_RXT0) {
4128da14cebeSEric Cheng 			mp = igb_rx(&igb->rx_rings[0], IGB_NO_POLL);
4129c869993eSxy150489 		}
4130c869993eSxy150489 
4131c869993eSxy150489 		if (icr & E1000_ICR_TXDW) {
4132c869993eSxy150489 			tx_ring = &igb->tx_rings[0];
4133c869993eSxy150489 
4134c869993eSxy150489 			/* Recycle the tx descriptors */
4135c869993eSxy150489 			tx_ring->tx_recycle(tx_ring);
4136c869993eSxy150489 
4137c869993eSxy150489 			/* Schedule the re-transmit */
4138c869993eSxy150489 			tx_reschedule = (tx_ring->reschedule &&
4139ac7f5757Schenlu chen - Sun Microsystems - Beijing China 			    (tx_ring->tbd_free >= igb->tx_resched_thresh));
4140c869993eSxy150489 		}
4141c869993eSxy150489 
4142c869993eSxy150489 		if (icr & E1000_ICR_LSC) {
4143c869993eSxy150489 			/*
4144c869993eSxy150489 			 * Because we got a link-status-change interrupt, force
4145c869993eSxy150489 			 * e1000_check_for_link() to look at phy
4146c869993eSxy150489 			 */
4147c869993eSxy150489 			igb->hw.mac.get_link_status = B_TRUE;
4148c869993eSxy150489 
4149c869993eSxy150489 			/* igb_link_check takes care of link status change */
4150c869993eSxy150489 			link_changed = igb_link_check(igb);
4151c869993eSxy150489 
4152c869993eSxy150489 			/* Get new phy state */
4153c869993eSxy150489 			igb_get_phy_state(igb);
4154c869993eSxy150489 		}
4155c869993eSxy150489 
41563f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		if (icr & E1000_ICR_DRSTA) {
41573f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			/* 82580 Full Device Reset needed */
4158cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 			atomic_or_32(&igb->igb_state, IGB_STALL);
41593f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		}
41603f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
4161c869993eSxy150489 		result = DDI_INTR_CLAIMED;
4162c869993eSxy150489 	} else {
4163c869993eSxy150489 		/*
4164c869993eSxy150489 		 * E1000_ICR_INT_ASSERTED bit was not set:
4165c869993eSxy150489 		 * Don't claim this interrupt.
4166c869993eSxy150489 		 */
4167c869993eSxy150489 		result = DDI_INTR_UNCLAIMED;
4168c869993eSxy150489 	}
4169c869993eSxy150489 
4170c869993eSxy150489 	mutex_exit(&igb->gen_lock);
4171c869993eSxy150489 
4172c869993eSxy150489 	/*
4173c869993eSxy150489 	 * Do the following work outside of the gen_lock
4174c869993eSxy150489 	 */
4175c869993eSxy150489 	if (mp != NULL)
4176c869993eSxy150489 		mac_rx(igb->mac_hdl, NULL, mp);
4177c869993eSxy150489 
4178c869993eSxy150489 	if (tx_reschedule)  {
4179c869993eSxy150489 		tx_ring->reschedule = B_FALSE;
4180da14cebeSEric Cheng 		mac_tx_ring_update(igb->mac_hdl, tx_ring->ring_handle);
4181c869993eSxy150489 		IGB_DEBUG_STAT(tx_ring->stat_reschedule);
4182c869993eSxy150489 	}
4183c869993eSxy150489 
4184c869993eSxy150489 	if (link_changed)
4185c869993eSxy150489 		mac_link_update(igb->mac_hdl, igb->link_state);
4186c869993eSxy150489 
4187c869993eSxy150489 	return (result);
4188c869993eSxy150489 }
4189c869993eSxy150489 
4190c869993eSxy150489 /*
4191c869993eSxy150489  * igb_intr_msi - Interrupt handler for MSI
4192c869993eSxy150489  */
4193c869993eSxy150489 static uint_t
4194c869993eSxy150489 igb_intr_msi(void *arg1, void *arg2)
4195c869993eSxy150489 {
4196c869993eSxy150489 	igb_t *igb = (igb_t *)arg1;
4197c869993eSxy150489 	uint32_t icr;
4198c869993eSxy150489 
4199c869993eSxy150489 	_NOTE(ARGUNUSED(arg2));
4200c869993eSxy150489 
4201c869993eSxy150489 	icr = E1000_READ_REG(&igb->hw, E1000_ICR);
4202c869993eSxy150489 
4203cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
4204cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
4205cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		atomic_or_32(&igb->igb_state, IGB_ERROR);
4206cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		return (DDI_INTR_CLAIMED);
4207cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	}
4208cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
420980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* Make sure all interrupt causes cleared */
421080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	(void) E1000_READ_REG(&igb->hw, E1000_EICR);
421180a11ad2Schenlu chen - Sun Microsystems - Beijing China 
4212c869993eSxy150489 	/*
4213c869993eSxy150489 	 * For MSI interrupt, we have only one vector,
4214c869993eSxy150489 	 * so we have only one rx ring and one tx ring enabled.
4215c869993eSxy150489 	 */
4216c869993eSxy150489 	ASSERT(igb->num_rx_rings == 1);
4217c869993eSxy150489 	ASSERT(igb->num_tx_rings == 1);
4218c869993eSxy150489 
4219c869993eSxy150489 	if (icr & E1000_ICR_RXT0) {
4220c869993eSxy150489 		igb_intr_rx_work(&igb->rx_rings[0]);
4221c869993eSxy150489 	}
4222c869993eSxy150489 
4223c869993eSxy150489 	if (icr & E1000_ICR_TXDW) {
4224c869993eSxy150489 		igb_intr_tx_work(&igb->tx_rings[0]);
4225c869993eSxy150489 	}
4226c869993eSxy150489 
4227c869993eSxy150489 	if (icr & E1000_ICR_LSC) {
4228da14cebeSEric Cheng 		igb_intr_link_work(igb);
4229c869993eSxy150489 	}
4230c869993eSxy150489 
42313f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	if (icr & E1000_ICR_DRSTA) {
42323f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		/* 82580 Full Device Reset needed */
4233cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		atomic_or_32(&igb->igb_state, IGB_STALL);
42343f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	}
42353f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
4236c869993eSxy150489 	return (DDI_INTR_CLAIMED);
4237c869993eSxy150489 }
4238c869993eSxy150489 
4239c869993eSxy150489 /*
4240c869993eSxy150489  * igb_intr_rx - Interrupt handler for rx
4241c869993eSxy150489  */
4242c869993eSxy150489 static uint_t
4243c869993eSxy150489 igb_intr_rx(void *arg1, void *arg2)
4244c869993eSxy150489 {
4245c869993eSxy150489 	igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)arg1;
4246c869993eSxy150489 
4247c869993eSxy150489 	_NOTE(ARGUNUSED(arg2));
4248c869993eSxy150489 
4249c869993eSxy150489 	/*
4250c869993eSxy150489 	 * Only used via MSI-X vector so don't check cause bits
4251c869993eSxy150489 	 * and only clean the given ring.
4252c869993eSxy150489 	 */
4253c869993eSxy150489 	igb_intr_rx_work(rx_ring);
4254c869993eSxy150489 
4255c869993eSxy150489 	return (DDI_INTR_CLAIMED);
4256c869993eSxy150489 }
4257c869993eSxy150489 
4258c869993eSxy150489 /*
4259da14cebeSEric Cheng  * igb_intr_tx - Interrupt handler for tx
4260da14cebeSEric Cheng  */
4261da14cebeSEric Cheng static uint_t
4262da14cebeSEric Cheng igb_intr_tx(void *arg1, void *arg2)
4263da14cebeSEric Cheng {
4264da14cebeSEric Cheng 	igb_tx_ring_t *tx_ring = (igb_tx_ring_t *)arg1;
4265da14cebeSEric Cheng 
4266da14cebeSEric Cheng 	_NOTE(ARGUNUSED(arg2));
4267da14cebeSEric Cheng 
4268da14cebeSEric Cheng 	/*
4269da14cebeSEric Cheng 	 * Only used via MSI-X vector so don't check cause bits
4270da14cebeSEric Cheng 	 * and only clean the given ring.
4271da14cebeSEric Cheng 	 */
4272da14cebeSEric Cheng 	igb_intr_tx_work(tx_ring);
4273da14cebeSEric Cheng 
4274da14cebeSEric Cheng 	return (DDI_INTR_CLAIMED);
4275da14cebeSEric Cheng }
4276da14cebeSEric Cheng 
4277da14cebeSEric Cheng /*
4278c869993eSxy150489  * igb_intr_tx_other - Interrupt handler for both tx and other
4279c869993eSxy150489  *
4280c869993eSxy150489  */
4281c869993eSxy150489 static uint_t
4282c869993eSxy150489 igb_intr_tx_other(void *arg1, void *arg2)
4283c869993eSxy150489 {
4284c869993eSxy150489 	igb_t *igb = (igb_t *)arg1;
4285c869993eSxy150489 	uint32_t icr;
4286c869993eSxy150489 
4287c869993eSxy150489 	_NOTE(ARGUNUSED(arg2));
4288c869993eSxy150489 
4289c869993eSxy150489 	icr = E1000_READ_REG(&igb->hw, E1000_ICR);
4290c869993eSxy150489 
4291cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
4292cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
4293cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		atomic_or_32(&igb->igb_state, IGB_ERROR);
4294cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		return (DDI_INTR_CLAIMED);
4295cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 	}
4296cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 
4297c869993eSxy150489 	/*
4298da14cebeSEric Cheng 	 * Look for tx reclaiming work first. Remember, in the
4299da14cebeSEric Cheng 	 * case of only interrupt sharing, only one tx ring is
4300da14cebeSEric Cheng 	 * used
4301c869993eSxy150489 	 */
4302c869993eSxy150489 	igb_intr_tx_work(&igb->tx_rings[0]);
4303c869993eSxy150489 
4304c869993eSxy150489 	/*
4305b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * Check for "other" causes.
4306c869993eSxy150489 	 */
4307c869993eSxy150489 	if (icr & E1000_ICR_LSC) {
4308da14cebeSEric Cheng 		igb_intr_link_work(igb);
4309c869993eSxy150489 	}
4310c869993eSxy150489 
4311b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	/*
4312b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * The DOUTSYNC bit indicates a tx packet dropped because
4313b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * DMA engine gets "out of sync". There isn't a real fix
4314b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * for this. The Intel recommendation is to count the number
4315b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * of occurrences so user can detect when it is happening.
4316b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * The issue is non-fatal and there's no recovery action
4317b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 * available.
4318b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	 */
4319b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	if (icr & E1000_ICR_DOUTSYNC) {
4320b8d0a377Schenlu chen - Sun Microsystems - Beijing China 		IGB_STAT(igb->dout_sync);
4321b8d0a377Schenlu chen - Sun Microsystems - Beijing China 	}
4322b8d0a377Schenlu chen - Sun Microsystems - Beijing China 
43233f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	if (icr & E1000_ICR_DRSTA) {
43243f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		/* 82580 Full Device Reset needed */
4325cf8dcc9bSzhefeng xu - Sun Microsystems - Beijing China 		atomic_or_32(&igb->igb_state, IGB_STALL);
43263f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	}
43273f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
4328c869993eSxy150489 	return (DDI_INTR_CLAIMED);
4329c869993eSxy150489 }
4330c869993eSxy150489 
4331c869993eSxy150489 /*
4332c869993eSxy150489  * igb_alloc_intrs - Allocate interrupts for the driver
4333c869993eSxy150489  *
4334c869993eSxy150489  * Normal sequence is to try MSI-X; if not sucessful, try MSI;
4335c869993eSxy150489  * if not successful, try Legacy.
4336c869993eSxy150489  * igb->intr_force can be used to force sequence to start with
4337c869993eSxy150489  * any of the 3 types.
4338c869993eSxy150489  * If MSI-X is not used, number of tx/rx rings is forced to 1.
4339c869993eSxy150489  */
4340c869993eSxy150489 static int
4341c869993eSxy150489 igb_alloc_intrs(igb_t *igb)
4342c869993eSxy150489 {
4343c869993eSxy150489 	dev_info_t *devinfo;
4344c869993eSxy150489 	int intr_types;
4345c869993eSxy150489 	int rc;
4346c869993eSxy150489 
4347c869993eSxy150489 	devinfo = igb->dip;
4348c869993eSxy150489 
4349c869993eSxy150489 	/* Get supported interrupt types */
4350c869993eSxy150489 	rc = ddi_intr_get_supported_types(devinfo, &intr_types);
4351c869993eSxy150489 
4352c869993eSxy150489 	if (rc != DDI_SUCCESS) {
4353*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_ERROR,
4354c869993eSxy150489 		    "Get supported interrupt types failed: %d", rc);
4355c869993eSxy150489 		return (IGB_FAILURE);
4356c869993eSxy150489 	}
4357*e5513923SYuri Pankov 	igb_log(igb, IGB_LOG_INFO, "Supported interrupt types: %x",
4358*e5513923SYuri Pankov 	    intr_types);
4359c869993eSxy150489 
4360c869993eSxy150489 	igb->intr_type = 0;
4361c869993eSxy150489 
4362c869993eSxy150489 	/* Install MSI-X interrupts */
4363c869993eSxy150489 	if ((intr_types & DDI_INTR_TYPE_MSIX) &&
4364c869993eSxy150489 	    (igb->intr_force <= IGB_INTR_MSIX)) {
4365fa25784cSxy150489 		rc = igb_alloc_intr_handles(igb, DDI_INTR_TYPE_MSIX);
4366c869993eSxy150489 
4367c869993eSxy150489 		if (rc == IGB_SUCCESS)
4368c869993eSxy150489 			return (IGB_SUCCESS);
4369c869993eSxy150489 
4370*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4371c869993eSxy150489 		    "Allocate MSI-X failed, trying MSI interrupts...");
4372c869993eSxy150489 	}
4373c869993eSxy150489 
4374c869993eSxy150489 	/* MSI-X not used, force rings to 1 */
4375c869993eSxy150489 	igb->num_rx_rings = 1;
4376c869993eSxy150489 	igb->num_tx_rings = 1;
4377*e5513923SYuri Pankov 	igb_log(igb, IGB_LOG_INFO,
4378c869993eSxy150489 	    "MSI-X not used, force rx and tx queue number to 1");
4379c869993eSxy150489 
4380c869993eSxy150489 	/* Install MSI interrupts */
4381c869993eSxy150489 	if ((intr_types & DDI_INTR_TYPE_MSI) &&
4382c869993eSxy150489 	    (igb->intr_force <= IGB_INTR_MSI)) {
4383fa25784cSxy150489 		rc = igb_alloc_intr_handles(igb, DDI_INTR_TYPE_MSI);
4384c869993eSxy150489 
4385c869993eSxy150489 		if (rc == IGB_SUCCESS)
4386c869993eSxy150489 			return (IGB_SUCCESS);
4387c869993eSxy150489 
4388*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4389c869993eSxy150489 		    "Allocate MSI failed, trying Legacy interrupts...");
4390c869993eSxy150489 	}
4391c869993eSxy150489 
4392c869993eSxy150489 	/* Install legacy interrupts */
4393c869993eSxy150489 	if (intr_types & DDI_INTR_TYPE_FIXED) {
4394fa25784cSxy150489 		rc = igb_alloc_intr_handles(igb, DDI_INTR_TYPE_FIXED);
4395c869993eSxy150489 
4396c869993eSxy150489 		if (rc == IGB_SUCCESS)
4397c869993eSxy150489 			return (IGB_SUCCESS);
4398c869993eSxy150489 
4399*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4400c869993eSxy150489 		    "Allocate Legacy interrupts failed");
4401c869993eSxy150489 	}
4402c869993eSxy150489 
4403c869993eSxy150489 	/* If none of the 3 types succeeded, return failure */
4404c869993eSxy150489 	return (IGB_FAILURE);
4405c869993eSxy150489 }
4406c869993eSxy150489 
4407c869993eSxy150489 /*
4408fa25784cSxy150489  * igb_alloc_intr_handles - Allocate interrupt handles.
4409c869993eSxy150489  *
4410fa25784cSxy150489  * For legacy and MSI, only 1 handle is needed.  For MSI-X,
4411fa25784cSxy150489  * if fewer than 2 handles are available, return failure.
4412c869993eSxy150489  * Upon success, this sets the number of Rx rings to a number that
4413fa25784cSxy150489  * matches the handles available for Rx interrupts.
4414c869993eSxy150489  */
4415c869993eSxy150489 static int
4416fa25784cSxy150489 igb_alloc_intr_handles(igb_t *igb, int intr_type)
4417c869993eSxy150489 {
4418c869993eSxy150489 	dev_info_t *devinfo;
4419da14cebeSEric Cheng 	int orig, request, count, avail, actual;
4420da14cebeSEric Cheng 	int diff, minimum;
4421c869993eSxy150489 	int rc;
4422c869993eSxy150489 
4423c869993eSxy150489 	devinfo = igb->dip;
4424c869993eSxy150489 
4425fa25784cSxy150489 	switch (intr_type) {
4426fa25784cSxy150489 	case DDI_INTR_TYPE_FIXED:
4427fa25784cSxy150489 		request = 1;	/* Request 1 legacy interrupt handle */
4428fa25784cSxy150489 		minimum = 1;
4429*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO, "interrupt type: legacy");
4430fa25784cSxy150489 		break;
4431fa25784cSxy150489 
4432fa25784cSxy150489 	case DDI_INTR_TYPE_MSI:
4433fa25784cSxy150489 		request = 1;	/* Request 1 MSI interrupt handle */
4434fa25784cSxy150489 		minimum = 1;
4435*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO, "interrupt type: MSI");
4436fa25784cSxy150489 		break;
4437fa25784cSxy150489 
4438fa25784cSxy150489 	case DDI_INTR_TYPE_MSIX:
4439c869993eSxy150489 		/*
4440da14cebeSEric Cheng 		 * Number of vectors for the adapter is
4441da14cebeSEric Cheng 		 * # rx rings + # tx rings
4442da14cebeSEric Cheng 		 * One of tx vectors is for tx & other
4443c869993eSxy150489 		 */
4444da14cebeSEric Cheng 		request = igb->num_rx_rings + igb->num_tx_rings;
4445da14cebeSEric Cheng 		orig = request;
4446fa25784cSxy150489 		minimum = 2;
4447*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO, "interrupt type: MSI-X");
4448fa25784cSxy150489 		break;
4449c869993eSxy150489 
4450fa25784cSxy150489 	default:
4451*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4452fa25784cSxy150489 		    "invalid call to igb_alloc_intr_handles(): %d\n",
4453fa25784cSxy150489 		    intr_type);
4454c869993eSxy150489 		return (IGB_FAILURE);
4455c869993eSxy150489 	}
4456*e5513923SYuri Pankov 	igb_log(igb, IGB_LOG_INFO,
4457*e5513923SYuri Pankov 	    "interrupt handles requested: %d  minimum: %d",
4458fa25784cSxy150489 	    request, minimum);
4459c869993eSxy150489 
4460fa25784cSxy150489 	/*
4461fa25784cSxy150489 	 * Get number of supported interrupts
4462fa25784cSxy150489 	 */
4463fa25784cSxy150489 	rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
4464fa25784cSxy150489 	if ((rc != DDI_SUCCESS) || (count < minimum)) {
4465*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4466fa25784cSxy150489 		    "Get supported interrupt number failed. "
4467fa25784cSxy150489 		    "Return: %d, count: %d", rc, count);
4468fa25784cSxy150489 		return (IGB_FAILURE);
4469fa25784cSxy150489 	}
4470*e5513923SYuri Pankov 	igb_log(igb, IGB_LOG_INFO, "interrupts supported: %d", count);
4471fa25784cSxy150489 
4472fa25784cSxy150489 	/*
4473fa25784cSxy150489 	 * Get number of available interrupts
4474fa25784cSxy150489 	 */
4475fa25784cSxy150489 	rc = ddi_intr_get_navail(devinfo, intr_type, &avail);
4476fa25784cSxy150489 	if ((rc != DDI_SUCCESS) || (avail < minimum)) {
4477*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4478fa25784cSxy150489 		    "Get available interrupt number failed. "
4479c869993eSxy150489 		    "Return: %d, available: %d", rc, avail);
4480c869993eSxy150489 		return (IGB_FAILURE);
4481c869993eSxy150489 	}
4482*e5513923SYuri Pankov 	igb_log(igb, IGB_LOG_INFO, "interrupts available: %d", avail);
4483c869993eSxy150489 
4484c869993eSxy150489 	if (avail < request) {
4485*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4486*e5513923SYuri Pankov 		    "Request %d handles, %d available",
4487c869993eSxy150489 		    request, avail);
4488c869993eSxy150489 		request = avail;
4489c869993eSxy150489 	}
4490c869993eSxy150489 
4491c869993eSxy150489 	actual = 0;
4492c869993eSxy150489 	igb->intr_cnt = 0;
4493c869993eSxy150489 
4494fa25784cSxy150489 	/*
4495fa25784cSxy150489 	 * Allocate an array of interrupt handles
4496fa25784cSxy150489 	 */
4497c869993eSxy150489 	igb->intr_size = request * sizeof (ddi_intr_handle_t);
4498c869993eSxy150489 	igb->htable = kmem_alloc(igb->intr_size, KM_SLEEP);
4499c869993eSxy150489 
4500fa25784cSxy150489 	rc = ddi_intr_alloc(devinfo, igb->htable, intr_type, 0,
4501c869993eSxy150489 	    request, &actual, DDI_INTR_ALLOC_NORMAL);
4502c869993eSxy150489 	if (rc != DDI_SUCCESS) {
4503*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO, "Allocate interrupts failed. "
4504c869993eSxy150489 		    "return: %d, request: %d, actual: %d",
4505c869993eSxy150489 		    rc, request, actual);
4506fa25784cSxy150489 		goto alloc_handle_fail;
4507c869993eSxy150489 	}
4508*e5513923SYuri Pankov 	igb_log(igb, IGB_LOG_INFO, "interrupts actually allocated: %d", actual);
4509c869993eSxy150489 
4510c869993eSxy150489 	igb->intr_cnt = actual;
4511c869993eSxy150489 
4512fa25784cSxy150489 	if (actual < minimum) {
4513*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4514*e5513923SYuri Pankov 		    "Insufficient interrupt handles allocated: %d",
4515c869993eSxy150489 		    actual);
4516fa25784cSxy150489 		goto alloc_handle_fail;
4517c869993eSxy150489 	}
4518c869993eSxy150489 
4519fa25784cSxy150489 	/*
4520da14cebeSEric Cheng 	 * For MSI-X, actual might force us to reduce number of tx & rx rings
4521fa25784cSxy150489 	 */
4522da14cebeSEric Cheng 	if ((intr_type == DDI_INTR_TYPE_MSIX) && (orig > actual)) {
4523da14cebeSEric Cheng 		diff = orig - actual;
4524da14cebeSEric Cheng 		if (diff < igb->num_tx_rings) {
4525*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO,
4526da14cebeSEric Cheng 			    "MSI-X vectors force Tx queue number to %d",
4527da14cebeSEric Cheng 			    igb->num_tx_rings - diff);
4528da14cebeSEric Cheng 			igb->num_tx_rings -= diff;
4529da14cebeSEric Cheng 		} else {
4530*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO,
4531da14cebeSEric Cheng 			    "MSI-X vectors force Tx queue number to 1");
4532da14cebeSEric Cheng 			igb->num_tx_rings = 1;
4533da14cebeSEric Cheng 
4534*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO,
4535fa25784cSxy150489 			    "MSI-X vectors force Rx queue number to %d",
4536da14cebeSEric Cheng 			    actual - 1);
4537da14cebeSEric Cheng 			igb->num_rx_rings = actual - 1;
4538c869993eSxy150489 		}
4539fa25784cSxy150489 	}
4540c869993eSxy150489 
4541fa25784cSxy150489 	/*
4542fa25784cSxy150489 	 * Get priority for first vector, assume remaining are all the same
4543fa25784cSxy150489 	 */
4544c869993eSxy150489 	rc = ddi_intr_get_pri(igb->htable[0], &igb->intr_pri);
4545c869993eSxy150489 	if (rc != DDI_SUCCESS) {
4546*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4547c869993eSxy150489 		    "Get interrupt priority failed: %d", rc);
4548fa25784cSxy150489 		goto alloc_handle_fail;
4549c869993eSxy150489 	}
4550c869993eSxy150489 
4551c869993eSxy150489 	rc = ddi_intr_get_cap(igb->htable[0], &igb->intr_cap);
4552c869993eSxy150489 	if (rc != DDI_SUCCESS) {
4553*e5513923SYuri Pankov 		igb_log(igb, IGB_LOG_INFO,
4554c869993eSxy150489 		    "Get interrupt cap failed: %d", rc);
4555fa25784cSxy150489 		goto alloc_handle_fail;
4556c869993eSxy150489 	}
4557c869993eSxy150489 
4558fa25784cSxy150489 	igb->intr_type = intr_type;
4559c869993eSxy150489 
4560c869993eSxy150489 	return (IGB_SUCCESS);
4561c869993eSxy150489 
4562fa25784cSxy150489 alloc_handle_fail:
4563c869993eSxy150489 	igb_rem_intrs(igb);
4564c869993eSxy150489 
4565c869993eSxy150489 	return (IGB_FAILURE);
4566c869993eSxy150489 }
4567c869993eSxy150489 
4568c869993eSxy150489 /*
4569c869993eSxy150489  * igb_add_intr_handlers - Add interrupt handlers based on the interrupt type
4570c869993eSxy150489  *
4571c869993eSxy150489  * Before adding the interrupt handlers, the interrupt vectors have
4572c869993eSxy150489  * been allocated, and the rx/tx rings have also been allocated.
4573c869993eSxy150489  */
4574c869993eSxy150489 static int
4575c869993eSxy150489 igb_add_intr_handlers(igb_t *igb)
4576c869993eSxy150489 {
4577c869993eSxy150489 	igb_rx_ring_t *rx_ring;
4578da14cebeSEric Cheng 	igb_tx_ring_t *tx_ring;
4579c869993eSxy150489 	int vector;
4580c869993eSxy150489 	int rc;
4581c869993eSxy150489 	int i;
4582c869993eSxy150489 
4583c869993eSxy150489 	vector = 0;
4584c869993eSxy150489 
4585c869993eSxy150489 	switch (igb->intr_type) {
4586c869993eSxy150489 	case DDI_INTR_TYPE_MSIX:
4587c869993eSxy150489 		/* Add interrupt handler for tx + other */
4588da14cebeSEric Cheng 		tx_ring = &igb->tx_rings[0];
4589c869993eSxy150489 		rc = ddi_intr_add_handler(igb->htable[vector],
4590c869993eSxy150489 		    (ddi_intr_handler_t *)igb_intr_tx_other,
4591c869993eSxy150489 		    (void *)igb, NULL);
4592da14cebeSEric Cheng 
4593c869993eSxy150489 		if (rc != DDI_SUCCESS) {
4594*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO,
4595c869993eSxy150489 			    "Add tx/other interrupt handler failed: %d", rc);
4596c869993eSxy150489 			return (IGB_FAILURE);
4597c869993eSxy150489 		}
4598da14cebeSEric Cheng 		tx_ring->intr_vector = vector;
4599c869993eSxy150489 		vector++;
4600c869993eSxy150489 
4601c869993eSxy150489 		/* Add interrupt handler for each rx ring */
4602c869993eSxy150489 		for (i = 0; i < igb->num_rx_rings; i++) {
4603c869993eSxy150489 			rx_ring = &igb->rx_rings[i];
4604c869993eSxy150489 
4605c869993eSxy150489 			rc = ddi_intr_add_handler(igb->htable[vector],
4606c869993eSxy150489 			    (ddi_intr_handler_t *)igb_intr_rx,
4607c869993eSxy150489 			    (void *)rx_ring, NULL);
4608c869993eSxy150489 
4609c869993eSxy150489 			if (rc != DDI_SUCCESS) {
4610*e5513923SYuri Pankov 				igb_log(igb, IGB_LOG_INFO,
4611c869993eSxy150489 				    "Add rx interrupt handler failed. "
4612c869993eSxy150489 				    "return: %d, rx ring: %d", rc, i);
4613c869993eSxy150489 				for (vector--; vector >= 0; vector--) {
4614c869993eSxy150489 					(void) ddi_intr_remove_handler(
4615c869993eSxy150489 					    igb->htable[vector]);
4616c869993eSxy150489 				}
4617c869993eSxy150489 				return (IGB_FAILURE);
4618c869993eSxy150489 			}
4619c869993eSxy150489 
4620c869993eSxy150489 			rx_ring->intr_vector = vector;
4621c869993eSxy150489 
4622c869993eSxy150489 			vector++;
4623c869993eSxy150489 		}
4624da14cebeSEric Cheng 
4625da14cebeSEric Cheng 		/* Add interrupt handler for each tx ring from 2nd ring */
4626da14cebeSEric Cheng 		for (i = 1; i < igb->num_tx_rings; i++) {
4627da14cebeSEric Cheng 			tx_ring = &igb->tx_rings[i];
4628da14cebeSEric Cheng 
4629da14cebeSEric Cheng 			rc = ddi_intr_add_handler(igb->htable[vector],
4630da14cebeSEric Cheng 			    (ddi_intr_handler_t *)igb_intr_tx,
4631da14cebeSEric Cheng 			    (void *)tx_ring, NULL);
4632da14cebeSEric Cheng 
4633da14cebeSEric Cheng 			if (rc != DDI_SUCCESS) {
4634*e5513923SYuri Pankov 				igb_log(igb, IGB_LOG_INFO,
4635da14cebeSEric Cheng 				    "Add tx interrupt handler failed. "
4636da14cebeSEric Cheng 				    "return: %d, tx ring: %d", rc, i);
4637da14cebeSEric Cheng 				for (vector--; vector >= 0; vector--) {
4638da14cebeSEric Cheng 					(void) ddi_intr_remove_handler(
4639da14cebeSEric Cheng 					    igb->htable[vector]);
4640da14cebeSEric Cheng 				}
4641da14cebeSEric Cheng 				return (IGB_FAILURE);
4642da14cebeSEric Cheng 			}
4643da14cebeSEric Cheng 
4644da14cebeSEric Cheng 			tx_ring->intr_vector = vector;
4645da14cebeSEric Cheng 
4646da14cebeSEric Cheng 			vector++;
4647da14cebeSEric Cheng 		}
4648da14cebeSEric Cheng 
4649c869993eSxy150489 		break;
4650c869993eSxy150489 
4651c869993eSxy150489 	case DDI_INTR_TYPE_MSI:
4652c869993eSxy150489 		/* Add interrupt handlers for the only vector */
4653c869993eSxy150489 		rc = ddi_intr_add_handler(igb->htable[vector],
4654c869993eSxy150489 		    (ddi_intr_handler_t *)igb_intr_msi,
4655c869993eSxy150489 		    (void *)igb, NULL);
4656c869993eSxy150489 
4657c869993eSxy150489 		if (rc != DDI_SUCCESS) {
4658*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO,
4659c869993eSxy150489 			    "Add MSI interrupt handler failed: %d", rc);
4660c869993eSxy150489 			return (IGB_FAILURE);
4661c869993eSxy150489 		}
4662c869993eSxy150489 
4663c869993eSxy150489 		rx_ring = &igb->rx_rings[0];
4664c869993eSxy150489 		rx_ring->intr_vector = vector;
4665c869993eSxy150489 
4666c869993eSxy150489 		vector++;
4667c869993eSxy150489 		break;
4668c869993eSxy150489 
4669c869993eSxy150489 	case DDI_INTR_TYPE_FIXED:
4670c869993eSxy150489 		/* Add interrupt handlers for the only vector */
4671c869993eSxy150489 		rc = ddi_intr_add_handler(igb->htable[vector],
4672c869993eSxy150489 		    (ddi_intr_handler_t *)igb_intr_legacy,
4673c869993eSxy150489 		    (void *)igb, NULL);
4674c869993eSxy150489 
4675c869993eSxy150489 		if (rc != DDI_SUCCESS) {
4676*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO,
4677c869993eSxy150489 			    "Add legacy interrupt handler failed: %d", rc);
4678c869993eSxy150489 			return (IGB_FAILURE);
4679c869993eSxy150489 		}
4680c869993eSxy150489 
4681c869993eSxy150489 		rx_ring = &igb->rx_rings[0];
4682c869993eSxy150489 		rx_ring->intr_vector = vector;
4683c869993eSxy150489 
4684c869993eSxy150489 		vector++;
4685c869993eSxy150489 		break;
4686c869993eSxy150489 
4687c869993eSxy150489 	default:
4688c869993eSxy150489 		return (IGB_FAILURE);
4689c869993eSxy150489 	}
4690c869993eSxy150489 
4691c869993eSxy150489 	ASSERT(vector == igb->intr_cnt);
4692c869993eSxy150489 
4693c869993eSxy150489 	return (IGB_SUCCESS);
4694c869993eSxy150489 }
4695c869993eSxy150489 
4696c869993eSxy150489 /*
469780a11ad2Schenlu chen - Sun Microsystems - Beijing China  * igb_setup_msix_82575 - setup 82575 adapter to use MSI-X interrupts
4698c869993eSxy150489  *
4699c869993eSxy150489  * For each vector enabled on the adapter, Set the MSIXBM register accordingly
4700c869993eSxy150489  */
4701c869993eSxy150489 static void
470280a11ad2Schenlu chen - Sun Microsystems - Beijing China igb_setup_msix_82575(igb_t *igb)
4703c869993eSxy150489 {
4704c869993eSxy150489 	uint32_t eims = 0;
4705c869993eSxy150489 	int i, vector;
4706c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
4707c869993eSxy150489 
4708c869993eSxy150489 	/*
470980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * Set vector for tx ring 0 and other causes.
471080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * NOTE assumption that it is vector 0.
4711c869993eSxy150489 	 */
4712c869993eSxy150489 	vector = 0;
4713da14cebeSEric Cheng 
4714c869993eSxy150489 	igb->eims_mask = E1000_EICR_TX_QUEUE0 | E1000_EICR_OTHER;
4715c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_MSIXBM(vector), igb->eims_mask);
4716c869993eSxy150489 	vector++;
4717da14cebeSEric Cheng 
4718c869993eSxy150489 	for (i = 0; i < igb->num_rx_rings; i++) {
4719c869993eSxy150489 		/*
4720c869993eSxy150489 		 * Set vector for each rx ring
4721c869993eSxy150489 		 */
4722c869993eSxy150489 		eims = (E1000_EICR_RX_QUEUE0 << i);
4723c869993eSxy150489 		E1000_WRITE_REG(hw, E1000_MSIXBM(vector), eims);
4724c869993eSxy150489 
4725c869993eSxy150489 		/*
472680a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 * Accumulate bits to enable in
472780a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 * igb_enable_adapter_interrupts_82575()
4728c869993eSxy150489 		 */
4729c869993eSxy150489 		igb->eims_mask |= eims;
4730c869993eSxy150489 
4731c869993eSxy150489 		vector++;
4732c869993eSxy150489 	}
4733c869993eSxy150489 
4734da14cebeSEric Cheng 	for (i = 1; i < igb->num_tx_rings; i++) {
4735da14cebeSEric Cheng 		/*
4736da14cebeSEric Cheng 		 * Set vector for each tx ring from 2nd tx ring
4737da14cebeSEric Cheng 		 */
4738da14cebeSEric Cheng 		eims = (E1000_EICR_TX_QUEUE0 << i);
4739da14cebeSEric Cheng 		E1000_WRITE_REG(hw, E1000_MSIXBM(vector), eims);
4740da14cebeSEric Cheng 
4741da14cebeSEric Cheng 		/*
474280a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 * Accumulate bits to enable in
474380a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 * igb_enable_adapter_interrupts_82575()
4744da14cebeSEric Cheng 		 */
4745da14cebeSEric Cheng 		igb->eims_mask |= eims;
4746da14cebeSEric Cheng 
4747da14cebeSEric Cheng 		vector++;
4748da14cebeSEric Cheng 	}
4749da14cebeSEric Cheng 
4750c869993eSxy150489 	ASSERT(vector == igb->intr_cnt);
4751c869993eSxy150489 
4752c869993eSxy150489 	/*
4753c869993eSxy150489 	 * Disable IAM for ICR interrupt bits
4754c869993eSxy150489 	 */
4755c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_IAM, 0);
4756c869993eSxy150489 	E1000_WRITE_FLUSH(hw);
4757c869993eSxy150489 }
4758c869993eSxy150489 
4759c869993eSxy150489 /*
476080a11ad2Schenlu chen - Sun Microsystems - Beijing China  * igb_setup_msix_82576 - setup 82576 adapter to use MSI-X interrupts
476180a11ad2Schenlu chen - Sun Microsystems - Beijing China  *
476280a11ad2Schenlu chen - Sun Microsystems - Beijing China  * 82576 uses a table based method for assigning vectors.  Each queue has a
476380a11ad2Schenlu chen - Sun Microsystems - Beijing China  * single entry in the table to which we write a vector number along with a
476480a11ad2Schenlu chen - Sun Microsystems - Beijing China  * "valid" bit.  The entry is a single byte in a 4-byte register.  Vectors
476580a11ad2Schenlu chen - Sun Microsystems - Beijing China  * take a different position in the 4-byte register depending on whether
476680a11ad2Schenlu chen - Sun Microsystems - Beijing China  * they are numbered above or below 8.
476780a11ad2Schenlu chen - Sun Microsystems - Beijing China  */
476880a11ad2Schenlu chen - Sun Microsystems - Beijing China static void
476980a11ad2Schenlu chen - Sun Microsystems - Beijing China igb_setup_msix_82576(igb_t *igb)
477080a11ad2Schenlu chen - Sun Microsystems - Beijing China {
477180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	struct e1000_hw *hw = &igb->hw;
477280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	uint32_t ivar, index, vector;
477380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	int i;
477480a11ad2Schenlu chen - Sun Microsystems - Beijing China 
477580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* must enable msi-x capability before IVAR settings */
477680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_GPIE,
477780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	    (E1000_GPIE_MSIX_MODE | E1000_GPIE_PBA | E1000_GPIE_NSICR));
477880a11ad2Schenlu chen - Sun Microsystems - Beijing China 
477980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/*
478080a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * Set vector for tx ring 0 and other causes.
478180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * NOTE assumption that it is vector 0.
478280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * This is also interdependent with installation of interrupt service
478380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 * routines in igb_add_intr_handlers().
478480a11ad2Schenlu chen - Sun Microsystems - Beijing China 	 */
478580a11ad2Schenlu chen - Sun Microsystems - Beijing China 
478680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* assign "other" causes to vector 0 */
478780a11ad2Schenlu chen - Sun Microsystems - Beijing China 	vector = 0;
478880a11ad2Schenlu chen - Sun Microsystems - Beijing China 	ivar = ((vector | E1000_IVAR_VALID) << 8);
478980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_IVAR_MISC, ivar);
479080a11ad2Schenlu chen - Sun Microsystems - Beijing China 
479180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* assign tx ring 0 to vector 0 */
479280a11ad2Schenlu chen - Sun Microsystems - Beijing China 	ivar = ((vector | E1000_IVAR_VALID) << 8);
479380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_IVAR0, ivar);
479480a11ad2Schenlu chen - Sun Microsystems - Beijing China 
479580a11ad2Schenlu chen - Sun Microsystems - Beijing China 	/* prepare to enable tx & other interrupt causes */
479680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	igb->eims_mask = (1 << vector);
479780a11ad2Schenlu chen - Sun Microsystems - Beijing China 
479880a11ad2Schenlu chen - Sun Microsystems - Beijing China 	vector ++;
479980a11ad2Schenlu chen - Sun Microsystems - Beijing China 	for (i = 0; i < igb->num_rx_rings; i++) {
480080a11ad2Schenlu chen - Sun Microsystems - Beijing China 		/*
480180a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 * Set vector for each rx ring
480280a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 */
480380a11ad2Schenlu chen - Sun Microsystems - Beijing China 		index = (i & 0x7);
480480a11ad2Schenlu chen - Sun Microsystems - Beijing China 		ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
480580a11ad2Schenlu chen - Sun Microsystems - Beijing China 
480680a11ad2Schenlu chen - Sun Microsystems - Beijing China 		if (i < 8) {
480780a11ad2Schenlu chen - Sun Microsystems - Beijing China 			/* vector goes into low byte of register */
480880a11ad2Schenlu chen - Sun Microsystems - Beijing China 			ivar = ivar & 0xFFFFFF00;
480980a11ad2Schenlu chen - Sun Microsystems - Beijing China 			ivar |= (vector | E1000_IVAR_VALID);
481080a11ad2Schenlu chen - Sun Microsystems - Beijing China 		} else {
481180a11ad2Schenlu chen - Sun Microsystems - Beijing China 			/* vector goes into third byte of register */
481280a11ad2Schenlu chen - Sun Microsystems - Beijing China 			ivar = ivar & 0xFF00FFFF;
481380a11ad2Schenlu chen - Sun Microsystems - Beijing China 			ivar |= ((vector | E1000_IVAR_VALID) << 16);
481480a11ad2Schenlu chen - Sun Microsystems - Beijing China 		}
481580a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar);
481680a11ad2Schenlu chen - Sun Microsystems - Beijing China 
481780a11ad2Schenlu chen - Sun Microsystems - Beijing China 		/* Accumulate interrupt-cause bits to enable */
481880a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->eims_mask |= (1 << vector);
481980a11ad2Schenlu chen - Sun Microsystems - Beijing China 
482080a11ad2Schenlu chen - Sun Microsystems - Beijing China 		vector ++;
482180a11ad2Schenlu chen - Sun Microsystems - Beijing China 	}
482280a11ad2Schenlu chen - Sun Microsystems - Beijing China 
482380a11ad2Schenlu chen - Sun Microsystems - Beijing China 	for (i = 1; i < igb->num_tx_rings; i++) {
482480a11ad2Schenlu chen - Sun Microsystems - Beijing China 		/*
482580a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 * Set vector for each tx ring from 2nd tx ring.
482680a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 * Note assumption that tx vectors numericall follow rx vectors.
482780a11ad2Schenlu chen - Sun Microsystems - Beijing China 		 */
482880a11ad2Schenlu chen - Sun Microsystems - Beijing China 		index = (i & 0x7);
482980a11ad2Schenlu chen - Sun Microsystems - Beijing China 		ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
483080a11ad2Schenlu chen - Sun Microsystems - Beijing China 
483180a11ad2Schenlu chen - Sun Microsystems - Beijing China 		if (i < 8) {
483280a11ad2Schenlu chen - Sun Microsystems - Beijing China 			/* vector goes into second byte of register */
483380a11ad2Schenlu chen - Sun Microsystems - Beijing China 			ivar = ivar & 0xFFFF00FF;
483480a11ad2Schenlu chen - Sun Microsystems - Beijing China 			ivar |= ((vector | E1000_IVAR_VALID) << 8);
483580a11ad2Schenlu chen - Sun Microsystems - Beijing China 		} else {
483680a11ad2Schenlu chen - Sun Microsystems - Beijing China 			/* vector goes into fourth byte of register */
483780a11ad2Schenlu chen - Sun Microsystems - Beijing China 			ivar = ivar & 0x00FFFFFF;
483880a11ad2Schenlu chen - Sun Microsystems - Beijing China 			ivar |= (vector | E1000_IVAR_VALID) << 24;
483980a11ad2Schenlu chen - Sun Microsystems - Beijing China 		}
484080a11ad2Schenlu chen - Sun Microsystems - Beijing China 		E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar);
484180a11ad2Schenlu chen - Sun Microsystems - Beijing China 
484280a11ad2Schenlu chen - Sun Microsystems - Beijing China 		/* Accumulate interrupt-cause bits to enable */
484380a11ad2Schenlu chen - Sun Microsystems - Beijing China 		igb->eims_mask |= (1 << vector);
484480a11ad2Schenlu chen - Sun Microsystems - Beijing China 
484580a11ad2Schenlu chen - Sun Microsystems - Beijing China 		vector ++;
484680a11ad2Schenlu chen - Sun Microsystems - Beijing China 	}
484780a11ad2Schenlu chen - Sun Microsystems - Beijing China 
484880a11ad2Schenlu chen - Sun Microsystems - Beijing China 	ASSERT(vector == igb->intr_cnt);
484980a11ad2Schenlu chen - Sun Microsystems - Beijing China }
485080a11ad2Schenlu chen - Sun Microsystems - Beijing China 
485180a11ad2Schenlu chen - Sun Microsystems - Beijing China /*
48523f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  * igb_setup_msix_82580 - setup 82580 adapter to use MSI-X interrupts
48533f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  *
48543f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  * 82580 uses same table approach at 82576 but has fewer entries.  Each
48553f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  * queue has a single entry in the table to which we write a vector number
48563f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  * along with a "valid" bit.  Vectors take a different position in the
48573f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  * register depending on * whether * they are numbered above or below 4.
48583f7e60a6Szhefeng xu - Sun Microsystems - Beijing China  */
48593f7e60a6Szhefeng xu - Sun Microsystems - Beijing China static void
48603f7e60a6Szhefeng xu - Sun Microsystems - Beijing China igb_setup_msix_82580(igb_t *igb)
48613f7e60a6Szhefeng xu - Sun Microsystems - Beijing China {
48623f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	struct e1000_hw *hw = &igb->hw;
48633f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	uint32_t ivar, index, vector;
48643f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	int i;
48653f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
48663f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* must enable msi-x capability before IVAR settings */
48673f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_GPIE, (E1000_GPIE_MSIX_MODE |
48683f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	    E1000_GPIE_PBA | E1000_GPIE_NSICR | E1000_GPIE_EIAME));
48693f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/*
48703f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	 * Set vector for tx ring 0 and other causes.
48713f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	 * NOTE assumption that it is vector 0.
48723f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	 * This is also interdependent with installation of interrupt service
48733f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	 * routines in igb_add_intr_handlers().
48743f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	 */
48753f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
48763f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* assign "other" causes to vector 0 */
48773f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	vector = 0;
48783f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	ivar = ((vector | E1000_IVAR_VALID) << 8);
48793f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_IVAR_MISC, ivar);
48803f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
48813f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* assign tx ring 0 to vector 0 */
48823f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	ivar = ((vector | E1000_IVAR_VALID) << 8);
48833f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	E1000_WRITE_REG(hw, E1000_IVAR0, ivar);
48843f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
48853f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	/* prepare to enable tx & other interrupt causes */
48863f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	igb->eims_mask = (1 << vector);
48873f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
48883f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	vector ++;
48893f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
48903f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	for (i = 0; i < igb->num_rx_rings; i++) {
48913f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		/*
48923f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		 * Set vector for each rx ring
48933f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		 */
48943f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		index = (i >> 1);
48953f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
48963f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
48973f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		if (i & 1) {
48983f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			/* vector goes into third byte of register */
48993f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			ivar = ivar & 0xFF00FFFF;
49003f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			ivar |= ((vector | E1000_IVAR_VALID) << 16);
49013f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		} else {
49023f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			/* vector goes into low byte of register */
49033f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			ivar = ivar & 0xFFFFFF00;
49043f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			ivar |= (vector | E1000_IVAR_VALID);
49053f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		}
49063f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar);
49073f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
49083f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		/* Accumulate interrupt-cause bits to enable */
49093f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		igb->eims_mask |= (1 << vector);
49103f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
49113f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		vector ++;
49123f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	}
49133f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
49143f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	for (i = 1; i < igb->num_tx_rings; i++) {
49153f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		/*
49163f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		 * Set vector for each tx ring from 2nd tx ring.
49173f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		 * Note assumption that tx vectors numericall follow rx vectors.
49183f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		 */
49193f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		index = (i >> 1);
49203f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
49213f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
49223f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		if (i & 1) {
49233f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			/* vector goes into high byte of register */
49243f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			ivar = ivar & 0x00FFFFFF;
49253f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			ivar |= ((vector | E1000_IVAR_VALID) << 24);
49263f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		} else {
49273f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			/* vector goes into second byte of register */
49283f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			ivar = ivar & 0xFFFF00FF;
49293f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 			ivar |= (vector | E1000_IVAR_VALID) << 8;
49303f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		}
49313f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar);
49323f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
49333f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		/* Accumulate interrupt-cause bits to enable */
49343f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		igb->eims_mask |= (1 << vector);
49353f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
49363f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 		vector ++;
49373f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	}
49383f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 	ASSERT(vector == igb->intr_cnt);
49393f7e60a6Szhefeng xu - Sun Microsystems - Beijing China }
49403f7e60a6Szhefeng xu - Sun Microsystems - Beijing China 
49413f7e60a6Szhefeng xu - Sun Microsystems - Beijing China /*
4942c869993eSxy150489  * igb_rem_intr_handlers - remove the interrupt handlers
4943c869993eSxy150489  */
4944c869993eSxy150489 static void
4945c869993eSxy150489 igb_rem_intr_handlers(igb_t *igb)
4946c869993eSxy150489 {
4947c869993eSxy150489 	int i;
4948c869993eSxy150489 	int rc;
4949c869993eSxy150489 
4950c869993eSxy150489 	for (i = 0; i < igb->intr_cnt; i++) {
4951c869993eSxy150489 		rc = ddi_intr_remove_handler(igb->htable[i]);
4952c869993eSxy150489 		if (rc != DDI_SUCCESS) {
4953*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO,
4954c869993eSxy150489 			    "Remove intr handler failed: %d", rc);
4955c869993eSxy150489 		}
4956c869993eSxy150489 	}
4957c869993eSxy150489 }
4958c869993eSxy150489 
4959c869993eSxy150489 /*
4960c869993eSxy150489  * igb_rem_intrs - remove the allocated interrupts
4961c869993eSxy150489  */
4962c869993eSxy150489 static void
4963c869993eSxy150489 igb_rem_intrs(igb_t *igb)
4964c869993eSxy150489 {
4965c869993eSxy150489 	int i;
4966c869993eSxy150489 	int rc;
4967c869993eSxy150489 
4968c869993eSxy150489 	for (i = 0; i < igb->intr_cnt; i++) {
4969c869993eSxy150489 		rc = ddi_intr_free(igb->htable[i]);
4970c869993eSxy150489 		if (rc != DDI_SUCCESS) {
4971*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_INFO,
4972c869993eSxy150489 			    "Free intr failed: %d", rc);
4973c869993eSxy150489 		}
4974c869993eSxy150489 	}
4975c869993eSxy150489 
4976c869993eSxy150489 	kmem_free(igb->htable, igb->intr_size);
4977c869993eSxy150489 	igb->htable = NULL;
4978c869993eSxy150489 }
4979c869993eSxy150489 
4980c869993eSxy150489 /*
4981c869993eSxy150489  * igb_enable_intrs - enable all the ddi interrupts
4982c869993eSxy150489  */
4983c869993eSxy150489 static int
4984c869993eSxy150489 igb_enable_intrs(igb_t *igb)
4985c869993eSxy150489 {
4986c869993eSxy150489 	int i;
4987c869993eSxy150489 	int rc;
4988c869993eSxy150489 
4989c869993eSxy150489 	/* Enable interrupts */
4990c869993eSxy150489 	if (igb->intr_cap & DDI_INTR_FLAG_BLOCK) {
4991c869993eSxy150489 		/* Call ddi_intr_block_enable() for MSI */
4992c869993eSxy150489 		rc = ddi_intr_block_enable(igb->htable, igb->intr_cnt);
4993c869993eSxy150489 		if (rc != DDI_SUCCESS) {
4994*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
4995c869993eSxy150489 			    "Enable block intr failed: %d", rc);
4996c869993eSxy150489 			return (IGB_FAILURE);
4997c869993eSxy150489 		}
4998c869993eSxy150489 	} else {
4999c869993eSxy150489 		/* Call ddi_intr_enable() for Legacy/MSI non block enable */
5000c869993eSxy150489 		for (i = 0; i < igb->intr_cnt; i++) {
5001c869993eSxy150489 			rc = ddi_intr_enable(igb->htable[i]);
5002c869993eSxy150489 			if (rc != DDI_SUCCESS) {
5003*e5513923SYuri Pankov 				igb_log(igb, IGB_LOG_ERROR,
5004c869993eSxy150489 				    "Enable intr failed: %d", rc);
5005c869993eSxy150489 				return (IGB_FAILURE);
5006c869993eSxy150489 			}
5007c869993eSxy150489 		}
5008c869993eSxy150489 	}
5009c869993eSxy150489 
5010c869993eSxy150489 	return (IGB_SUCCESS);
5011c869993eSxy150489 }
5012c869993eSxy150489 
5013c869993eSxy150489 /*
5014c869993eSxy150489  * igb_disable_intrs - disable all the ddi interrupts
5015c869993eSxy150489  */
5016c869993eSxy150489 static int
5017c869993eSxy150489 igb_disable_intrs(igb_t *igb)
5018c869993eSxy150489 {
5019c869993eSxy150489 	int i;
5020c869993eSxy150489 	int rc;
5021c869993eSxy150489 
5022c869993eSxy150489 	/* Disable all interrupts */
5023c869993eSxy150489 	if (igb->intr_cap & DDI_INTR_FLAG_BLOCK) {
5024c869993eSxy150489 		rc = ddi_intr_block_disable(igb->htable, igb->intr_cnt);
5025c869993eSxy150489 		if (rc != DDI_SUCCESS) {
5026*e5513923SYuri Pankov 			igb_log(igb, IGB_LOG_ERROR,
5027c869993eSxy150489 			    "Disable block intr failed: %d", rc);
5028c869993eSxy150489 			return (IGB_FAILURE);
5029c869993eSxy150489 		}
5030c869993eSxy150489 	} else {
5031c869993eSxy150489 		for (i = 0; i < igb->intr_cnt; i++) {
5032c869993eSxy150489 			rc = ddi_intr_disable(igb->htable[i]);
5033c869993eSxy150489 			if (rc != DDI_SUCCESS) {
5034*e5513923SYuri Pankov 				igb_log(igb, IGB_LOG_ERROR,
5035c869993eSxy150489 				    "Disable intr failed: %d", rc);
5036c869993eSxy150489 				return (IGB_FAILURE);
5037c869993eSxy150489 			}
5038c869993eSxy150489 		}
5039c869993eSxy150489 	}
5040c869993eSxy150489 
5041c869993eSxy150489 	return (IGB_SUCCESS);
5042c869993eSxy150489 }
5043c869993eSxy150489 
5044c869993eSxy150489 /*
5045c869993eSxy150489  * igb_get_phy_state - Get and save the parameters read from PHY registers
5046c869993eSxy150489  */
5047c869993eSxy150489 static void
5048c869993eSxy150489 igb_get_phy_state(igb_t *igb)
5049c869993eSxy150489 {
5050c869993eSxy150489 	struct e1000_hw *hw = &igb->hw;
5051c869993eSxy150489 	uint16_t phy_ctrl;
5052c869993eSxy150489 	uint16_t phy_status;
5053c869993eSxy150489 	uint16_t phy_an_adv;
5054c869993eSxy150489 	uint16_t phy_an_exp;
5055c869993eSxy150489 	uint16_t phy_ext_status;
5056c869993eSxy150489 	uint16_t phy_1000t_ctrl;
5057c869993eSxy150489 	uint16_t phy_1000t_status;
5058c869993eSxy150489 	uint16_t phy_lp_able;
5059c869993eSxy150489 
5060c869993eSxy150489 	ASSERT(mutex_owned(&igb->gen_lock));
5061c869993eSxy150489 
5062ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	if (hw->phy.media_type == e1000_media_type_copper) {
5063c869993eSxy150489 		(void) e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl);
5064c869993eSxy150489 		(void) e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
5065c869993eSxy150489 		(void) e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_an_adv);
5066c869993eSxy150489 		(void) e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_an_exp);
5067c869993eSxy150489 		(void) e1000_read_phy_reg(hw, PHY_EXT_STATUS, &phy_ext_status);
5068c869993eSxy150489 		(void) e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_1000t_ctrl);
5069ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		(void) e1000_read_phy_reg(hw,
5070ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    PHY_1000T_STATUS, &phy_1000t_status);
5071c869993eSxy150489 		(void) e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_lp_able);
5072c869993eSxy150489 
5073c869993eSxy150489 		igb->param_autoneg_cap =
5074c869993eSxy150489 		    (phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0;
5075c869993eSxy150489 		igb->param_pause_cap =
5076c869993eSxy150489 		    (phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
5077c869993eSxy150489 		igb->param_asym_pause_cap =
5078c869993eSxy150489 		    (phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
5079ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_1000fdx_cap =
5080ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
5081c869993eSxy150489 		    (phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0;
5082ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_1000hdx_cap =
5083ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		    ((phy_ext_status & IEEE_ESR_1000T_HD_CAPS) ||
5084c869993eSxy150489 		    (phy_ext_status & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0;
5085c869993eSxy150489 		igb->param_100t4_cap =
5086c869993eSxy150489 		    (phy_status & MII_SR_100T4_CAPS) ? 1 : 0;
5087c869993eSxy150489 		igb->param_100fdx_cap = ((phy_status & MII_SR_100X_FD_CAPS) ||
5088c869993eSxy150489 		    (phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0;
5089c869993eSxy150489 		igb->param_100hdx_cap = ((phy_status & MII_SR_100X_HD_CAPS) ||
5090c869993eSxy150489 		    (phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0;
5091c869993eSxy150489 		igb->param_10fdx_cap =
5092c869993eSxy150489 		    (phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0;
5093c869993eSxy150489 		igb->param_10hdx_cap =
5094c869993eSxy150489 		    (phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0;
5095c869993eSxy150489 		igb->param_rem_fault =
5096c869993eSxy150489 		    (phy_status & MII_SR_REMOTE_FAULT) ? 1 : 0;
5097c869993eSxy150489 
5098c869993eSxy150489 		igb->param_adv_autoneg_cap = hw->mac.autoneg;
5099c869993eSxy150489 		igb->param_adv_pause_cap =
5100c869993eSxy150489 		    (phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
5101c869993eSxy150489 		igb->param_adv_asym_pause_cap =
5102c869993eSxy150489 		    (phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
5103c869993eSxy150489 		igb->param_adv_1000hdx_cap =
5104c869993eSxy150489 		    (phy_1000t_ctrl & CR_1000T_HD_CAPS) ? 1 : 0;
5105c869993eSxy150489 		igb->param_adv_100t4_cap =
5106c869993eSxy150489 		    (phy_an_adv & NWAY_AR_100T4_CAPS) ? 1 : 0;
5107c869993eSxy150489 		igb->param_adv_rem_fault =
5108c869993eSxy150489 		    (phy_an_adv & NWAY_AR_REMOTE_FAULT) ? 1 : 0;
5109c869993eSxy150489 		if (igb->param_adv_autoneg_cap == 1) {
5110c869993eSxy150489 			igb->param_adv_1000fdx_cap =
5111c869993eSxy150489 			    (phy_1000t_ctrl & CR_1000T_FD_CAPS) ? 1 : 0;
5112c869993eSxy150489 			igb->param_adv_100fdx_cap =
5113c869993eSxy150489 			    (phy_an_adv & NWAY_AR_100TX_FD_CAPS) ? 1 : 0;
5114c869993eSxy150489 			igb->param_adv_100hdx_cap =
5115c869993eSxy150489 			    (phy_an_adv & NWAY_AR_100TX_HD_CAPS) ? 1 : 0;
5116c869993eSxy150489 			igb->param_adv_10fdx_cap =
5117c869993eSxy150489 			    (phy_an_adv & NWAY_AR_10T_FD_CAPS) ? 1 : 0;
5118c869993eSxy150489 			igb->param_adv_10hdx_cap =
5119c869993eSxy150489 			    (phy_an_adv & NWAY_AR_10T_HD_CAPS) ? 1 : 0;
5120c869993eSxy150489 		}
5121c869993eSxy150489 
5122c869993eSxy150489 		igb->param_lp_autoneg_cap =
5123c869993eSxy150489 		    (phy_an_exp & NWAY_ER_LP_NWAY_CAPS) ? 1 : 0;
5124c869993eSxy150489 		igb->param_lp_pause_cap =
5125c869993eSxy150489 		    (phy_lp_able & NWAY_LPAR_PAUSE) ? 1 : 0;
5126c869993eSxy150489 		igb->param_lp_asym_pause_cap =
5127c869993eSxy150489 		    (phy_lp_able & NWAY_LPAR_ASM_DIR) ? 1 : 0;
5128c869993eSxy150489 		igb->param_lp_1000fdx_cap =
5129c869993eSxy150489 		    (phy_1000t_status & SR_1000T_LP_FD_CAPS) ? 1 : 0;
5130c869993eSxy150489 		igb->param_lp_1000hdx_cap =
5131c869993eSxy150489 		    (phy_1000t_status & SR_1000T_LP_HD_CAPS) ? 1 : 0;
5132c869993eSxy150489 		igb->param_lp_100t4_cap =
5133c869993eSxy150489 		    (phy_lp_able & NWAY_LPAR_100T4_CAPS) ? 1 : 0;
5134c869993eSxy150489 		igb->param_lp_100fdx_cap =
5135c869993eSxy150489 		    (phy_lp_able & NWAY_LPAR_100TX_FD_CAPS) ? 1 : 0;
5136c869993eSxy150489 		igb->param_lp_100hdx_cap =
5137c869993eSxy150489 		    (phy_lp_able & NWAY_LPAR_100TX_HD_CAPS) ? 1 : 0;
5138c869993eSxy150489 		igb->param_lp_10fdx_cap =
5139c869993eSxy150489 		    (phy_lp_able & NWAY_LPAR_10T_FD_CAPS) ? 1 : 0;
5140c869993eSxy150489 		igb->param_lp_10hdx_cap =
5141c869993eSxy150489 		    (phy_lp_able & NWAY_LPAR_10T_HD_CAPS) ? 1 : 0;
5142c869993eSxy150489 		igb->param_lp_rem_fault =
5143c869993eSxy150489 		    (phy_lp_able & NWAY_LPAR_REMOTE_FAULT) ? 1 : 0;
5144ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	} else {
5145ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		/*
5146ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		 * 1Gig Fiber adapter only offers 1Gig Full Duplex.
5147ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		 */
5148ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_autoneg_cap = 0;
5149ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_pause_cap = 1;
5150ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_asym_pause_cap = 1;
5151ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_1000fdx_cap = 1;
5152ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_1000hdx_cap = 0;
5153ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_100t4_cap = 0;
5154ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_100fdx_cap = 0;
5155ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_100hdx_cap = 0;
5156ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_10fdx_cap = 0;
5157ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_10hdx_cap = 0;
5158ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
5159ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_autoneg_cap = 0;
5160ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_pause_cap = 1;
5161ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_asym_pause_cap = 1;
5162ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_1000fdx_cap = 1;
5163ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_1000hdx_cap = 0;
5164ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_100t4_cap = 0;
5165ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_100fdx_cap = 0;
5166ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_100hdx_cap = 0;
5167ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_10fdx_cap = 0;
5168ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_adv_10hdx_cap = 0;
5169ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
5170ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_autoneg_cap = 0;
5171ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_pause_cap = 0;
5172ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_asym_pause_cap = 0;
5173ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_1000fdx_cap = 0;
5174ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_1000hdx_cap = 0;
5175ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_100t4_cap = 0;
5176ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_100fdx_cap = 0;
5177ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_100hdx_cap = 0;
5178ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_10fdx_cap = 0;
5179ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_10hdx_cap = 0;
5180ac7f5757Schenlu chen - Sun Microsystems - Beijing China 		igb->param_lp_rem_fault = 0;
5181ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	}
5182ac7f5757Schenlu chen - Sun Microsystems - Beijing China }
5183ac7f5757Schenlu chen - Sun Microsystems - Beijing China 
5184ac7f5757Schenlu chen - Sun Microsystems - Beijing China /*
5185ac7f5757Schenlu chen - Sun Microsystems - Beijing China  * synchronize the adv* and en* parameters.
5186ac7f5757Schenlu chen - Sun Microsystems - Beijing China  *
5187ac7f5757Schenlu chen - Sun Microsystems - Beijing China  * See comments in <sys/dld.h> for details of the *_en_*
5188ac7f5757Schenlu chen - Sun Microsystems - Beijing China  * parameters. The usage of ndd for setting adv parameters will
5189ac7f5757Schenlu chen - Sun Microsystems - Beijing China  * synchronize all the en parameters with the e1000g parameters,
5190ac7f5757Schenlu chen - Sun Microsystems - Beijing China  * implicitly disabling any settings made via dladm.
5191ac7f5757Schenlu chen - Sun Microsystems - Beijing China  */
5192ac7f5757Schenlu chen - Sun Microsystems - Beijing China static void
5193ac7f5757Schenlu chen - Sun Microsystems - Beijing China igb_param_sync(igb_t *igb)
5194ac7f5757Schenlu chen - Sun Microsystems - Beijing China {
5195ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb->param_en_1000fdx_cap = igb->param_adv_1000fdx_cap;
5196ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb->param_en_1000hdx_cap = igb->param_adv_1000hdx_cap;
5197ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb->param_en_100t4_cap = igb->param_adv_100t4_cap;
5198ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb->param_en_100fdx_cap = igb->param_adv_100fdx_cap;
5199ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb->param_en_100hdx_cap = igb->param_adv_100hdx_cap;
5200ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb->param_en_10fdx_cap = igb->param_adv_10fdx_cap;
5201ac7f5757Schenlu chen - Sun Microsystems - Beijing China 	igb->param_en_10hdx_cap = igb->param_adv_10hdx_cap;
5202c869993eSxy150489 }
5203c869993eSxy150489 
5204c869993eSxy150489 /*
5205c869993eSxy150489  * igb_get_driver_control
5206c869993eSxy150489  */
5207c869993eSxy150489 static void
5208c869993eSxy150489 igb_get_driver_control(struct e1000_hw *hw)
5209c869993eSxy150489 {
5210c869993eSxy150489 	uint32_t ctrl_ext;
5211c869993eSxy150489 
5212c869993eSxy150489 	/* Notify firmware that driver is in control of device */
5213c869993eSxy150489 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
5214c869993eSxy150489 	ctrl_ext |= E1000_CTRL_EXT_DRV_LOAD;
5215c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
5216c869993eSxy150489 }
5217c869993eSxy150489 
5218c869993eSxy150489 /*
5219c869993eSxy150489  * igb_release_driver_control
5220c869993eSxy150489  */
5221c869993eSxy150489 static void
5222c869993eSxy150489 igb_release_driver_control(struct e1000_hw *hw)
5223c869993eSxy150489 {
5224c869993eSxy150489 	uint32_t ctrl_ext;
5225c869993eSxy150489 
5226c869993eSxy150489 	/* Notify firmware that driver is no longer in control of device */
5227c869993eSxy150489 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
5228c869993eSxy150489 	ctrl_ext &= ~E1000_CTRL_EXT_DRV_LOAD;
5229c869993eSxy150489 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
5230c869993eSxy150489 }
5231c869993eSxy150489 
5232c869993eSxy150489 /*
5233c869993eSxy150489  * igb_atomic_reserve - Atomic decrease operation
5234c869993eSxy150489  */
5235c869993eSxy150489 int
5236c869993eSxy150489 igb_atomic_reserve(uint32_t *count_p, uint32_t n)
5237c869993eSxy150489 {
5238c869993eSxy150489 	uint32_t oldval;
5239c869993eSxy150489 	uint32_t newval;
5240c869993eSxy150489 
5241c869993eSxy150489 	/* ATOMICALLY */
5242c869993eSxy150489 	do {
5243c869993eSxy150489 		oldval = *count_p;
5244c869993eSxy150489 		if (oldval < n)
5245c869993eSxy150489 			return (-1);
5246c869993eSxy150489 		newval = oldval - n;
5247c869993eSxy150489 	} while (atomic_cas_32(count_p, oldval, newval) != oldval);
5248c869993eSxy150489 
5249c869993eSxy150489 	return (newval);
5250c869993eSxy150489 }
52518bb4b220Sgl147354 
52528bb4b220Sgl147354 /*
52538bb4b220Sgl147354  * FMA support
52548bb4b220Sgl147354  */
52558bb4b220Sgl147354 
52568bb4b220Sgl147354 int
52578bb4b220Sgl147354 igb_check_acc_handle(ddi_acc_handle_t handle)
52588bb4b220Sgl147354 {
52598bb4b220Sgl147354 	ddi_fm_error_t de;
52608bb4b220Sgl147354 
52618bb4b220Sgl147354 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
52628bb4b220Sgl147354 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
52638bb4b220Sgl147354 	return (de.fme_status);
52648bb4b220Sgl147354 }
52658bb4b220Sgl147354 
52668bb4b220Sgl147354 int
52678bb4b220Sgl147354 igb_check_dma_handle(ddi_dma_handle_t handle)
52688bb4b220Sgl147354 {
52698bb4b220Sgl147354 	ddi_fm_error_t de;
52708bb4b220Sgl147354 
52718bb4b220Sgl147354 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
52728bb4b220Sgl147354 	return (de.fme_status);
52738bb4b220Sgl147354 }
52748bb4b220Sgl147354 
52758bb4b220Sgl147354 /*
52768bb4b220Sgl147354  * The IO fault service error handling callback function
52778bb4b220Sgl147354  */
52788bb4b220Sgl147354 /*ARGSUSED*/
52798bb4b220Sgl147354 static int
52808bb4b220Sgl147354 igb_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
52818bb4b220Sgl147354 {
52828bb4b220Sgl147354 	/*
52838bb4b220Sgl147354 	 * as the driver can always deal with an error in any dma or
52848bb4b220Sgl147354 	 * access handle, we can just return the fme_status value.
52858bb4b220Sgl147354 	 */
52868bb4b220Sgl147354 	pci_ereport_post(dip, err, NULL);
52878bb4b220Sgl147354 	return (err->fme_status);
52888bb4b220Sgl147354 }
52898bb4b220Sgl147354 
52908bb4b220Sgl147354 static void
52918bb4b220Sgl147354 igb_fm_init(igb_t *igb)
52928bb4b220Sgl147354 {
52938bb4b220Sgl147354 	ddi_iblock_cookie_t iblk;
5294837c1ac4SStephen Hanson 	int fma_dma_flag;
52958bb4b220Sgl147354 
52968bb4b220Sgl147354 	/* Only register with IO Fault Services if we have some capability */
52978bb4b220Sgl147354 	if (igb->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
52988bb4b220Sgl147354 		igb_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
52998bb4b220Sgl147354 	} else {
53008bb4b220Sgl147354 		igb_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
53018bb4b220Sgl147354 	}
53028bb4b220Sgl147354 
53038bb4b220Sgl147354 	if (igb->fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
53048bb4b220Sgl147354 		fma_dma_flag = 1;
53058bb4b220Sgl147354 	} else {
53068bb4b220Sgl147354 		fma_dma_flag = 0;
53078bb4b220Sgl147354 	}
53088bb4b220Sgl147354 
5309837c1ac4SStephen Hanson 	(void) igb_set_fma_flags(fma_dma_flag);
53108bb4b220Sgl147354 
53118bb4b220Sgl147354 	if (igb->fm_capabilities) {
53128bb4b220Sgl147354 
53138bb4b220Sgl147354 		/* Register capabilities with IO Fault Services */
53148bb4b220Sgl147354 		ddi_fm_init(igb->dip, &igb->fm_capabilities, &iblk);
53158bb4b220Sgl147354 
53168bb4b220Sgl147354 		/*
53178bb4b220Sgl147354 		 * Initialize pci ereport capabilities if ereport capable
53188bb4b220Sgl147354 		 */
53198bb4b220Sgl147354 		if (DDI_FM_EREPORT_CAP(igb->fm_capabilities) ||
53208bb4b220Sgl147354 		    DDI_FM_ERRCB_CAP(igb->fm_capabilities))
53218bb4b220Sgl147354 			pci_ereport_setup(igb->dip);
53228bb4b220Sgl147354 
53238bb4b220Sgl147354 		/*
53248bb4b220Sgl147354 		 * Register error callback if error callback capable
53258bb4b220Sgl147354 		 */
53268bb4b220Sgl147354 		if (DDI_FM_ERRCB_CAP(igb->fm_capabilities))
53278bb4b220Sgl147354 			ddi_fm_handler_register(igb->dip,
53288bb4b220Sgl147354 			    igb_fm_error_cb, (void*) igb);
53298bb4b220Sgl147354 	}
53308bb4b220Sgl147354 }
53318bb4b220Sgl147354 
53328bb4b220Sgl147354 static void
53338bb4b220Sgl147354 igb_fm_fini(igb_t *igb)
53348bb4b220Sgl147354 {
53358bb4b220Sgl147354 	/* Only unregister FMA capabilities if we registered some */
53368bb4b220Sgl147354 	if (igb->fm_capabilities) {
53378bb4b220Sgl147354 
53388bb4b220Sgl147354 		/*
53398bb4b220Sgl147354 		 * Release any resources allocated by pci_ereport_setup()
53408bb4b220Sgl147354 		 */
53418bb4b220Sgl147354 		if (DDI_FM_EREPORT_CAP(igb->fm_capabilities) ||
53428bb4b220Sgl147354 		    DDI_FM_ERRCB_CAP(igb->fm_capabilities))
53438bb4b220Sgl147354 			pci_ereport_teardown(igb->dip);
53448bb4b220Sgl147354 
53458bb4b220Sgl147354 		/*
53468bb4b220Sgl147354 		 * Un-register error callback if error callback capable
53478bb4b220Sgl147354 		 */
53488bb4b220Sgl147354 		if (DDI_FM_ERRCB_CAP(igb->fm_capabilities))
53498bb4b220Sgl147354 			ddi_fm_handler_unregister(igb->dip);
53508bb4b220Sgl147354 
53518bb4b220Sgl147354 		/* Unregister from IO Fault Services */
53528bb4b220Sgl147354 		ddi_fm_fini(igb->dip);
53538bb4b220Sgl147354 	}
53548bb4b220Sgl147354 }
53558bb4b220Sgl147354 
53568bb4b220Sgl147354 void
53578bb4b220Sgl147354 igb_fm_ereport(igb_t *igb, char *detail)
53588bb4b220Sgl147354 {
53598bb4b220Sgl147354 	uint64_t ena;
53608bb4b220Sgl147354 	char buf[FM_MAX_CLASS];
53618bb4b220Sgl147354 
53628bb4b220Sgl147354 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
53638bb4b220Sgl147354 	ena = fm_ena_generate(0, FM_ENA_FMT1);
53648bb4b220Sgl147354 	if (DDI_FM_EREPORT_CAP(igb->fm_capabilities)) {
53658bb4b220Sgl147354 		ddi_fm_ereport_post(igb->dip, buf, ena, DDI_NOSLEEP,
53668bb4b220Sgl147354 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
53678bb4b220Sgl147354 	}
53688bb4b220Sgl147354 }
5369