xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000g_main.c (revision 8949:a41435b42fab)
13526Sxy150489 /*
23526Sxy150489  * This file is provided under a CDDLv1 license.  When using or
33526Sxy150489  * redistributing this file, you may do so under this license.
43526Sxy150489  * In redistributing this file this license must be included
53526Sxy150489  * and no other modification of this header file is permitted.
63526Sxy150489  *
73526Sxy150489  * CDDL LICENSE SUMMARY
83526Sxy150489  *
98479SChenlu.Chen@Sun.COM  * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
103526Sxy150489  *
113526Sxy150489  * The contents of this file are subject to the terms of Version
123526Sxy150489  * 1.0 of the Common Development and Distribution License (the "License").
133526Sxy150489  *
143526Sxy150489  * You should have received a copy of the License with this software.
153526Sxy150489  * You can obtain a copy of the License at
163526Sxy150489  *	http://www.opensolaris.org/os/licensing.
173526Sxy150489  * See the License for the specific language governing permissions
183526Sxy150489  * and limitations under the License.
193526Sxy150489  */
203526Sxy150489 
213526Sxy150489 /*
228479SChenlu.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238118SVasumathi.Sundaram@Sun.COM  * Use is subject to license terms.
243526Sxy150489  */
253526Sxy150489 
263526Sxy150489 /*
273526Sxy150489  * **********************************************************************
283526Sxy150489  *									*
293526Sxy150489  * Module Name:								*
303526Sxy150489  *   e1000g_main.c							*
313526Sxy150489  *									*
323526Sxy150489  * Abstract:								*
334919Sxy150489  *   This file contains the interface routines for the solaris OS.	*
344919Sxy150489  *   It has all DDI entry point routines and GLD entry point routines.	*
353526Sxy150489  *									*
364919Sxy150489  *   This file also contains routines that take care of initialization	*
374919Sxy150489  *   uninit routine and interrupt routine.				*
383526Sxy150489  *									*
393526Sxy150489  * **********************************************************************
403526Sxy150489  */
413526Sxy150489 
423526Sxy150489 #include <sys/dlpi.h>
433526Sxy150489 #include <sys/mac.h>
443526Sxy150489 #include "e1000g_sw.h"
453526Sxy150489 #include "e1000g_debug.h"
463526Sxy150489 
477656SSherry.Moore@Sun.COM static char ident[] = "Intel PRO/1000 Ethernet";
483526Sxy150489 static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection";
49*8949SChangqing.Li@Sun.COM static char e1000g_version[] = "Driver Ver. 5.3.5";
503526Sxy150489 
513526Sxy150489 /*
523526Sxy150489  * Proto types for DDI entry points
533526Sxy150489  */
544919Sxy150489 static int e1000g_attach(dev_info_t *, ddi_attach_cmd_t);
554919Sxy150489 static int e1000g_detach(dev_info_t *, ddi_detach_cmd_t);
567656SSherry.Moore@Sun.COM static int e1000g_quiesce(dev_info_t *);
573526Sxy150489 
583526Sxy150489 /*
593526Sxy150489  * init and intr routines prototype
603526Sxy150489  */
614919Sxy150489 static int e1000g_resume(dev_info_t *);
624919Sxy150489 static int e1000g_suspend(dev_info_t *);
633526Sxy150489 static uint_t e1000g_intr_pciexpress(caddr_t);
643526Sxy150489 static uint_t e1000g_intr(caddr_t);
653526Sxy150489 static void e1000g_intr_work(struct e1000g *, uint32_t);
663526Sxy150489 #pragma inline(e1000g_intr_work)
673526Sxy150489 static int e1000g_init(struct e1000g *);
684919Sxy150489 static int e1000g_start(struct e1000g *, boolean_t);
694919Sxy150489 static void e1000g_stop(struct e1000g *, boolean_t);
703526Sxy150489 static int e1000g_m_start(void *);
713526Sxy150489 static void e1000g_m_stop(void *);
723526Sxy150489 static int e1000g_m_promisc(void *, boolean_t);
733526Sxy150489 static boolean_t e1000g_m_getcapab(void *, mac_capab_t, void *);
743526Sxy150489 static int e1000g_m_multicst(void *, boolean_t, const uint8_t *);
753526Sxy150489 static void e1000g_m_ioctl(void *, queue_t *, mblk_t *);
766394Scc210113 static int e1000g_m_setprop(void *, const char *, mac_prop_id_t,
776394Scc210113     uint_t, const void *);
786394Scc210113 static int e1000g_m_getprop(void *, const char *, mac_prop_id_t,
798118SVasumathi.Sundaram@Sun.COM     uint_t, uint_t, void *, uint_t *);
806394Scc210113 static int e1000g_set_priv_prop(struct e1000g *, const char *, uint_t,
816394Scc210113     const void *);
826394Scc210113 static int e1000g_get_priv_prop(struct e1000g *, const char *, uint_t,
838118SVasumathi.Sundaram@Sun.COM     uint_t, void *, uint_t *);
844919Sxy150489 static void e1000g_init_locks(struct e1000g *);
854919Sxy150489 static void e1000g_destroy_locks(struct e1000g *);
864919Sxy150489 static int e1000g_identify_hardware(struct e1000g *);
874919Sxy150489 static int e1000g_regs_map(struct e1000g *);
884919Sxy150489 static int e1000g_set_driver_params(struct e1000g *);
896394Scc210113 static void e1000g_set_bufsize(struct e1000g *);
904919Sxy150489 static int e1000g_register_mac(struct e1000g *);
914919Sxy150489 static boolean_t e1000g_rx_drain(struct e1000g *);
924919Sxy150489 static boolean_t e1000g_tx_drain(struct e1000g *);
934919Sxy150489 static void e1000g_init_unicst(struct e1000g *);
948275SEric Cheng static int e1000g_unicst_set(struct e1000g *, const uint8_t *, int);
958850SMin.Xu@Sun.COM static int e1000g_alloc_rx_data(struct e1000g *);
963526Sxy150489 
973526Sxy150489 /*
983526Sxy150489  * Local routines
993526Sxy150489  */
1007656SSherry.Moore@Sun.COM static boolean_t e1000g_reset_adapter(struct e1000g *);
1014919Sxy150489 static void e1000g_tx_clean(struct e1000g *);
1024919Sxy150489 static void e1000g_rx_clean(struct e1000g *);
1034061Sxy150489 static void e1000g_link_timer(void *);
1044919Sxy150489 static void e1000g_local_timer(void *);
1054061Sxy150489 static boolean_t e1000g_link_check(struct e1000g *);
1063526Sxy150489 static boolean_t e1000g_stall_check(struct e1000g *);
1073526Sxy150489 static void e1000g_smartspeed(struct e1000g *);
1084919Sxy150489 static void e1000g_get_conf(struct e1000g *);
1094919Sxy150489 static int e1000g_get_prop(struct e1000g *, char *, int, int, int);
1104919Sxy150489 static void enable_watchdog_timer(struct e1000g *);
1114919Sxy150489 static void disable_watchdog_timer(struct e1000g *);
1124919Sxy150489 static void start_watchdog_timer(struct e1000g *);
1134919Sxy150489 static void restart_watchdog_timer(struct e1000g *);
1144919Sxy150489 static void stop_watchdog_timer(struct e1000g *);
1154919Sxy150489 static void stop_link_timer(struct e1000g *);
1164919Sxy150489 static void stop_82547_timer(e1000g_tx_ring_t *);
1174919Sxy150489 static void e1000g_force_speed_duplex(struct e1000g *);
1184919Sxy150489 static void e1000g_get_max_frame_size(struct e1000g *);
1194919Sxy150489 static boolean_t is_valid_mac_addr(uint8_t *);
1203526Sxy150489 static void e1000g_unattach(dev_info_t *, struct e1000g *);
1214919Sxy150489 #ifdef E1000G_DEBUG
1224919Sxy150489 static void e1000g_ioc_peek_reg(struct e1000g *, e1000g_peekpoke_t *);
1234919Sxy150489 static void e1000g_ioc_poke_reg(struct e1000g *, e1000g_peekpoke_t *);
1244919Sxy150489 static void e1000g_ioc_peek_mem(struct e1000g *, e1000g_peekpoke_t *);
1254919Sxy150489 static void e1000g_ioc_poke_mem(struct e1000g *, e1000g_peekpoke_t *);
1264919Sxy150489 static enum ioc_reply e1000g_pp_ioctl(struct e1000g *,
1274919Sxy150489     struct iocblk *, mblk_t *);
1284919Sxy150489 #endif
1294919Sxy150489 static enum ioc_reply e1000g_loopback_ioctl(struct e1000g *,
1304919Sxy150489     struct iocblk *, mblk_t *);
1317133Scc210113 static boolean_t e1000g_check_loopback_support(struct e1000_hw *);
1324919Sxy150489 static boolean_t e1000g_set_loopback_mode(struct e1000g *, uint32_t);
1334919Sxy150489 static void e1000g_set_internal_loopback(struct e1000g *);
1344919Sxy150489 static void e1000g_set_external_loopback_1000(struct e1000g *);
1354919Sxy150489 static void e1000g_set_external_loopback_100(struct e1000g *);
1364919Sxy150489 static void e1000g_set_external_loopback_10(struct e1000g *);
1374919Sxy150489 static int e1000g_add_intrs(struct e1000g *);
1384919Sxy150489 static int e1000g_intr_add(struct e1000g *, int);
1394919Sxy150489 static int e1000g_rem_intrs(struct e1000g *);
1404919Sxy150489 static int e1000g_enable_intrs(struct e1000g *);
1414919Sxy150489 static int e1000g_disable_intrs(struct e1000g *);
1424919Sxy150489 static boolean_t e1000g_link_up(struct e1000g *);
1433526Sxy150489 #ifdef __sparc
1444919Sxy150489 static boolean_t e1000g_find_mac_address(struct e1000g *);
1453526Sxy150489 #endif
1465082Syy150190 static void e1000g_get_phy_state(struct e1000g *);
1475273Sgl147354 static int e1000g_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
1485273Sgl147354     const void *impl_data);
1495273Sgl147354 static void e1000g_fm_init(struct e1000g *Adapter);
1505273Sgl147354 static void e1000g_fm_fini(struct e1000g *Adapter);
1516512Ssowmini static int e1000g_get_def_val(struct e1000g *, mac_prop_id_t, uint_t, void *);
1526512Ssowmini static void e1000g_param_sync(struct e1000g *);
1537607STed.You@Sun.COM static void e1000g_get_driver_control(struct e1000_hw *);
1547607STed.You@Sun.COM static void e1000g_release_driver_control(struct e1000_hw *);
1557722SShuguo.Yang@Sun.COM static void e1000g_restore_promisc(struct e1000g *Adapter);
1566512Ssowmini 
1576512Ssowmini mac_priv_prop_t e1000g_priv_props[] = {
1586512Ssowmini 	{"_tx_bcopy_threshold", MAC_PROP_PERM_RW},
1596512Ssowmini 	{"_tx_interrupt_enable", MAC_PROP_PERM_RW},
1606512Ssowmini 	{"_tx_intr_delay", MAC_PROP_PERM_RW},
1616512Ssowmini 	{"_tx_intr_abs_delay", MAC_PROP_PERM_RW},
1626512Ssowmini 	{"_rx_bcopy_threshold", MAC_PROP_PERM_RW},
1636512Ssowmini 	{"_max_num_rcv_packets", MAC_PROP_PERM_RW},
1646512Ssowmini 	{"_rx_intr_delay", MAC_PROP_PERM_RW},
1656512Ssowmini 	{"_rx_intr_abs_delay", MAC_PROP_PERM_RW},
1666512Ssowmini 	{"_intr_throttling_rate", MAC_PROP_PERM_RW},
1676512Ssowmini 	{"_intr_adaptive", MAC_PROP_PERM_RW},
1686512Ssowmini 	{"_adv_pause_cap", MAC_PROP_PERM_READ},
1696512Ssowmini 	{"_adv_asym_pause_cap", MAC_PROP_PERM_READ},
1706512Ssowmini };
1716512Ssowmini #define	E1000G_MAX_PRIV_PROPS	\
1726512Ssowmini 	(sizeof (e1000g_priv_props)/sizeof (mac_priv_prop_t))
1736512Ssowmini 
1743526Sxy150489 
1753526Sxy150489 static struct cb_ops cb_ws_ops = {
1763526Sxy150489 	nulldev,		/* cb_open */
1773526Sxy150489 	nulldev,		/* cb_close */
1783526Sxy150489 	nodev,			/* cb_strategy */
1793526Sxy150489 	nodev,			/* cb_print */
1803526Sxy150489 	nodev,			/* cb_dump */
1813526Sxy150489 	nodev,			/* cb_read */
1823526Sxy150489 	nodev,			/* cb_write */
1833526Sxy150489 	nodev,			/* cb_ioctl */
1843526Sxy150489 	nodev,			/* cb_devmap */
1853526Sxy150489 	nodev,			/* cb_mmap */
1863526Sxy150489 	nodev,			/* cb_segmap */
1873526Sxy150489 	nochpoll,		/* cb_chpoll */
1883526Sxy150489 	ddi_prop_op,		/* cb_prop_op */
1893526Sxy150489 	NULL,			/* cb_stream */
1903526Sxy150489 	D_MP | D_HOTPLUG,	/* cb_flag */
1913526Sxy150489 	CB_REV,			/* cb_rev */
1923526Sxy150489 	nodev,			/* cb_aread */
1933526Sxy150489 	nodev			/* cb_awrite */
1943526Sxy150489 };
1953526Sxy150489 
1963526Sxy150489 static struct dev_ops ws_ops = {
1973526Sxy150489 	DEVO_REV,		/* devo_rev */
1983526Sxy150489 	0,			/* devo_refcnt */
1993526Sxy150489 	NULL,			/* devo_getinfo */
2003526Sxy150489 	nulldev,		/* devo_identify */
2013526Sxy150489 	nulldev,		/* devo_probe */
2024919Sxy150489 	e1000g_attach,		/* devo_attach */
2034919Sxy150489 	e1000g_detach,		/* devo_detach */
2043526Sxy150489 	nodev,			/* devo_reset */
2053526Sxy150489 	&cb_ws_ops,		/* devo_cb_ops */
2063526Sxy150489 	NULL,			/* devo_bus_ops */
2077656SSherry.Moore@Sun.COM 	ddi_power,		/* devo_power */
2087656SSherry.Moore@Sun.COM 	e1000g_quiesce		/* devo_quiesce */
2093526Sxy150489 };
2103526Sxy150489 
2113526Sxy150489 static struct modldrv modldrv = {
2123526Sxy150489 	&mod_driverops,		/* Type of module.  This one is a driver */
2133526Sxy150489 	ident,			/* Discription string */
2143526Sxy150489 	&ws_ops,		/* driver ops */
2153526Sxy150489 };
2163526Sxy150489 
2173526Sxy150489 static struct modlinkage modlinkage = {
2183526Sxy150489 	MODREV_1, &modldrv, NULL
2193526Sxy150489 };
2203526Sxy150489 
2214919Sxy150489 /* Access attributes for register mapping */
2224919Sxy150489 static ddi_device_acc_attr_t e1000g_regs_acc_attr = {
2233526Sxy150489 	DDI_DEVICE_ATTR_V0,
2243526Sxy150489 	DDI_STRUCTURE_LE_ACC,
2253526Sxy150489 	DDI_STRICTORDER_ACC,
2265273Sgl147354 	DDI_FLAGERR_ACC
2273526Sxy150489 };
2283526Sxy150489 
2296394Scc210113 #define	E1000G_M_CALLBACK_FLAGS \
2306394Scc210113 	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
2313526Sxy150489 
2323526Sxy150489 static mac_callbacks_t e1000g_m_callbacks = {
2333526Sxy150489 	E1000G_M_CALLBACK_FLAGS,
2343526Sxy150489 	e1000g_m_stat,
2353526Sxy150489 	e1000g_m_start,
2363526Sxy150489 	e1000g_m_stop,
2373526Sxy150489 	e1000g_m_promisc,
2383526Sxy150489 	e1000g_m_multicst,
2398275SEric Cheng 	NULL,
2403526Sxy150489 	e1000g_m_tx,
2413526Sxy150489 	e1000g_m_ioctl,
2426394Scc210113 	e1000g_m_getcapab,
2436394Scc210113 	NULL,
2446394Scc210113 	NULL,
2456394Scc210113 	e1000g_m_setprop,
2466394Scc210113 	e1000g_m_getprop
2473526Sxy150489 };
2483526Sxy150489 
2493526Sxy150489 /*
2503526Sxy150489  * Global variables
2513526Sxy150489  */
2523526Sxy150489 uint32_t e1000g_mblks_pending = 0;
2533526Sxy150489 /*
2544894Syy150190  * Workaround for Dynamic Reconfiguration support, for x86 platform only.
2554349Sxy150489  * Here we maintain a private dev_info list if e1000g_force_detach is
2564349Sxy150489  * enabled. If we force the driver to detach while there are still some
2574349Sxy150489  * rx buffers retained in the upper layer, we have to keep a copy of the
2584349Sxy150489  * dev_info. In some cases (Dynamic Reconfiguration), the dev_info data
2594349Sxy150489  * structure will be freed after the driver is detached. However when we
2604349Sxy150489  * finally free those rx buffers released by the upper layer, we need to
2614349Sxy150489  * refer to the dev_info to free the dma buffers. So we save a copy of
2624894Syy150190  * the dev_info for this purpose. On x86 platform, we assume this copy
2634894Syy150190  * of dev_info is always valid, but on SPARC platform, it could be invalid
2644894Syy150190  * after the system board level DR operation. For this reason, the global
2654894Syy150190  * variable e1000g_force_detach must be B_FALSE on SPARC platform.
2664349Sxy150489  */
2674894Syy150190 #ifdef __sparc
2684894Syy150190 boolean_t e1000g_force_detach = B_FALSE;
2694894Syy150190 #else
2704894Syy150190 boolean_t e1000g_force_detach = B_TRUE;
2714894Syy150190 #endif
2724349Sxy150489 private_devi_list_t *e1000g_private_devi_list = NULL;
2734894Syy150190 
2744349Sxy150489 /*
2758850SMin.Xu@Sun.COM  * The mutex e1000g_rx_detach_lock is defined to protect the processing of
2768850SMin.Xu@Sun.COM  * the private dev_info list, and to serialize the processing of rx buffer
2778850SMin.Xu@Sun.COM  * freeing and rx buffer recycling.
2783526Sxy150489  */
2798850SMin.Xu@Sun.COM kmutex_t e1000g_rx_detach_lock;
2803526Sxy150489 /*
2813526Sxy150489  * The rwlock e1000g_dma_type_lock is defined to protect the global flag
2823526Sxy150489  * e1000g_dma_type. For SPARC, the initial value of the flag is "USE_DVMA".
2833526Sxy150489  * If there are many e1000g instances, the system may run out of DVMA
2843526Sxy150489  * resources during the initialization of the instances, then the flag will
2853526Sxy150489  * be changed to "USE_DMA". Because different e1000g instances are initialized
2863526Sxy150489  * in parallel, we need to use this lock to protect the flag.
2873526Sxy150489  */
2883526Sxy150489 krwlock_t e1000g_dma_type_lock;
2893526Sxy150489 
2907133Scc210113 /*
2917133Scc210113  * The 82546 chipset is a dual-port device, both the ports share one eeprom.
2927133Scc210113  * Based on the information from Intel, the 82546 chipset has some hardware
2937133Scc210113  * problem. When one port is being reset and the other port is trying to
2947133Scc210113  * access the eeprom, it could cause system hang or panic. To workaround this
2957133Scc210113  * hardware problem, we use a global mutex to prevent such operations from
2967133Scc210113  * happening simultaneously on different instances. This workaround is applied
2977133Scc210113  * to all the devices supported by this driver.
2987133Scc210113  */
2997133Scc210113 kmutex_t e1000g_nvm_lock;
3003526Sxy150489 
3013526Sxy150489 /*
3023526Sxy150489  * Loadable module configuration entry points for the driver
3033526Sxy150489  */
3043526Sxy150489 
3053526Sxy150489 /*
3064919Sxy150489  * _init - module initialization
3073526Sxy150489  */
3083526Sxy150489 int
3093526Sxy150489 _init(void)
3103526Sxy150489 {
3113526Sxy150489 	int status;
3123526Sxy150489 
3133526Sxy150489 	mac_init_ops(&ws_ops, WSNAME);
3143526Sxy150489 	status = mod_install(&modlinkage);
3153526Sxy150489 	if (status != DDI_SUCCESS)
3163526Sxy150489 		mac_fini_ops(&ws_ops);
3173526Sxy150489 	else {
3188850SMin.Xu@Sun.COM 		mutex_init(&e1000g_rx_detach_lock, NULL, MUTEX_DRIVER, NULL);
3193526Sxy150489 		rw_init(&e1000g_dma_type_lock, NULL, RW_DRIVER, NULL);
3207133Scc210113 		mutex_init(&e1000g_nvm_lock, NULL, MUTEX_DRIVER, NULL);
3213526Sxy150489 	}
3223526Sxy150489 
3233526Sxy150489 	return (status);
3243526Sxy150489 }
3253526Sxy150489 
3263526Sxy150489 /*
3274919Sxy150489  * _fini - module finalization
3283526Sxy150489  */
3293526Sxy150489 int
3303526Sxy150489 _fini(void)
3313526Sxy150489 {
3323526Sxy150489 	int status;
3333526Sxy150489 
3348850SMin.Xu@Sun.COM 	if (e1000g_mblks_pending != 0)
3353526Sxy150489 		return (EBUSY);
3363526Sxy150489 
3373526Sxy150489 	status = mod_remove(&modlinkage);
3383526Sxy150489 	if (status == DDI_SUCCESS) {
3393526Sxy150489 		mac_fini_ops(&ws_ops);
3404349Sxy150489 
3414349Sxy150489 		if (e1000g_force_detach) {
3424349Sxy150489 			private_devi_list_t *devi_node;
3434349Sxy150489 
3448850SMin.Xu@Sun.COM 			mutex_enter(&e1000g_rx_detach_lock);
3454349Sxy150489 			while (e1000g_private_devi_list != NULL) {
3464349Sxy150489 				devi_node = e1000g_private_devi_list;
3474349Sxy150489 				e1000g_private_devi_list =
3484349Sxy150489 				    e1000g_private_devi_list->next;
3494349Sxy150489 
3504349Sxy150489 				kmem_free(devi_node->priv_dip,
3514349Sxy150489 				    sizeof (struct dev_info));
3524349Sxy150489 				kmem_free(devi_node,
3534349Sxy150489 				    sizeof (private_devi_list_t));
3544349Sxy150489 			}
3558850SMin.Xu@Sun.COM 			mutex_exit(&e1000g_rx_detach_lock);
3564349Sxy150489 		}
3574349Sxy150489 
3588850SMin.Xu@Sun.COM 		mutex_destroy(&e1000g_rx_detach_lock);
3593526Sxy150489 		rw_destroy(&e1000g_dma_type_lock);
3607133Scc210113 		mutex_destroy(&e1000g_nvm_lock);
3613526Sxy150489 	}
3623526Sxy150489 
3633526Sxy150489 	return (status);
3643526Sxy150489 }
3653526Sxy150489 
3663526Sxy150489 /*
3674919Sxy150489  * _info - module information
3683526Sxy150489  */
3693526Sxy150489 int
3703526Sxy150489 _info(struct modinfo *modinfop)
3713526Sxy150489 {
3723526Sxy150489 	return (mod_info(&modlinkage, modinfop));
3733526Sxy150489 }
3743526Sxy150489 
3753526Sxy150489 /*
3764919Sxy150489  * e1000g_attach - driver attach
3774919Sxy150489  *
3784919Sxy150489  * This function is the device-specific initialization entry
3794919Sxy150489  * point. This entry point is required and must be written.
3804919Sxy150489  * The DDI_ATTACH command must be provided in the attach entry
3814919Sxy150489  * point. When attach() is called with cmd set to DDI_ATTACH,
3824919Sxy150489  * all normal kernel services (such as kmem_alloc(9F)) are
3834919Sxy150489  * available for use by the driver.
3844919Sxy150489  *
3854919Sxy150489  * The attach() function will be called once for each instance
3864919Sxy150489  * of  the  device  on  the  system with cmd set to DDI_ATTACH.
3874919Sxy150489  * Until attach() succeeds, the only driver entry points which
3884919Sxy150489  * may be called are open(9E) and getinfo(9E).
3893526Sxy150489  */
3903526Sxy150489 static int
3914919Sxy150489 e1000g_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3923526Sxy150489 {
3933526Sxy150489 	struct e1000g *Adapter;
3943526Sxy150489 	struct e1000_hw *hw;
3954919Sxy150489 	struct e1000g_osdep *osdep;
3963526Sxy150489 	int instance;
3973526Sxy150489 
3983526Sxy150489 	switch (cmd) {
3993526Sxy150489 	default:
4003526Sxy150489 		e1000g_log(NULL, CE_WARN,
4014919Sxy150489 		    "Unsupported command send to e1000g_attach... ");
4023526Sxy150489 		return (DDI_FAILURE);
4033526Sxy150489 
4043526Sxy150489 	case DDI_RESUME:
4053526Sxy150489 		return (e1000g_resume(devinfo));
4063526Sxy150489 
4073526Sxy150489 	case DDI_ATTACH:
4083526Sxy150489 		break;
4093526Sxy150489 	}
4103526Sxy150489 
4113526Sxy150489 	/*
4123526Sxy150489 	 * get device instance number
4133526Sxy150489 	 */
4143526Sxy150489 	instance = ddi_get_instance(devinfo);
4153526Sxy150489 
4163526Sxy150489 	/*
4173526Sxy150489 	 * Allocate soft data structure
4183526Sxy150489 	 */
4193526Sxy150489 	Adapter =
4203526Sxy150489 	    (struct e1000g *)kmem_zalloc(sizeof (*Adapter), KM_SLEEP);
4213526Sxy150489 
4223526Sxy150489 	Adapter->dip = devinfo;
4234919Sxy150489 	Adapter->instance = instance;
4243526Sxy150489 	Adapter->tx_ring->adapter = Adapter;
4253526Sxy150489 	Adapter->rx_ring->adapter = Adapter;
4263526Sxy150489 
4274919Sxy150489 	hw = &Adapter->shared;
4284919Sxy150489 	osdep = &Adapter->osdep;
4294919Sxy150489 	hw->back = osdep;
4304919Sxy150489 	osdep->adapter = Adapter;
4314919Sxy150489 
4323526Sxy150489 	ddi_set_driver_private(devinfo, (caddr_t)Adapter);
4333526Sxy150489 
4344919Sxy150489 	/*
4355273Sgl147354 	 * Initialize for fma support
4365273Sgl147354 	 */
4375273Sgl147354 	Adapter->fm_capabilities = e1000g_get_prop(Adapter, "fm-capable",
4385273Sgl147354 	    0, 0x0f,
4395273Sgl147354 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
4405273Sgl147354 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
4415273Sgl147354 	e1000g_fm_init(Adapter);
4425273Sgl147354 	Adapter->attach_progress |= ATTACH_PROGRESS_FMINIT;
4435273Sgl147354 
4445273Sgl147354 	/*
4454919Sxy150489 	 * PCI Configure
4464919Sxy150489 	 */
4474919Sxy150489 	if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
4484919Sxy150489 		e1000g_log(Adapter, CE_WARN, "PCI configuration failed");
4494919Sxy150489 		goto attach_fail;
4504919Sxy150489 	}
4514919Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
4524919Sxy150489 
4534919Sxy150489 	/*
4544919Sxy150489 	 * Setup hardware
4554919Sxy150489 	 */
4564919Sxy150489 	if (e1000g_identify_hardware(Adapter) != DDI_SUCCESS) {
4574919Sxy150489 		e1000g_log(Adapter, CE_WARN, "Identify hardware failed");
4584919Sxy150489 		goto attach_fail;
4594919Sxy150489 	}
4603526Sxy150489 
4613526Sxy150489 	/*
4623526Sxy150489 	 * Map in the device registers.
4633526Sxy150489 	 */
4644919Sxy150489 	if (e1000g_regs_map(Adapter) != DDI_SUCCESS) {
4654919Sxy150489 		e1000g_log(Adapter, CE_WARN, "Mapping registers failed");
4663526Sxy150489 		goto attach_fail;
4673526Sxy150489 	}
4684919Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_REGS_MAP;
4693526Sxy150489 
4703526Sxy150489 	/*
4713526Sxy150489 	 * Initialize driver parameters
4723526Sxy150489 	 */
4733526Sxy150489 	if (e1000g_set_driver_params(Adapter) != DDI_SUCCESS) {
4743526Sxy150489 		goto attach_fail;
4753526Sxy150489 	}
4764919Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_SETUP;
4773526Sxy150489 
4785273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.cfg_handle) != DDI_FM_OK) {
4795273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST);
4805273Sgl147354 		goto attach_fail;
4815273Sgl147354 	}
4825273Sgl147354 
4833526Sxy150489 	/*
4843526Sxy150489 	 * Initialize interrupts
4853526Sxy150489 	 */
4863526Sxy150489 	if (e1000g_add_intrs(Adapter) != DDI_SUCCESS) {
4873526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Add interrupts failed");
4883526Sxy150489 		goto attach_fail;
4893526Sxy150489 	}
4904919Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
4913526Sxy150489 
4923526Sxy150489 	/*
4933526Sxy150489 	 * Initialize mutex's for this device.
4943526Sxy150489 	 * Do this before enabling the interrupt handler and
4953526Sxy150489 	 * register the softint to avoid the condition where
4963526Sxy150489 	 * interrupt handler can try using uninitialized mutex
4973526Sxy150489 	 */
4983526Sxy150489 	e1000g_init_locks(Adapter);
4993526Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_LOCKS;
5003526Sxy150489 
5013526Sxy150489 	/*
5023526Sxy150489 	 * Initialize Driver Counters
5033526Sxy150489 	 */
5044919Sxy150489 	if (e1000g_init_stats(Adapter) != DDI_SUCCESS) {
5053526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Init stats failed");
5063526Sxy150489 		goto attach_fail;
5073526Sxy150489 	}
5083526Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_KSTATS;
5093526Sxy150489 
5103526Sxy150489 	/*
5113526Sxy150489 	 * Initialize chip hardware and software structures
5123526Sxy150489 	 */
5138479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
5143526Sxy150489 	if (e1000g_init(Adapter) != DDI_SUCCESS) {
5158479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
5163526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Adapter initialization failed");
5173526Sxy150489 		goto attach_fail;
5183526Sxy150489 	}
5198479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
5203526Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_INIT;
5213526Sxy150489 
5223526Sxy150489 	/*
5233526Sxy150489 	 * Register the driver to the MAC
5243526Sxy150489 	 */
5253526Sxy150489 	if (e1000g_register_mac(Adapter) != DDI_SUCCESS) {
5263526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Register MAC failed");
5273526Sxy150489 		goto attach_fail;
5283526Sxy150489 	}
5294919Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_MAC;
5303526Sxy150489 
5313526Sxy150489 	/*
5323526Sxy150489 	 * Now that mutex locks are initialized, and the chip is also
5333526Sxy150489 	 * initialized, enable interrupts.
5343526Sxy150489 	 */
5353526Sxy150489 	if (e1000g_enable_intrs(Adapter) != DDI_SUCCESS) {
5363526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Enable DDI interrupts failed");
5373526Sxy150489 		goto attach_fail;
5383526Sxy150489 	}
5394919Sxy150489 	Adapter->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
5403526Sxy150489 
5414982Syy150190 	/*
5424982Syy150190 	 * If e1000g_force_detach is enabled, in global private dip list,
5434982Syy150190 	 * we will create a new entry, which maintains the priv_dip for DR
5444982Syy150190 	 * supports after driver detached.
5454982Syy150190 	 */
5464982Syy150190 	if (e1000g_force_detach) {
5474982Syy150190 		private_devi_list_t *devi_node;
5484982Syy150190 
5494982Syy150190 		Adapter->priv_dip =
5504982Syy150190 		    kmem_zalloc(sizeof (struct dev_info), KM_SLEEP);
5514982Syy150190 		bcopy(DEVI(devinfo), DEVI(Adapter->priv_dip),
5524982Syy150190 		    sizeof (struct dev_info));
5534982Syy150190 
5544982Syy150190 		devi_node =
5554982Syy150190 		    kmem_zalloc(sizeof (private_devi_list_t), KM_SLEEP);
5564982Syy150190 
5578850SMin.Xu@Sun.COM 		mutex_enter(&e1000g_rx_detach_lock);
5584982Syy150190 		devi_node->priv_dip = Adapter->priv_dip;
5594982Syy150190 		devi_node->flag = E1000G_PRIV_DEVI_ATTACH;
5608850SMin.Xu@Sun.COM 		devi_node->pending_rx_count = 0;
5618850SMin.Xu@Sun.COM 
5628850SMin.Xu@Sun.COM 		Adapter->priv_devi_node = devi_node;
5638850SMin.Xu@Sun.COM 
5648850SMin.Xu@Sun.COM 		if (e1000g_private_devi_list == NULL) {
5658850SMin.Xu@Sun.COM 			devi_node->prev = NULL;
5668850SMin.Xu@Sun.COM 			devi_node->next = NULL;
5678850SMin.Xu@Sun.COM 			e1000g_private_devi_list = devi_node;
5688850SMin.Xu@Sun.COM 		} else {
5698850SMin.Xu@Sun.COM 			devi_node->prev = NULL;
5708850SMin.Xu@Sun.COM 			devi_node->next = e1000g_private_devi_list;
5718850SMin.Xu@Sun.COM 			e1000g_private_devi_list->prev = devi_node;
5728850SMin.Xu@Sun.COM 			e1000g_private_devi_list = devi_node;
5738850SMin.Xu@Sun.COM 		}
5748850SMin.Xu@Sun.COM 		mutex_exit(&e1000g_rx_detach_lock);
5754982Syy150190 	}
5764982Syy150190 
5773526Sxy150489 	cmn_err(CE_CONT, "!%s, %s\n", e1000g_string, e1000g_version);
5788479SChenlu.Chen@Sun.COM 	Adapter->e1000g_state = E1000G_INITIALIZED;
5793526Sxy150489 
5803526Sxy150489 	return (DDI_SUCCESS);
5813526Sxy150489 
5823526Sxy150489 attach_fail:
5833526Sxy150489 	e1000g_unattach(devinfo, Adapter);
5843526Sxy150489 	return (DDI_FAILURE);
5853526Sxy150489 }
5863526Sxy150489 
5873526Sxy150489 static int
5883526Sxy150489 e1000g_register_mac(struct e1000g *Adapter)
5893526Sxy150489 {
5904919Sxy150489 	struct e1000_hw *hw = &Adapter->shared;
5913526Sxy150489 	mac_register_t *mac;
5923526Sxy150489 	int err;
5933526Sxy150489 
5943526Sxy150489 	if ((mac = mac_alloc(MAC_VERSION)) == NULL)
5953526Sxy150489 		return (DDI_FAILURE);
5964919Sxy150489 
5973526Sxy150489 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
5983526Sxy150489 	mac->m_driver = Adapter;
5993526Sxy150489 	mac->m_dip = Adapter->dip;
6004919Sxy150489 	mac->m_src_addr = hw->mac.addr;
6013526Sxy150489 	mac->m_callbacks = &e1000g_m_callbacks;
6023526Sxy150489 	mac->m_min_sdu = 0;
6036394Scc210113 	mac->m_max_sdu = Adapter->default_mtu;
6045895Syz147064 	mac->m_margin = VLAN_TAGSZ;
6056512Ssowmini 	mac->m_priv_props = e1000g_priv_props;
6066512Ssowmini 	mac->m_priv_prop_count = E1000G_MAX_PRIV_PROPS;
6078275SEric Cheng 	mac->m_v12n = MAC_VIRT_LEVEL1;
6084919Sxy150489 
6093526Sxy150489 	err = mac_register(mac, &Adapter->mh);
6103526Sxy150489 	mac_free(mac);
6114919Sxy150489 
6123526Sxy150489 	return (err == 0 ? DDI_SUCCESS : DDI_FAILURE);
6133526Sxy150489 }
6143526Sxy150489 
6153526Sxy150489 static int
6164919Sxy150489 e1000g_identify_hardware(struct e1000g *Adapter)
6174919Sxy150489 {
6184919Sxy150489 	struct e1000_hw *hw = &Adapter->shared;
6194919Sxy150489 	struct e1000g_osdep *osdep = &Adapter->osdep;
6204919Sxy150489 
6214919Sxy150489 	/* Get the device id */
6224919Sxy150489 	hw->vendor_id =
6234919Sxy150489 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
6244919Sxy150489 	hw->device_id =
6254919Sxy150489 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
6264919Sxy150489 	hw->revision_id =
6274919Sxy150489 	    pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
6284919Sxy150489 	hw->subsystem_device_id =
6294919Sxy150489 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
6304919Sxy150489 	hw->subsystem_vendor_id =
6314919Sxy150489 	    pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
6324919Sxy150489 
6334919Sxy150489 	if (e1000_set_mac_type(hw) != E1000_SUCCESS) {
6344919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
6354919Sxy150489 		    "MAC type could not be set properly.");
6364919Sxy150489 		return (DDI_FAILURE);
6374919Sxy150489 	}
6384919Sxy150489 
6394919Sxy150489 	return (DDI_SUCCESS);
6404919Sxy150489 }
6414919Sxy150489 
6424919Sxy150489 static int
6434919Sxy150489 e1000g_regs_map(struct e1000g *Adapter)
6444919Sxy150489 {
6454919Sxy150489 	dev_info_t *devinfo = Adapter->dip;
6464919Sxy150489 	struct e1000_hw *hw = &Adapter->shared;
6474919Sxy150489 	struct e1000g_osdep *osdep = &Adapter->osdep;
6484919Sxy150489 	off_t mem_size;
6494919Sxy150489 
6507607STed.You@Sun.COM 	/* Get size of adapter register memory */
6517607STed.You@Sun.COM 	if (ddi_dev_regsize(devinfo, ADAPTER_REG_SET, &mem_size) !=
6527607STed.You@Sun.COM 	    DDI_SUCCESS) {
6534919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, CE_WARN,
6544919Sxy150489 		    "ddi_dev_regsize for registers failed");
6554919Sxy150489 		return (DDI_FAILURE);
6564919Sxy150489 	}
6574919Sxy150489 
6587607STed.You@Sun.COM 	/* Map adapter register memory */
6597607STed.You@Sun.COM 	if ((ddi_regs_map_setup(devinfo, ADAPTER_REG_SET,
6604919Sxy150489 	    (caddr_t *)&hw->hw_addr, 0, mem_size, &e1000g_regs_acc_attr,
6614919Sxy150489 	    &osdep->reg_handle)) != DDI_SUCCESS) {
6624919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, CE_WARN,
6634919Sxy150489 		    "ddi_regs_map_setup for registers failed");
6644919Sxy150489 		goto regs_map_fail;
6654919Sxy150489 	}
6664919Sxy150489 
6674919Sxy150489 	/* ICH needs to map flash memory */
6687607STed.You@Sun.COM 	if (hw->mac.type == e1000_ich8lan ||
6697607STed.You@Sun.COM 	    hw->mac.type == e1000_ich9lan ||
6707607STed.You@Sun.COM 	    hw->mac.type == e1000_ich10lan) {
6714919Sxy150489 		/* get flash size */
6724919Sxy150489 		if (ddi_dev_regsize(devinfo, ICH_FLASH_REG_SET,
6734919Sxy150489 		    &mem_size) != DDI_SUCCESS) {
6744919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, CE_WARN,
6754919Sxy150489 			    "ddi_dev_regsize for ICH flash failed");
6764919Sxy150489 			goto regs_map_fail;
6774919Sxy150489 		}
6784919Sxy150489 
6794919Sxy150489 		/* map flash in */
6804919Sxy150489 		if (ddi_regs_map_setup(devinfo, ICH_FLASH_REG_SET,
6814919Sxy150489 		    (caddr_t *)&hw->flash_address, 0,
6824919Sxy150489 		    mem_size, &e1000g_regs_acc_attr,
6834919Sxy150489 		    &osdep->ich_flash_handle) != DDI_SUCCESS) {
6844919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, CE_WARN,
6854919Sxy150489 			    "ddi_regs_map_setup for ICH flash failed");
6864919Sxy150489 			goto regs_map_fail;
6874919Sxy150489 		}
6884919Sxy150489 	}
6894919Sxy150489 
6904919Sxy150489 	return (DDI_SUCCESS);
6914919Sxy150489 
6924919Sxy150489 regs_map_fail:
6934919Sxy150489 	if (osdep->reg_handle != NULL)
6944919Sxy150489 		ddi_regs_map_free(&osdep->reg_handle);
6954919Sxy150489 
6964919Sxy150489 	return (DDI_FAILURE);
6974919Sxy150489 }
6984919Sxy150489 
6994919Sxy150489 static int
7003526Sxy150489 e1000g_set_driver_params(struct e1000g *Adapter)
7013526Sxy150489 {
7023526Sxy150489 	struct e1000_hw *hw;
7034919Sxy150489 	uint32_t mem_bar, io_bar, bar64;
7043526Sxy150489 
7054919Sxy150489 	hw = &Adapter->shared;
7064919Sxy150489 
7074919Sxy150489 	/* Set MAC type and initialize hardware functions */
7084919Sxy150489 	if (e1000_setup_init_funcs(hw, B_TRUE) != E1000_SUCCESS) {
7094919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, CE_WARN,
7104919Sxy150489 		    "Could not setup hardware functions");
7113526Sxy150489 		return (DDI_FAILURE);
7123526Sxy150489 	}
7133526Sxy150489 
7144919Sxy150489 	/* Get bus information */
7154919Sxy150489 	if (e1000_get_bus_info(hw) != E1000_SUCCESS) {
7164919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, CE_WARN,
7174919Sxy150489 		    "Could not get bus information");
7184919Sxy150489 		return (DDI_FAILURE);
7193526Sxy150489 	}
7203526Sxy150489 
7213526Sxy150489 	/* get mem_base addr */
7224919Sxy150489 	mem_bar = pci_config_get32(Adapter->osdep.cfg_handle, PCI_CONF_BASE0);
7234919Sxy150489 	bar64 = mem_bar & PCI_BASE_TYPE_ALL;
7243526Sxy150489 
7253526Sxy150489 	/* get io_base addr */
7264919Sxy150489 	if (hw->mac.type >= e1000_82544) {
7274919Sxy150489 		if (bar64) {
7283526Sxy150489 			/* IO BAR is different for 64 bit BAR mode */
7294919Sxy150489 			io_bar = pci_config_get32(Adapter->osdep.cfg_handle,
7304919Sxy150489 			    PCI_CONF_BASE4);
7313526Sxy150489 		} else {
7323526Sxy150489 			/* normal 32-bit BAR mode */
7334919Sxy150489 			io_bar = pci_config_get32(Adapter->osdep.cfg_handle,
7344919Sxy150489 			    PCI_CONF_BASE2);
7353526Sxy150489 		}
7363526Sxy150489 		hw->io_base = io_bar & PCI_BASE_IO_ADDR_M;
7373526Sxy150489 	} else {
7383526Sxy150489 		/* no I/O access for adapters prior to 82544 */
7393526Sxy150489 		hw->io_base = 0x0;
7403526Sxy150489 	}
7413526Sxy150489 
7424919Sxy150489 	e1000_read_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->bus.pci_cmd_word);
7434919Sxy150489 
7444919Sxy150489 	hw->mac.autoneg_failed = B_TRUE;
7454919Sxy150489 
7466735Scc210113 	/* Set the autoneg_wait_to_complete flag to B_FALSE */
7476735Scc210113 	hw->phy.autoneg_wait_to_complete = B_FALSE;
7483526Sxy150489 
7493526Sxy150489 	/* Adaptive IFS related changes */
7504919Sxy150489 	hw->mac.adaptive_ifs = B_TRUE;
7514919Sxy150489 
7524919Sxy150489 	/* Enable phy init script for IGP phy of 82541/82547 */
7534919Sxy150489 	if ((hw->mac.type == e1000_82547) ||
7544919Sxy150489 	    (hw->mac.type == e1000_82541) ||
7554919Sxy150489 	    (hw->mac.type == e1000_82547_rev_2) ||
7564919Sxy150489 	    (hw->mac.type == e1000_82541_rev_2))
7574919Sxy150489 		e1000_init_script_state_82541(hw, B_TRUE);
7584919Sxy150489 
7594919Sxy150489 	/* Enable the TTL workaround for 82541/82547 */
7604919Sxy150489 	e1000_set_ttl_workaround_state_82541(hw, B_TRUE);
7613526Sxy150489 
7624608Syy150190 #ifdef __sparc
7634608Syy150190 	Adapter->strip_crc = B_TRUE;
7644608Syy150190 #else
7654608Syy150190 	Adapter->strip_crc = B_FALSE;
7664608Syy150190 #endif
7674608Syy150190 
7683526Sxy150489 	/* Get conf file properties */
7694919Sxy150489 	e1000g_get_conf(Adapter);
7704919Sxy150489 
7714919Sxy150489 	/* Get speed/duplex settings in conf file */
7724919Sxy150489 	hw->mac.forced_speed_duplex = ADVERTISE_100_FULL;
7734919Sxy150489 	hw->phy.autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
7743526Sxy150489 	e1000g_force_speed_duplex(Adapter);
7753526Sxy150489 
7764919Sxy150489 	/* Get Jumbo Frames settings in conf file */
7773526Sxy150489 	e1000g_get_max_frame_size(Adapter);
7783526Sxy150489 
7793526Sxy150489 	/* Set Rx/Tx buffer size */
7806394Scc210113 	e1000g_set_bufsize(Adapter);
7814919Sxy150489 
7824919Sxy150489 	/* Master Latency Timer */
7834919Sxy150489 	Adapter->master_latency_timer = DEFAULT_MASTER_LATENCY_TIMER;
7844919Sxy150489 
7853526Sxy150489 	/* copper options */
7866735Scc210113 	if (hw->phy.media_type == e1000_media_type_copper) {
7874919Sxy150489 		hw->phy.mdix = 0;	/* AUTO_ALL_MODES */
7884919Sxy150489 		hw->phy.disable_polarity_correction = B_FALSE;
7894919Sxy150489 		hw->phy.ms_type = e1000_ms_hw_default;	/* E1000_MASTER_SLAVE */
7903526Sxy150489 	}
7913526Sxy150489 
7924919Sxy150489 	/* The initial link state should be "unknown" */
7934061Sxy150489 	Adapter->link_state = LINK_STATE_UNKNOWN;
7944061Sxy150489 
7955882Syy150190 	/* Initialize rx parameters */
7965882Syy150190 	Adapter->rx_intr_delay = DEFAULT_RX_INTR_DELAY;
7975882Syy150190 	Adapter->rx_intr_abs_delay = DEFAULT_RX_INTR_ABS_DELAY;
7985882Syy150190 
7994919Sxy150489 	/* Initialize tx parameters */
8004919Sxy150489 	Adapter->tx_intr_enable = DEFAULT_TX_INTR_ENABLE;
8014919Sxy150489 	Adapter->tx_bcopy_thresh = DEFAULT_TX_BCOPY_THRESHOLD;
8025882Syy150190 	Adapter->tx_intr_delay = DEFAULT_TX_INTR_DELAY;
8035882Syy150190 	Adapter->tx_intr_abs_delay = DEFAULT_TX_INTR_ABS_DELAY;
8044919Sxy150489 
8054919Sxy150489 	/* Initialize rx parameters */
8064919Sxy150489 	Adapter->rx_bcopy_thresh = DEFAULT_RX_BCOPY_THRESHOLD;
8074919Sxy150489 
8083526Sxy150489 	return (DDI_SUCCESS);
8093526Sxy150489 }
8103526Sxy150489 
8116394Scc210113 static void
8126394Scc210113 e1000g_set_bufsize(struct e1000g *Adapter)
8136394Scc210113 {
8146394Scc210113 	struct e1000_mac_info *mac = &Adapter->shared.mac;
8156394Scc210113 	uint64_t rx_size;
8166394Scc210113 	uint64_t tx_size;
8176394Scc210113 
8188073SMin.Xu@Sun.COM 	dev_info_t *devinfo = Adapter->dip;
8196394Scc210113 #ifdef __sparc
8206394Scc210113 	ulong_t iommu_pagesize;
8218073SMin.Xu@Sun.COM #endif
8226394Scc210113 	/* Get the system page size */
8236394Scc210113 	Adapter->sys_page_sz = ddi_ptob(devinfo, (ulong_t)1);
8248073SMin.Xu@Sun.COM 
8258073SMin.Xu@Sun.COM #ifdef __sparc
8266394Scc210113 	iommu_pagesize = dvma_pagesize(devinfo);
8276394Scc210113 	if (iommu_pagesize != 0) {
8286394Scc210113 		if (Adapter->sys_page_sz == iommu_pagesize) {
8296394Scc210113 			if (iommu_pagesize > 0x4000)
8306394Scc210113 				Adapter->sys_page_sz = 0x4000;
8316394Scc210113 		} else {
8326394Scc210113 			if (Adapter->sys_page_sz > iommu_pagesize)
8336394Scc210113 				Adapter->sys_page_sz = iommu_pagesize;
8346394Scc210113 		}
8356394Scc210113 	}
8366986Smx205022 	if (Adapter->lso_enable) {
8376986Smx205022 		Adapter->dvma_page_num = E1000_LSO_MAXLEN /
8386986Smx205022 		    Adapter->sys_page_sz + E1000G_DEFAULT_DVMA_PAGE_NUM;
8396986Smx205022 	} else {
8406986Smx205022 		Adapter->dvma_page_num = Adapter->max_frame_size /
8416986Smx205022 		    Adapter->sys_page_sz + E1000G_DEFAULT_DVMA_PAGE_NUM;
8426986Smx205022 	}
8436394Scc210113 	ASSERT(Adapter->dvma_page_num >= E1000G_DEFAULT_DVMA_PAGE_NUM);
8446394Scc210113 #endif
8456394Scc210113 
8466735Scc210113 	Adapter->min_frame_size = ETHERMIN + ETHERFCSL;
8476735Scc210113 
8488417SChenlu.Chen@Sun.COM 	if (Adapter->mem_workaround_82546 &&
8498417SChenlu.Chen@Sun.COM 	    ((mac->type == e1000_82545) ||
8508178SChenlu.Chen@Sun.COM 	    (mac->type == e1000_82546) ||
8518417SChenlu.Chen@Sun.COM 	    (mac->type == e1000_82546_rev_3))) {
8526394Scc210113 		Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_2K;
8538178SChenlu.Chen@Sun.COM 	} else {
8548178SChenlu.Chen@Sun.COM 		rx_size = Adapter->max_frame_size + E1000G_IPALIGNPRESERVEROOM;
8558178SChenlu.Chen@Sun.COM 		if ((rx_size > FRAME_SIZE_UPTO_2K) &&
8568178SChenlu.Chen@Sun.COM 		    (rx_size <= FRAME_SIZE_UPTO_4K))
8578178SChenlu.Chen@Sun.COM 			Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_4K;
8588178SChenlu.Chen@Sun.COM 		else if ((rx_size > FRAME_SIZE_UPTO_4K) &&
8598178SChenlu.Chen@Sun.COM 		    (rx_size <= FRAME_SIZE_UPTO_8K))
8608178SChenlu.Chen@Sun.COM 			Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_8K;
8618178SChenlu.Chen@Sun.COM 		else if ((rx_size > FRAME_SIZE_UPTO_8K) &&
8628178SChenlu.Chen@Sun.COM 		    (rx_size <= FRAME_SIZE_UPTO_16K))
8638178SChenlu.Chen@Sun.COM 			Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_16K;
8648178SChenlu.Chen@Sun.COM 		else
8658178SChenlu.Chen@Sun.COM 			Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_2K;
8668178SChenlu.Chen@Sun.COM 	}
8676394Scc210113 
8686735Scc210113 	tx_size = Adapter->max_frame_size;
8696394Scc210113 	if ((tx_size > FRAME_SIZE_UPTO_2K) && (tx_size <= FRAME_SIZE_UPTO_4K))
8706394Scc210113 		Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_4K;
8716394Scc210113 	else if ((tx_size > FRAME_SIZE_UPTO_4K) &&
8726394Scc210113 	    (tx_size <= FRAME_SIZE_UPTO_8K))
8736394Scc210113 		Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_8K;
8746394Scc210113 	else if ((tx_size > FRAME_SIZE_UPTO_8K) &&
8756394Scc210113 	    (tx_size <= FRAME_SIZE_UPTO_16K))
8766394Scc210113 		Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_16K;
8776394Scc210113 	else
8786394Scc210113 		Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_2K;
8796394Scc210113 
8806394Scc210113 	/*
8816394Scc210113 	 * For Wiseman adapters we have an requirement of having receive
8826394Scc210113 	 * buffers aligned at 256 byte boundary. Since Livengood does not
8836394Scc210113 	 * require this and forcing it for all hardwares will have
8846394Scc210113 	 * performance implications, I am making it applicable only for
8856394Scc210113 	 * Wiseman and for Jumbo frames enabled mode as rest of the time,
8866394Scc210113 	 * it is okay to have normal frames...but it does involve a
8876394Scc210113 	 * potential risk where we may loose data if buffer is not
8886394Scc210113 	 * aligned...so all wiseman boards to have 256 byte aligned
8896394Scc210113 	 * buffers
8906394Scc210113 	 */
8916394Scc210113 	if (mac->type < e1000_82543)
8926394Scc210113 		Adapter->rx_buf_align = RECEIVE_BUFFER_ALIGN_SIZE;
8936394Scc210113 	else
8946394Scc210113 		Adapter->rx_buf_align = 1;
8956394Scc210113 }
8966394Scc210113 
8973526Sxy150489 /*
8984919Sxy150489  * e1000g_detach - driver detach
8994919Sxy150489  *
9004919Sxy150489  * The detach() function is the complement of the attach routine.
9014919Sxy150489  * If cmd is set to DDI_DETACH, detach() is used to remove  the
9024919Sxy150489  * state  associated  with  a  given  instance of a device node
9034919Sxy150489  * prior to the removal of that instance from the system.
9044919Sxy150489  *
9054919Sxy150489  * The detach() function will be called once for each  instance
9064919Sxy150489  * of the device for which there has been a successful attach()
9074919Sxy150489  * once there are no longer  any  opens  on  the  device.
9084919Sxy150489  *
9094919Sxy150489  * Interrupts routine are disabled, All memory allocated by this
9104919Sxy150489  * driver are freed.
9113526Sxy150489  */
9123526Sxy150489 static int
9134919Sxy150489 e1000g_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
9143526Sxy150489 {
9153526Sxy150489 	struct e1000g *Adapter;
9164982Syy150190 	boolean_t rx_drain;
9173526Sxy150489 
9183526Sxy150489 	switch (cmd) {
9193526Sxy150489 	default:
9203526Sxy150489 		return (DDI_FAILURE);
9213526Sxy150489 
9223526Sxy150489 	case DDI_SUSPEND:
9233526Sxy150489 		return (e1000g_suspend(devinfo));
9243526Sxy150489 
9253526Sxy150489 	case DDI_DETACH:
9263526Sxy150489 		break;
9273526Sxy150489 	}
9283526Sxy150489 
9293526Sxy150489 	Adapter = (struct e1000g *)ddi_get_driver_private(devinfo);
9303526Sxy150489 	if (Adapter == NULL)
9313526Sxy150489 		return (DDI_FAILURE);
9323526Sxy150489 
9338275SEric Cheng 	rx_drain = e1000g_rx_drain(Adapter);
9348275SEric Cheng 	if (!rx_drain && !e1000g_force_detach)
9358275SEric Cheng 		return (DDI_FAILURE);
9368275SEric Cheng 
9374919Sxy150489 	if (mac_unregister(Adapter->mh) != 0) {
9384919Sxy150489 		e1000g_log(Adapter, CE_WARN, "Unregister MAC failed");
9394919Sxy150489 		return (DDI_FAILURE);
9404919Sxy150489 	}
9414919Sxy150489 	Adapter->attach_progress &= ~ATTACH_PROGRESS_MAC;
9424919Sxy150489 
9438479SChenlu.Chen@Sun.COM 	ASSERT(!(Adapter->e1000g_state & E1000G_STARTED));
9444982Syy150190 
9458850SMin.Xu@Sun.COM 	if (!e1000g_force_detach && !rx_drain)
9468850SMin.Xu@Sun.COM 		return (DDI_FAILURE);
9473526Sxy150489 
9483526Sxy150489 	e1000g_unattach(devinfo, Adapter);
9493526Sxy150489 
9503526Sxy150489 	return (DDI_SUCCESS);
9513526Sxy150489 }
9523526Sxy150489 
9534982Syy150190 /*
9544982Syy150190  * e1000g_free_priv_devi_node - free a priv_dip entry for driver instance
9554982Syy150190  */
9568850SMin.Xu@Sun.COM void
9578850SMin.Xu@Sun.COM e1000g_free_priv_devi_node(private_devi_list_t *devi_node)
9584982Syy150190 {
9594982Syy150190 	ASSERT(e1000g_private_devi_list != NULL);
9608850SMin.Xu@Sun.COM 	ASSERT(devi_node != NULL);
9618850SMin.Xu@Sun.COM 
9628850SMin.Xu@Sun.COM 	if (devi_node->prev != NULL)
9638850SMin.Xu@Sun.COM 		devi_node->prev->next = devi_node->next;
9648850SMin.Xu@Sun.COM 	if (devi_node->next != NULL)
9658850SMin.Xu@Sun.COM 		devi_node->next->prev = devi_node->prev;
9668850SMin.Xu@Sun.COM 	if (devi_node == e1000g_private_devi_list)
9678850SMin.Xu@Sun.COM 		e1000g_private_devi_list = devi_node->next;
9688850SMin.Xu@Sun.COM 
9698850SMin.Xu@Sun.COM 	kmem_free(devi_node->priv_dip,
9708850SMin.Xu@Sun.COM 	    sizeof (struct dev_info));
9718850SMin.Xu@Sun.COM 	kmem_free(devi_node,
9728850SMin.Xu@Sun.COM 	    sizeof (private_devi_list_t));
9734982Syy150190 }
9744982Syy150190 
9753526Sxy150489 static void
9763526Sxy150489 e1000g_unattach(dev_info_t *devinfo, struct e1000g *Adapter)
9773526Sxy150489 {
9788850SMin.Xu@Sun.COM 	private_devi_list_t *devi_node;
9797133Scc210113 	int result;
9807133Scc210113 
9814919Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
9823526Sxy150489 		(void) e1000g_disable_intrs(Adapter);
9833526Sxy150489 	}
9843526Sxy150489 
9854919Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_MAC) {
9863526Sxy150489 		(void) mac_unregister(Adapter->mh);
9873526Sxy150489 	}
9883526Sxy150489 
9894919Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
9903526Sxy150489 		(void) e1000g_rem_intrs(Adapter);
9913526Sxy150489 	}
9923526Sxy150489 
9934919Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_SETUP) {
9943526Sxy150489 		(void) ddi_prop_remove_all(devinfo);
9953526Sxy150489 	}
9963526Sxy150489 
9973526Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_KSTATS) {
9983526Sxy150489 		kstat_delete((kstat_t *)Adapter->e1000g_ksp);
9993526Sxy150489 	}
10003526Sxy150489 
10013526Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_INIT) {
10024919Sxy150489 		stop_link_timer(Adapter);
10037133Scc210113 
10047133Scc210113 		mutex_enter(&e1000g_nvm_lock);
10057133Scc210113 		result = e1000_reset_hw(&Adapter->shared);
10067133Scc210113 		mutex_exit(&e1000g_nvm_lock);
10077133Scc210113 
10087133Scc210113 		if (result != E1000_SUCCESS) {
10095273Sgl147354 			e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE);
10105273Sgl147354 			ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST);
10115273Sgl147354 		}
10123526Sxy150489 	}
10133526Sxy150489 
10144919Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
10154919Sxy150489 		if (Adapter->osdep.reg_handle != NULL)
10164919Sxy150489 			ddi_regs_map_free(&Adapter->osdep.reg_handle);
10174919Sxy150489 		if (Adapter->osdep.ich_flash_handle != NULL)
10184919Sxy150489 			ddi_regs_map_free(&Adapter->osdep.ich_flash_handle);
10193526Sxy150489 	}
10203526Sxy150489 
10214919Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) {
10224919Sxy150489 		if (Adapter->osdep.cfg_handle != NULL)
10234919Sxy150489 			pci_config_teardown(&Adapter->osdep.cfg_handle);
10243526Sxy150489 	}
10253526Sxy150489 
10263526Sxy150489 	if (Adapter->attach_progress & ATTACH_PROGRESS_LOCKS) {
10273526Sxy150489 		e1000g_destroy_locks(Adapter);
10283526Sxy150489 	}
10293526Sxy150489 
10305273Sgl147354 	if (Adapter->attach_progress & ATTACH_PROGRESS_FMINIT) {
10315273Sgl147354 		e1000g_fm_fini(Adapter);
10325273Sgl147354 	}
10335273Sgl147354 
10348850SMin.Xu@Sun.COM 	mutex_enter(&e1000g_rx_detach_lock);
10358850SMin.Xu@Sun.COM 	if (e1000g_force_detach) {
10368850SMin.Xu@Sun.COM 		devi_node = Adapter->priv_devi_node;
10378850SMin.Xu@Sun.COM 		devi_node->flag |= E1000G_PRIV_DEVI_DETACH;
10388850SMin.Xu@Sun.COM 
10398850SMin.Xu@Sun.COM 		if (devi_node->pending_rx_count == 0) {
10408850SMin.Xu@Sun.COM 			e1000g_free_priv_devi_node(devi_node);
10418850SMin.Xu@Sun.COM 		}
10428850SMin.Xu@Sun.COM 	}
10438850SMin.Xu@Sun.COM 	mutex_exit(&e1000g_rx_detach_lock);
10448850SMin.Xu@Sun.COM 
10453526Sxy150489 	kmem_free((caddr_t)Adapter, sizeof (struct e1000g));
10463526Sxy150489 
10473526Sxy150489 	/*
10483526Sxy150489 	 * Another hotplug spec requirement,
10493526Sxy150489 	 * run ddi_set_driver_private(devinfo, null);
10503526Sxy150489 	 */
10513526Sxy150489 	ddi_set_driver_private(devinfo, NULL);
10523526Sxy150489 }
10533526Sxy150489 
10543526Sxy150489 static void
10553526Sxy150489 e1000g_init_locks(struct e1000g *Adapter)
10563526Sxy150489 {
10573526Sxy150489 	e1000g_tx_ring_t *tx_ring;
10583526Sxy150489 	e1000g_rx_ring_t *rx_ring;
10593526Sxy150489 
10603526Sxy150489 	rw_init(&Adapter->chip_lock, NULL,
10613526Sxy150489 	    RW_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
10624919Sxy150489 	mutex_init(&Adapter->link_lock, NULL,
10633526Sxy150489 	    MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
10644919Sxy150489 	mutex_init(&Adapter->watchdog_lock, NULL,
10653526Sxy150489 	    MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
10663526Sxy150489 
10673526Sxy150489 	tx_ring = Adapter->tx_ring;
10683526Sxy150489 
10693526Sxy150489 	mutex_init(&tx_ring->tx_lock, NULL,
10703526Sxy150489 	    MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
10713526Sxy150489 	mutex_init(&tx_ring->usedlist_lock, NULL,
10723526Sxy150489 	    MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
10733526Sxy150489 	mutex_init(&tx_ring->freelist_lock, NULL,
10743526Sxy150489 	    MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
10753526Sxy150489 
10763526Sxy150489 	rx_ring = Adapter->rx_ring;
10773526Sxy150489 
10787436STed.You@Sun.COM 	mutex_init(&rx_ring->rx_lock, NULL,
10797436STed.You@Sun.COM 	    MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
10803526Sxy150489 }
10813526Sxy150489 
10823526Sxy150489 static void
10833526Sxy150489 e1000g_destroy_locks(struct e1000g *Adapter)
10843526Sxy150489 {
10853526Sxy150489 	e1000g_tx_ring_t *tx_ring;
10863526Sxy150489 	e1000g_rx_ring_t *rx_ring;
10873526Sxy150489 
10883526Sxy150489 	tx_ring = Adapter->tx_ring;
10893526Sxy150489 	mutex_destroy(&tx_ring->tx_lock);
10903526Sxy150489 	mutex_destroy(&tx_ring->usedlist_lock);
10913526Sxy150489 	mutex_destroy(&tx_ring->freelist_lock);
10923526Sxy150489 
10933526Sxy150489 	rx_ring = Adapter->rx_ring;
10947436STed.You@Sun.COM 	mutex_destroy(&rx_ring->rx_lock);
10953526Sxy150489 
10964919Sxy150489 	mutex_destroy(&Adapter->link_lock);
10974919Sxy150489 	mutex_destroy(&Adapter->watchdog_lock);
10983526Sxy150489 	rw_destroy(&Adapter->chip_lock);
10993526Sxy150489 }
11003526Sxy150489 
11013526Sxy150489 static int
11023526Sxy150489 e1000g_resume(dev_info_t *devinfo)
11033526Sxy150489 {
11043526Sxy150489 	struct e1000g *Adapter;
11053526Sxy150489 
11063526Sxy150489 	Adapter = (struct e1000g *)ddi_get_driver_private(devinfo);
11073526Sxy150489 	if (Adapter == NULL)
11088479SChenlu.Chen@Sun.COM 		e1000g_log(Adapter, CE_PANIC,
11098479SChenlu.Chen@Sun.COM 		    "Instance pointer is null\n");
11108479SChenlu.Chen@Sun.COM 
11118479SChenlu.Chen@Sun.COM 	if (Adapter->dip != devinfo)
11128479SChenlu.Chen@Sun.COM 		e1000g_log(Adapter, CE_PANIC,
11138479SChenlu.Chen@Sun.COM 		    "Devinfo is not the same as saved devinfo\n");
11148479SChenlu.Chen@Sun.COM 
11158479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
11168479SChenlu.Chen@Sun.COM 
11178479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_STARTED) {
11188479SChenlu.Chen@Sun.COM 		if (e1000g_start(Adapter, B_FALSE) != DDI_SUCCESS) {
11198479SChenlu.Chen@Sun.COM 			rw_exit(&Adapter->chip_lock);
11208479SChenlu.Chen@Sun.COM 			/*
11218479SChenlu.Chen@Sun.COM 			 * We note the failure, but return success, as the
11228479SChenlu.Chen@Sun.COM 			 * system is still usable without this controller.
11238479SChenlu.Chen@Sun.COM 			 */
11248479SChenlu.Chen@Sun.COM 			e1000g_log(Adapter, CE_WARN,
11258479SChenlu.Chen@Sun.COM 			    "e1000g_resume: failed to restart controller\n");
11268479SChenlu.Chen@Sun.COM 			return (DDI_SUCCESS);
11278479SChenlu.Chen@Sun.COM 		}
11288479SChenlu.Chen@Sun.COM 		/* Enable and start the watchdog timer */
11298479SChenlu.Chen@Sun.COM 		enable_watchdog_timer(Adapter);
11308479SChenlu.Chen@Sun.COM 	}
11318479SChenlu.Chen@Sun.COM 
11328479SChenlu.Chen@Sun.COM 	Adapter->e1000g_state &= ~E1000G_SUSPENDED;
11338479SChenlu.Chen@Sun.COM 
11348479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
11353526Sxy150489 
11363526Sxy150489 	return (DDI_SUCCESS);
11373526Sxy150489 }
11383526Sxy150489 
11393526Sxy150489 static int
11403526Sxy150489 e1000g_suspend(dev_info_t *devinfo)
11413526Sxy150489 {
11423526Sxy150489 	struct e1000g *Adapter;
11433526Sxy150489 
11443526Sxy150489 	Adapter = (struct e1000g *)ddi_get_driver_private(devinfo);
11453526Sxy150489 	if (Adapter == NULL)
11463526Sxy150489 		return (DDI_FAILURE);
11473526Sxy150489 
11488479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
11498479SChenlu.Chen@Sun.COM 
11508479SChenlu.Chen@Sun.COM 	Adapter->e1000g_state |= E1000G_SUSPENDED;
11518479SChenlu.Chen@Sun.COM 
11528479SChenlu.Chen@Sun.COM 	/* if the port isn't plumbed, we can simply return */
11538479SChenlu.Chen@Sun.COM 	if (!(Adapter->e1000g_state & E1000G_STARTED)) {
11548479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
11558479SChenlu.Chen@Sun.COM 		return (DDI_SUCCESS);
11568479SChenlu.Chen@Sun.COM 	}
11578479SChenlu.Chen@Sun.COM 
11588479SChenlu.Chen@Sun.COM 	e1000g_stop(Adapter, B_FALSE);
11598479SChenlu.Chen@Sun.COM 
11608479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
11618479SChenlu.Chen@Sun.COM 
11628479SChenlu.Chen@Sun.COM 	/* Disable and stop all the timers */
11638479SChenlu.Chen@Sun.COM 	disable_watchdog_timer(Adapter);
11648479SChenlu.Chen@Sun.COM 	stop_link_timer(Adapter);
11658479SChenlu.Chen@Sun.COM 	stop_82547_timer(Adapter->tx_ring);
11663526Sxy150489 
11673526Sxy150489 	return (DDI_SUCCESS);
11683526Sxy150489 }
11693526Sxy150489 
11703526Sxy150489 static int
11713526Sxy150489 e1000g_init(struct e1000g *Adapter)
11723526Sxy150489 {
11733526Sxy150489 	uint32_t pba;
11744919Sxy150489 	uint32_t high_water;
11753526Sxy150489 	struct e1000_hw *hw;
11764061Sxy150489 	clock_t link_timeout;
11777133Scc210113 	int result;
11783526Sxy150489 
11794919Sxy150489 	hw = &Adapter->shared;
11803526Sxy150489 
11813526Sxy150489 	/*
11823526Sxy150489 	 * reset to put the hardware in a known state
11833526Sxy150489 	 * before we try to do anything with the eeprom
11843526Sxy150489 	 */
11857133Scc210113 	mutex_enter(&e1000g_nvm_lock);
11867133Scc210113 	result = e1000_reset_hw(hw);
11877133Scc210113 	mutex_exit(&e1000g_nvm_lock);
11887133Scc210113 
11897133Scc210113 	if (result != E1000_SUCCESS) {
11905273Sgl147354 		e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE);
11915273Sgl147354 		goto init_fail;
11925273Sgl147354 	}
11933526Sxy150489 
11947133Scc210113 	mutex_enter(&e1000g_nvm_lock);
11957133Scc210113 	result = e1000_validate_nvm_checksum(hw);
11967133Scc210113 	if (result < E1000_SUCCESS) {
11974061Sxy150489 		/*
11984061Sxy150489 		 * Some PCI-E parts fail the first check due to
11994061Sxy150489 		 * the link being in sleep state.  Call it again,
12004061Sxy150489 		 * if it fails a second time its a real issue.
12014061Sxy150489 		 */
12027133Scc210113 		result = e1000_validate_nvm_checksum(hw);
12037133Scc210113 	}
12047133Scc210113 	mutex_exit(&e1000g_nvm_lock);
12057133Scc210113 
12067133Scc210113 	if (result < E1000_SUCCESS) {
12077133Scc210113 		e1000g_log(Adapter, CE_WARN,
12087133Scc210113 		    "Invalid NVM checksum. Please contact "
12097133Scc210113 		    "the vendor to update the NVM.");
12107133Scc210113 		e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE);
12117133Scc210113 		goto init_fail;
12127133Scc210113 	}
12137133Scc210113 
12147133Scc210113 	result = 0;
12153526Sxy150489 #ifdef __sparc
12163526Sxy150489 	/*
12177607STed.You@Sun.COM 	 * First, we try to get the local ethernet address from OBP. If
12187133Scc210113 	 * failed, then we get it from the EEPROM of NIC card.
12193526Sxy150489 	 */
12207133Scc210113 	result = e1000g_find_mac_address(Adapter);
12217133Scc210113 #endif
12223526Sxy150489 	/* Get the local ethernet address. */
12237133Scc210113 	if (!result) {
12247133Scc210113 		mutex_enter(&e1000g_nvm_lock);
12257140Scc210113 		result = e1000_read_mac_addr(hw);
12267133Scc210113 		mutex_exit(&e1000g_nvm_lock);
12277133Scc210113 	}
12287133Scc210113 
12297133Scc210113 	if (result < E1000_SUCCESS) {
12303526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Read mac addr failed");
12315273Sgl147354 		e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE);
12323526Sxy150489 		goto init_fail;
12333526Sxy150489 	}
12343526Sxy150489 
12353526Sxy150489 	/* check for valid mac address */
12364919Sxy150489 	if (!is_valid_mac_addr(hw->mac.addr)) {
12373526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Invalid mac addr");
12385273Sgl147354 		e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE);
12393526Sxy150489 		goto init_fail;
12403526Sxy150489 	}
12413526Sxy150489 
12424919Sxy150489 	/* Set LAA state for 82571 chipset */
12434919Sxy150489 	e1000_set_laa_state_82571(hw, B_TRUE);
12443526Sxy150489 
12453526Sxy150489 	/* Master Latency Timer implementation */
12464919Sxy150489 	if (Adapter->master_latency_timer) {
12474919Sxy150489 		pci_config_put8(Adapter->osdep.cfg_handle,
12484919Sxy150489 		    PCI_CONF_LATENCY_TIMER, Adapter->master_latency_timer);
12493526Sxy150489 	}
12503526Sxy150489 
12514919Sxy150489 	if (hw->mac.type < e1000_82547) {
12523526Sxy150489 		/*
12533526Sxy150489 		 * Total FIFO is 64K
12543526Sxy150489 		 */
12556735Scc210113 		if (Adapter->max_frame_size > FRAME_SIZE_UPTO_8K)
12563526Sxy150489 			pba = E1000_PBA_40K;	/* 40K for Rx, 24K for Tx */
12573526Sxy150489 		else
12583526Sxy150489 			pba = E1000_PBA_48K;	/* 48K for Rx, 16K for Tx */
12597140Scc210113 	} else if ((hw->mac.type == e1000_82571) ||
12607140Scc210113 	    (hw->mac.type == e1000_82572) ||
12617140Scc210113 	    (hw->mac.type == e1000_80003es2lan)) {
12623526Sxy150489 		/*
12633526Sxy150489 		 * Total FIFO is 48K
12643526Sxy150489 		 */
12656735Scc210113 		if (Adapter->max_frame_size > FRAME_SIZE_UPTO_8K)
12663526Sxy150489 			pba = E1000_PBA_30K;	/* 30K for Rx, 18K for Tx */
12673526Sxy150489 		else
12683526Sxy150489 			pba = E1000_PBA_38K;	/* 38K for Rx, 10K for Tx */
12697607STed.You@Sun.COM 	} else if (hw->mac.type == e1000_82573) {
12707607STed.You@Sun.COM 		pba = E1000_PBA_20K;		/* 20K for Rx, 12K for Tx */
12717607STed.You@Sun.COM 	} else if (hw->mac.type == e1000_82574) {
12727607STed.You@Sun.COM 		/* Keep adapter default: 20K for Rx, 20K for Tx */
12737607STed.You@Sun.COM 		pba = E1000_READ_REG(hw, E1000_PBA);
12744919Sxy150489 	} else if (hw->mac.type == e1000_ich8lan) {
12753526Sxy150489 		pba = E1000_PBA_8K;		/* 8K for Rx, 12K for Tx */
12764919Sxy150489 	} else if (hw->mac.type == e1000_ich9lan) {
12777607STed.You@Sun.COM 		pba = E1000_PBA_10K;
12787607STed.You@Sun.COM 	} else if (hw->mac.type == e1000_ich10lan) {
12797607STed.You@Sun.COM 		pba = E1000_PBA_10K;
12803526Sxy150489 	} else {
12813526Sxy150489 		/*
12823526Sxy150489 		 * Total FIFO is 40K
12833526Sxy150489 		 */
12846735Scc210113 		if (Adapter->max_frame_size > FRAME_SIZE_UPTO_8K)
12853526Sxy150489 			pba = E1000_PBA_22K;	/* 22K for Rx, 18K for Tx */
12863526Sxy150489 		else
12873526Sxy150489 			pba = E1000_PBA_30K;	/* 30K for Rx, 10K for Tx */
12883526Sxy150489 	}
12894919Sxy150489 	E1000_WRITE_REG(hw, E1000_PBA, pba);
12903526Sxy150489 
12913526Sxy150489 	/*
12923526Sxy150489 	 * These parameters set thresholds for the adapter's generation(Tx)
12933526Sxy150489 	 * and response(Rx) to Ethernet PAUSE frames.  These are just threshold
12943526Sxy150489 	 * settings.  Flow control is enabled or disabled in the configuration
12953526Sxy150489 	 * file.
12963526Sxy150489 	 * High-water mark is set down from the top of the rx fifo (not
12973526Sxy150489 	 * sensitive to max_frame_size) and low-water is set just below
12983526Sxy150489 	 * high-water mark.
12994919Sxy150489 	 * The high water mark must be low enough to fit one full frame above
13004919Sxy150489 	 * it in the rx FIFO.  Should be the lower of:
13014919Sxy150489 	 * 90% of the Rx FIFO size and the full Rx FIFO size minus the early
13024919Sxy150489 	 * receive size (assuming ERT set to E1000_ERT_2048), or the full
13034919Sxy150489 	 * Rx FIFO size minus one full frame.
13043526Sxy150489 	 */
13054919Sxy150489 	high_water = min(((pba << 10) * 9 / 10),
13068479SChenlu.Chen@Sun.COM 	    ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574 ||
13078479SChenlu.Chen@Sun.COM 	    hw->mac.type == e1000_ich9lan || hw->mac.type == e1000_ich10lan) ?
13084919Sxy150489 	    ((pba << 10) - (E1000_ERT_2048 << 3)) :
13096735Scc210113 	    ((pba << 10) - Adapter->max_frame_size)));
13106735Scc210113 
13116735Scc210113 	hw->fc.high_water = high_water & 0xFFF8;
13126735Scc210113 	hw->fc.low_water = hw->fc.high_water - 8;
13134919Sxy150489 
13144919Sxy150489 	if (hw->mac.type == e1000_80003es2lan)
13156735Scc210113 		hw->fc.pause_time = 0xFFFF;
13164919Sxy150489 	else
13176735Scc210113 		hw->fc.pause_time = E1000_FC_PAUSE_TIME;
13186735Scc210113 	hw->fc.send_xon = B_TRUE;
13193526Sxy150489 
13203526Sxy150489 	/*
13213526Sxy150489 	 * Reset the adapter hardware the second time.
13223526Sxy150489 	 */
13237133Scc210113 	mutex_enter(&e1000g_nvm_lock);
13247133Scc210113 	result = e1000_reset_hw(hw);
13257133Scc210113 	mutex_exit(&e1000g_nvm_lock);
13267133Scc210113 
13277133Scc210113 	if (result != E1000_SUCCESS) {
13285273Sgl147354 		e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE);
13295273Sgl147354 		goto init_fail;
13305273Sgl147354 	}
13313526Sxy150489 
13323526Sxy150489 	/* disable wakeup control by default */
13334919Sxy150489 	if (hw->mac.type >= e1000_82544)
13344919Sxy150489 		E1000_WRITE_REG(hw, E1000_WUC, 0);
13353526Sxy150489 
13368178SChenlu.Chen@Sun.COM 	/*
13378178SChenlu.Chen@Sun.COM 	 * MWI should be disabled on 82546.
13388178SChenlu.Chen@Sun.COM 	 */
13398178SChenlu.Chen@Sun.COM 	if (hw->mac.type == e1000_82546)
13408178SChenlu.Chen@Sun.COM 		e1000_pci_clear_mwi(hw);
13418178SChenlu.Chen@Sun.COM 	else
13428178SChenlu.Chen@Sun.COM 		e1000_pci_set_mwi(hw);
13433526Sxy150489 
13443526Sxy150489 	/*
13453526Sxy150489 	 * Configure/Initialize hardware
13463526Sxy150489 	 */
13477133Scc210113 	mutex_enter(&e1000g_nvm_lock);
13487133Scc210113 	result = e1000_init_hw(hw);
13497133Scc210113 	mutex_exit(&e1000g_nvm_lock);
13507133Scc210113 
13517133Scc210113 	if (result < E1000_SUCCESS) {
13523526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Initialize hw failed");
13535273Sgl147354 		e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE);
13543526Sxy150489 		goto init_fail;
13553526Sxy150489 	}
13563526Sxy150489 
13577436STed.You@Sun.COM 	/*
13587436STed.You@Sun.COM 	 * Restore LED settings to the default from EEPROM
13597436STed.You@Sun.COM 	 * to meet the standard for Sun platforms.
13607436STed.You@Sun.COM 	 */
13618572SMin.Xu@Sun.COM 	if ((hw->mac.type != e1000_82541) &&
13628572SMin.Xu@Sun.COM 	    (hw->mac.type != e1000_82541_rev_2) &&
13638572SMin.Xu@Sun.COM 	    (hw->mac.type != e1000_82547) &&
13648572SMin.Xu@Sun.COM 	    (hw->mac.type != e1000_82547_rev_2))
13658572SMin.Xu@Sun.COM 		(void) e1000_cleanup_led(hw);
13667436STed.You@Sun.COM 
13673526Sxy150489 	/* Disable Smart Power Down */
13683526Sxy150489 	phy_spd_state(hw, B_FALSE);
13693526Sxy150489 
13705082Syy150190 	/* Make sure driver has control */
13715082Syy150190 	e1000g_get_driver_control(hw);
13725082Syy150190 
13733526Sxy150489 	/*
13743526Sxy150489 	 * Initialize unicast addresses.
13753526Sxy150489 	 */
13763526Sxy150489 	e1000g_init_unicst(Adapter);
13773526Sxy150489 
13783526Sxy150489 	/*
13793526Sxy150489 	 * Setup and initialize the mctable structures.  After this routine
13803526Sxy150489 	 * completes  Multicast table will be set
13813526Sxy150489 	 */
13824919Sxy150489 	e1000g_setup_multicast(Adapter);
13834919Sxy150489 	msec_delay(5);
13843526Sxy150489 
13853526Sxy150489 	/*
13863526Sxy150489 	 * Implement Adaptive IFS
13873526Sxy150489 	 */
13883526Sxy150489 	e1000_reset_adaptive(hw);
13893526Sxy150489 
13903526Sxy150489 	/* Setup Interrupt Throttling Register */
13915882Syy150190 	if (hw->mac.type >= e1000_82540) {
13925882Syy150190 		E1000_WRITE_REG(hw, E1000_ITR, Adapter->intr_throttling_rate);
13935882Syy150190 	} else
13945882Syy150190 		Adapter->intr_adaptive = B_FALSE;
13953526Sxy150489 
13964061Sxy150489 	/* Start the timer for link setup */
13974919Sxy150489 	if (hw->mac.autoneg)
13984919Sxy150489 		link_timeout = PHY_AUTO_NEG_LIMIT * drv_usectohz(100000);
13994061Sxy150489 	else
14004919Sxy150489 		link_timeout = PHY_FORCE_LIMIT * drv_usectohz(100000);
14014919Sxy150489 
14024919Sxy150489 	mutex_enter(&Adapter->link_lock);
14036735Scc210113 	if (hw->phy.autoneg_wait_to_complete) {
14044061Sxy150489 		Adapter->link_complete = B_TRUE;
14053526Sxy150489 	} else {
14064061Sxy150489 		Adapter->link_complete = B_FALSE;
14074061Sxy150489 		Adapter->link_tid = timeout(e1000g_link_timer,
14084061Sxy150489 		    (void *)Adapter, link_timeout);
14093526Sxy150489 	}
14104919Sxy150489 	mutex_exit(&Adapter->link_lock);
14113526Sxy150489 
14123526Sxy150489 	/* Enable PCI-Ex master */
14134919Sxy150489 	if (hw->bus.type == e1000_bus_type_pci_express) {
14143526Sxy150489 		e1000_enable_pciex_master(hw);
14153526Sxy150489 	}
14163526Sxy150489 
14175082Syy150190 	/* Save the state of the phy */
14185082Syy150190 	e1000g_get_phy_state(Adapter);
14195082Syy150190 
14206512Ssowmini 	e1000g_param_sync(Adapter);
14216512Ssowmini 
14223526Sxy150489 	Adapter->init_count++;
14233526Sxy150489 
14245273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.cfg_handle) != DDI_FM_OK) {
14255273Sgl147354 		goto init_fail;
14265273Sgl147354 	}
14275273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
14285273Sgl147354 		goto init_fail;
14295273Sgl147354 	}
14305273Sgl147354 
14318275SEric Cheng 	Adapter->poll_mode = e1000g_poll_mode;
14328275SEric Cheng 
14333526Sxy150489 	return (DDI_SUCCESS);
14343526Sxy150489 
14353526Sxy150489 init_fail:
14365273Sgl147354 	ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST);
14373526Sxy150489 	return (DDI_FAILURE);
14383526Sxy150489 }
14393526Sxy150489 
14408850SMin.Xu@Sun.COM static int
14418850SMin.Xu@Sun.COM e1000g_alloc_rx_data(struct e1000g *Adapter)
14428850SMin.Xu@Sun.COM {
14438850SMin.Xu@Sun.COM 	e1000g_rx_ring_t *rx_ring;
14448850SMin.Xu@Sun.COM 	e1000g_rx_data_t *rx_data;
14458850SMin.Xu@Sun.COM 
14468850SMin.Xu@Sun.COM 	rx_ring = Adapter->rx_ring;
14478850SMin.Xu@Sun.COM 
14488850SMin.Xu@Sun.COM 	rx_data = kmem_zalloc(sizeof (e1000g_rx_data_t), KM_NOSLEEP);
14498850SMin.Xu@Sun.COM 
14508850SMin.Xu@Sun.COM 	if (rx_data == NULL)
14518850SMin.Xu@Sun.COM 		return (DDI_FAILURE);
14528850SMin.Xu@Sun.COM 
14538850SMin.Xu@Sun.COM 	rx_data->priv_devi_node = Adapter->priv_devi_node;
14548850SMin.Xu@Sun.COM 	rx_data->rx_ring = rx_ring;
14558850SMin.Xu@Sun.COM 
14568850SMin.Xu@Sun.COM 	mutex_init(&rx_data->freelist_lock, NULL,
14578850SMin.Xu@Sun.COM 	    MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
14588850SMin.Xu@Sun.COM 	mutex_init(&rx_data->recycle_lock, NULL,
14598850SMin.Xu@Sun.COM 	    MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
14608850SMin.Xu@Sun.COM 
14618850SMin.Xu@Sun.COM 	rx_ring->rx_data = rx_data;
14628850SMin.Xu@Sun.COM 
14638850SMin.Xu@Sun.COM 	return (DDI_SUCCESS);
14648850SMin.Xu@Sun.COM }
14658850SMin.Xu@Sun.COM 
14668850SMin.Xu@Sun.COM void
14678850SMin.Xu@Sun.COM e1000g_free_rx_pending_buffers(e1000g_rx_data_t *rx_data)
14688850SMin.Xu@Sun.COM {
14698850SMin.Xu@Sun.COM 	rx_sw_packet_t *packet, *next_packet;
14708850SMin.Xu@Sun.COM 
14718850SMin.Xu@Sun.COM 	if (rx_data == NULL)
14728850SMin.Xu@Sun.COM 		return;
14738850SMin.Xu@Sun.COM 
14748850SMin.Xu@Sun.COM 	packet = rx_data->packet_area;
14758850SMin.Xu@Sun.COM 	while (packet != NULL) {
14768850SMin.Xu@Sun.COM 		next_packet = packet->next;
14778850SMin.Xu@Sun.COM 		e1000g_free_rx_sw_packet(packet, B_TRUE);
14788850SMin.Xu@Sun.COM 		packet = next_packet;
14798850SMin.Xu@Sun.COM 	}
14808850SMin.Xu@Sun.COM 	rx_data->packet_area = NULL;
14818850SMin.Xu@Sun.COM }
14828850SMin.Xu@Sun.COM 
14838850SMin.Xu@Sun.COM void
14848850SMin.Xu@Sun.COM e1000g_free_rx_data(e1000g_rx_data_t *rx_data)
14858850SMin.Xu@Sun.COM {
14868850SMin.Xu@Sun.COM 	if (rx_data == NULL)
14878850SMin.Xu@Sun.COM 		return;
14888850SMin.Xu@Sun.COM 
14898850SMin.Xu@Sun.COM 	mutex_destroy(&rx_data->freelist_lock);
14908850SMin.Xu@Sun.COM 	mutex_destroy(&rx_data->recycle_lock);
14918850SMin.Xu@Sun.COM 
14928850SMin.Xu@Sun.COM 	kmem_free(rx_data, sizeof (e1000g_rx_data_t));
14938850SMin.Xu@Sun.COM }
14948850SMin.Xu@Sun.COM 
14953526Sxy150489 /*
14963526Sxy150489  * Check if the link is up
14973526Sxy150489  */
14983526Sxy150489 static boolean_t
14993526Sxy150489 e1000g_link_up(struct e1000g *Adapter)
15003526Sxy150489 {
15013526Sxy150489 	struct e1000_hw *hw;
15023526Sxy150489 	boolean_t link_up;
15033526Sxy150489 
15044919Sxy150489 	hw = &Adapter->shared;
15053526Sxy150489 
15067426SChenliang.Xu@Sun.COM 	(void) e1000_check_for_link(hw);
15073526Sxy150489 
15084919Sxy150489 	if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) ||
15094919Sxy150489 	    ((!hw->mac.get_link_status) && (hw->mac.type == e1000_82543)) ||
15106735Scc210113 	    ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
15114919Sxy150489 	    (hw->mac.serdes_has_link))) {
15123526Sxy150489 		link_up = B_TRUE;
15133526Sxy150489 	} else {
15143526Sxy150489 		link_up = B_FALSE;
15153526Sxy150489 	}
15163526Sxy150489 
15173526Sxy150489 	return (link_up);
15183526Sxy150489 }
15193526Sxy150489 
15203526Sxy150489 static void
15213526Sxy150489 e1000g_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
15223526Sxy150489 {
15233526Sxy150489 	struct iocblk *iocp;
15243526Sxy150489 	struct e1000g *e1000gp;
15253526Sxy150489 	enum ioc_reply status;
15267426SChenliang.Xu@Sun.COM 
15277426SChenliang.Xu@Sun.COM 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
15283526Sxy150489 	iocp->ioc_error = 0;
15293526Sxy150489 	e1000gp = (struct e1000g *)arg;
15303526Sxy150489 
15313526Sxy150489 	ASSERT(e1000gp);
15323526Sxy150489 	if (e1000gp == NULL) {
15333526Sxy150489 		miocnak(q, mp, 0, EINVAL);
15343526Sxy150489 		return;
15353526Sxy150489 	}
15363526Sxy150489 
15378479SChenlu.Chen@Sun.COM 	rw_enter(&e1000gp->chip_lock, RW_READER);
15388479SChenlu.Chen@Sun.COM 	if (e1000gp->e1000g_state & E1000G_SUSPENDED) {
15398479SChenlu.Chen@Sun.COM 		rw_exit(&e1000gp->chip_lock);
15408479SChenlu.Chen@Sun.COM 		miocnak(q, mp, 0, EINVAL);
15418479SChenlu.Chen@Sun.COM 		return;
15428479SChenlu.Chen@Sun.COM 	}
15438479SChenlu.Chen@Sun.COM 	rw_exit(&e1000gp->chip_lock);
15448479SChenlu.Chen@Sun.COM 
15453526Sxy150489 	switch (iocp->ioc_cmd) {
15463526Sxy150489 
15473526Sxy150489 	case LB_GET_INFO_SIZE:
15483526Sxy150489 	case LB_GET_INFO:
15493526Sxy150489 	case LB_GET_MODE:
15503526Sxy150489 	case LB_SET_MODE:
15513526Sxy150489 		status = e1000g_loopback_ioctl(e1000gp, iocp, mp);
15523526Sxy150489 		break;
15533526Sxy150489 
15543526Sxy150489 
15554919Sxy150489 #ifdef E1000G_DEBUG
15563526Sxy150489 	case E1000G_IOC_REG_PEEK:
15573526Sxy150489 	case E1000G_IOC_REG_POKE:
15583526Sxy150489 		status = e1000g_pp_ioctl(e1000gp, iocp, mp);
15593526Sxy150489 		break;
15603526Sxy150489 	case E1000G_IOC_CHIP_RESET:
15613526Sxy150489 		e1000gp->reset_count++;
15627656SSherry.Moore@Sun.COM 		if (e1000g_reset_adapter(e1000gp))
15633526Sxy150489 			status = IOC_ACK;
15643526Sxy150489 		else
15653526Sxy150489 			status = IOC_INVAL;
15663526Sxy150489 		break;
15674919Sxy150489 #endif
15683526Sxy150489 	default:
15693526Sxy150489 		status = IOC_INVAL;
15703526Sxy150489 		break;
15713526Sxy150489 	}
15723526Sxy150489 
15733526Sxy150489 	/*
15743526Sxy150489 	 * Decide how to reply
15753526Sxy150489 	 */
15763526Sxy150489 	switch (status) {
15773526Sxy150489 	default:
15783526Sxy150489 	case IOC_INVAL:
15793526Sxy150489 		/*
15803526Sxy150489 		 * Error, reply with a NAK and EINVAL or the specified error
15813526Sxy150489 		 */
15823526Sxy150489 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
15834349Sxy150489 		    EINVAL : iocp->ioc_error);
15843526Sxy150489 		break;
15853526Sxy150489 
15863526Sxy150489 	case IOC_DONE:
15873526Sxy150489 		/*
15883526Sxy150489 		 * OK, reply already sent
15893526Sxy150489 		 */
15903526Sxy150489 		break;
15913526Sxy150489 
15923526Sxy150489 	case IOC_ACK:
15933526Sxy150489 		/*
15943526Sxy150489 		 * OK, reply with an ACK
15953526Sxy150489 		 */
15963526Sxy150489 		miocack(q, mp, 0, 0);
15973526Sxy150489 		break;
15983526Sxy150489 
15993526Sxy150489 	case IOC_REPLY:
16003526Sxy150489 		/*
16013526Sxy150489 		 * OK, send prepared reply as ACK or NAK
16023526Sxy150489 		 */
16033526Sxy150489 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
16044349Sxy150489 		    M_IOCACK : M_IOCNAK;
16053526Sxy150489 		qreply(q, mp);
16063526Sxy150489 		break;
16073526Sxy150489 	}
16083526Sxy150489 }
16093526Sxy150489 
16108275SEric Cheng /*
16118275SEric Cheng  * The default value of e1000g_poll_mode == 0 assumes that the NIC is
16128275SEric Cheng  * capable of supporting only one interrupt and we shouldn't disable
16138275SEric Cheng  * the physical interrupt. In this case we let the interrupt come and
16148275SEric Cheng  * we queue the packets in the rx ring itself in case we are in polling
16158275SEric Cheng  * mode (better latency but slightly lower performance and a very
16168275SEric Cheng  * high intrrupt count in mpstat which is harmless).
16178275SEric Cheng  *
16188275SEric Cheng  * e1000g_poll_mode == 1 assumes that we have per Rx ring interrupt
16198275SEric Cheng  * which can be disabled in poll mode. This gives better overall
16208275SEric Cheng  * throughput (compared to the mode above), shows very low interrupt
16218275SEric Cheng  * count but has slightly higher latency since we pick the packets when
16228275SEric Cheng  * the poll thread does polling.
16238275SEric Cheng  *
16248275SEric Cheng  * Currently, this flag should be enabled only while doing performance
16258275SEric Cheng  * measurement or when it can be guaranteed that entire NIC going
16268275SEric Cheng  * in poll mode will not harm any traffic like cluster heartbeat etc.
16278275SEric Cheng  */
16288275SEric Cheng int e1000g_poll_mode = 0;
16298275SEric Cheng 
16308275SEric Cheng /*
16318275SEric Cheng  * Called from the upper layers when driver is in polling mode to
16328275SEric Cheng  * pick up any queued packets. Care should be taken to not block
16338275SEric Cheng  * this thread.
16348275SEric Cheng  */
16358275SEric Cheng static mblk_t *e1000g_poll_ring(void *arg, int bytes_to_pickup)
16368275SEric Cheng {
16378275SEric Cheng 	e1000g_rx_ring_t	*rx_ring = (e1000g_rx_ring_t *)arg;
16388275SEric Cheng 	mblk_t			*mp = NULL;
16398275SEric Cheng 	mblk_t			*tail;
16408275SEric Cheng 	struct e1000g 		*adapter;
16418275SEric Cheng 
16428275SEric Cheng 	adapter = rx_ring->adapter;
16438275SEric Cheng 
16448479SChenlu.Chen@Sun.COM 	rw_enter(&adapter->chip_lock, RW_READER);
16458479SChenlu.Chen@Sun.COM 
16468479SChenlu.Chen@Sun.COM 	if (adapter->e1000g_state & E1000G_SUSPENDED) {
16478479SChenlu.Chen@Sun.COM 		rw_exit(&adapter->chip_lock);
16488479SChenlu.Chen@Sun.COM 		return (NULL);
16498479SChenlu.Chen@Sun.COM 	}
16508479SChenlu.Chen@Sun.COM 
16518275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
16528833SVenu.Iyer@Sun.COM 	mp = e1000g_receive(rx_ring, &tail, bytes_to_pickup);
16538275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
16548479SChenlu.Chen@Sun.COM 	rw_exit(&adapter->chip_lock);
16558275SEric Cheng 	return (mp);
16568275SEric Cheng }
16578275SEric Cheng 
16583526Sxy150489 static int
16593526Sxy150489 e1000g_m_start(void *arg)
16603526Sxy150489 {
16613526Sxy150489 	struct e1000g *Adapter = (struct e1000g *)arg;
16623526Sxy150489 
16638479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
16648479SChenlu.Chen@Sun.COM 
16658479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_SUSPENDED) {
16668479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
16678479SChenlu.Chen@Sun.COM 		return (ECANCELED);
16688479SChenlu.Chen@Sun.COM 	}
16698479SChenlu.Chen@Sun.COM 
16708479SChenlu.Chen@Sun.COM 	if (e1000g_start(Adapter, B_TRUE) != DDI_SUCCESS) {
16718479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
16728479SChenlu.Chen@Sun.COM 		return (ENOTACTIVE);
16738479SChenlu.Chen@Sun.COM 	}
16748479SChenlu.Chen@Sun.COM 
16758479SChenlu.Chen@Sun.COM 	Adapter->e1000g_state |= E1000G_STARTED;
16768479SChenlu.Chen@Sun.COM 
16778479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
16788479SChenlu.Chen@Sun.COM 
16798479SChenlu.Chen@Sun.COM 	/* Enable and start the watchdog timer */
16808479SChenlu.Chen@Sun.COM 	enable_watchdog_timer(Adapter);
16818479SChenlu.Chen@Sun.COM 
16828479SChenlu.Chen@Sun.COM 	return (0);
16833526Sxy150489 }
16843526Sxy150489 
16853526Sxy150489 static int
16864919Sxy150489 e1000g_start(struct e1000g *Adapter, boolean_t global)
16873526Sxy150489 {
16888850SMin.Xu@Sun.COM 	e1000g_rx_data_t *rx_data;
16898850SMin.Xu@Sun.COM 
16904919Sxy150489 	if (global) {
16918850SMin.Xu@Sun.COM 		if (e1000g_alloc_rx_data(Adapter) != DDI_SUCCESS) {
16928850SMin.Xu@Sun.COM 			e1000g_log(Adapter, CE_WARN, "Allocate rx data failed");
16938850SMin.Xu@Sun.COM 			goto start_fail;
16948850SMin.Xu@Sun.COM 		}
16958850SMin.Xu@Sun.COM 
16964919Sxy150489 		/* Allocate dma resources for descriptors and buffers */
16974919Sxy150489 		if (e1000g_alloc_dma_resources(Adapter) != DDI_SUCCESS) {
16984919Sxy150489 			e1000g_log(Adapter, CE_WARN,
16994919Sxy150489 			    "Alloc DMA resources failed");
17008850SMin.Xu@Sun.COM 			goto start_fail;
17014919Sxy150489 		}
17024919Sxy150489 		Adapter->rx_buffer_setup = B_FALSE;
17034919Sxy150489 	}
17044919Sxy150489 
17053526Sxy150489 	if (!(Adapter->attach_progress & ATTACH_PROGRESS_INIT)) {
17063526Sxy150489 		if (e1000g_init(Adapter) != DDI_SUCCESS) {
17073526Sxy150489 			e1000g_log(Adapter, CE_WARN,
17083526Sxy150489 			    "Adapter initialization failed");
17098850SMin.Xu@Sun.COM 			goto start_fail;
17103526Sxy150489 		}
17113526Sxy150489 	}
17123526Sxy150489 
17134919Sxy150489 	/* Setup and initialize the transmit structures */
17144919Sxy150489 	e1000g_tx_setup(Adapter);
17154919Sxy150489 	msec_delay(5);
17164919Sxy150489 
17174919Sxy150489 	/* Setup and initialize the receive structures */
17184919Sxy150489 	e1000g_rx_setup(Adapter);
17194919Sxy150489 	msec_delay(5);
17204919Sxy150489 
17217722SShuguo.Yang@Sun.COM 	/* Restore the e1000g promiscuous mode */
17227722SShuguo.Yang@Sun.COM 	e1000g_restore_promisc(Adapter);
17237722SShuguo.Yang@Sun.COM 
17244919Sxy150489 	e1000g_mask_interrupt(Adapter);
17253526Sxy150489 
17268479SChenlu.Chen@Sun.COM 	Adapter->attach_progress |= ATTACH_PROGRESS_INIT;
17278479SChenlu.Chen@Sun.COM 
17285273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
17295273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST);
17308850SMin.Xu@Sun.COM 		goto start_fail;
17318479SChenlu.Chen@Sun.COM 	}
17328479SChenlu.Chen@Sun.COM 
17338479SChenlu.Chen@Sun.COM 	return (DDI_SUCCESS);
17348850SMin.Xu@Sun.COM 
17358850SMin.Xu@Sun.COM start_fail:
17368850SMin.Xu@Sun.COM 	rx_data = Adapter->rx_ring->rx_data;
17378850SMin.Xu@Sun.COM 
17388850SMin.Xu@Sun.COM 	if (global) {
17398850SMin.Xu@Sun.COM 		e1000g_release_dma_resources(Adapter);
17408850SMin.Xu@Sun.COM 		e1000g_free_rx_pending_buffers(rx_data);
17418850SMin.Xu@Sun.COM 		e1000g_free_rx_data(rx_data);
17428850SMin.Xu@Sun.COM 	}
17438850SMin.Xu@Sun.COM 
17448850SMin.Xu@Sun.COM 	mutex_enter(&e1000g_nvm_lock);
17458850SMin.Xu@Sun.COM 	(void) e1000_reset_hw(&Adapter->shared);
17468850SMin.Xu@Sun.COM 	mutex_exit(&e1000g_nvm_lock);
17478850SMin.Xu@Sun.COM 
17488850SMin.Xu@Sun.COM 	return (DDI_FAILURE);
17493526Sxy150489 }
17503526Sxy150489 
17513526Sxy150489 static void
17523526Sxy150489 e1000g_m_stop(void *arg)
17533526Sxy150489 {
17543526Sxy150489 	struct e1000g *Adapter = (struct e1000g *)arg;
17553526Sxy150489 
17568479SChenlu.Chen@Sun.COM 	/* Drain tx sessions */
17578479SChenlu.Chen@Sun.COM 	(void) e1000g_tx_drain(Adapter);
17588479SChenlu.Chen@Sun.COM 
17598479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
17608479SChenlu.Chen@Sun.COM 
17618479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_SUSPENDED) {
17628479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
17638479SChenlu.Chen@Sun.COM 		return;
17648479SChenlu.Chen@Sun.COM 	}
17658479SChenlu.Chen@Sun.COM 	Adapter->e1000g_state &= ~E1000G_STARTED;
17664919Sxy150489 	e1000g_stop(Adapter, B_TRUE);
17678479SChenlu.Chen@Sun.COM 
17688479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
17698479SChenlu.Chen@Sun.COM 
17708479SChenlu.Chen@Sun.COM 	/* Disable and stop all the timers */
17718479SChenlu.Chen@Sun.COM 	disable_watchdog_timer(Adapter);
17728479SChenlu.Chen@Sun.COM 	stop_link_timer(Adapter);
17738479SChenlu.Chen@Sun.COM 	stop_82547_timer(Adapter->tx_ring);
17743526Sxy150489 }
17753526Sxy150489 
17763526Sxy150489 static void
17774919Sxy150489 e1000g_stop(struct e1000g *Adapter, boolean_t global)
17783526Sxy150489 {
17798850SMin.Xu@Sun.COM 	private_devi_list_t *devi_node;
17808850SMin.Xu@Sun.COM 	e1000g_rx_data_t *rx_data;
17817133Scc210113 	int result;
17827133Scc210113 
17833526Sxy150489 	Adapter->attach_progress &= ~ATTACH_PROGRESS_INIT;
17843526Sxy150489 
17853526Sxy150489 	/* Stop the chip and release pending resources */
17863526Sxy150489 
17877607STed.You@Sun.COM 	/* Tell firmware driver is no longer in control */
17887607STed.You@Sun.COM 	e1000g_release_driver_control(&Adapter->shared);
17897607STed.You@Sun.COM 
17904919Sxy150489 	e1000g_clear_all_interrupts(Adapter);
17917133Scc210113 
17927133Scc210113 	mutex_enter(&e1000g_nvm_lock);
17937133Scc210113 	result = e1000_reset_hw(&Adapter->shared);
17947133Scc210113 	mutex_exit(&e1000g_nvm_lock);
17957133Scc210113 
17967133Scc210113 	if (result != E1000_SUCCESS) {
17975273Sgl147354 		e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE);
17985273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST);
17995273Sgl147354 	}
18003526Sxy150489 
18013526Sxy150489 	/* Release resources still held by the TX descriptors */
18024919Sxy150489 	e1000g_tx_clean(Adapter);
18034061Sxy150489 
18045273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK)
18055273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST);
18065273Sgl147354 
18074061Sxy150489 	/* Clean the pending rx jumbo packet fragment */
18084919Sxy150489 	e1000g_rx_clean(Adapter);
18094061Sxy150489 
18108850SMin.Xu@Sun.COM 	if (global) {
18114919Sxy150489 		e1000g_release_dma_resources(Adapter);
18128850SMin.Xu@Sun.COM 
18138850SMin.Xu@Sun.COM 		mutex_enter(&e1000g_rx_detach_lock);
18148850SMin.Xu@Sun.COM 		rx_data = Adapter->rx_ring->rx_data;
18158850SMin.Xu@Sun.COM 		rx_data->flag |= E1000G_RX_STOPPED;
18168850SMin.Xu@Sun.COM 
18178850SMin.Xu@Sun.COM 		if (rx_data->pending_count == 0) {
18188850SMin.Xu@Sun.COM 			e1000g_free_rx_pending_buffers(rx_data);
18198850SMin.Xu@Sun.COM 			e1000g_free_rx_data(rx_data);
18208850SMin.Xu@Sun.COM 		} else {
18218850SMin.Xu@Sun.COM 			devi_node = rx_data->priv_devi_node;
18228850SMin.Xu@Sun.COM 			if (devi_node != NULL)
18238850SMin.Xu@Sun.COM 				atomic_inc_32(&devi_node->pending_rx_count);
18248850SMin.Xu@Sun.COM 			else
18258850SMin.Xu@Sun.COM 				atomic_inc_32(&Adapter->pending_rx_count);
18268850SMin.Xu@Sun.COM 		}
18278850SMin.Xu@Sun.COM 		mutex_exit(&e1000g_rx_detach_lock);
18288850SMin.Xu@Sun.COM 	}
18294061Sxy150489 }
18304061Sxy150489 
18314061Sxy150489 static void
18324919Sxy150489 e1000g_rx_clean(struct e1000g *Adapter)
18334919Sxy150489 {
18348850SMin.Xu@Sun.COM 	e1000g_rx_data_t *rx_data = Adapter->rx_ring->rx_data;
18358850SMin.Xu@Sun.COM 
18368850SMin.Xu@Sun.COM 	if (rx_data == NULL)
18378850SMin.Xu@Sun.COM 		return;
18388850SMin.Xu@Sun.COM 
18398850SMin.Xu@Sun.COM 	if (rx_data->rx_mblk != NULL) {
18408850SMin.Xu@Sun.COM 		freemsg(rx_data->rx_mblk);
18418850SMin.Xu@Sun.COM 		rx_data->rx_mblk = NULL;
18428850SMin.Xu@Sun.COM 		rx_data->rx_mblk_tail = NULL;
18438850SMin.Xu@Sun.COM 		rx_data->rx_mblk_len = 0;
18444919Sxy150489 	}
18454919Sxy150489 }
18464919Sxy150489 
18474919Sxy150489 static void
18484919Sxy150489 e1000g_tx_clean(struct e1000g *Adapter)
18494061Sxy150489 {
18504061Sxy150489 	e1000g_tx_ring_t *tx_ring;
18514919Sxy150489 	p_tx_sw_packet_t packet;
18524061Sxy150489 	mblk_t *mp;
18534061Sxy150489 	mblk_t *nmp;
18544061Sxy150489 	uint32_t packet_count;
18554061Sxy150489 
18564061Sxy150489 	tx_ring = Adapter->tx_ring;
18574061Sxy150489 
18583526Sxy150489 	/*
18593526Sxy150489 	 * Here we don't need to protect the lists using
18603526Sxy150489 	 * the usedlist_lock and freelist_lock, for they
18613526Sxy150489 	 * have been protected by the chip_lock.
18623526Sxy150489 	 */
18633526Sxy150489 	mp = NULL;
18643526Sxy150489 	nmp = NULL;
18654061Sxy150489 	packet_count = 0;
18664919Sxy150489 	packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(&tx_ring->used_list);
18673526Sxy150489 	while (packet != NULL) {
18683526Sxy150489 		if (packet->mp != NULL) {
18693526Sxy150489 			/* Assemble the message chain */
18703526Sxy150489 			if (mp == NULL) {
18713526Sxy150489 				mp = packet->mp;
18723526Sxy150489 				nmp = packet->mp;
18733526Sxy150489 			} else {
18743526Sxy150489 				nmp->b_next = packet->mp;
18753526Sxy150489 				nmp = packet->mp;
18763526Sxy150489 			}
18773526Sxy150489 			/* Disconnect the message from the sw packet */
18783526Sxy150489 			packet->mp = NULL;
18793526Sxy150489 		}
18803526Sxy150489 
18814919Sxy150489 		e1000g_free_tx_swpkt(packet);
18824061Sxy150489 		packet_count++;
18833526Sxy150489 
18844919Sxy150489 		packet = (p_tx_sw_packet_t)
18853526Sxy150489 		    QUEUE_GET_NEXT(&tx_ring->used_list, &packet->Link);
18863526Sxy150489 	}
18873526Sxy150489 
18885882Syy150190 	if (mp != NULL)
18895882Syy150190 		freemsgchain(mp);
18904061Sxy150489 
18914061Sxy150489 	if (packet_count > 0) {
18924061Sxy150489 		QUEUE_APPEND(&tx_ring->free_list, &tx_ring->used_list);
18934061Sxy150489 		QUEUE_INIT_LIST(&tx_ring->used_list);
18944061Sxy150489 
18954061Sxy150489 		/* Setup TX descriptor pointers */
18964061Sxy150489 		tx_ring->tbd_next = tx_ring->tbd_first;
18974061Sxy150489 		tx_ring->tbd_oldest = tx_ring->tbd_first;
18984061Sxy150489 
18994061Sxy150489 		/* Setup our HW Tx Head & Tail descriptor pointers */
19006735Scc210113 		E1000_WRITE_REG(&Adapter->shared, E1000_TDH(0), 0);
19016735Scc210113 		E1000_WRITE_REG(&Adapter->shared, E1000_TDT(0), 0);
19023526Sxy150489 	}
19033526Sxy150489 }
19043526Sxy150489 
19053526Sxy150489 static boolean_t
19063526Sxy150489 e1000g_tx_drain(struct e1000g *Adapter)
19073526Sxy150489 {
19083526Sxy150489 	int i;
19093526Sxy150489 	boolean_t done;
19103526Sxy150489 	e1000g_tx_ring_t *tx_ring;
19113526Sxy150489 
19123526Sxy150489 	tx_ring = Adapter->tx_ring;
19133526Sxy150489 
19143526Sxy150489 	/* Allow up to 'wsdraintime' for pending xmit's to complete. */
19154919Sxy150489 	for (i = 0; i < TX_DRAIN_TIME; i++) {
19163526Sxy150489 		mutex_enter(&tx_ring->usedlist_lock);
19173526Sxy150489 		done = IS_QUEUE_EMPTY(&tx_ring->used_list);
19183526Sxy150489 		mutex_exit(&tx_ring->usedlist_lock);
19193526Sxy150489 
19203526Sxy150489 		if (done)
19213526Sxy150489 			break;
19223526Sxy150489 
19233526Sxy150489 		msec_delay(1);
19243526Sxy150489 	}
19253526Sxy150489 
19263526Sxy150489 	return (done);
19273526Sxy150489 }
19283526Sxy150489 
19293526Sxy150489 static boolean_t
19303526Sxy150489 e1000g_rx_drain(struct e1000g *Adapter)
19313526Sxy150489 {
19328850SMin.Xu@Sun.COM 	int i;
19333526Sxy150489 	boolean_t done;
19343526Sxy150489 
19358850SMin.Xu@Sun.COM 	/*
19368850SMin.Xu@Sun.COM 	 * Allow up to RX_DRAIN_TIME for pending received packets to complete.
19378850SMin.Xu@Sun.COM 	 */
19388850SMin.Xu@Sun.COM 	for (i = 0; i < RX_DRAIN_TIME; i++) {
19398850SMin.Xu@Sun.COM 		done = (Adapter->pending_rx_count == 0);
19408850SMin.Xu@Sun.COM 
19418850SMin.Xu@Sun.COM 		if (done)
19428850SMin.Xu@Sun.COM 			break;
19438850SMin.Xu@Sun.COM 
19448850SMin.Xu@Sun.COM 		msec_delay(1);
19458850SMin.Xu@Sun.COM 	}
19463526Sxy150489 
19473526Sxy150489 	return (done);
19483526Sxy150489 }
19493526Sxy150489 
19507656SSherry.Moore@Sun.COM static boolean_t
19517656SSherry.Moore@Sun.COM e1000g_reset_adapter(struct e1000g *Adapter)
19523526Sxy150489 {
19538479SChenlu.Chen@Sun.COM 	/* Disable and stop all the timers */
19548479SChenlu.Chen@Sun.COM 	disable_watchdog_timer(Adapter);
19558479SChenlu.Chen@Sun.COM 	stop_link_timer(Adapter);
19568479SChenlu.Chen@Sun.COM 	stop_82547_timer(Adapter->tx_ring);
19578479SChenlu.Chen@Sun.COM 
19588479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
19598479SChenlu.Chen@Sun.COM 
19604919Sxy150489 	e1000g_stop(Adapter, B_FALSE);
19614919Sxy150489 
19628479SChenlu.Chen@Sun.COM 	if (e1000g_start(Adapter, B_FALSE) != DDI_SUCCESS) {
19638479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
19643526Sxy150489 		e1000g_log(Adapter, CE_WARN, "Reset failed");
19658479SChenlu.Chen@Sun.COM 			return (B_FALSE);
19668479SChenlu.Chen@Sun.COM 	}
19678479SChenlu.Chen@Sun.COM 
19688479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
19698479SChenlu.Chen@Sun.COM 
19708479SChenlu.Chen@Sun.COM 	/* Enable and start the watchdog timer */
19718479SChenlu.Chen@Sun.COM 	enable_watchdog_timer(Adapter);
19723526Sxy150489 
19733526Sxy150489 	return (B_TRUE);
19743526Sxy150489 }
19753526Sxy150489 
19765273Sgl147354 boolean_t
19775273Sgl147354 e1000g_global_reset(struct e1000g *Adapter)
19785273Sgl147354 {
19798479SChenlu.Chen@Sun.COM 	/* Disable and stop all the timers */
19808479SChenlu.Chen@Sun.COM 	disable_watchdog_timer(Adapter);
19818479SChenlu.Chen@Sun.COM 	stop_link_timer(Adapter);
19828479SChenlu.Chen@Sun.COM 	stop_82547_timer(Adapter->tx_ring);
19838479SChenlu.Chen@Sun.COM 
19848479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
19858479SChenlu.Chen@Sun.COM 
19865273Sgl147354 	e1000g_stop(Adapter, B_TRUE);
19875273Sgl147354 
19885273Sgl147354 	Adapter->init_count = 0;
19895273Sgl147354 
19908479SChenlu.Chen@Sun.COM 	if (e1000g_start(Adapter, B_TRUE) != DDI_SUCCESS) {
19918479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
19925273Sgl147354 		e1000g_log(Adapter, CE_WARN, "Reset failed");
19935273Sgl147354 		return (B_FALSE);
19945273Sgl147354 	}
19955273Sgl147354 
19968479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
19978479SChenlu.Chen@Sun.COM 
19988479SChenlu.Chen@Sun.COM 	/* Enable and start the watchdog timer */
19998479SChenlu.Chen@Sun.COM 	enable_watchdog_timer(Adapter);
20008479SChenlu.Chen@Sun.COM 
20015273Sgl147354 	return (B_TRUE);
20025273Sgl147354 }
20035273Sgl147354 
20043526Sxy150489 /*
20054919Sxy150489  * e1000g_intr_pciexpress - ISR for PCI Express chipsets
20064919Sxy150489  *
20074919Sxy150489  * This interrupt service routine is for PCI-Express adapters.
20084919Sxy150489  * The ICR contents is valid only when the E1000_ICR_INT_ASSERTED
20094919Sxy150489  * bit is set.
20103526Sxy150489  */
20113526Sxy150489 static uint_t
20123526Sxy150489 e1000g_intr_pciexpress(caddr_t arg)
20133526Sxy150489 {
20143526Sxy150489 	struct e1000g *Adapter;
20154919Sxy150489 	uint32_t icr;
20163526Sxy150489 
20177426SChenliang.Xu@Sun.COM 	Adapter = (struct e1000g *)(uintptr_t)arg;
20184919Sxy150489 	icr = E1000_READ_REG(&Adapter->shared, E1000_ICR);
20194919Sxy150489 
20205273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK)
20215273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
20225273Sgl147354 
20234919Sxy150489 	if (icr & E1000_ICR_INT_ASSERTED) {
20243526Sxy150489 		/*
20253526Sxy150489 		 * E1000_ICR_INT_ASSERTED bit was set:
20263526Sxy150489 		 * Read(Clear) the ICR, claim this interrupt,
20273526Sxy150489 		 * look for work to do.
20283526Sxy150489 		 */
20294919Sxy150489 		e1000g_intr_work(Adapter, icr);
20303526Sxy150489 		return (DDI_INTR_CLAIMED);
20313526Sxy150489 	} else {
20323526Sxy150489 		/*
20333526Sxy150489 		 * E1000_ICR_INT_ASSERTED bit was not set:
20343526Sxy150489 		 * Don't claim this interrupt, return immediately.
20353526Sxy150489 		 */
20363526Sxy150489 		return (DDI_INTR_UNCLAIMED);
20373526Sxy150489 	}
20383526Sxy150489 }
20393526Sxy150489 
20403526Sxy150489 /*
20414919Sxy150489  * e1000g_intr - ISR for PCI/PCI-X chipsets
20424919Sxy150489  *
20434919Sxy150489  * This interrupt service routine is for PCI/PCI-X adapters.
20444919Sxy150489  * We check the ICR contents no matter the E1000_ICR_INT_ASSERTED
20454919Sxy150489  * bit is set or not.
20463526Sxy150489  */
20473526Sxy150489 static uint_t
20483526Sxy150489 e1000g_intr(caddr_t arg)
20493526Sxy150489 {
20503526Sxy150489 	struct e1000g *Adapter;
20514919Sxy150489 	uint32_t icr;
20523526Sxy150489 
20537426SChenliang.Xu@Sun.COM 	Adapter = (struct e1000g *)(uintptr_t)arg;
20544919Sxy150489 	icr = E1000_READ_REG(&Adapter->shared, E1000_ICR);
20554919Sxy150489 
20565273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK)
20575273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
20585273Sgl147354 
20594919Sxy150489 	if (icr) {
20603526Sxy150489 		/*
20613526Sxy150489 		 * Any bit was set in ICR:
20623526Sxy150489 		 * Read(Clear) the ICR, claim this interrupt,
20633526Sxy150489 		 * look for work to do.
20643526Sxy150489 		 */
20654919Sxy150489 		e1000g_intr_work(Adapter, icr);
20663526Sxy150489 		return (DDI_INTR_CLAIMED);
20673526Sxy150489 	} else {
20683526Sxy150489 		/*
20693526Sxy150489 		 * No bit was set in ICR:
20703526Sxy150489 		 * Don't claim this interrupt, return immediately.
20713526Sxy150489 		 */
20723526Sxy150489 		return (DDI_INTR_UNCLAIMED);
20733526Sxy150489 	}
20743526Sxy150489 }
20753526Sxy150489 
20763526Sxy150489 /*
20774919Sxy150489  * e1000g_intr_work - actual processing of ISR
20784919Sxy150489  *
20794919Sxy150489  * Read(clear) the ICR contents and call appropriate interrupt
20804919Sxy150489  * processing routines.
20813526Sxy150489  */
20823526Sxy150489 static void
20834919Sxy150489 e1000g_intr_work(struct e1000g *Adapter, uint32_t icr)
20843526Sxy150489 {
20855882Syy150190 	struct e1000_hw *hw;
20865882Syy150190 	hw = &Adapter->shared;
20875882Syy150190 	e1000g_tx_ring_t *tx_ring = Adapter->tx_ring;
20885882Syy150190 
20895882Syy150190 	Adapter->rx_pkt_cnt = 0;
20905882Syy150190 	Adapter->tx_pkt_cnt = 0;
20915882Syy150190 
20924919Sxy150489 	rw_enter(&Adapter->chip_lock, RW_READER);
20938479SChenlu.Chen@Sun.COM 
20948479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_SUSPENDED) {
20958479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
20968479SChenlu.Chen@Sun.COM 		return;
20978479SChenlu.Chen@Sun.COM 	}
20984919Sxy150489 	/*
20998479SChenlu.Chen@Sun.COM 	 * Here we need to check the "e1000g_state" flag within the chip_lock to
21004919Sxy150489 	 * ensure the receive routine will not execute when the adapter is
21014919Sxy150489 	 * being reset.
21024919Sxy150489 	 */
21038479SChenlu.Chen@Sun.COM 	if (!(Adapter->e1000g_state & E1000G_STARTED)) {
21044919Sxy150489 		rw_exit(&Adapter->chip_lock);
21054919Sxy150489 		return;
21064919Sxy150489 	}
21074919Sxy150489 
21084919Sxy150489 	if (icr & E1000_ICR_RXT0) {
21098833SVenu.Iyer@Sun.COM 		mblk_t			*mp = NULL;
21108833SVenu.Iyer@Sun.COM 		mblk_t			*tail = NULL;
21118275SEric Cheng 		e1000g_rx_ring_t	*rx_ring;
21128275SEric Cheng 
21138275SEric Cheng 		rx_ring = Adapter->rx_ring;
21148275SEric Cheng 		mutex_enter(&rx_ring->rx_lock);
21158275SEric Cheng 		/*
21168833SVenu.Iyer@Sun.COM 		 * Sometimes with legacy interrupts, it possible that
21178833SVenu.Iyer@Sun.COM 		 * there is a single interrupt for Rx/Tx. In which
21188833SVenu.Iyer@Sun.COM 		 * case, if poll flag is set, we shouldn't really
21198833SVenu.Iyer@Sun.COM 		 * be doing Rx processing.
21208275SEric Cheng 		 */
21218833SVenu.Iyer@Sun.COM 		if (!rx_ring->poll_flag)
21228833SVenu.Iyer@Sun.COM 			mp = e1000g_receive(rx_ring, &tail,
21238833SVenu.Iyer@Sun.COM 			    E1000G_CHAIN_NO_LIMIT);
21248833SVenu.Iyer@Sun.COM 		mutex_exit(&rx_ring->rx_lock);
21254919Sxy150489 		rw_exit(&Adapter->chip_lock);
21268833SVenu.Iyer@Sun.COM 		if (mp != NULL)
21278275SEric Cheng 			mac_rx_ring(Adapter->mh, rx_ring->mrh,
21288833SVenu.Iyer@Sun.COM 			    mp, rx_ring->ring_gen_num);
21294919Sxy150489 	} else
21304919Sxy150489 		rw_exit(&Adapter->chip_lock);
21313526Sxy150489 
21325882Syy150190 	if (icr & E1000_ICR_TXDW) {
21335882Syy150190 		if (!Adapter->tx_intr_enable)
21345882Syy150190 			e1000g_clear_tx_interrupt(Adapter);
21355882Syy150190 
21365882Syy150190 		/* Recycle the tx descriptors */
21375882Syy150190 		rw_enter(&Adapter->chip_lock, RW_READER);
21387426SChenliang.Xu@Sun.COM 		(void) e1000g_recycle(tx_ring);
21395882Syy150190 		E1000G_DEBUG_STAT(tx_ring->stat_recycle_intr);
21405882Syy150190 		rw_exit(&Adapter->chip_lock);
21415882Syy150190 
21425882Syy150190 		if (tx_ring->resched_needed &&
21435882Syy150190 		    (tx_ring->tbd_avail > DEFAULT_TX_UPDATE_THRESHOLD)) {
21445882Syy150190 			tx_ring->resched_needed = B_FALSE;
21455882Syy150190 			mac_tx_update(Adapter->mh);
21465882Syy150190 			E1000G_STAT(tx_ring->stat_reschedule);
21475882Syy150190 		}
21485882Syy150190 	}
21495882Syy150190 
21503526Sxy150489 	/*
21513526Sxy150489 	 * The Receive Sequence errors RXSEQ and the link status change LSC
21523526Sxy150489 	 * are checked to detect that the cable has been pulled out. For
21533526Sxy150489 	 * the Wiseman 2.0 silicon, the receive sequence errors interrupt
21543526Sxy150489 	 * are an indication that cable is not connected.
21553526Sxy150489 	 */
21564919Sxy150489 	if ((icr & E1000_ICR_RXSEQ) ||
21574919Sxy150489 	    (icr & E1000_ICR_LSC) ||
21584919Sxy150489 	    (icr & E1000_ICR_GPI_EN1)) {
21594061Sxy150489 		boolean_t link_changed;
21604061Sxy150489 		timeout_id_t tid = 0;
21613526Sxy150489 
21624919Sxy150489 		stop_watchdog_timer(Adapter);
21634919Sxy150489 
21645082Syy150190 		rw_enter(&Adapter->chip_lock, RW_WRITER);
21655082Syy150190 
21665082Syy150190 		/*
21675082Syy150190 		 * Because we got a link-status-change interrupt, force
21685082Syy150190 		 * e1000_check_for_link() to look at phy
21695082Syy150190 		 */
21705082Syy150190 		Adapter->shared.mac.get_link_status = B_TRUE;
21715082Syy150190 
21724061Sxy150489 		/* e1000g_link_check takes care of link status change */
21734061Sxy150489 		link_changed = e1000g_link_check(Adapter);
21745082Syy150190 
21755082Syy150190 		/* Get new phy state */
21765082Syy150190 		e1000g_get_phy_state(Adapter);
21775082Syy150190 
21784061Sxy150489 		/*
21794061Sxy150489 		 * If the link timer has not timed out, we'll not notify
21804919Sxy150489 		 * the upper layer with any link state until the link is up.
21814061Sxy150489 		 */
21824061Sxy150489 		if (link_changed && !Adapter->link_complete) {
21834061Sxy150489 			if (Adapter->link_state == LINK_STATE_UP) {
21845082Syy150190 				mutex_enter(&Adapter->link_lock);
21854061Sxy150489 				Adapter->link_complete = B_TRUE;
21864061Sxy150489 				tid = Adapter->link_tid;
21874061Sxy150489 				Adapter->link_tid = 0;
21885082Syy150190 				mutex_exit(&Adapter->link_lock);
21894061Sxy150489 			} else {
21904061Sxy150489 				link_changed = B_FALSE;
21914061Sxy150489 			}
21924061Sxy150489 		}
21935082Syy150190 		rw_exit(&Adapter->chip_lock);
21943526Sxy150489 
21954061Sxy150489 		if (link_changed) {
21964061Sxy150489 			if (tid != 0)
21974061Sxy150489 				(void) untimeout(tid);
21984061Sxy150489 
21994139Sxy150489 			/*
22004139Sxy150489 			 * Workaround for esb2. Data stuck in fifo on a link
22017133Scc210113 			 * down event. Stop receiver here and reset in watchdog.
22024139Sxy150489 			 */
22034139Sxy150489 			if ((Adapter->link_state == LINK_STATE_DOWN) &&
22047133Scc210113 			    (Adapter->shared.mac.type == e1000_80003es2lan)) {
22057133Scc210113 				uint32_t rctl = E1000_READ_REG(hw, E1000_RCTL);
22067133Scc210113 				E1000_WRITE_REG(hw, E1000_RCTL,
22077133Scc210113 				    rctl & ~E1000_RCTL_EN);
22087133Scc210113 				e1000g_log(Adapter, CE_WARN,
22097133Scc210113 				    "ESB2 receiver disabled");
22107133Scc210113 				Adapter->esb2_workaround = B_TRUE;
22117133Scc210113 			}
22128850SMin.Xu@Sun.COM 			if (!Adapter->reset_flag)
22138850SMin.Xu@Sun.COM 				mac_link_update(Adapter->mh,
22148850SMin.Xu@Sun.COM 				    Adapter->link_state);
22158850SMin.Xu@Sun.COM 			if (Adapter->link_state == LINK_STATE_UP)
22168850SMin.Xu@Sun.COM 				Adapter->reset_flag = B_FALSE;
22173526Sxy150489 		}
22183526Sxy150489 
22194919Sxy150489 		start_watchdog_timer(Adapter);
22203526Sxy150489 	}
22215882Syy150190 }
22225882Syy150190 
22233526Sxy150489 static void
22243526Sxy150489 e1000g_init_unicst(struct e1000g *Adapter)
22253526Sxy150489 {
22263526Sxy150489 	struct e1000_hw *hw;
22273526Sxy150489 	int slot;
22283526Sxy150489 
22294919Sxy150489 	hw = &Adapter->shared;
22303526Sxy150489 
22318275SEric Cheng 	if (Adapter->init_count == 0) {
22323526Sxy150489 		/* Initialize the multiple unicast addresses */
22333526Sxy150489 		Adapter->unicst_total = MAX_NUM_UNICAST_ADDRESSES;
22343526Sxy150489 
22358275SEric Cheng 		/* Workaround for an erratum of 82571 chipst */
22364919Sxy150489 		if ((hw->mac.type == e1000_82571) &&
22374919Sxy150489 		    (e1000_get_laa_state_82571(hw) == B_TRUE))
22383526Sxy150489 			Adapter->unicst_total--;
22393526Sxy150489 
22408275SEric Cheng 		Adapter->unicst_avail = Adapter->unicst_total;
22418275SEric Cheng 
22428275SEric Cheng 		for (slot = 0; slot < Adapter->unicst_total; slot++) {
22438275SEric Cheng 			/* Clear both the flag and MAC address */
22448275SEric Cheng 			Adapter->unicst_addr[slot].reg.high = 0;
22458275SEric Cheng 			Adapter->unicst_addr[slot].reg.low = 0;
22468275SEric Cheng 		}
22473526Sxy150489 	} else {
22488275SEric Cheng 		/* Workaround for an erratum of 82571 chipst */
22494919Sxy150489 		if ((hw->mac.type == e1000_82571) &&
22504919Sxy150489 		    (e1000_get_laa_state_82571(hw) == B_TRUE))
22514919Sxy150489 			e1000_rar_set(hw, hw->mac.addr, LAST_RAR_ENTRY);
22523526Sxy150489 
22533526Sxy150489 		/* Re-configure the RAR registers */
22548275SEric Cheng 		for (slot = 0; slot < Adapter->unicst_total; slot++)
22558275SEric Cheng 			if (Adapter->unicst_addr[slot].mac.set == 1)
22568275SEric Cheng 				e1000_rar_set(hw,
22578275SEric Cheng 				    Adapter->unicst_addr[slot].mac.addr, slot);
22583526Sxy150489 	}
22595273Sgl147354 
22605273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK)
22615273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
22623526Sxy150489 }
22633526Sxy150489 
22643526Sxy150489 static int
22653526Sxy150489 e1000g_unicst_set(struct e1000g *Adapter, const uint8_t *mac_addr,
22668275SEric Cheng     int slot)
22673526Sxy150489 {
22683526Sxy150489 	struct e1000_hw *hw;
22693526Sxy150489 
22704919Sxy150489 	hw = &Adapter->shared;
22713526Sxy150489 
22723526Sxy150489 	/*
22733526Sxy150489 	 * The first revision of Wiseman silicon (rev 2.0) has an errata
22743526Sxy150489 	 * that requires the receiver to be in reset when any of the
22753526Sxy150489 	 * receive address registers (RAR regs) are accessed.  The first
22763526Sxy150489 	 * rev of Wiseman silicon also requires MWI to be disabled when
22773526Sxy150489 	 * a global reset or a receive reset is issued.  So before we
22783526Sxy150489 	 * initialize the RARs, we check the rev of the Wiseman controller
22793526Sxy150489 	 * and work around any necessary HW errata.
22803526Sxy150489 	 */
22814919Sxy150489 	if ((hw->mac.type == e1000_82542) &&
22824919Sxy150489 	    (hw->revision_id == E1000_REVISION_2)) {
22833526Sxy150489 		e1000_pci_clear_mwi(hw);
22844919Sxy150489 		E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST);
22854919Sxy150489 		msec_delay(5);
22863526Sxy150489 	}
22878275SEric Cheng 	if (mac_addr == NULL) {
22888275SEric Cheng 		E1000_WRITE_REG_ARRAY(hw, E1000_RA, slot << 1, 0);
22898275SEric Cheng 		E1000_WRITE_FLUSH(hw);
22908275SEric Cheng 		E1000_WRITE_REG_ARRAY(hw, E1000_RA, (slot << 1) + 1, 0);
22918275SEric Cheng 		E1000_WRITE_FLUSH(hw);
22928275SEric Cheng 		/* Clear both the flag and MAC address */
22938275SEric Cheng 		Adapter->unicst_addr[slot].reg.high = 0;
22948275SEric Cheng 		Adapter->unicst_addr[slot].reg.low = 0;
22958275SEric Cheng 	} else {
22968275SEric Cheng 		bcopy(mac_addr, Adapter->unicst_addr[slot].mac.addr,
22978275SEric Cheng 		    ETHERADDRL);
22988275SEric Cheng 		e1000_rar_set(hw, (uint8_t *)mac_addr, slot);
22998275SEric Cheng 		Adapter->unicst_addr[slot].mac.set = 1;
23008275SEric Cheng 	}
23018275SEric Cheng 
23028275SEric Cheng 	/* Workaround for an erratum of 82571 chipst */
23033526Sxy150489 	if (slot == 0) {
23044919Sxy150489 		if ((hw->mac.type == e1000_82571) &&
23054919Sxy150489 		    (e1000_get_laa_state_82571(hw) == B_TRUE))
23068275SEric Cheng 			if (mac_addr == NULL) {
23078275SEric Cheng 				E1000_WRITE_REG_ARRAY(hw, E1000_RA,
23088275SEric Cheng 				    slot << 1, 0);
23098275SEric Cheng 				E1000_WRITE_FLUSH(hw);
23108275SEric Cheng 				E1000_WRITE_REG_ARRAY(hw, E1000_RA,
23118275SEric Cheng 				    (slot << 1) + 1, 0);
23128275SEric Cheng 				E1000_WRITE_FLUSH(hw);
23138275SEric Cheng 			} else {
23148275SEric Cheng 				e1000_rar_set(hw, (uint8_t *)mac_addr,
23158275SEric Cheng 				    LAST_RAR_ENTRY);
23168275SEric Cheng 			}
23173526Sxy150489 	}
23183526Sxy150489 
23193526Sxy150489 	/*
23203526Sxy150489 	 * If we are using Wiseman rev 2.0 silicon, we will have previously
23213526Sxy150489 	 * put the receive in reset, and disabled MWI, to work around some
23223526Sxy150489 	 * HW errata.  Now we should take the receiver out of reset, and
23233526Sxy150489 	 * re-enabled if MWI if it was previously enabled by the PCI BIOS.
23243526Sxy150489 	 */
23254919Sxy150489 	if ((hw->mac.type == e1000_82542) &&
23264919Sxy150489 	    (hw->revision_id == E1000_REVISION_2)) {
23274919Sxy150489 		E1000_WRITE_REG(hw, E1000_RCTL, 0);
23284919Sxy150489 		msec_delay(1);
23294919Sxy150489 		if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
23303526Sxy150489 			e1000_pci_set_mwi(hw);
23314919Sxy150489 		e1000g_rx_setup(Adapter);
23323526Sxy150489 	}
23333526Sxy150489 
23345273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
23355273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
23365273Sgl147354 		return (EIO);
23375273Sgl147354 	}
23385273Sgl147354 
23393526Sxy150489 	return (0);
23403526Sxy150489 }
23413526Sxy150489 
23423526Sxy150489 static int
23433526Sxy150489 multicst_add(struct e1000g *Adapter, const uint8_t *multiaddr)
23443526Sxy150489 {
23454919Sxy150489 	struct e1000_hw *hw = &Adapter->shared;
23463526Sxy150489 	int res = 0;
23473526Sxy150489 
23483526Sxy150489 	if ((multiaddr[0] & 01) == 0) {
23493526Sxy150489 		res = EINVAL;
23503526Sxy150489 		goto done;
23513526Sxy150489 	}
23523526Sxy150489 
23533526Sxy150489 	if (Adapter->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) {
23543526Sxy150489 		res = ENOENT;
23553526Sxy150489 		goto done;
23563526Sxy150489 	}
23573526Sxy150489 
23583526Sxy150489 	bcopy(multiaddr,
23593526Sxy150489 	    &Adapter->mcast_table[Adapter->mcast_count], ETHERADDRL);
23603526Sxy150489 	Adapter->mcast_count++;
23613526Sxy150489 
23623526Sxy150489 	/*
23633526Sxy150489 	 * Update the MC table in the hardware
23643526Sxy150489 	 */
23654919Sxy150489 	e1000g_clear_interrupt(Adapter);
23664919Sxy150489 
23674919Sxy150489 	e1000g_setup_multicast(Adapter);
23684919Sxy150489 
23694919Sxy150489 	if ((hw->mac.type == e1000_82542) &&
23704919Sxy150489 	    (hw->revision_id == E1000_REVISION_2))
23714919Sxy150489 		e1000g_rx_setup(Adapter);
23724919Sxy150489 
23734919Sxy150489 	e1000g_mask_interrupt(Adapter);
23743526Sxy150489 
23755273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
23765273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
23775273Sgl147354 		res = EIO;
23785273Sgl147354 	}
23795273Sgl147354 
23808479SChenlu.Chen@Sun.COM done:
23813526Sxy150489 	return (res);
23823526Sxy150489 }
23833526Sxy150489 
23843526Sxy150489 static int
23853526Sxy150489 multicst_remove(struct e1000g *Adapter, const uint8_t *multiaddr)
23863526Sxy150489 {
23874919Sxy150489 	struct e1000_hw *hw = &Adapter->shared;
23883526Sxy150489 	unsigned i;
23893526Sxy150489 
23903526Sxy150489 	for (i = 0; i < Adapter->mcast_count; i++) {
23913526Sxy150489 		if (bcmp(multiaddr, &Adapter->mcast_table[i],
23923526Sxy150489 		    ETHERADDRL) == 0) {
23933526Sxy150489 			for (i++; i < Adapter->mcast_count; i++) {
23943526Sxy150489 				Adapter->mcast_table[i - 1] =
23953526Sxy150489 				    Adapter->mcast_table[i];
23963526Sxy150489 			}
23973526Sxy150489 			Adapter->mcast_count--;
23983526Sxy150489 			break;
23993526Sxy150489 		}
24003526Sxy150489 	}
24013526Sxy150489 
24023526Sxy150489 	/*
24033526Sxy150489 	 * Update the MC table in the hardware
24043526Sxy150489 	 */
24054919Sxy150489 	e1000g_clear_interrupt(Adapter);
24064919Sxy150489 
24074919Sxy150489 	e1000g_setup_multicast(Adapter);
24084919Sxy150489 
24094919Sxy150489 	if ((hw->mac.type == e1000_82542) &&
24104919Sxy150489 	    (hw->revision_id == E1000_REVISION_2))
24114919Sxy150489 		e1000g_rx_setup(Adapter);
24124919Sxy150489 
24134919Sxy150489 	e1000g_mask_interrupt(Adapter);
24143526Sxy150489 
24155273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
24165273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
24175273Sgl147354 		return (EIO);
24185273Sgl147354 	}
24195273Sgl147354 
24203526Sxy150489 	return (0);
24213526Sxy150489 }
24223526Sxy150489 
24234919Sxy150489 /*
24244919Sxy150489  * e1000g_setup_multicast - setup multicast data structures
24254919Sxy150489  *
24264919Sxy150489  * This routine initializes all of the multicast related structures.
24274919Sxy150489  */
24284919Sxy150489 void
24294919Sxy150489 e1000g_setup_multicast(struct e1000g *Adapter)
24304919Sxy150489 {
24314919Sxy150489 	uint8_t *mc_addr_list;
24324919Sxy150489 	uint32_t mc_addr_count;
24334919Sxy150489 	uint32_t rctl;
24344919Sxy150489 	struct e1000_hw *hw;
24354919Sxy150489 
24364919Sxy150489 	hw = &Adapter->shared;
24374919Sxy150489 
24384919Sxy150489 	/*
24394919Sxy150489 	 * The e1000g has the ability to do perfect filtering of 16
24404919Sxy150489 	 * addresses. The driver uses one of the e1000g's 16 receive
24414919Sxy150489 	 * address registers for its node/network/mac/individual address.
24424919Sxy150489 	 * So, we have room for up to 15 multicast addresses in the CAM,
24434919Sxy150489 	 * additional MC addresses are handled by the MTA (Multicast Table
24444919Sxy150489 	 * Array)
24454919Sxy150489 	 */
24464919Sxy150489 
24474919Sxy150489 	rctl = E1000_READ_REG(hw, E1000_RCTL);
24484919Sxy150489 
24494919Sxy150489 	mc_addr_list = (uint8_t *)Adapter->mcast_table;
24504919Sxy150489 
24514919Sxy150489 	if (Adapter->mcast_count > MAX_NUM_MULTICAST_ADDRESSES) {
24524919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, CE_WARN,
24534919Sxy150489 		    "Adapter requested more than %d MC Addresses.\n",
24544919Sxy150489 		    MAX_NUM_MULTICAST_ADDRESSES);
24554919Sxy150489 		mc_addr_count = MAX_NUM_MULTICAST_ADDRESSES;
24564919Sxy150489 	} else {
24574919Sxy150489 		/*
24584919Sxy150489 		 * Set the number of MC addresses that we are being
24594919Sxy150489 		 * requested to use
24604919Sxy150489 		 */
24614919Sxy150489 		mc_addr_count = Adapter->mcast_count;
24624919Sxy150489 	}
24634919Sxy150489 	/*
24644919Sxy150489 	 * The Wiseman 2.0 silicon has an errata by which the receiver will
24654919Sxy150489 	 * hang  while writing to the receive address registers if the receiver
24664919Sxy150489 	 * is not in reset before writing to the registers. Updating the RAR
24674919Sxy150489 	 * is done during the setting up of the multicast table, hence the
24684919Sxy150489 	 * receiver has to be put in reset before updating the multicast table
24694919Sxy150489 	 * and then taken out of reset at the end
24704919Sxy150489 	 */
24714919Sxy150489 	/*
24724919Sxy150489 	 * if WMI was enabled then dis able it before issueing the global
24734919Sxy150489 	 * reset to the hardware.
24744919Sxy150489 	 */
24754919Sxy150489 	/*
24764919Sxy150489 	 * Only required for WISEMAN_2_0
24774919Sxy150489 	 */
24784919Sxy150489 	if ((hw->mac.type == e1000_82542) &&
24794919Sxy150489 	    (hw->revision_id == E1000_REVISION_2)) {
24804919Sxy150489 		e1000_pci_clear_mwi(hw);
24814919Sxy150489 		/*
24824919Sxy150489 		 * The e1000g must be in reset before changing any RA
24834919Sxy150489 		 * registers. Reset receive unit.  The chip will remain in
24844919Sxy150489 		 * the reset state until software explicitly restarts it.
24854919Sxy150489 		 */
24864919Sxy150489 		E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST);
24874919Sxy150489 		/* Allow receiver time to go in to reset */
24884919Sxy150489 		msec_delay(5);
24894919Sxy150489 	}
24906735Scc210113 
24916735Scc210113 	e1000_update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
24924919Sxy150489 	    Adapter->unicst_total, hw->mac.rar_entry_count);
24934919Sxy150489 
24944919Sxy150489 	/*
24954919Sxy150489 	 * Only for Wiseman_2_0
24964919Sxy150489 	 * If MWI was enabled then re-enable it after issueing (as we
24974919Sxy150489 	 * disabled it up there) the receive reset command.
24984919Sxy150489 	 * Wainwright does not have a receive reset command and only thing
24994919Sxy150489 	 * close to it is global reset which will require tx setup also
25004919Sxy150489 	 */
25014919Sxy150489 	if ((hw->mac.type == e1000_82542) &&
25024919Sxy150489 	    (hw->revision_id == E1000_REVISION_2)) {
25034919Sxy150489 		/*
25044919Sxy150489 		 * if WMI was enabled then reenable it after issueing the
25054919Sxy150489 		 * global or receive reset to the hardware.
25064919Sxy150489 		 */
25074919Sxy150489 
25084919Sxy150489 		/*
25094919Sxy150489 		 * Take receiver out of reset
25104919Sxy150489 		 * clear E1000_RCTL_RST bit (and all others)
25114919Sxy150489 		 */
25124919Sxy150489 		E1000_WRITE_REG(hw, E1000_RCTL, 0);
25134919Sxy150489 		msec_delay(5);
25144919Sxy150489 		if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
25154919Sxy150489 			e1000_pci_set_mwi(hw);
25164919Sxy150489 	}
25174919Sxy150489 
25184919Sxy150489 	/*
25194919Sxy150489 	 * Restore original value
25204919Sxy150489 	 */
25214919Sxy150489 	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
25224919Sxy150489 }
25234919Sxy150489 
25243526Sxy150489 int
25253526Sxy150489 e1000g_m_multicst(void *arg, boolean_t add, const uint8_t *addr)
25263526Sxy150489 {
25273526Sxy150489 	struct e1000g *Adapter = (struct e1000g *)arg;
25288479SChenlu.Chen@Sun.COM 	int result;
25298479SChenlu.Chen@Sun.COM 
25308479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
25318479SChenlu.Chen@Sun.COM 
25328479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_SUSPENDED) {
25338479SChenlu.Chen@Sun.COM 		result = ECANCELED;
25348479SChenlu.Chen@Sun.COM 		goto done;
25358479SChenlu.Chen@Sun.COM 	}
25368479SChenlu.Chen@Sun.COM 
25378479SChenlu.Chen@Sun.COM 	result = (add) ? multicst_add(Adapter, addr)
25388479SChenlu.Chen@Sun.COM 	    : multicst_remove(Adapter, addr);
25398479SChenlu.Chen@Sun.COM 
25408479SChenlu.Chen@Sun.COM done:
25418479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
25428479SChenlu.Chen@Sun.COM 	return (result);
25438479SChenlu.Chen@Sun.COM 
25443526Sxy150489 }
25453526Sxy150489 
25463526Sxy150489 int
25473526Sxy150489 e1000g_m_promisc(void *arg, boolean_t on)
25483526Sxy150489 {
25493526Sxy150489 	struct e1000g *Adapter = (struct e1000g *)arg;
25504919Sxy150489 	uint32_t rctl;
25513526Sxy150489 
25523526Sxy150489 	rw_enter(&Adapter->chip_lock, RW_WRITER);
25533526Sxy150489 
25548479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_SUSPENDED) {
25558479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
25568479SChenlu.Chen@Sun.COM 		return (ECANCELED);
25578479SChenlu.Chen@Sun.COM 	}
25588479SChenlu.Chen@Sun.COM 
25594919Sxy150489 	rctl = E1000_READ_REG(&Adapter->shared, E1000_RCTL);
25603526Sxy150489 
25613526Sxy150489 	if (on)
25624919Sxy150489 		rctl |=
25633526Sxy150489 		    (E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_BAM);
25643526Sxy150489 	else
25654919Sxy150489 		rctl &= (~(E1000_RCTL_UPE | E1000_RCTL_MPE));
25664919Sxy150489 
25674919Sxy150489 	E1000_WRITE_REG(&Adapter->shared, E1000_RCTL, rctl);
25683526Sxy150489 
25693526Sxy150489 	Adapter->e1000g_promisc = on;
25703526Sxy150489 
25713526Sxy150489 	rw_exit(&Adapter->chip_lock);
25723526Sxy150489 
25735273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
25745273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
25755273Sgl147354 		return (EIO);
25765273Sgl147354 	}
25775273Sgl147354 
25783526Sxy150489 	return (0);
25793526Sxy150489 }
25803526Sxy150489 
25818275SEric Cheng /*
25828275SEric Cheng  * Entry points to enable and disable interrupts at the granularity of
25838275SEric Cheng  * a group.
25848275SEric Cheng  * Turns the poll_mode for the whole adapter on and off to enable or
25858275SEric Cheng  * override the ring level polling control over the hardware interrupts.
25868275SEric Cheng  */
25878275SEric Cheng static int
25888275SEric Cheng e1000g_rx_group_intr_enable(mac_intr_handle_t arg)
25898275SEric Cheng {
25908275SEric Cheng 	struct e1000g		*adapter = (struct e1000g *)arg;
25918275SEric Cheng 	e1000g_rx_ring_t *rx_ring = adapter->rx_ring;
25928275SEric Cheng 
25938275SEric Cheng 	/*
25948275SEric Cheng 	 * Later interrupts at the granularity of the this ring will
25958275SEric Cheng 	 * invoke mac_rx() with NULL, indicating the need for another
25968275SEric Cheng 	 * software classification.
25978275SEric Cheng 	 * We have a single ring usable per adapter now, so we only need to
25988275SEric Cheng 	 * reset the rx handle for that one.
25998275SEric Cheng 	 * When more RX rings can be used, we should update each one of them.
26008275SEric Cheng 	 */
26018275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
26028275SEric Cheng 	rx_ring->mrh = NULL;
26038275SEric Cheng 	adapter->poll_mode = B_FALSE;
26048275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
26058275SEric Cheng 	return (0);
26068275SEric Cheng }
26078275SEric Cheng 
26088275SEric Cheng static int
26098275SEric Cheng e1000g_rx_group_intr_disable(mac_intr_handle_t arg)
26108275SEric Cheng {
26118275SEric Cheng 	struct e1000g *adapter = (struct e1000g *)arg;
26128275SEric Cheng 	e1000g_rx_ring_t *rx_ring = adapter->rx_ring;
26138275SEric Cheng 
26148275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
26158275SEric Cheng 
26168275SEric Cheng 	/*
26178275SEric Cheng 	 * Later interrupts at the granularity of the this ring will
26188275SEric Cheng 	 * invoke mac_rx() with the handle for this ring;
26198275SEric Cheng 	 */
26208275SEric Cheng 	adapter->poll_mode = B_TRUE;
26218275SEric Cheng 	rx_ring->mrh = rx_ring->mrh_init;
26228275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
26238275SEric Cheng 	return (0);
26248275SEric Cheng }
26258275SEric Cheng 
26268275SEric Cheng /*
26278275SEric Cheng  * Entry points to enable and disable interrupts at the granularity of
26288275SEric Cheng  * a ring.
26298275SEric Cheng  * adapter poll_mode controls whether we actually proceed with hardware
26308275SEric Cheng  * interrupt toggling.
26318275SEric Cheng  */
26328275SEric Cheng static int
26338275SEric Cheng e1000g_rx_ring_intr_enable(mac_intr_handle_t intrh)
26348275SEric Cheng {
26358275SEric Cheng 	e1000g_rx_ring_t	*rx_ring = (e1000g_rx_ring_t *)intrh;
26368275SEric Cheng 	struct e1000g 		*adapter = rx_ring->adapter;
26378275SEric Cheng 	struct e1000_hw 	*hw = &adapter->shared;
26388275SEric Cheng 	uint32_t		intr_mask;
26398275SEric Cheng 
26408479SChenlu.Chen@Sun.COM 	rw_enter(&adapter->chip_lock, RW_READER);
26418479SChenlu.Chen@Sun.COM 
26428479SChenlu.Chen@Sun.COM 	if (adapter->e1000g_state & E1000G_SUSPENDED) {
26438479SChenlu.Chen@Sun.COM 		rw_exit(&adapter->chip_lock);
26448479SChenlu.Chen@Sun.COM 		return (0);
26458479SChenlu.Chen@Sun.COM 	}
26468479SChenlu.Chen@Sun.COM 
26478275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
26488275SEric Cheng 	rx_ring->poll_flag = 0;
26498275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
26508275SEric Cheng 
26518833SVenu.Iyer@Sun.COM 	/* Rx interrupt enabling for MSI and legacy */
26528833SVenu.Iyer@Sun.COM 	intr_mask = E1000_READ_REG(hw, E1000_IMS);
26538833SVenu.Iyer@Sun.COM 	intr_mask |= E1000_IMS_RXT0;
26548833SVenu.Iyer@Sun.COM 	E1000_WRITE_REG(hw, E1000_IMS, intr_mask);
26558833SVenu.Iyer@Sun.COM 	E1000_WRITE_FLUSH(hw);
26568833SVenu.Iyer@Sun.COM 
26578833SVenu.Iyer@Sun.COM 	/* Trigger a Rx interrupt to check Rx ring */
26588833SVenu.Iyer@Sun.COM 	E1000_WRITE_REG(hw, E1000_ICS, E1000_IMS_RXT0);
26598833SVenu.Iyer@Sun.COM 	E1000_WRITE_FLUSH(hw);
26608479SChenlu.Chen@Sun.COM 
26618479SChenlu.Chen@Sun.COM 	rw_exit(&adapter->chip_lock);
26628275SEric Cheng 	return (0);
26638275SEric Cheng }
26648275SEric Cheng 
26658275SEric Cheng static int
26668275SEric Cheng e1000g_rx_ring_intr_disable(mac_intr_handle_t intrh)
26678275SEric Cheng {
26688275SEric Cheng 	e1000g_rx_ring_t	*rx_ring = (e1000g_rx_ring_t *)intrh;
26698275SEric Cheng 	struct e1000g 		*adapter = rx_ring->adapter;
26708275SEric Cheng 	struct e1000_hw 	*hw = &adapter->shared;
26718275SEric Cheng 
26728479SChenlu.Chen@Sun.COM 	rw_enter(&adapter->chip_lock, RW_READER);
26738479SChenlu.Chen@Sun.COM 
26748479SChenlu.Chen@Sun.COM 	if (adapter->e1000g_state & E1000G_SUSPENDED) {
26758479SChenlu.Chen@Sun.COM 		rw_exit(&adapter->chip_lock);
26768479SChenlu.Chen@Sun.COM 		return (0);
26778479SChenlu.Chen@Sun.COM 	}
26788275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
26798275SEric Cheng 	rx_ring->poll_flag = 1;
26808275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
26818275SEric Cheng 
26828833SVenu.Iyer@Sun.COM 	/* Rx interrupt disabling for MSI and legacy */
26838833SVenu.Iyer@Sun.COM 	E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_RXT0);
26848833SVenu.Iyer@Sun.COM 	E1000_WRITE_FLUSH(hw);
26858479SChenlu.Chen@Sun.COM 
26868479SChenlu.Chen@Sun.COM 	rw_exit(&adapter->chip_lock);
26878275SEric Cheng 	return (0);
26888275SEric Cheng }
26898275SEric Cheng 
26908275SEric Cheng /*
26918275SEric Cheng  * e1000g_unicst_find - Find the slot for the specified unicast address
26928275SEric Cheng  */
26938275SEric Cheng static int
26948275SEric Cheng e1000g_unicst_find(struct e1000g *Adapter, const uint8_t *mac_addr)
26958275SEric Cheng {
26968275SEric Cheng 	int slot;
26978275SEric Cheng 
26988275SEric Cheng 	for (slot = 0; slot < Adapter->unicst_total; slot++) {
26998479SChenlu.Chen@Sun.COM 		if ((Adapter->unicst_addr[slot].mac.set == 1) &&
27008479SChenlu.Chen@Sun.COM 		    (bcmp(Adapter->unicst_addr[slot].mac.addr,
27018479SChenlu.Chen@Sun.COM 		    mac_addr, ETHERADDRL) == 0))
27028275SEric Cheng 				return (slot);
27038275SEric Cheng 	}
27048275SEric Cheng 
27058275SEric Cheng 	return (-1);
27068275SEric Cheng }
27078275SEric Cheng 
27088275SEric Cheng /*
27098275SEric Cheng  * Entry points to add and remove a MAC address to a ring group.
27108275SEric Cheng  * The caller takes care of adding and removing the MAC addresses
27118275SEric Cheng  * to the filter via these two routines.
27128275SEric Cheng  */
27138275SEric Cheng 
27148275SEric Cheng static int
27158275SEric Cheng e1000g_addmac(void *arg, const uint8_t *mac_addr)
27168275SEric Cheng {
27178275SEric Cheng 	struct e1000g *Adapter = (struct e1000g *)arg;
27188400SNicolas.Droux@Sun.COM 	int slot, err;
27198275SEric Cheng 
27208479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
27218479SChenlu.Chen@Sun.COM 
27228479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_SUSPENDED) {
27238479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
27248479SChenlu.Chen@Sun.COM 		return (ECANCELED);
27258479SChenlu.Chen@Sun.COM 	}
27268275SEric Cheng 
27278275SEric Cheng 	if (e1000g_unicst_find(Adapter, mac_addr) != -1) {
27288275SEric Cheng 		/* The same address is already in slot */
27298479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
27308275SEric Cheng 		return (0);
27318275SEric Cheng 	}
27328275SEric Cheng 
27338275SEric Cheng 	if (Adapter->unicst_avail == 0) {
27348275SEric Cheng 		/* no slots available */
27358479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
27368275SEric Cheng 		return (ENOSPC);
27378275SEric Cheng 	}
27388275SEric Cheng 
27398275SEric Cheng 	/* Search for a free slot */
27408275SEric Cheng 	for (slot = 0; slot < Adapter->unicst_total; slot++) {
27418275SEric Cheng 		if (Adapter->unicst_addr[slot].mac.set == 0)
27428275SEric Cheng 			break;
27438275SEric Cheng 	}
27448275SEric Cheng 	ASSERT(slot < Adapter->unicst_total);
27458275SEric Cheng 
27468400SNicolas.Droux@Sun.COM 	err = e1000g_unicst_set(Adapter, mac_addr, slot);
27478400SNicolas.Droux@Sun.COM 	if (err == 0)
27488400SNicolas.Droux@Sun.COM 		Adapter->unicst_avail--;
27498275SEric Cheng 
27508479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
27518275SEric Cheng 
27528400SNicolas.Droux@Sun.COM 	return (err);
27538275SEric Cheng }
27548275SEric Cheng 
27558275SEric Cheng static int
27568275SEric Cheng e1000g_remmac(void *arg, const uint8_t *mac_addr)
27578275SEric Cheng {
27588275SEric Cheng 	struct e1000g *Adapter = (struct e1000g *)arg;
27598400SNicolas.Droux@Sun.COM 	int slot, err;
27608275SEric Cheng 
27618479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_WRITER);
27628479SChenlu.Chen@Sun.COM 
27638479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_SUSPENDED) {
27648479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
27658479SChenlu.Chen@Sun.COM 		return (ECANCELED);
27668479SChenlu.Chen@Sun.COM 	}
27678275SEric Cheng 
27688275SEric Cheng 	slot = e1000g_unicst_find(Adapter, mac_addr);
27698275SEric Cheng 	if (slot == -1) {
27708479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
27718275SEric Cheng 		return (EINVAL);
27728275SEric Cheng 	}
27738275SEric Cheng 
27748275SEric Cheng 	ASSERT(Adapter->unicst_addr[slot].mac.set);
27758275SEric Cheng 
27768275SEric Cheng 	/* Clear this slot */
27778400SNicolas.Droux@Sun.COM 	err = e1000g_unicst_set(Adapter, NULL, slot);
27788400SNicolas.Droux@Sun.COM 	if (err == 0)
27798400SNicolas.Droux@Sun.COM 		Adapter->unicst_avail++;
27808275SEric Cheng 
27818479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
27828275SEric Cheng 
27838400SNicolas.Droux@Sun.COM 	return (err);
27848275SEric Cheng }
27858275SEric Cheng 
27868275SEric Cheng static int
27878275SEric Cheng e1000g_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
27888275SEric Cheng {
27898275SEric Cheng 	e1000g_rx_ring_t *rx_ring = (e1000g_rx_ring_t *)rh;
27908275SEric Cheng 
27918275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
27928275SEric Cheng 	rx_ring->ring_gen_num = mr_gen_num;
27938275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
27948275SEric Cheng 	return (0);
27958275SEric Cheng }
27968275SEric Cheng 
27978275SEric Cheng /*
27988275SEric Cheng  * Callback funtion for MAC layer to register all rings.
27998275SEric Cheng  *
28008275SEric Cheng  * The hardware supports a single group with currently only one ring
28018275SEric Cheng  * available.
28028275SEric Cheng  * Though not offering virtualization ability per se, exposing the
28038275SEric Cheng  * group/ring still enables the polling and interrupt toggling.
28048275SEric Cheng  */
28058275SEric Cheng void
28068275SEric Cheng e1000g_fill_ring(void *arg, mac_ring_type_t rtype, const int grp_index,
28078275SEric Cheng     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
28088275SEric Cheng {
28098275SEric Cheng 	struct e1000g *Adapter = (struct e1000g *)arg;
28108275SEric Cheng 	e1000g_rx_ring_t *rx_ring = Adapter->rx_ring;
28118275SEric Cheng 	mac_intr_t *mintr;
28128275SEric Cheng 
28138275SEric Cheng 	/*
28148275SEric Cheng 	 * We advertised only RX group/rings, so the MAC framework shouldn't
28158275SEric Cheng 	 * ask for any thing else.
28168275SEric Cheng 	 */
28178275SEric Cheng 	ASSERT(rtype == MAC_RING_TYPE_RX && grp_index == 0 && ring_index == 0);
28188275SEric Cheng 
28198275SEric Cheng 	rx_ring->mrh = rx_ring->mrh_init = rh;
28208275SEric Cheng 	infop->mri_driver = (mac_ring_driver_t)rx_ring;
28218275SEric Cheng 	infop->mri_start = e1000g_ring_start;
28228275SEric Cheng 	infop->mri_stop = NULL;
28238275SEric Cheng 	infop->mri_poll = e1000g_poll_ring;
28248275SEric Cheng 
28258275SEric Cheng 	/* Ring level interrupts */
28268275SEric Cheng 	mintr = &infop->mri_intr;
28278275SEric Cheng 	mintr->mi_handle = (mac_intr_handle_t)rx_ring;
28288275SEric Cheng 	mintr->mi_enable = e1000g_rx_ring_intr_enable;
28298275SEric Cheng 	mintr->mi_disable = e1000g_rx_ring_intr_disable;
28308275SEric Cheng }
28318275SEric Cheng 
28328275SEric Cheng static void
28338275SEric Cheng e1000g_fill_group(void *arg, mac_ring_type_t rtype, const int grp_index,
28348275SEric Cheng     mac_group_info_t *infop, mac_group_handle_t gh)
28358275SEric Cheng {
28368275SEric Cheng 	struct e1000g *Adapter = (struct e1000g *)arg;
28378275SEric Cheng 	mac_intr_t *mintr;
28388275SEric Cheng 
28398275SEric Cheng 	/*
28408275SEric Cheng 	 * We advertised a single RX ring. Getting a request for anything else
28418275SEric Cheng 	 * signifies a bug in the MAC framework.
28428275SEric Cheng 	 */
28438275SEric Cheng 	ASSERT(rtype == MAC_RING_TYPE_RX && grp_index == 0);
28448275SEric Cheng 
28458275SEric Cheng 	Adapter->rx_group = gh;
28468275SEric Cheng 
28478275SEric Cheng 	infop->mgi_driver = (mac_group_driver_t)Adapter;
28488275SEric Cheng 	infop->mgi_start = NULL;
28498275SEric Cheng 	infop->mgi_stop = NULL;
28508275SEric Cheng 	infop->mgi_addmac = e1000g_addmac;
28518275SEric Cheng 	infop->mgi_remmac = e1000g_remmac;
28528275SEric Cheng 	infop->mgi_count = 1;
28538275SEric Cheng 
28548275SEric Cheng 	/* Group level interrupts */
28558275SEric Cheng 	mintr = &infop->mgi_intr;
28568275SEric Cheng 	mintr->mi_handle = (mac_intr_handle_t)Adapter;
28578275SEric Cheng 	mintr->mi_enable = e1000g_rx_group_intr_enable;
28588275SEric Cheng 	mintr->mi_disable = e1000g_rx_group_intr_disable;
28598275SEric Cheng }
28608275SEric Cheng 
28613526Sxy150489 static boolean_t
28623526Sxy150489 e1000g_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
28633526Sxy150489 {
28643526Sxy150489 	struct e1000g *Adapter = (struct e1000g *)arg;
28653526Sxy150489 
28663526Sxy150489 	switch (cap) {
28673526Sxy150489 	case MAC_CAPAB_HCKSUM: {
28683526Sxy150489 		uint32_t *txflags = cap_data;
28696986Smx205022 
28706986Smx205022 		if (Adapter->tx_hcksum_enable)
28716986Smx205022 			*txflags = HCKSUM_IPHDRCKSUM |
28726986Smx205022 			    HCKSUM_INET_PARTIAL;
28736986Smx205022 		else
28743526Sxy150489 			return (B_FALSE);
28753526Sxy150489 		break;
28763526Sxy150489 	}
28776986Smx205022 
28786986Smx205022 	case MAC_CAPAB_LSO: {
28796986Smx205022 		mac_capab_lso_t *cap_lso = cap_data;
28806986Smx205022 
28816986Smx205022 		if (Adapter->lso_enable) {
28826986Smx205022 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
28836986Smx205022 			cap_lso->lso_basic_tcp_ipv4.lso_max =
28846986Smx205022 			    E1000_LSO_MAXLEN;
28856986Smx205022 		} else
28866986Smx205022 			return (B_FALSE);
28876986Smx205022 		break;
28886986Smx205022 	}
28898275SEric Cheng 	case MAC_CAPAB_RINGS: {
28908275SEric Cheng 		mac_capab_rings_t *cap_rings = cap_data;
28918275SEric Cheng 
28928275SEric Cheng 		/* No TX rings exposed yet */
28938275SEric Cheng 		if (cap_rings->mr_type != MAC_RING_TYPE_RX)
28948275SEric Cheng 			return (B_FALSE);
28958275SEric Cheng 
28968275SEric Cheng 		cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
28978275SEric Cheng 		cap_rings->mr_rnum = 1;
28988275SEric Cheng 		cap_rings->mr_gnum = 1;
28998275SEric Cheng 		cap_rings->mr_rget = e1000g_fill_ring;
29008275SEric Cheng 		cap_rings->mr_gget = e1000g_fill_group;
29018275SEric Cheng 		break;
29028275SEric Cheng 	}
29033526Sxy150489 	default:
29043526Sxy150489 		return (B_FALSE);
29053526Sxy150489 	}
29063526Sxy150489 	return (B_TRUE);
29073526Sxy150489 }
29083526Sxy150489 
29096394Scc210113 static boolean_t
29106394Scc210113 e1000g_param_locked(mac_prop_id_t pr_num)
29116394Scc210113 {
29126394Scc210113 	/*
29136394Scc210113 	 * All en_* parameters are locked (read-only) while
29146394Scc210113 	 * the device is in any sort of loopback mode ...
29156394Scc210113 	 */
29166394Scc210113 	switch (pr_num) {
29176789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
29186789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
29196789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
29206789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
29216789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
29226789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
29236789Sam223141 		case MAC_PROP_AUTONEG:
29246789Sam223141 		case MAC_PROP_FLOWCTRL:
29256394Scc210113 			return (B_TRUE);
29266394Scc210113 	}
29276394Scc210113 	return (B_FALSE);
29286394Scc210113 }
29296394Scc210113 
29306394Scc210113 /*
29316394Scc210113  * callback function for set/get of properties
29326394Scc210113  */
29336394Scc210113 static int
29346394Scc210113 e1000g_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
29356394Scc210113     uint_t pr_valsize, const void *pr_val)
29366394Scc210113 {
29376394Scc210113 	struct e1000g *Adapter = arg;
29386394Scc210113 	struct e1000_mac_info *mac = &Adapter->shared.mac;
29396394Scc210113 	struct e1000_phy_info *phy = &Adapter->shared.phy;
29406735Scc210113 	struct e1000_fc_info *fc = &Adapter->shared.fc;
29416394Scc210113 	int err = 0;
29426735Scc210113 	link_flowctrl_t flowctrl;
29436512Ssowmini 	uint32_t cur_mtu, new_mtu;
29446394Scc210113 	uint64_t tmp = 0;
29456394Scc210113 
29466394Scc210113 	rw_enter(&Adapter->chip_lock, RW_WRITER);
29478479SChenlu.Chen@Sun.COM 
29488479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_SUSPENDED) {
29498479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
29508479SChenlu.Chen@Sun.COM 		return (ECANCELED);
29518479SChenlu.Chen@Sun.COM 	}
29528479SChenlu.Chen@Sun.COM 
29536394Scc210113 	if (Adapter->loopback_mode != E1000G_LB_NONE &&
29546394Scc210113 	    e1000g_param_locked(pr_num)) {
29556394Scc210113 		/*
29566394Scc210113 		 * All en_* parameters are locked (read-only)
29576394Scc210113 		 * while the device is in any sort of loopback mode.
29586394Scc210113 		 */
29596394Scc210113 		rw_exit(&Adapter->chip_lock);
29606394Scc210113 		return (EBUSY);
29616394Scc210113 	}
29626394Scc210113 
29636394Scc210113 	switch (pr_num) {
29646789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
29656394Scc210113 			Adapter->param_en_1000fdx = *(uint8_t *)pr_val;
29666394Scc210113 			Adapter->param_adv_1000fdx = *(uint8_t *)pr_val;
29676394Scc210113 			goto reset;
29686789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
29696394Scc210113 			Adapter->param_en_100fdx = *(uint8_t *)pr_val;
29706394Scc210113 			Adapter->param_adv_100fdx = *(uint8_t *)pr_val;
29716394Scc210113 			goto reset;
29726789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
29736394Scc210113 			Adapter->param_en_100hdx = *(uint8_t *)pr_val;
29746394Scc210113 			Adapter->param_adv_100hdx = *(uint8_t *)pr_val;
29756394Scc210113 			goto reset;
29766789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
29776394Scc210113 			Adapter->param_en_10fdx = *(uint8_t *)pr_val;
29786394Scc210113 			Adapter->param_adv_10fdx = *(uint8_t *)pr_val;
29796394Scc210113 			goto reset;
29806789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
29816394Scc210113 			Adapter->param_en_10hdx = *(uint8_t *)pr_val;
29826394Scc210113 			Adapter->param_adv_10hdx = *(uint8_t *)pr_val;
29836394Scc210113 			goto reset;
29846789Sam223141 		case MAC_PROP_AUTONEG:
29856394Scc210113 			Adapter->param_adv_autoneg = *(uint8_t *)pr_val;
29866394Scc210113 			goto reset;
29876789Sam223141 		case MAC_PROP_FLOWCTRL:
29886735Scc210113 			fc->send_xon = B_TRUE;
29896735Scc210113 			bcopy(pr_val, &flowctrl, sizeof (flowctrl));
29906735Scc210113 
29916735Scc210113 			switch (flowctrl) {
29926394Scc210113 			default:
29936394Scc210113 				err = EINVAL;
29946394Scc210113 				break;
29956394Scc210113 			case LINK_FLOWCTRL_NONE:
29968539SChenlu.Chen@Sun.COM 				fc->requested_mode = e1000_fc_none;
29976394Scc210113 				break;
29986394Scc210113 			case LINK_FLOWCTRL_RX:
29998539SChenlu.Chen@Sun.COM 				fc->requested_mode = e1000_fc_rx_pause;
30006394Scc210113 				break;
30016394Scc210113 			case LINK_FLOWCTRL_TX:
30028539SChenlu.Chen@Sun.COM 				fc->requested_mode = e1000_fc_tx_pause;
30036394Scc210113 				break;
30046394Scc210113 			case LINK_FLOWCTRL_BI:
30058539SChenlu.Chen@Sun.COM 				fc->requested_mode = e1000_fc_full;
30066394Scc210113 				break;
30076394Scc210113 			}
30086394Scc210113 reset:
30096394Scc210113 			if (err == 0) {
30106394Scc210113 				if (e1000g_reset_link(Adapter) != DDI_SUCCESS)
30116394Scc210113 					err = EINVAL;
30126394Scc210113 			}
30136394Scc210113 			break;
30146789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
30156789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
30166789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
30176789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
30186789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
30196789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
30208118SVasumathi.Sundaram@Sun.COM 		case MAC_PROP_EN_1000HDX_CAP:
30216789Sam223141 		case MAC_PROP_STATUS:
30226789Sam223141 		case MAC_PROP_SPEED:
30236789Sam223141 		case MAC_PROP_DUPLEX:
30246394Scc210113 			err = ENOTSUP; /* read-only prop. Can't set this. */
30256394Scc210113 			break;
30266789Sam223141 		case MAC_PROP_MTU:
30276394Scc210113 			cur_mtu = Adapter->default_mtu;
30286394Scc210113 			bcopy(pr_val, &new_mtu, sizeof (new_mtu));
30296394Scc210113 			if (new_mtu == cur_mtu) {
30306394Scc210113 				err = 0;
30316394Scc210113 				break;
30326394Scc210113 			}
30336394Scc210113 
30346394Scc210113 			tmp = new_mtu + sizeof (struct ether_vlan_header) +
30356394Scc210113 			    ETHERFCSL;
30366394Scc210113 			if ((tmp < DEFAULT_FRAME_SIZE) ||
30376394Scc210113 			    (tmp > MAXIMUM_FRAME_SIZE)) {
30386394Scc210113 				err = EINVAL;
30396394Scc210113 				break;
30406394Scc210113 			}
30416394Scc210113 
30427607STed.You@Sun.COM 			/* ich8 does not support jumbo frames */
30436394Scc210113 			if ((mac->type == e1000_ich8lan) &&
30446394Scc210113 			    (tmp > DEFAULT_FRAME_SIZE)) {
30456394Scc210113 				err = EINVAL;
30466394Scc210113 				break;
30476394Scc210113 			}
30486394Scc210113 			/* ich9 does not do jumbo frames on one phy type */
30496394Scc210113 			if ((mac->type == e1000_ich9lan) &&
30506394Scc210113 			    (phy->type == e1000_phy_ife) &&
30516394Scc210113 			    (tmp > DEFAULT_FRAME_SIZE)) {
30526394Scc210113 				err = EINVAL;
30536394Scc210113 				break;
30546394Scc210113 			}
30558479SChenlu.Chen@Sun.COM 			if (Adapter->e1000g_state & E1000G_STARTED) {
30566394Scc210113 				err = EBUSY;
30576394Scc210113 				break;
30586394Scc210113 			}
30596394Scc210113 
30606394Scc210113 			err = mac_maxsdu_update(Adapter->mh, new_mtu);
30616394Scc210113 			if (err == 0) {
30627426SChenliang.Xu@Sun.COM 				Adapter->max_frame_size = (uint32_t)tmp;
30636394Scc210113 				Adapter->default_mtu = new_mtu;
30646394Scc210113 				e1000g_set_bufsize(Adapter);
30656394Scc210113 			}
30666394Scc210113 			break;
30676789Sam223141 		case MAC_PROP_PRIVATE:
30686394Scc210113 			err = e1000g_set_priv_prop(Adapter, pr_name,
30696394Scc210113 			    pr_valsize, pr_val);
30706394Scc210113 			break;
30716394Scc210113 		default:
30726394Scc210113 			err = ENOTSUP;
30736394Scc210113 			break;
30746394Scc210113 	}
30756394Scc210113 	rw_exit(&Adapter->chip_lock);
30766394Scc210113 	return (err);
30776394Scc210113 }
30786394Scc210113 
30796394Scc210113 static int
30806394Scc210113 e1000g_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
30818118SVasumathi.Sundaram@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
30826394Scc210113 {
30836394Scc210113 	struct e1000g *Adapter = arg;
30846735Scc210113 	struct e1000_fc_info *fc = &Adapter->shared.fc;
30856512Ssowmini 	int err = 0;
30866735Scc210113 	link_flowctrl_t flowctrl;
30876394Scc210113 	uint64_t tmp = 0;
30886394Scc210113 
30896512Ssowmini 	if (pr_valsize == 0)
30906512Ssowmini 		return (EINVAL);
30916512Ssowmini 
30928118SVasumathi.Sundaram@Sun.COM 	*perm = MAC_PROP_PERM_RW;
30938118SVasumathi.Sundaram@Sun.COM 
30946394Scc210113 	bzero(pr_val, pr_valsize);
30956789Sam223141 	if ((pr_flags & MAC_PROP_DEFAULT) && (pr_num != MAC_PROP_PRIVATE)) {
30966512Ssowmini 		return (e1000g_get_def_val(Adapter, pr_num,
30976512Ssowmini 		    pr_valsize, pr_val));
30986512Ssowmini 	}
30996512Ssowmini 
31006394Scc210113 	switch (pr_num) {
31016789Sam223141 		case MAC_PROP_DUPLEX:
31028118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31036512Ssowmini 			if (pr_valsize >= sizeof (link_duplex_t)) {
31046512Ssowmini 				bcopy(&Adapter->link_duplex, pr_val,
31056512Ssowmini 				    sizeof (link_duplex_t));
31066512Ssowmini 			} else
31076512Ssowmini 				err = EINVAL;
31086394Scc210113 			break;
31096789Sam223141 		case MAC_PROP_SPEED:
31108118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31116394Scc210113 			if (pr_valsize >= sizeof (uint64_t)) {
31126394Scc210113 				tmp = Adapter->link_speed * 1000000ull;
31136394Scc210113 				bcopy(&tmp, pr_val, sizeof (tmp));
31146512Ssowmini 			} else
31156512Ssowmini 				err = EINVAL;
31166394Scc210113 			break;
31176789Sam223141 		case MAC_PROP_AUTONEG:
31186512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_adv_autoneg;
31196394Scc210113 			break;
31206789Sam223141 		case MAC_PROP_FLOWCTRL:
31216394Scc210113 			if (pr_valsize >= sizeof (link_flowctrl_t)) {
31228479SChenlu.Chen@Sun.COM 				switch (fc->current_mode) {
31236394Scc210113 					case e1000_fc_none:
31246735Scc210113 						flowctrl = LINK_FLOWCTRL_NONE;
31256394Scc210113 						break;
31266394Scc210113 					case e1000_fc_rx_pause:
31276735Scc210113 						flowctrl = LINK_FLOWCTRL_RX;
31286394Scc210113 						break;
31296394Scc210113 					case e1000_fc_tx_pause:
31306735Scc210113 						flowctrl = LINK_FLOWCTRL_TX;
31316394Scc210113 						break;
31326394Scc210113 					case e1000_fc_full:
31336735Scc210113 						flowctrl = LINK_FLOWCTRL_BI;
31346394Scc210113 						break;
31356394Scc210113 				}
31366735Scc210113 				bcopy(&flowctrl, pr_val, sizeof (flowctrl));
31376512Ssowmini 			} else
31386512Ssowmini 				err = EINVAL;
31396394Scc210113 			break;
31406789Sam223141 		case MAC_PROP_ADV_1000FDX_CAP:
31418118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31426512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_adv_1000fdx;
31436394Scc210113 			break;
31446789Sam223141 		case MAC_PROP_EN_1000FDX_CAP:
31456512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_en_1000fdx;
31466394Scc210113 			break;
31476789Sam223141 		case MAC_PROP_ADV_1000HDX_CAP:
31488118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31496512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_adv_1000hdx;
31506394Scc210113 			break;
31516789Sam223141 		case MAC_PROP_EN_1000HDX_CAP:
31528118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31536512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_en_1000hdx;
31546394Scc210113 			break;
31556789Sam223141 		case MAC_PROP_ADV_100FDX_CAP:
31568118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31576512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_adv_100fdx;
31586394Scc210113 			break;
31596789Sam223141 		case MAC_PROP_EN_100FDX_CAP:
31606512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_en_100fdx;
31616394Scc210113 			break;
31626789Sam223141 		case MAC_PROP_ADV_100HDX_CAP:
31638118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31646512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_adv_100hdx;
31656394Scc210113 			break;
31666789Sam223141 		case MAC_PROP_EN_100HDX_CAP:
31676512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_en_100hdx;
31686394Scc210113 			break;
31696789Sam223141 		case MAC_PROP_ADV_10FDX_CAP:
31708118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31716512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_adv_10fdx;
31726394Scc210113 			break;
31736789Sam223141 		case MAC_PROP_EN_10FDX_CAP:
31746512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_en_10fdx;
31756394Scc210113 			break;
31766789Sam223141 		case MAC_PROP_ADV_10HDX_CAP:
31778118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31786512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_adv_10hdx;
31796394Scc210113 			break;
31806789Sam223141 		case MAC_PROP_EN_10HDX_CAP:
31816512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_en_10hdx;
31826512Ssowmini 			break;
31836789Sam223141 		case MAC_PROP_ADV_100T4_CAP:
31846789Sam223141 		case MAC_PROP_EN_100T4_CAP:
31858118SVasumathi.Sundaram@Sun.COM 			*perm = MAC_PROP_PERM_READ;
31866512Ssowmini 			*(uint8_t *)pr_val = Adapter->param_adv_100t4;
31876394Scc210113 			break;
31886789Sam223141 		case MAC_PROP_PRIVATE:
31896394Scc210113 			err = e1000g_get_priv_prop(Adapter, pr_name,
31908118SVasumathi.Sundaram@Sun.COM 			    pr_flags, pr_valsize, pr_val, perm);
31916394Scc210113 			break;
31926394Scc210113 		default:
31936394Scc210113 			err = ENOTSUP;
31946394Scc210113 			break;
31956394Scc210113 	}
31966394Scc210113 	return (err);
31976394Scc210113 }
31986394Scc210113 
31997426SChenliang.Xu@Sun.COM /* ARGSUSED2 */
32006394Scc210113 static int
32016394Scc210113 e1000g_set_priv_prop(struct e1000g *Adapter, const char *pr_name,
32026394Scc210113     uint_t pr_valsize, const void *pr_val)
32036394Scc210113 {
32046394Scc210113 	int err = 0;
32056394Scc210113 	long result;
32066394Scc210113 	struct e1000_hw *hw = &Adapter->shared;
32076394Scc210113 
32086394Scc210113 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
32096394Scc210113 		if (pr_val == NULL) {
32106394Scc210113 			err = EINVAL;
32116394Scc210113 			return (err);
32126394Scc210113 		}
32136394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
32146394Scc210113 		if (result < MIN_TX_BCOPY_THRESHOLD ||
32156394Scc210113 		    result > MAX_TX_BCOPY_THRESHOLD)
32166394Scc210113 			err = EINVAL;
32176394Scc210113 		else {
32186394Scc210113 			Adapter->tx_bcopy_thresh = (uint32_t)result;
32196394Scc210113 		}
32206394Scc210113 		return (err);
32216394Scc210113 	}
32226394Scc210113 	if (strcmp(pr_name, "_tx_interrupt_enable") == 0) {
32236394Scc210113 		if (pr_val == NULL) {
32246394Scc210113 			err = EINVAL;
32256394Scc210113 			return (err);
32266394Scc210113 		}
32276394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
32286394Scc210113 		if (result < 0 || result > 1)
32296394Scc210113 			err = EINVAL;
32306394Scc210113 		else {
32316394Scc210113 			Adapter->tx_intr_enable = (result == 1) ?
32326394Scc210113 			    B_TRUE: B_FALSE;
32336394Scc210113 			if (Adapter->tx_intr_enable)
32346394Scc210113 				e1000g_mask_tx_interrupt(Adapter);
32356394Scc210113 			else
32366394Scc210113 				e1000g_clear_tx_interrupt(Adapter);
32376394Scc210113 			if (e1000g_check_acc_handle(
32386394Scc210113 			    Adapter->osdep.reg_handle) != DDI_FM_OK)
32396394Scc210113 				ddi_fm_service_impact(Adapter->dip,
32406394Scc210113 				    DDI_SERVICE_DEGRADED);
32416394Scc210113 		}
32426394Scc210113 		return (err);
32436394Scc210113 	}
32446394Scc210113 	if (strcmp(pr_name, "_tx_intr_delay") == 0) {
32456394Scc210113 		if (pr_val == NULL) {
32466394Scc210113 			err = EINVAL;
32476394Scc210113 			return (err);
32486394Scc210113 		}
32496394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
32506394Scc210113 		if (result < MIN_TX_INTR_DELAY ||
32516394Scc210113 		    result > MAX_TX_INTR_DELAY)
32526394Scc210113 			err = EINVAL;
32536394Scc210113 		else {
32546394Scc210113 			Adapter->tx_intr_delay = (uint32_t)result;
32556394Scc210113 			E1000_WRITE_REG(hw, E1000_TIDV, Adapter->tx_intr_delay);
32566394Scc210113 			if (e1000g_check_acc_handle(
32576394Scc210113 			    Adapter->osdep.reg_handle) != DDI_FM_OK)
32586394Scc210113 				ddi_fm_service_impact(Adapter->dip,
32596394Scc210113 				    DDI_SERVICE_DEGRADED);
32606394Scc210113 		}
32616394Scc210113 		return (err);
32626394Scc210113 	}
32636394Scc210113 	if (strcmp(pr_name, "_tx_intr_abs_delay") == 0) {
32646394Scc210113 		if (pr_val == NULL) {
32656394Scc210113 			err = EINVAL;
32666394Scc210113 			return (err);
32676394Scc210113 		}
32686394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
32696394Scc210113 		if (result < MIN_TX_INTR_ABS_DELAY ||
32706394Scc210113 		    result > MAX_TX_INTR_ABS_DELAY)
32716394Scc210113 			err = EINVAL;
32726394Scc210113 		else {
32736394Scc210113 			Adapter->tx_intr_abs_delay = (uint32_t)result;
32746394Scc210113 			E1000_WRITE_REG(hw, E1000_TADV,
32756394Scc210113 			    Adapter->tx_intr_abs_delay);
32766394Scc210113 			if (e1000g_check_acc_handle(
32776394Scc210113 			    Adapter->osdep.reg_handle) != DDI_FM_OK)
32786394Scc210113 				ddi_fm_service_impact(Adapter->dip,
32796394Scc210113 				    DDI_SERVICE_DEGRADED);
32806394Scc210113 		}
32816394Scc210113 		return (err);
32826394Scc210113 	}
32836394Scc210113 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
32846394Scc210113 		if (pr_val == NULL) {
32856394Scc210113 			err = EINVAL;
32866394Scc210113 			return (err);
32876394Scc210113 		}
32886394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
32896394Scc210113 		if (result < MIN_RX_BCOPY_THRESHOLD ||
32906394Scc210113 		    result > MAX_RX_BCOPY_THRESHOLD)
32916394Scc210113 			err = EINVAL;
32926394Scc210113 		else
32936394Scc210113 			Adapter->rx_bcopy_thresh = (uint32_t)result;
32946394Scc210113 		return (err);
32956394Scc210113 	}
32966394Scc210113 	if (strcmp(pr_name, "_max_num_rcv_packets") == 0) {
32976394Scc210113 		if (pr_val == NULL) {
32986394Scc210113 			err = EINVAL;
32996394Scc210113 			return (err);
33006394Scc210113 		}
33016394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
33026394Scc210113 		if (result < MIN_RX_LIMIT_ON_INTR ||
33036394Scc210113 		    result > MAX_RX_LIMIT_ON_INTR)
33046394Scc210113 			err = EINVAL;
33056394Scc210113 		else
33066394Scc210113 			Adapter->rx_limit_onintr = (uint32_t)result;
33076394Scc210113 		return (err);
33086394Scc210113 	}
33096394Scc210113 	if (strcmp(pr_name, "_rx_intr_delay") == 0) {
33106394Scc210113 		if (pr_val == NULL) {
33116394Scc210113 			err = EINVAL;
33126394Scc210113 			return (err);
33136394Scc210113 		}
33146394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
33156394Scc210113 		if (result < MIN_RX_INTR_DELAY ||
33166394Scc210113 		    result > MAX_RX_INTR_DELAY)
33176394Scc210113 			err = EINVAL;
33186394Scc210113 		else {
33196394Scc210113 			Adapter->rx_intr_delay = (uint32_t)result;
33206394Scc210113 			E1000_WRITE_REG(hw, E1000_RDTR, Adapter->rx_intr_delay);
33216394Scc210113 			if (e1000g_check_acc_handle(
33226394Scc210113 			    Adapter->osdep.reg_handle) != DDI_FM_OK)
33236394Scc210113 				ddi_fm_service_impact(Adapter->dip,
33246394Scc210113 				    DDI_SERVICE_DEGRADED);
33256394Scc210113 		}
33266394Scc210113 		return (err);
33276394Scc210113 	}
33286394Scc210113 	if (strcmp(pr_name, "_rx_intr_abs_delay") == 0) {
33296394Scc210113 		if (pr_val == NULL) {
33306394Scc210113 			err = EINVAL;
33316394Scc210113 			return (err);
33326394Scc210113 		}
33336394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
33346394Scc210113 		if (result < MIN_RX_INTR_ABS_DELAY ||
33356394Scc210113 		    result > MAX_RX_INTR_ABS_DELAY)
33366394Scc210113 			err = EINVAL;
33376394Scc210113 		else {
33386394Scc210113 			Adapter->rx_intr_abs_delay = (uint32_t)result;
33396394Scc210113 			E1000_WRITE_REG(hw, E1000_RADV,
33406394Scc210113 			    Adapter->rx_intr_abs_delay);
33416394Scc210113 			if (e1000g_check_acc_handle(
33426394Scc210113 			    Adapter->osdep.reg_handle) != DDI_FM_OK)
33436394Scc210113 				ddi_fm_service_impact(Adapter->dip,
33446394Scc210113 				    DDI_SERVICE_DEGRADED);
33456394Scc210113 		}
33466394Scc210113 		return (err);
33476394Scc210113 	}
33486394Scc210113 	if (strcmp(pr_name, "_intr_throttling_rate") == 0) {
33496394Scc210113 		if (pr_val == NULL) {
33506394Scc210113 			err = EINVAL;
33516394Scc210113 			return (err);
33526394Scc210113 		}
33536394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
33546394Scc210113 		if (result < MIN_INTR_THROTTLING ||
33556394Scc210113 		    result > MAX_INTR_THROTTLING)
33566394Scc210113 			err = EINVAL;
33576394Scc210113 		else {
33586394Scc210113 			if (hw->mac.type >= e1000_82540) {
33596394Scc210113 				Adapter->intr_throttling_rate =
33606394Scc210113 				    (uint32_t)result;
33616394Scc210113 				E1000_WRITE_REG(hw, E1000_ITR,
33626394Scc210113 				    Adapter->intr_throttling_rate);
33636394Scc210113 				if (e1000g_check_acc_handle(
33646394Scc210113 				    Adapter->osdep.reg_handle) != DDI_FM_OK)
33656394Scc210113 					ddi_fm_service_impact(Adapter->dip,
33666394Scc210113 					    DDI_SERVICE_DEGRADED);
33676394Scc210113 			} else
33686394Scc210113 				err = EINVAL;
33696394Scc210113 		}
33706394Scc210113 		return (err);
33716394Scc210113 	}
33726394Scc210113 	if (strcmp(pr_name, "_intr_adaptive") == 0) {
33736394Scc210113 		if (pr_val == NULL) {
33746394Scc210113 			err = EINVAL;
33756394Scc210113 			return (err);
33766394Scc210113 		}
33776394Scc210113 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
33786394Scc210113 		if (result < 0 || result > 1)
33796394Scc210113 			err = EINVAL;
33806394Scc210113 		else {
33816394Scc210113 			if (hw->mac.type >= e1000_82540) {
33826394Scc210113 				Adapter->intr_adaptive = (result == 1) ?
33836394Scc210113 				    B_TRUE : B_FALSE;
33846394Scc210113 			} else {
33856394Scc210113 				err = EINVAL;
33866394Scc210113 			}
33876394Scc210113 		}
33886394Scc210113 		return (err);
33896394Scc210113 	}
33906394Scc210113 	return (ENOTSUP);
33916394Scc210113 }
33926394Scc210113 
33936394Scc210113 static int
33946394Scc210113 e1000g_get_priv_prop(struct e1000g *Adapter, const char *pr_name,
33958118SVasumathi.Sundaram@Sun.COM     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
33966394Scc210113 {
33976394Scc210113 	int err = ENOTSUP;
33986789Sam223141 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
33996512Ssowmini 	int value;
34006512Ssowmini 
34016512Ssowmini 	if (strcmp(pr_name, "_adv_pause_cap") == 0) {
34028118SVasumathi.Sundaram@Sun.COM 		*perm = MAC_PROP_PERM_READ;
34036512Ssowmini 		if (is_default)
34046512Ssowmini 			goto done;
34056512Ssowmini 		value = Adapter->param_adv_pause;
34066512Ssowmini 		err = 0;
34076512Ssowmini 		goto done;
34086512Ssowmini 	}
34096512Ssowmini 	if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
34108118SVasumathi.Sundaram@Sun.COM 		*perm = MAC_PROP_PERM_READ;
34116512Ssowmini 		if (is_default)
34126512Ssowmini 			goto done;
34136512Ssowmini 		value = Adapter->param_adv_asym_pause;
34146512Ssowmini 		err = 0;
34156512Ssowmini 		goto done;
34166512Ssowmini 	}
34176394Scc210113 	if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) {
34186512Ssowmini 		value = (is_default ? DEFAULT_TX_BCOPY_THRESHOLD :
34196512Ssowmini 		    Adapter->tx_bcopy_thresh);
34206394Scc210113 		err = 0;
34216394Scc210113 		goto done;
34226394Scc210113 	}
34236394Scc210113 	if (strcmp(pr_name, "_tx_interrupt_enable") == 0) {
34246512Ssowmini 		value = (is_default ? DEFAULT_TX_INTR_ENABLE :
34256512Ssowmini 		    Adapter->tx_intr_enable);
34266394Scc210113 		err = 0;
34276394Scc210113 		goto done;
34286394Scc210113 	}
34296394Scc210113 	if (strcmp(pr_name, "_tx_intr_delay") == 0) {
34306512Ssowmini 		value = (is_default ? DEFAULT_TX_INTR_DELAY :
34316512Ssowmini 		    Adapter->tx_intr_delay);
34326394Scc210113 		err = 0;
34336394Scc210113 		goto done;
34346394Scc210113 	}
34356394Scc210113 	if (strcmp(pr_name, "_tx_intr_abs_delay") == 0) {
34366512Ssowmini 		value = (is_default ? DEFAULT_TX_INTR_ABS_DELAY :
34376512Ssowmini 		    Adapter->tx_intr_abs_delay);
34386394Scc210113 		err = 0;
34396394Scc210113 		goto done;
34406394Scc210113 	}
34416394Scc210113 	if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) {
34426512Ssowmini 		value = (is_default ? DEFAULT_RX_BCOPY_THRESHOLD :
34436512Ssowmini 		    Adapter->rx_bcopy_thresh);
34446394Scc210113 		err = 0;
34456394Scc210113 		goto done;
34466394Scc210113 	}
34476394Scc210113 	if (strcmp(pr_name, "_max_num_rcv_packets") == 0) {
34486512Ssowmini 		value = (is_default ? DEFAULT_RX_LIMIT_ON_INTR :
34496512Ssowmini 		    Adapter->rx_limit_onintr);
34506394Scc210113 		err = 0;
34516394Scc210113 		goto done;
34526394Scc210113 	}
34536394Scc210113 	if (strcmp(pr_name, "_rx_intr_delay") == 0) {
34546512Ssowmini 		value = (is_default ? DEFAULT_RX_INTR_DELAY :
34556512Ssowmini 		    Adapter->rx_intr_delay);
34566394Scc210113 		err = 0;
34576394Scc210113 		goto done;
34586394Scc210113 	}
34596394Scc210113 	if (strcmp(pr_name, "_rx_intr_abs_delay") == 0) {
34606512Ssowmini 		value = (is_default ? DEFAULT_RX_INTR_ABS_DELAY :
34616512Ssowmini 		    Adapter->rx_intr_abs_delay);
34626394Scc210113 		err = 0;
34636394Scc210113 		goto done;
34646394Scc210113 	}
34656394Scc210113 	if (strcmp(pr_name, "_intr_throttling_rate") == 0) {
34666512Ssowmini 		value = (is_default ? DEFAULT_INTR_THROTTLING :
34676512Ssowmini 		    Adapter->intr_throttling_rate);
34686394Scc210113 		err = 0;
34696394Scc210113 		goto done;
34706394Scc210113 	}
34716394Scc210113 	if (strcmp(pr_name, "_intr_adaptive") == 0) {
34726512Ssowmini 		value = (is_default ? 1 : Adapter->intr_adaptive);
34736394Scc210113 		err = 0;
34746394Scc210113 		goto done;
34756394Scc210113 	}
34766394Scc210113 done:
34776394Scc210113 	if (err == 0) {
34786512Ssowmini 		(void) snprintf(pr_val, pr_valsize, "%d", value);
34796394Scc210113 	}
34806394Scc210113 	return (err);
34816394Scc210113 }
34826394Scc210113 
34833526Sxy150489 /*
34844919Sxy150489  * e1000g_get_conf - get configurations set in e1000g.conf
34854919Sxy150489  * This routine gets user-configured values out of the configuration
34864919Sxy150489  * file e1000g.conf.
34874919Sxy150489  *
34884919Sxy150489  * For each configurable value, there is a minimum, a maximum, and a
34894919Sxy150489  * default.
34904919Sxy150489  * If user does not configure a value, use the default.
34914919Sxy150489  * If user configures below the minimum, use the minumum.
34924919Sxy150489  * If user configures above the maximum, use the maxumum.
34933526Sxy150489  */
34943526Sxy150489 static void
34954919Sxy150489 e1000g_get_conf(struct e1000g *Adapter)
34963526Sxy150489 {
34974919Sxy150489 	struct e1000_hw *hw = &Adapter->shared;
34984919Sxy150489 	boolean_t tbi_compatibility = B_FALSE;
34994919Sxy150489 
35003526Sxy150489 	/*
35013526Sxy150489 	 * get each configurable property from e1000g.conf
35023526Sxy150489 	 */
35033526Sxy150489 
35043526Sxy150489 	/*
35053526Sxy150489 	 * NumTxDescriptors
35063526Sxy150489 	 */
35074919Sxy150489 	Adapter->tx_desc_num =
35084919Sxy150489 	    e1000g_get_prop(Adapter, "NumTxDescriptors",
35094919Sxy150489 	    MIN_NUM_TX_DESCRIPTOR, MAX_NUM_TX_DESCRIPTOR,
35104919Sxy150489 	    DEFAULT_NUM_TX_DESCRIPTOR);
35113526Sxy150489 
35123526Sxy150489 	/*
35133526Sxy150489 	 * NumRxDescriptors
35143526Sxy150489 	 */
35154919Sxy150489 	Adapter->rx_desc_num =
35164919Sxy150489 	    e1000g_get_prop(Adapter, "NumRxDescriptors",
35174919Sxy150489 	    MIN_NUM_RX_DESCRIPTOR, MAX_NUM_RX_DESCRIPTOR,
35184919Sxy150489 	    DEFAULT_NUM_RX_DESCRIPTOR);
35193526Sxy150489 
35203526Sxy150489 	/*
35213526Sxy150489 	 * NumRxFreeList
35223526Sxy150489 	 */
35234919Sxy150489 	Adapter->rx_freelist_num =
35244919Sxy150489 	    e1000g_get_prop(Adapter, "NumRxFreeList",
35254919Sxy150489 	    MIN_NUM_RX_FREELIST, MAX_NUM_RX_FREELIST,
35264919Sxy150489 	    DEFAULT_NUM_RX_FREELIST);
35273526Sxy150489 
35283526Sxy150489 	/*
35293526Sxy150489 	 * NumTxPacketList
35303526Sxy150489 	 */
35314919Sxy150489 	Adapter->tx_freelist_num =
35324919Sxy150489 	    e1000g_get_prop(Adapter, "NumTxPacketList",
35334919Sxy150489 	    MIN_NUM_TX_FREELIST, MAX_NUM_TX_FREELIST,
35344919Sxy150489 	    DEFAULT_NUM_TX_FREELIST);
35353526Sxy150489 
35363526Sxy150489 	/*
35373526Sxy150489 	 * FlowControl
35383526Sxy150489 	 */
35396735Scc210113 	hw->fc.send_xon = B_TRUE;
35408539SChenlu.Chen@Sun.COM 	hw->fc.requested_mode =
35414919Sxy150489 	    e1000g_get_prop(Adapter, "FlowControl",
35424919Sxy150489 	    e1000_fc_none, 4, DEFAULT_FLOW_CONTROL);
35433526Sxy150489 	/* 4 is the setting that says "let the eeprom decide" */
35448539SChenlu.Chen@Sun.COM 	if (hw->fc.requested_mode == 4)
35458539SChenlu.Chen@Sun.COM 		hw->fc.requested_mode = e1000_fc_default;
35463526Sxy150489 
35473526Sxy150489 	/*
35484919Sxy150489 	 * Max Num Receive Packets on Interrupt
35493526Sxy150489 	 */
35504919Sxy150489 	Adapter->rx_limit_onintr =
35514919Sxy150489 	    e1000g_get_prop(Adapter, "MaxNumReceivePackets",
35524919Sxy150489 	    MIN_RX_LIMIT_ON_INTR, MAX_RX_LIMIT_ON_INTR,
35534919Sxy150489 	    DEFAULT_RX_LIMIT_ON_INTR);
35543526Sxy150489 
35553526Sxy150489 	/*
35563526Sxy150489 	 * PHY master slave setting
35573526Sxy150489 	 */
35584919Sxy150489 	hw->phy.ms_type =
35594919Sxy150489 	    e1000g_get_prop(Adapter, "SetMasterSlave",
35603526Sxy150489 	    e1000_ms_hw_default, e1000_ms_auto,
35613526Sxy150489 	    e1000_ms_hw_default);
35623526Sxy150489 
35633526Sxy150489 	/*
35643526Sxy150489 	 * Parameter which controls TBI mode workaround, which is only
35653526Sxy150489 	 * needed on certain switches such as Cisco 6500/Foundry
35663526Sxy150489 	 */
35674919Sxy150489 	tbi_compatibility =
35684919Sxy150489 	    e1000g_get_prop(Adapter, "TbiCompatibilityEnable",
35694919Sxy150489 	    0, 1, DEFAULT_TBI_COMPAT_ENABLE);
35704919Sxy150489 	e1000_set_tbi_compatibility_82543(hw, tbi_compatibility);
35713526Sxy150489 
35723526Sxy150489 	/*
35733526Sxy150489 	 * MSI Enable
35743526Sxy150489 	 */
35756986Smx205022 	Adapter->msi_enable =
35764919Sxy150489 	    e1000g_get_prop(Adapter, "MSIEnable",
35774919Sxy150489 	    0, 1, DEFAULT_MSI_ENABLE);
35783526Sxy150489 
35793526Sxy150489 	/*
35803526Sxy150489 	 * Interrupt Throttling Rate
35813526Sxy150489 	 */
35823526Sxy150489 	Adapter->intr_throttling_rate =
35834919Sxy150489 	    e1000g_get_prop(Adapter, "intr_throttling_rate",
35844919Sxy150489 	    MIN_INTR_THROTTLING, MAX_INTR_THROTTLING,
35854919Sxy150489 	    DEFAULT_INTR_THROTTLING);
35863526Sxy150489 
35873526Sxy150489 	/*
35883526Sxy150489 	 * Adaptive Interrupt Blanking Enable/Disable
35893526Sxy150489 	 * It is enabled by default
35903526Sxy150489 	 */
35913526Sxy150489 	Adapter->intr_adaptive =
35924919Sxy150489 	    (e1000g_get_prop(Adapter, "intr_adaptive", 0, 1, 1) == 1) ?
35933526Sxy150489 	    B_TRUE : B_FALSE;
35945882Syy150190 
35955882Syy150190 	/*
35966011Ssv141092 	 * Hardware checksum enable/disable parameter
35976011Ssv141092 	 */
35986986Smx205022 	Adapter->tx_hcksum_enable =
35996986Smx205022 	    e1000g_get_prop(Adapter, "tx_hcksum_enable",
36006011Ssv141092 	    0, 1, DEFAULT_TX_HCKSUM_ENABLE);
36016986Smx205022 	/*
36026986Smx205022 	 * Checksum on/off selection via global parameters.
36036986Smx205022 	 *
36046986Smx205022 	 * If the chip is flagged as not capable of (correctly)
36056986Smx205022 	 * handling checksumming, we don't enable it on either
36066986Smx205022 	 * Rx or Tx side.  Otherwise, we take this chip's settings
36076986Smx205022 	 * from the patchable global defaults.
36086986Smx205022 	 *
36096986Smx205022 	 * We advertise our capabilities only if TX offload is
36106986Smx205022 	 * enabled.  On receive, the stack will accept checksummed
36116986Smx205022 	 * packets anyway, even if we haven't said we can deliver
36126986Smx205022 	 * them.
36136986Smx205022 	 */
36146986Smx205022 	switch (hw->mac.type) {
36156986Smx205022 		case e1000_82540:
36166986Smx205022 		case e1000_82544:
36176986Smx205022 		case e1000_82545:
36186986Smx205022 		case e1000_82545_rev_3:
36196986Smx205022 		case e1000_82546:
36206986Smx205022 		case e1000_82546_rev_3:
36216986Smx205022 		case e1000_82571:
36226986Smx205022 		case e1000_82572:
36236986Smx205022 		case e1000_82573:
36246986Smx205022 		case e1000_80003es2lan:
36256986Smx205022 			break;
36266986Smx205022 		/*
36276986Smx205022 		 * For the following Intel PRO/1000 chipsets, we have not
36286986Smx205022 		 * tested the hardware checksum offload capability, so we
36296986Smx205022 		 * disable the capability for them.
36306986Smx205022 		 *	e1000_82542,
36316986Smx205022 		 *	e1000_82543,
36326986Smx205022 		 *	e1000_82541,
36336986Smx205022 		 *	e1000_82541_rev_2,
36346986Smx205022 		 *	e1000_82547,
36356986Smx205022 		 *	e1000_82547_rev_2,
36366986Smx205022 		 */
36376986Smx205022 		default:
36386986Smx205022 			Adapter->tx_hcksum_enable = B_FALSE;
36396986Smx205022 	}
36406986Smx205022 
36416986Smx205022 	/*
36426986Smx205022 	 * Large Send Offloading(LSO) Enable/Disable
36436986Smx205022 	 * If the tx hardware checksum is not enabled, LSO should be
36446986Smx205022 	 * disabled.
36456986Smx205022 	 */
36466986Smx205022 	Adapter->lso_enable =
36476986Smx205022 	    e1000g_get_prop(Adapter, "lso_enable",
36486986Smx205022 	    0, 1, DEFAULT_LSO_ENABLE);
36496986Smx205022 
36506986Smx205022 	switch (hw->mac.type) {
36516986Smx205022 		case e1000_82546:
36526986Smx205022 		case e1000_82546_rev_3:
36536986Smx205022 			if (Adapter->lso_enable)
36546986Smx205022 				Adapter->lso_premature_issue = B_TRUE;
36557426SChenliang.Xu@Sun.COM 			/* FALLTHRU */
36566986Smx205022 		case e1000_82571:
36576986Smx205022 		case e1000_82572:
36586986Smx205022 		case e1000_82573:
36598073SMin.Xu@Sun.COM 		case e1000_80003es2lan:
36606986Smx205022 			break;
36616986Smx205022 		default:
36626986Smx205022 			Adapter->lso_enable = B_FALSE;
36636986Smx205022 	}
36646986Smx205022 
36656986Smx205022 	if (!Adapter->tx_hcksum_enable) {
36666986Smx205022 		Adapter->lso_premature_issue = B_FALSE;
36676986Smx205022 		Adapter->lso_enable = B_FALSE;
36686986Smx205022 	}
36698417SChenlu.Chen@Sun.COM 
36708417SChenlu.Chen@Sun.COM 	/*
36718417SChenlu.Chen@Sun.COM 	 * If mem_workaround_82546 is enabled, the rx buffer allocated by
36728417SChenlu.Chen@Sun.COM 	 * e1000_82545, e1000_82546 and e1000_82546_rev_3
36738417SChenlu.Chen@Sun.COM 	 * will not cross 64k boundary.
36748417SChenlu.Chen@Sun.COM 	 */
36758417SChenlu.Chen@Sun.COM 	Adapter->mem_workaround_82546 =
36768417SChenlu.Chen@Sun.COM 	    e1000g_get_prop(Adapter, "mem_workaround_82546",
36778417SChenlu.Chen@Sun.COM 	    0, 1, DEFAULT_MEM_WORKAROUND_82546);
36783526Sxy150489 }
36793526Sxy150489 
36803526Sxy150489 /*
36814919Sxy150489  * e1000g_get_prop - routine to read properties
36824919Sxy150489  *
36834919Sxy150489  * Get a user-configure property value out of the configuration
36844919Sxy150489  * file e1000g.conf.
36854919Sxy150489  *
36864919Sxy150489  * Caller provides name of the property, a default value, a minimum
36874919Sxy150489  * value, and a maximum value.
36884919Sxy150489  *
36894919Sxy150489  * Return configured value of the property, with default, minimum and
36904919Sxy150489  * maximum properly applied.
36913526Sxy150489  */
36923526Sxy150489 static int
36934919Sxy150489 e1000g_get_prop(struct e1000g *Adapter,	/* point to per-adapter structure */
36943526Sxy150489     char *propname,		/* name of the property */
36953526Sxy150489     int minval,			/* minimum acceptable value */
36963526Sxy150489     int maxval,			/* maximim acceptable value */
36973526Sxy150489     int defval)			/* default value */
36983526Sxy150489 {
36993526Sxy150489 	int propval;		/* value returned for requested property */
37003526Sxy150489 	int *props;		/* point to array of properties returned */
37013526Sxy150489 	uint_t nprops;		/* number of property value returned */
37023526Sxy150489 
37033526Sxy150489 	/*
37043526Sxy150489 	 * get the array of properties from the config file
37053526Sxy150489 	 */
37063526Sxy150489 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, Adapter->dip,
37073526Sxy150489 	    DDI_PROP_DONTPASS, propname, &props, &nprops) == DDI_PROP_SUCCESS) {
37083526Sxy150489 		/* got some properties, test if we got enough */
37094919Sxy150489 		if (Adapter->instance < nprops) {
37104919Sxy150489 			propval = props[Adapter->instance];
37113526Sxy150489 		} else {
37123526Sxy150489 			/* not enough properties configured */
37133526Sxy150489 			propval = defval;
37144919Sxy150489 			E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL,
37153526Sxy150489 			    "Not Enough %s values found in e1000g.conf"
37163526Sxy150489 			    " - set to %d\n",
37173526Sxy150489 			    propname, propval);
37183526Sxy150489 		}
37193526Sxy150489 
37203526Sxy150489 		/* free memory allocated for properties */
37213526Sxy150489 		ddi_prop_free(props);
37223526Sxy150489 
37233526Sxy150489 	} else {
37243526Sxy150489 		propval = defval;
37253526Sxy150489 	}
37263526Sxy150489 
37273526Sxy150489 	/*
37283526Sxy150489 	 * enforce limits
37293526Sxy150489 	 */
37303526Sxy150489 	if (propval > maxval) {
37313526Sxy150489 		propval = maxval;
37324919Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL,
37333526Sxy150489 		    "Too High %s value in e1000g.conf - set to %d\n",
37343526Sxy150489 		    propname, propval);
37353526Sxy150489 	}
37363526Sxy150489 
37373526Sxy150489 	if (propval < minval) {
37383526Sxy150489 		propval = minval;
37394919Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL,
37403526Sxy150489 		    "Too Low %s value in e1000g.conf - set to %d\n",
37413526Sxy150489 		    propname, propval);
37423526Sxy150489 	}
37433526Sxy150489 
37443526Sxy150489 	return (propval);
37453526Sxy150489 }
37463526Sxy150489 
37473526Sxy150489 static boolean_t
37484061Sxy150489 e1000g_link_check(struct e1000g *Adapter)
37493526Sxy150489 {
37504061Sxy150489 	uint16_t speed, duplex, phydata;
37514061Sxy150489 	boolean_t link_changed = B_FALSE;
37523526Sxy150489 	struct e1000_hw *hw;
37533526Sxy150489 	uint32_t reg_tarc;
37543526Sxy150489 
37554919Sxy150489 	hw = &Adapter->shared;
37563526Sxy150489 
37573526Sxy150489 	if (e1000g_link_up(Adapter)) {
37583526Sxy150489 		/*
37593526Sxy150489 		 * The Link is up, check whether it was marked as down earlier
37603526Sxy150489 		 */
37614061Sxy150489 		if (Adapter->link_state != LINK_STATE_UP) {
37627426SChenliang.Xu@Sun.COM 			(void) e1000_get_speed_and_duplex(hw, &speed, &duplex);
37634061Sxy150489 			Adapter->link_speed = speed;
37644061Sxy150489 			Adapter->link_duplex = duplex;
37654061Sxy150489 			Adapter->link_state = LINK_STATE_UP;
37664061Sxy150489 			link_changed = B_TRUE;
37674061Sxy150489 
37688850SMin.Xu@Sun.COM 			if (Adapter->link_speed == SPEED_1000)
37698850SMin.Xu@Sun.COM 				Adapter->stall_threshold = TX_STALL_TIME_2S;
37708850SMin.Xu@Sun.COM 			else
37718850SMin.Xu@Sun.COM 				Adapter->stall_threshold = TX_STALL_TIME_8S;
37728850SMin.Xu@Sun.COM 
37734061Sxy150489 			Adapter->tx_link_down_timeout = 0;
37744061Sxy150489 
37754919Sxy150489 			if ((hw->mac.type == e1000_82571) ||
37764919Sxy150489 			    (hw->mac.type == e1000_82572)) {
37776735Scc210113 				reg_tarc = E1000_READ_REG(hw, E1000_TARC(0));
37784061Sxy150489 				if (speed == SPEED_1000)
37794061Sxy150489 					reg_tarc |= (1 << 21);
37804061Sxy150489 				else
37814061Sxy150489 					reg_tarc &= ~(1 << 21);
37826735Scc210113 				E1000_WRITE_REG(hw, E1000_TARC(0), reg_tarc);
37833526Sxy150489 			}
37843526Sxy150489 		}
37853526Sxy150489 		Adapter->smartspeed = 0;
37863526Sxy150489 	} else {
37874061Sxy150489 		if (Adapter->link_state != LINK_STATE_DOWN) {
37883526Sxy150489 			Adapter->link_speed = 0;
37893526Sxy150489 			Adapter->link_duplex = 0;
37904061Sxy150489 			Adapter->link_state = LINK_STATE_DOWN;
37914061Sxy150489 			link_changed = B_TRUE;
37924061Sxy150489 
37933526Sxy150489 			/*
37943526Sxy150489 			 * SmartSpeed workaround for Tabor/TanaX, When the
37953526Sxy150489 			 * driver loses link disable auto master/slave
37963526Sxy150489 			 * resolution.
37973526Sxy150489 			 */
37984919Sxy150489 			if (hw->phy.type == e1000_phy_igp) {
37997426SChenliang.Xu@Sun.COM 				(void) e1000_read_phy_reg(hw,
38003526Sxy150489 				    PHY_1000T_CTRL, &phydata);
38013526Sxy150489 				phydata |= CR_1000T_MS_ENABLE;
38027426SChenliang.Xu@Sun.COM 				(void) e1000_write_phy_reg(hw,
38033526Sxy150489 				    PHY_1000T_CTRL, phydata);
38043526Sxy150489 			}
38053526Sxy150489 		} else {
38063526Sxy150489 			e1000g_smartspeed(Adapter);
38073526Sxy150489 		}
38084061Sxy150489 
38098479SChenlu.Chen@Sun.COM 		if (Adapter->e1000g_state & E1000G_STARTED) {
38104061Sxy150489 			if (Adapter->tx_link_down_timeout <
38114061Sxy150489 			    MAX_TX_LINK_DOWN_TIMEOUT) {
38124061Sxy150489 				Adapter->tx_link_down_timeout++;
38134061Sxy150489 			} else if (Adapter->tx_link_down_timeout ==
38144061Sxy150489 			    MAX_TX_LINK_DOWN_TIMEOUT) {
38154919Sxy150489 				e1000g_tx_clean(Adapter);
38164061Sxy150489 				Adapter->tx_link_down_timeout++;
38174061Sxy150489 			}
38184061Sxy150489 		}
38193526Sxy150489 	}
38203526Sxy150489 
38215273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK)
38225273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
38235273Sgl147354 
38244061Sxy150489 	return (link_changed);
38254061Sxy150489 }
38264061Sxy150489 
38276394Scc210113 /*
38286394Scc210113  * e1000g_reset_link - Using the link properties to setup the link
38296394Scc210113  */
38306394Scc210113 int
38316394Scc210113 e1000g_reset_link(struct e1000g *Adapter)
38326394Scc210113 {
38336394Scc210113 	struct e1000_mac_info *mac;
38346394Scc210113 	struct e1000_phy_info *phy;
38356394Scc210113 	boolean_t invalid;
38366394Scc210113 
38376394Scc210113 	mac = &Adapter->shared.mac;
38386394Scc210113 	phy = &Adapter->shared.phy;
38396394Scc210113 	invalid = B_FALSE;
38406394Scc210113 
38416394Scc210113 	if (Adapter->param_adv_autoneg == 1) {
38426394Scc210113 		mac->autoneg = B_TRUE;
38436394Scc210113 		phy->autoneg_advertised = 0;
38446394Scc210113 
38456394Scc210113 		/*
38466394Scc210113 		 * 1000hdx is not supported for autonegotiation
38476394Scc210113 		 */
38486394Scc210113 		if (Adapter->param_adv_1000fdx == 1)
38496394Scc210113 			phy->autoneg_advertised |= ADVERTISE_1000_FULL;
38506394Scc210113 
38516394Scc210113 		if (Adapter->param_adv_100fdx == 1)
38526394Scc210113 			phy->autoneg_advertised |= ADVERTISE_100_FULL;
38536394Scc210113 
38546394Scc210113 		if (Adapter->param_adv_100hdx == 1)
38556394Scc210113 			phy->autoneg_advertised |= ADVERTISE_100_HALF;
38566394Scc210113 
38576394Scc210113 		if (Adapter->param_adv_10fdx == 1)
38586394Scc210113 			phy->autoneg_advertised |= ADVERTISE_10_FULL;
38596394Scc210113 
38606394Scc210113 		if (Adapter->param_adv_10hdx == 1)
38616394Scc210113 			phy->autoneg_advertised |= ADVERTISE_10_HALF;
38626394Scc210113 
38636394Scc210113 		if (phy->autoneg_advertised == 0)
38646394Scc210113 			invalid = B_TRUE;
38656394Scc210113 	} else {
38666394Scc210113 		mac->autoneg = B_FALSE;
38676394Scc210113 
38686394Scc210113 		/*
38696394Scc210113 		 * 1000fdx and 1000hdx are not supported for forced link
38706394Scc210113 		 */
38716394Scc210113 		if (Adapter->param_adv_100fdx == 1)
38726394Scc210113 			mac->forced_speed_duplex = ADVERTISE_100_FULL;
38736394Scc210113 		else if (Adapter->param_adv_100hdx == 1)
38746394Scc210113 			mac->forced_speed_duplex = ADVERTISE_100_HALF;
38756394Scc210113 		else if (Adapter->param_adv_10fdx == 1)
38766394Scc210113 			mac->forced_speed_duplex = ADVERTISE_10_FULL;
38776394Scc210113 		else if (Adapter->param_adv_10hdx == 1)
38786394Scc210113 			mac->forced_speed_duplex = ADVERTISE_10_HALF;
38796394Scc210113 		else
38806394Scc210113 			invalid = B_TRUE;
38816394Scc210113 
38826394Scc210113 	}
38836394Scc210113 
38846394Scc210113 	if (invalid) {
38856394Scc210113 		e1000g_log(Adapter, CE_WARN,
38866394Scc210113 		    "Invalid link sets. Setup link to"
38876394Scc210113 		    "support autonegotiation with all link capabilities.");
38886394Scc210113 		mac->autoneg = B_TRUE;
38896394Scc210113 		phy->autoneg_advertised = ADVERTISE_1000_FULL |
38906394Scc210113 		    ADVERTISE_100_FULL | ADVERTISE_100_HALF |
38916394Scc210113 		    ADVERTISE_10_FULL | ADVERTISE_10_HALF;
38926394Scc210113 	}
38936394Scc210113 
38946394Scc210113 	return (e1000_setup_link(&Adapter->shared));
38956394Scc210113 }
38966394Scc210113 
38974061Sxy150489 static void
38988275SEric Cheng e1000g_timer_tx_resched(struct e1000g *Adapter)
38998275SEric Cheng {
39008275SEric Cheng 	e1000g_tx_ring_t *tx_ring = Adapter->tx_ring;
39018275SEric Cheng 
39028479SChenlu.Chen@Sun.COM 	rw_enter(&Adapter->chip_lock, RW_READER);
39038479SChenlu.Chen@Sun.COM 
39048275SEric Cheng 	if (tx_ring->resched_needed &&
39058275SEric Cheng 	    ((ddi_get_lbolt() - tx_ring->resched_timestamp) >
39068275SEric Cheng 	    drv_usectohz(1000000)) &&
39078479SChenlu.Chen@Sun.COM 	    (Adapter->e1000g_state & E1000G_STARTED) &&
39088275SEric Cheng 	    (tx_ring->tbd_avail >= DEFAULT_TX_NO_RESOURCE)) {
39098275SEric Cheng 		tx_ring->resched_needed = B_FALSE;
39108275SEric Cheng 		mac_tx_update(Adapter->mh);
39118275SEric Cheng 		E1000G_STAT(tx_ring->stat_reschedule);
39128275SEric Cheng 		E1000G_STAT(tx_ring->stat_timer_reschedule);
39138275SEric Cheng 	}
39148479SChenlu.Chen@Sun.COM 
39158479SChenlu.Chen@Sun.COM 	rw_exit(&Adapter->chip_lock);
39168275SEric Cheng }
39178275SEric Cheng 
39188275SEric Cheng static void
39194919Sxy150489 e1000g_local_timer(void *ws)
39204061Sxy150489 {
39214061Sxy150489 	struct e1000g *Adapter = (struct e1000g *)ws;
39224061Sxy150489 	struct e1000_hw *hw;
39234061Sxy150489 	e1000g_ether_addr_t ether_addr;
39244061Sxy150489 	boolean_t link_changed;
39254061Sxy150489 
39264919Sxy150489 	hw = &Adapter->shared;
39274919Sxy150489 
39288479SChenlu.Chen@Sun.COM 	if (Adapter->e1000g_state & E1000G_ERROR) {
39298479SChenlu.Chen@Sun.COM 		rw_enter(&Adapter->chip_lock, RW_WRITER);
39308479SChenlu.Chen@Sun.COM 		Adapter->e1000g_state &= ~E1000G_ERROR;
39318479SChenlu.Chen@Sun.COM 		rw_exit(&Adapter->chip_lock);
39328479SChenlu.Chen@Sun.COM 
39335273Sgl147354 		Adapter->reset_count++;
39348275SEric Cheng 		if (e1000g_global_reset(Adapter)) {
39355273Sgl147354 			ddi_fm_service_impact(Adapter->dip,
39365273Sgl147354 			    DDI_SERVICE_RESTORED);
39378275SEric Cheng 			e1000g_timer_tx_resched(Adapter);
39388275SEric Cheng 		} else
39395273Sgl147354 			ddi_fm_service_impact(Adapter->dip,
39405273Sgl147354 			    DDI_SERVICE_LOST);
39415273Sgl147354 		return;
39425273Sgl147354 	}
39435273Sgl147354 
39444061Sxy150489 	if (e1000g_stall_check(Adapter)) {
39454919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
39464061Sxy150489 		    "Tx stall detected. Activate automatic recovery.\n");
39475273Sgl147354 		e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_STALL);
39488479SChenlu.Chen@Sun.COM 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST);
39494061Sxy150489 		Adapter->reset_count++;
39508275SEric Cheng 		if (e1000g_reset_adapter(Adapter)) {
39515273Sgl147354 			ddi_fm_service_impact(Adapter->dip,
39525273Sgl147354 			    DDI_SERVICE_RESTORED);
39538275SEric Cheng 			e1000g_timer_tx_resched(Adapter);
39548479SChenlu.Chen@Sun.COM 		}
39555273Sgl147354 		return;
39564061Sxy150489 	}
39574061Sxy150489 
39584061Sxy150489 	link_changed = B_FALSE;
39595082Syy150190 	rw_enter(&Adapter->chip_lock, RW_READER);
39604061Sxy150489 	if (Adapter->link_complete)
39614061Sxy150489 		link_changed = e1000g_link_check(Adapter);
39625082Syy150190 	rw_exit(&Adapter->chip_lock);
39634061Sxy150489 
39648850SMin.Xu@Sun.COM 	if (link_changed) {
39658850SMin.Xu@Sun.COM 		if (!Adapter->reset_flag)
39668850SMin.Xu@Sun.COM 			mac_link_update(Adapter->mh, Adapter->link_state);
39678850SMin.Xu@Sun.COM 		if (Adapter->link_state == LINK_STATE_UP)
39688850SMin.Xu@Sun.COM 			Adapter->reset_flag = B_FALSE;
39698850SMin.Xu@Sun.COM 	}
39707133Scc210113 	/*
39717133Scc210113 	 * Workaround for esb2. Data stuck in fifo on a link
39727133Scc210113 	 * down event. Reset the adapter to recover it.
39737133Scc210113 	 */
39747133Scc210113 	if (Adapter->esb2_workaround) {
39757133Scc210113 		Adapter->esb2_workaround = B_FALSE;
39767656SSherry.Moore@Sun.COM 		(void) e1000g_reset_adapter(Adapter);
39778479SChenlu.Chen@Sun.COM 		return;
39784139Sxy150489 	}
39794061Sxy150489 
39803526Sxy150489 	/*
39813526Sxy150489 	 * With 82571 controllers, any locally administered address will
39823526Sxy150489 	 * be overwritten when there is a reset on the other port.
39833526Sxy150489 	 * Detect this circumstance and correct it.
39843526Sxy150489 	 */
39854919Sxy150489 	if ((hw->mac.type == e1000_82571) &&
39864919Sxy150489 	    (e1000_get_laa_state_82571(hw) == B_TRUE)) {
39874919Sxy150489 		ether_addr.reg.low = E1000_READ_REG_ARRAY(hw, E1000_RA, 0);
39884919Sxy150489 		ether_addr.reg.high = E1000_READ_REG_ARRAY(hw, E1000_RA, 1);
39893526Sxy150489 
39903526Sxy150489 		ether_addr.reg.low = ntohl(ether_addr.reg.low);
39913526Sxy150489 		ether_addr.reg.high = ntohl(ether_addr.reg.high);
39923526Sxy150489 
39934919Sxy150489 		if ((ether_addr.mac.addr[5] != hw->mac.addr[0]) ||
39944919Sxy150489 		    (ether_addr.mac.addr[4] != hw->mac.addr[1]) ||
39954919Sxy150489 		    (ether_addr.mac.addr[3] != hw->mac.addr[2]) ||
39964919Sxy150489 		    (ether_addr.mac.addr[2] != hw->mac.addr[3]) ||
39974919Sxy150489 		    (ether_addr.mac.addr[1] != hw->mac.addr[4]) ||
39984919Sxy150489 		    (ether_addr.mac.addr[0] != hw->mac.addr[5])) {
39994919Sxy150489 			e1000_rar_set(hw, hw->mac.addr, 0);
40003526Sxy150489 		}
40013526Sxy150489 	}
40023526Sxy150489 
40033526Sxy150489 	/*
40044919Sxy150489 	 * Long TTL workaround for 82541/82547
40053526Sxy150489 	 */
40067426SChenliang.Xu@Sun.COM 	(void) e1000_igp_ttl_workaround_82547(hw);
40073526Sxy150489 
40083526Sxy150489 	/*
40093526Sxy150489 	 * Check for Adaptive IFS settings If there are lots of collisions
40103526Sxy150489 	 * change the value in steps...
40113526Sxy150489 	 * These properties should only be set for 10/100
40123526Sxy150489 	 */
40136735Scc210113 	if ((hw->phy.media_type == e1000_media_type_copper) &&
40144061Sxy150489 	    ((Adapter->link_speed == SPEED_100) ||
40154061Sxy150489 	    (Adapter->link_speed == SPEED_10))) {
40163526Sxy150489 		e1000_update_adaptive(hw);
40173526Sxy150489 	}
40183526Sxy150489 	/*
40193526Sxy150489 	 * Set Timer Interrupts
40203526Sxy150489 	 */
40214919Sxy150489 	E1000_WRITE_REG(hw, E1000_ICS, E1000_IMS_RXT0);
40224919Sxy150489 
40235273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK)
40245273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
40258275SEric Cheng 	else
40268275SEric Cheng 		e1000g_timer_tx_resched(Adapter);
40275273Sgl147354 
40284919Sxy150489 	restart_watchdog_timer(Adapter);
40293526Sxy150489 }
40303526Sxy150489 
40314061Sxy150489 /*
40324061Sxy150489  * The function e1000g_link_timer() is called when the timer for link setup
40334061Sxy150489  * is expired, which indicates the completion of the link setup. The link
40344061Sxy150489  * state will not be updated until the link setup is completed. And the
40354061Sxy150489  * link state will not be sent to the upper layer through mac_link_update()
40364061Sxy150489  * in this function. It will be updated in the local timer routine or the
40374061Sxy150489  * interrupt service routine after the interface is started (plumbed).
40384061Sxy150489  */
40393526Sxy150489 static void
40404061Sxy150489 e1000g_link_timer(void *arg)
40413526Sxy150489 {
40424061Sxy150489 	struct e1000g *Adapter = (struct e1000g *)arg;
40433526Sxy150489 
40444919Sxy150489 	mutex_enter(&Adapter->link_lock);
40454061Sxy150489 	Adapter->link_complete = B_TRUE;
40464061Sxy150489 	Adapter->link_tid = 0;
40474919Sxy150489 	mutex_exit(&Adapter->link_lock);
40483526Sxy150489 }
40493526Sxy150489 
40503526Sxy150489 /*
40514919Sxy150489  * e1000g_force_speed_duplex - read forced speed/duplex out of e1000g.conf
40524919Sxy150489  *
40534919Sxy150489  * This function read the forced speed and duplex for 10/100 Mbps speeds
40544919Sxy150489  * and also for 1000 Mbps speeds from the e1000g.conf file
40553526Sxy150489  */
40563526Sxy150489 static void
40573526Sxy150489 e1000g_force_speed_duplex(struct e1000g *Adapter)
40583526Sxy150489 {
40593526Sxy150489 	int forced;
40604919Sxy150489 	struct e1000_mac_info *mac = &Adapter->shared.mac;
40614919Sxy150489 	struct e1000_phy_info *phy = &Adapter->shared.phy;
40623526Sxy150489 
40633526Sxy150489 	/*
40643526Sxy150489 	 * get value out of config file
40653526Sxy150489 	 */
40664919Sxy150489 	forced = e1000g_get_prop(Adapter, "ForceSpeedDuplex",
40673526Sxy150489 	    GDIAG_10_HALF, GDIAG_ANY, GDIAG_ANY);
40683526Sxy150489 
40693526Sxy150489 	switch (forced) {
40703526Sxy150489 	case GDIAG_10_HALF:
40713526Sxy150489 		/*
40723526Sxy150489 		 * Disable Auto Negotiation
40733526Sxy150489 		 */
40744919Sxy150489 		mac->autoneg = B_FALSE;
40754919Sxy150489 		mac->forced_speed_duplex = ADVERTISE_10_HALF;
40763526Sxy150489 		break;
40773526Sxy150489 	case GDIAG_10_FULL:
40783526Sxy150489 		/*
40793526Sxy150489 		 * Disable Auto Negotiation
40803526Sxy150489 		 */
40814919Sxy150489 		mac->autoneg = B_FALSE;
40824919Sxy150489 		mac->forced_speed_duplex = ADVERTISE_10_FULL;
40833526Sxy150489 		break;
40843526Sxy150489 	case GDIAG_100_HALF:
40853526Sxy150489 		/*
40863526Sxy150489 		 * Disable Auto Negotiation
40873526Sxy150489 		 */
40884919Sxy150489 		mac->autoneg = B_FALSE;
40894919Sxy150489 		mac->forced_speed_duplex = ADVERTISE_100_HALF;
40903526Sxy150489 		break;
40913526Sxy150489 	case GDIAG_100_FULL:
40923526Sxy150489 		/*
40933526Sxy150489 		 * Disable Auto Negotiation
40943526Sxy150489 		 */
40954919Sxy150489 		mac->autoneg = B_FALSE;
40964919Sxy150489 		mac->forced_speed_duplex = ADVERTISE_100_FULL;
40973526Sxy150489 		break;
40983526Sxy150489 	case GDIAG_1000_FULL:
40993526Sxy150489 		/*
41003526Sxy150489 		 * The gigabit spec requires autonegotiation.  Therefore,
41013526Sxy150489 		 * when the user wants to force the speed to 1000Mbps, we
41023526Sxy150489 		 * enable AutoNeg, but only allow the harware to advertise
41033526Sxy150489 		 * 1000Mbps.  This is different from 10/100 operation, where
41043526Sxy150489 		 * we are allowed to link without any negotiation.
41053526Sxy150489 		 */
41064919Sxy150489 		mac->autoneg = B_TRUE;
41074919Sxy150489 		phy->autoneg_advertised = ADVERTISE_1000_FULL;
41083526Sxy150489 		break;
41093526Sxy150489 	default:	/* obey the setting of AutoNegAdvertised */
41104919Sxy150489 		mac->autoneg = B_TRUE;
41114919Sxy150489 		phy->autoneg_advertised =
41124919Sxy150489 		    (uint16_t)e1000g_get_prop(Adapter, "AutoNegAdvertised",
41134349Sxy150489 		    0, AUTONEG_ADVERTISE_SPEED_DEFAULT,
41144349Sxy150489 		    AUTONEG_ADVERTISE_SPEED_DEFAULT);
41153526Sxy150489 		break;
41163526Sxy150489 	}	/* switch */
41173526Sxy150489 }
41183526Sxy150489 
41193526Sxy150489 /*
41204919Sxy150489  * e1000g_get_max_frame_size - get jumbo frame setting from e1000g.conf
41214919Sxy150489  *
41224919Sxy150489  * This function reads MaxFrameSize from e1000g.conf
41233526Sxy150489  */
41243526Sxy150489 static void
41253526Sxy150489 e1000g_get_max_frame_size(struct e1000g *Adapter)
41263526Sxy150489 {
41273526Sxy150489 	int max_frame;
41284919Sxy150489 	struct e1000_mac_info *mac = &Adapter->shared.mac;
41294919Sxy150489 	struct e1000_phy_info *phy = &Adapter->shared.phy;
41303526Sxy150489 
41313526Sxy150489 	/*
41323526Sxy150489 	 * get value out of config file
41333526Sxy150489 	 */
41344919Sxy150489 	max_frame = e1000g_get_prop(Adapter, "MaxFrameSize", 0, 3, 0);
41353526Sxy150489 
41363526Sxy150489 	switch (max_frame) {
41373526Sxy150489 	case 0:
41386394Scc210113 		Adapter->default_mtu = ETHERMTU;
41393526Sxy150489 		break;
41406394Scc210113 	/*
41416394Scc210113 	 * To avoid excessive memory allocation for rx buffers,
41426394Scc210113 	 * the bytes of E1000G_IPALIGNPRESERVEROOM are reserved.
41436394Scc210113 	 */
41443526Sxy150489 	case 1:
41456394Scc210113 		Adapter->default_mtu = FRAME_SIZE_UPTO_4K -
41466394Scc210113 		    sizeof (struct ether_vlan_header) - ETHERFCSL -
41476394Scc210113 		    E1000G_IPALIGNPRESERVEROOM;
41483526Sxy150489 		break;
41493526Sxy150489 	case 2:
41506394Scc210113 		Adapter->default_mtu = FRAME_SIZE_UPTO_8K -
41516394Scc210113 		    sizeof (struct ether_vlan_header) - ETHERFCSL -
41526394Scc210113 		    E1000G_IPALIGNPRESERVEROOM;
41533526Sxy150489 		break;
41543526Sxy150489 	case 3:
41556394Scc210113 		if (mac->type >= e1000_82571)
41566394Scc210113 			Adapter->default_mtu = MAXIMUM_MTU;
41573526Sxy150489 		else
41586394Scc210113 			Adapter->default_mtu = FRAME_SIZE_UPTO_16K -
41596394Scc210113 			    sizeof (struct ether_vlan_header) - ETHERFCSL -
41606394Scc210113 			    E1000G_IPALIGNPRESERVEROOM;
41613526Sxy150489 		break;
41623526Sxy150489 	default:
41636394Scc210113 		Adapter->default_mtu = ETHERMTU;
41643526Sxy150489 		break;
41653526Sxy150489 	}	/* switch */
41663526Sxy150489 
41676735Scc210113 	Adapter->max_frame_size = Adapter->default_mtu +
41686394Scc210113 	    sizeof (struct ether_vlan_header) + ETHERFCSL;
41696394Scc210113 
41703526Sxy150489 	/* ich8 does not do jumbo frames */
41714919Sxy150489 	if (mac->type == e1000_ich8lan) {
41728178SChenlu.Chen@Sun.COM 		Adapter->default_mtu = ETHERMTU;
41737133Scc210113 		Adapter->max_frame_size = ETHERMTU +
41747133Scc210113 		    sizeof (struct ether_vlan_header) + ETHERFCSL;
41754919Sxy150489 	}
41764919Sxy150489 
41774919Sxy150489 	/* ich9 does not do jumbo frames on one phy type */
41784919Sxy150489 	if ((mac->type == e1000_ich9lan) &&
41794919Sxy150489 	    (phy->type == e1000_phy_ife)) {
41808178SChenlu.Chen@Sun.COM 		Adapter->default_mtu = ETHERMTU;
41817133Scc210113 		Adapter->max_frame_size = ETHERMTU +
41827133Scc210113 		    sizeof (struct ether_vlan_header) + ETHERFCSL;
41833526Sxy150489 	}
41843526Sxy150489 }
41853526Sxy150489 
41863526Sxy150489 static void
41874919Sxy150489 arm_watchdog_timer(struct e1000g *Adapter)
41883526Sxy150489 {
41894919Sxy150489 	Adapter->watchdog_tid =
41904919Sxy150489 	    timeout(e1000g_local_timer,
41913526Sxy150489 	    (void *)Adapter, 1 * drv_usectohz(1000000));
41923526Sxy150489 }
41934919Sxy150489 #pragma inline(arm_watchdog_timer)
41944919Sxy150489 
41954919Sxy150489 static void
41964919Sxy150489 enable_watchdog_timer(struct e1000g *Adapter)
41974919Sxy150489 {
41984919Sxy150489 	mutex_enter(&Adapter->watchdog_lock);
41994919Sxy150489 
42004919Sxy150489 	if (!Adapter->watchdog_timer_enabled) {
42014919Sxy150489 		Adapter->watchdog_timer_enabled = B_TRUE;
42024919Sxy150489 		Adapter->watchdog_timer_started = B_TRUE;
42034919Sxy150489 		arm_watchdog_timer(Adapter);
42044919Sxy150489 	}
42054919Sxy150489 
42064919Sxy150489 	mutex_exit(&Adapter->watchdog_lock);
42074919Sxy150489 }
42083526Sxy150489 
42093526Sxy150489 static void
42104919Sxy150489 disable_watchdog_timer(struct e1000g *Adapter)
42113526Sxy150489 {
42123526Sxy150489 	timeout_id_t tid;
42133526Sxy150489 
42144919Sxy150489 	mutex_enter(&Adapter->watchdog_lock);
42154919Sxy150489 
42164919Sxy150489 	Adapter->watchdog_timer_enabled = B_FALSE;
42174919Sxy150489 	Adapter->watchdog_timer_started = B_FALSE;
42184919Sxy150489 	tid = Adapter->watchdog_tid;
42194919Sxy150489 	Adapter->watchdog_tid = 0;
42204919Sxy150489 
42214919Sxy150489 	mutex_exit(&Adapter->watchdog_lock);
42223526Sxy150489 
42233526Sxy150489 	if (tid != 0)
42243526Sxy150489 		(void) untimeout(tid);
42253526Sxy150489 }
42263526Sxy150489 
42273526Sxy150489 static void
42284919Sxy150489 start_watchdog_timer(struct e1000g *Adapter)
42293526Sxy150489 {
42304919Sxy150489 	mutex_enter(&Adapter->watchdog_lock);
42314919Sxy150489 
42324919Sxy150489 	if (Adapter->watchdog_timer_enabled) {
42334919Sxy150489 		if (!Adapter->watchdog_timer_started) {
42344919Sxy150489 			Adapter->watchdog_timer_started = B_TRUE;
42354919Sxy150489 			arm_watchdog_timer(Adapter);
42363526Sxy150489 		}
42373526Sxy150489 	}
42383526Sxy150489 
42394919Sxy150489 	mutex_exit(&Adapter->watchdog_lock);
42404919Sxy150489 }
42414919Sxy150489 
42424919Sxy150489 static void
42434919Sxy150489 restart_watchdog_timer(struct e1000g *Adapter)
42444919Sxy150489 {
42454919Sxy150489 	mutex_enter(&Adapter->watchdog_lock);
42464919Sxy150489 
42474919Sxy150489 	if (Adapter->watchdog_timer_started)
42484919Sxy150489 		arm_watchdog_timer(Adapter);
42494919Sxy150489 
42504919Sxy150489 	mutex_exit(&Adapter->watchdog_lock);
42513526Sxy150489 }
42523526Sxy150489 
42533526Sxy150489 static void
42544919Sxy150489 stop_watchdog_timer(struct e1000g *Adapter)
42553526Sxy150489 {
42564919Sxy150489 	timeout_id_t tid;
42574919Sxy150489 
42584919Sxy150489 	mutex_enter(&Adapter->watchdog_lock);
42594919Sxy150489 
42604919Sxy150489 	Adapter->watchdog_timer_started = B_FALSE;
42614919Sxy150489 	tid = Adapter->watchdog_tid;
42624919Sxy150489 	Adapter->watchdog_tid = 0;
42634919Sxy150489 
42644919Sxy150489 	mutex_exit(&Adapter->watchdog_lock);
42654919Sxy150489 
42664919Sxy150489 	if (tid != 0)
42674919Sxy150489 		(void) untimeout(tid);
42683526Sxy150489 }
42693526Sxy150489 
42703526Sxy150489 static void
42714919Sxy150489 stop_link_timer(struct e1000g *Adapter)
42723526Sxy150489 {
42733526Sxy150489 	timeout_id_t tid;
42743526Sxy150489 
42754919Sxy150489 	/* Disable the link timer */
42764919Sxy150489 	mutex_enter(&Adapter->link_lock);
42774919Sxy150489 
42784919Sxy150489 	tid = Adapter->link_tid;
42794919Sxy150489 	Adapter->link_tid = 0;
42804919Sxy150489 
42814919Sxy150489 	mutex_exit(&Adapter->link_lock);
42824919Sxy150489 
42834919Sxy150489 	if (tid != 0)
42844919Sxy150489 		(void) untimeout(tid);
42854919Sxy150489 }
42864919Sxy150489 
42874919Sxy150489 static void
42884919Sxy150489 stop_82547_timer(e1000g_tx_ring_t *tx_ring)
42894919Sxy150489 {
42904919Sxy150489 	timeout_id_t tid;
42914919Sxy150489 
42924919Sxy150489 	/* Disable the tx timer for 82547 chipset */
42934919Sxy150489 	mutex_enter(&tx_ring->tx_lock);
42944919Sxy150489 
42954919Sxy150489 	tx_ring->timer_enable_82547 = B_FALSE;
42964919Sxy150489 	tid = tx_ring->timer_id_82547;
42974919Sxy150489 	tx_ring->timer_id_82547 = 0;
42984919Sxy150489 
42994919Sxy150489 	mutex_exit(&tx_ring->tx_lock);
43003526Sxy150489 
43013526Sxy150489 	if (tid != 0)
43023526Sxy150489 		(void) untimeout(tid);
43033526Sxy150489 }
43043526Sxy150489 
43053526Sxy150489 void
43064919Sxy150489 e1000g_clear_interrupt(struct e1000g *Adapter)
43073526Sxy150489 {
43084919Sxy150489 	E1000_WRITE_REG(&Adapter->shared, E1000_IMC,
43094919Sxy150489 	    0xffffffff & ~E1000_IMS_RXSEQ);
43103526Sxy150489 }
43113526Sxy150489 
43123526Sxy150489 void
43134919Sxy150489 e1000g_mask_interrupt(struct e1000g *Adapter)
43143526Sxy150489 {
43154919Sxy150489 	E1000_WRITE_REG(&Adapter->shared, E1000_IMS,
43165882Syy150190 	    IMS_ENABLE_MASK & ~E1000_IMS_TXDW);
43175882Syy150190 
43185882Syy150190 	if (Adapter->tx_intr_enable)
43195882Syy150190 		e1000g_mask_tx_interrupt(Adapter);
43203526Sxy150489 }
43213526Sxy150489 
43227656SSherry.Moore@Sun.COM /*
43237656SSherry.Moore@Sun.COM  * This routine is called by e1000g_quiesce(), therefore must not block.
43247656SSherry.Moore@Sun.COM  */
43253526Sxy150489 void
43264919Sxy150489 e1000g_clear_all_interrupts(struct e1000g *Adapter)
43273526Sxy150489 {
43284919Sxy150489 	E1000_WRITE_REG(&Adapter->shared, E1000_IMC, 0xffffffff);
43293526Sxy150489 }
43303526Sxy150489 
43313526Sxy150489 void
43324919Sxy150489 e1000g_mask_tx_interrupt(struct e1000g *Adapter)
43333526Sxy150489 {
43345882Syy150190 	E1000_WRITE_REG(&Adapter->shared, E1000_IMS, E1000_IMS_TXDW);
43353526Sxy150489 }
43363526Sxy150489 
43373526Sxy150489 void
43384919Sxy150489 e1000g_clear_tx_interrupt(struct e1000g *Adapter)
43393526Sxy150489 {
43405882Syy150190 	E1000_WRITE_REG(&Adapter->shared, E1000_IMC, E1000_IMS_TXDW);
43413526Sxy150489 }
43423526Sxy150489 
43433526Sxy150489 static void
43444919Sxy150489 e1000g_smartspeed(struct e1000g *Adapter)
43453526Sxy150489 {
43464919Sxy150489 	struct e1000_hw *hw = &Adapter->shared;
43473526Sxy150489 	uint16_t phy_status;
43483526Sxy150489 	uint16_t phy_ctrl;
43493526Sxy150489 
43503526Sxy150489 	/*
43513526Sxy150489 	 * If we're not T-or-T, or we're not autoneg'ing, or we're not
43523526Sxy150489 	 * advertising 1000Full, we don't even use the workaround
43533526Sxy150489 	 */
43544919Sxy150489 	if ((hw->phy.type != e1000_phy_igp) ||
43554919Sxy150489 	    !hw->mac.autoneg ||
43564919Sxy150489 	    !(hw->phy.autoneg_advertised & ADVERTISE_1000_FULL))
43573526Sxy150489 		return;
43583526Sxy150489 
43593526Sxy150489 	/*
43603526Sxy150489 	 * True if this is the first call of this function or after every
43613526Sxy150489 	 * 30 seconds of not having link
43623526Sxy150489 	 */
43634919Sxy150489 	if (Adapter->smartspeed == 0) {
43643526Sxy150489 		/*
43653526Sxy150489 		 * If Master/Slave config fault is asserted twice, we
43663526Sxy150489 		 * assume back-to-back
43673526Sxy150489 		 */
43687426SChenliang.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
43693526Sxy150489 		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT))
43703526Sxy150489 			return;
43713526Sxy150489 
43727426SChenliang.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
43733526Sxy150489 		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT))
43743526Sxy150489 			return;
43753526Sxy150489 		/*
43763526Sxy150489 		 * We're assuming back-2-back because our status register
43773526Sxy150489 		 * insists! there's a fault in the master/slave
43783526Sxy150489 		 * relationship that was "negotiated"
43793526Sxy150489 		 */
43807426SChenliang.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl);
43813526Sxy150489 		/*
43823526Sxy150489 		 * Is the phy configured for manual configuration of
43833526Sxy150489 		 * master/slave?
43843526Sxy150489 		 */
43853526Sxy150489 		if (phy_ctrl & CR_1000T_MS_ENABLE) {
43863526Sxy150489 			/*
43873526Sxy150489 			 * Yes.  Then disable manual configuration (enable
43883526Sxy150489 			 * auto configuration) of master/slave
43893526Sxy150489 			 */
43903526Sxy150489 			phy_ctrl &= ~CR_1000T_MS_ENABLE;
43917426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw,
43923526Sxy150489 			    PHY_1000T_CTRL, phy_ctrl);
43933526Sxy150489 			/*
43943526Sxy150489 			 * Effectively starting the clock
43953526Sxy150489 			 */
43964919Sxy150489 			Adapter->smartspeed++;
43973526Sxy150489 			/*
43983526Sxy150489 			 * Restart autonegotiation
43993526Sxy150489 			 */
44004919Sxy150489 			if (!e1000_phy_setup_autoneg(hw) &&
44014919Sxy150489 			    !e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl)) {
44023526Sxy150489 				phy_ctrl |= (MII_CR_AUTO_NEG_EN |
44033526Sxy150489 				    MII_CR_RESTART_AUTO_NEG);
44047426SChenliang.Xu@Sun.COM 				(void) e1000_write_phy_reg(hw,
44054919Sxy150489 				    PHY_CONTROL, phy_ctrl);
44063526Sxy150489 			}
44073526Sxy150489 		}
44083526Sxy150489 		return;
44093526Sxy150489 		/*
44103526Sxy150489 		 * Has 6 seconds transpired still without link? Remember,
44113526Sxy150489 		 * you should reset the smartspeed counter once you obtain
44123526Sxy150489 		 * link
44133526Sxy150489 		 */
44144919Sxy150489 	} else if (Adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) {
44153526Sxy150489 		/*
44163526Sxy150489 		 * Yes.  Remember, we did at the start determine that
44173526Sxy150489 		 * there's a master/slave configuration fault, so we're
44183526Sxy150489 		 * still assuming there's someone on the other end, but we
44193526Sxy150489 		 * just haven't yet been able to talk to it. We then
44203526Sxy150489 		 * re-enable auto configuration of master/slave to see if
44213526Sxy150489 		 * we're running 2/3 pair cables.
44223526Sxy150489 		 */
44233526Sxy150489 		/*
44243526Sxy150489 		 * If still no link, perhaps using 2/3 pair cable
44253526Sxy150489 		 */
44267426SChenliang.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl);
44273526Sxy150489 		phy_ctrl |= CR_1000T_MS_ENABLE;
44287426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_ctrl);
44293526Sxy150489 		/*
44303526Sxy150489 		 * Restart autoneg with phy enabled for manual
44313526Sxy150489 		 * configuration of master/slave
44323526Sxy150489 		 */
44334919Sxy150489 		if (!e1000_phy_setup_autoneg(hw) &&
44344919Sxy150489 		    !e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl)) {
44353526Sxy150489 			phy_ctrl |=
44363526Sxy150489 			    (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
44377426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl);
44383526Sxy150489 		}
44393526Sxy150489 		/*
44403526Sxy150489 		 * Hopefully, there are no more faults and we've obtained
44413526Sxy150489 		 * link as a result.
44423526Sxy150489 		 */
44433526Sxy150489 	}
44443526Sxy150489 	/*
44453526Sxy150489 	 * Restart process after E1000_SMARTSPEED_MAX iterations (30
44463526Sxy150489 	 * seconds)
44473526Sxy150489 	 */
44484919Sxy150489 	if (Adapter->smartspeed++ == E1000_SMARTSPEED_MAX)
44494919Sxy150489 		Adapter->smartspeed = 0;
44503526Sxy150489 }
44513526Sxy150489 
44523526Sxy150489 static boolean_t
44533526Sxy150489 is_valid_mac_addr(uint8_t *mac_addr)
44543526Sxy150489 {
44553526Sxy150489 	const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 };
44563526Sxy150489 	const uint8_t addr_test2[6] =
44573526Sxy150489 	    { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
44583526Sxy150489 
44593526Sxy150489 	if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) ||
44603526Sxy150489 	    !(bcmp(addr_test2, mac_addr, ETHERADDRL)))
44613526Sxy150489 		return (B_FALSE);
44623526Sxy150489 
44633526Sxy150489 	return (B_TRUE);
44643526Sxy150489 }
44653526Sxy150489 
44663526Sxy150489 /*
44674919Sxy150489  * e1000g_stall_check - check for tx stall
44684919Sxy150489  *
44694919Sxy150489  * This function checks if the adapter is stalled (in transmit).
44704919Sxy150489  *
44714919Sxy150489  * It is called each time the watchdog timeout is invoked.
44724919Sxy150489  * If the transmit descriptor reclaim continuously fails,
44734919Sxy150489  * the watchdog value will increment by 1. If the watchdog
44744919Sxy150489  * value exceeds the threshold, the adapter is assumed to
44754919Sxy150489  * have stalled and need to be reset.
44763526Sxy150489  */
44773526Sxy150489 static boolean_t
44783526Sxy150489 e1000g_stall_check(struct e1000g *Adapter)
44793526Sxy150489 {
44804919Sxy150489 	e1000g_tx_ring_t *tx_ring;
44814919Sxy150489 
44824919Sxy150489 	tx_ring = Adapter->tx_ring;
44834919Sxy150489 
44844061Sxy150489 	if (Adapter->link_state != LINK_STATE_UP)
44853526Sxy150489 		return (B_FALSE);
44863526Sxy150489 
44878850SMin.Xu@Sun.COM 	(void) e1000g_recycle(tx_ring);
44888850SMin.Xu@Sun.COM 
44898850SMin.Xu@Sun.COM 	if (Adapter->stall_flag) {
44908850SMin.Xu@Sun.COM 		Adapter->stall_flag = B_FALSE;
44918850SMin.Xu@Sun.COM 		Adapter->reset_flag = B_TRUE;
44928850SMin.Xu@Sun.COM 		return (B_TRUE);
44938850SMin.Xu@Sun.COM 	}
44948850SMin.Xu@Sun.COM 
44958850SMin.Xu@Sun.COM 	return (B_FALSE);
44963526Sxy150489 }
44973526Sxy150489 
44984919Sxy150489 #ifdef E1000G_DEBUG
44993526Sxy150489 static enum ioc_reply
45003526Sxy150489 e1000g_pp_ioctl(struct e1000g *e1000gp, struct iocblk *iocp, mblk_t *mp)
45013526Sxy150489 {
45023526Sxy150489 	void (*ppfn)(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd);
45033526Sxy150489 	e1000g_peekpoke_t *ppd;
45043526Sxy150489 	uint64_t mem_va;
45053526Sxy150489 	uint64_t maxoff;
45063526Sxy150489 	boolean_t peek;
45073526Sxy150489 
45083526Sxy150489 	switch (iocp->ioc_cmd) {
45093526Sxy150489 
45103526Sxy150489 	case E1000G_IOC_REG_PEEK:
45113526Sxy150489 		peek = B_TRUE;
45123526Sxy150489 		break;
45133526Sxy150489 
45143526Sxy150489 	case E1000G_IOC_REG_POKE:
45153526Sxy150489 		peek = B_FALSE;
45163526Sxy150489 		break;
45173526Sxy150489 
45183526Sxy150489 	deault:
45194919Sxy150489 		E1000G_DEBUGLOG_1(e1000gp, E1000G_INFO_LEVEL,
45204349Sxy150489 		    "e1000g_diag_ioctl: invalid ioctl command 0x%X\n",
45214349Sxy150489 		    iocp->ioc_cmd);
45223526Sxy150489 		return (IOC_INVAL);
45233526Sxy150489 	}
45243526Sxy150489 
45253526Sxy150489 	/*
45263526Sxy150489 	 * Validate format of ioctl
45273526Sxy150489 	 */
45283526Sxy150489 	if (iocp->ioc_count != sizeof (e1000g_peekpoke_t))
45293526Sxy150489 		return (IOC_INVAL);
45303526Sxy150489 	if (mp->b_cont == NULL)
45313526Sxy150489 		return (IOC_INVAL);
45323526Sxy150489 
45337426SChenliang.Xu@Sun.COM 	ppd = (e1000g_peekpoke_t *)(uintptr_t)mp->b_cont->b_rptr;
45343526Sxy150489 
45353526Sxy150489 	/*
45363526Sxy150489 	 * Validate request parameters
45373526Sxy150489 	 */
45383526Sxy150489 	switch (ppd->pp_acc_space) {
45393526Sxy150489 
45403526Sxy150489 	default:
45414919Sxy150489 		E1000G_DEBUGLOG_1(e1000gp, E1000G_INFO_LEVEL,
45424349Sxy150489 		    "e1000g_diag_ioctl: invalid access space 0x%X\n",
45434349Sxy150489 		    ppd->pp_acc_space);
45443526Sxy150489 		return (IOC_INVAL);
45453526Sxy150489 
45463526Sxy150489 	case E1000G_PP_SPACE_REG:
45473526Sxy150489 		/*
45483526Sxy150489 		 * Memory-mapped I/O space
45493526Sxy150489 		 */
45503526Sxy150489 		ASSERT(ppd->pp_acc_size == 4);
45513526Sxy150489 		if (ppd->pp_acc_size != 4)
45523526Sxy150489 			return (IOC_INVAL);
45533526Sxy150489 
45543526Sxy150489 		if ((ppd->pp_acc_offset % ppd->pp_acc_size) != 0)
45553526Sxy150489 			return (IOC_INVAL);
45563526Sxy150489 
45573526Sxy150489 		mem_va = 0;
45583526Sxy150489 		maxoff = 0x10000;
45593526Sxy150489 		ppfn = peek ? e1000g_ioc_peek_reg : e1000g_ioc_poke_reg;
45603526Sxy150489 		break;
45613526Sxy150489 
45623526Sxy150489 	case E1000G_PP_SPACE_E1000G:
45633526Sxy150489 		/*
45643526Sxy150489 		 * E1000g data structure!
45653526Sxy150489 		 */
45663526Sxy150489 		mem_va = (uintptr_t)e1000gp;
45673526Sxy150489 		maxoff = sizeof (struct e1000g);
45683526Sxy150489 		ppfn = peek ? e1000g_ioc_peek_mem : e1000g_ioc_poke_mem;
45693526Sxy150489 		break;
45703526Sxy150489 
45713526Sxy150489 	}
45723526Sxy150489 
45733526Sxy150489 	if (ppd->pp_acc_offset >= maxoff)
45743526Sxy150489 		return (IOC_INVAL);
45753526Sxy150489 
45763526Sxy150489 	if (ppd->pp_acc_offset + ppd->pp_acc_size > maxoff)
45773526Sxy150489 		return (IOC_INVAL);
45783526Sxy150489 
45793526Sxy150489 	/*
45803526Sxy150489 	 * All OK - go!
45813526Sxy150489 	 */
45823526Sxy150489 	ppd->pp_acc_offset += mem_va;
45833526Sxy150489 	(*ppfn)(e1000gp, ppd);
45843526Sxy150489 	return (peek ? IOC_REPLY : IOC_ACK);
45853526Sxy150489 }
45863526Sxy150489 
45873526Sxy150489 static void
45883526Sxy150489 e1000g_ioc_peek_reg(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd)
45893526Sxy150489 {
45903526Sxy150489 	ddi_acc_handle_t handle;
45913526Sxy150489 	uint32_t *regaddr;
45923526Sxy150489 
45934919Sxy150489 	handle = e1000gp->osdep.reg_handle;
45947426SChenliang.Xu@Sun.COM 	regaddr = (uint32_t *)((uintptr_t)e1000gp->shared.hw_addr +
45957426SChenliang.Xu@Sun.COM 	    (uintptr_t)ppd->pp_acc_offset);
45963526Sxy150489 
45973526Sxy150489 	ppd->pp_acc_data = ddi_get32(handle, regaddr);
45983526Sxy150489 }
45993526Sxy150489 
46003526Sxy150489 static void
46013526Sxy150489 e1000g_ioc_poke_reg(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd)
46023526Sxy150489 {
46033526Sxy150489 	ddi_acc_handle_t handle;
46043526Sxy150489 	uint32_t *regaddr;
46053526Sxy150489 	uint32_t value;
46063526Sxy150489 
46074919Sxy150489 	handle = e1000gp->osdep.reg_handle;
46087426SChenliang.Xu@Sun.COM 	regaddr = (uint32_t *)((uintptr_t)e1000gp->shared.hw_addr +
46097426SChenliang.Xu@Sun.COM 	    (uintptr_t)ppd->pp_acc_offset);
46103526Sxy150489 	value = (uint32_t)ppd->pp_acc_data;
46113526Sxy150489 
46123526Sxy150489 	ddi_put32(handle, regaddr, value);
46133526Sxy150489 }
46143526Sxy150489 
46153526Sxy150489 static void
46163526Sxy150489 e1000g_ioc_peek_mem(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd)
46173526Sxy150489 {
46183526Sxy150489 	uint64_t value;
46193526Sxy150489 	void *vaddr;
46203526Sxy150489 
46213526Sxy150489 	vaddr = (void *)(uintptr_t)ppd->pp_acc_offset;
46223526Sxy150489 
46233526Sxy150489 	switch (ppd->pp_acc_size) {
46243526Sxy150489 	case 1:
46253526Sxy150489 		value = *(uint8_t *)vaddr;
46263526Sxy150489 		break;
46273526Sxy150489 
46283526Sxy150489 	case 2:
46293526Sxy150489 		value = *(uint16_t *)vaddr;
46303526Sxy150489 		break;
46313526Sxy150489 
46323526Sxy150489 	case 4:
46333526Sxy150489 		value = *(uint32_t *)vaddr;
46343526Sxy150489 		break;
46353526Sxy150489 
46363526Sxy150489 	case 8:
46373526Sxy150489 		value = *(uint64_t *)vaddr;
46383526Sxy150489 		break;
46393526Sxy150489 	}
46403526Sxy150489 
46414919Sxy150489 	E1000G_DEBUGLOG_4(e1000gp, E1000G_INFO_LEVEL,
46424349Sxy150489 	    "e1000g_ioc_peek_mem($%p, $%p) peeked 0x%llx from $%p\n",
46434349Sxy150489 	    (void *)e1000gp, (void *)ppd, value, vaddr);
46443526Sxy150489 
46453526Sxy150489 	ppd->pp_acc_data = value;
46463526Sxy150489 }
46473526Sxy150489 
46483526Sxy150489 static void
46493526Sxy150489 e1000g_ioc_poke_mem(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd)
46503526Sxy150489 {
46513526Sxy150489 	uint64_t value;
46523526Sxy150489 	void *vaddr;
46533526Sxy150489 
46543526Sxy150489 	vaddr = (void *)(uintptr_t)ppd->pp_acc_offset;
46553526Sxy150489 	value = ppd->pp_acc_data;
46563526Sxy150489 
46574919Sxy150489 	E1000G_DEBUGLOG_4(e1000gp, E1000G_INFO_LEVEL,
46584349Sxy150489 	    "e1000g_ioc_poke_mem($%p, $%p) poking 0x%llx at $%p\n",
46594349Sxy150489 	    (void *)e1000gp, (void *)ppd, value, vaddr);
46603526Sxy150489 
46613526Sxy150489 	switch (ppd->pp_acc_size) {
46623526Sxy150489 	case 1:
46633526Sxy150489 		*(uint8_t *)vaddr = (uint8_t)value;
46643526Sxy150489 		break;
46653526Sxy150489 
46663526Sxy150489 	case 2:
46673526Sxy150489 		*(uint16_t *)vaddr = (uint16_t)value;
46683526Sxy150489 		break;
46693526Sxy150489 
46703526Sxy150489 	case 4:
46713526Sxy150489 		*(uint32_t *)vaddr = (uint32_t)value;
46723526Sxy150489 		break;
46733526Sxy150489 
46743526Sxy150489 	case 8:
46753526Sxy150489 		*(uint64_t *)vaddr = (uint64_t)value;
46763526Sxy150489 		break;
46773526Sxy150489 	}
46783526Sxy150489 }
46794919Sxy150489 #endif
46803526Sxy150489 
46813526Sxy150489 /*
46823526Sxy150489  * Loopback Support
46833526Sxy150489  */
46843526Sxy150489 static lb_property_t lb_normal =
46853526Sxy150489 	{ normal,	"normal",	E1000G_LB_NONE		};
46863526Sxy150489 static lb_property_t lb_external1000 =
46873526Sxy150489 	{ external,	"1000Mbps",	E1000G_LB_EXTERNAL_1000	};
46883526Sxy150489 static lb_property_t lb_external100 =
46893526Sxy150489 	{ external,	"100Mbps",	E1000G_LB_EXTERNAL_100	};
46903526Sxy150489 static lb_property_t lb_external10 =
46913526Sxy150489 	{ external,	"10Mbps",	E1000G_LB_EXTERNAL_10	};
46923526Sxy150489 static lb_property_t lb_phy =
46933526Sxy150489 	{ internal,	"PHY",		E1000G_LB_INTERNAL_PHY	};
46943526Sxy150489 
46953526Sxy150489 static enum ioc_reply
46963526Sxy150489 e1000g_loopback_ioctl(struct e1000g *Adapter, struct iocblk *iocp, mblk_t *mp)
46973526Sxy150489 {
46983526Sxy150489 	lb_info_sz_t *lbsp;
46993526Sxy150489 	lb_property_t *lbpp;
47003526Sxy150489 	struct e1000_hw *hw;
47013526Sxy150489 	uint32_t *lbmp;
47023526Sxy150489 	uint32_t size;
47033526Sxy150489 	uint32_t value;
47043526Sxy150489 
47054919Sxy150489 	hw = &Adapter->shared;
47063526Sxy150489 
47073526Sxy150489 	if (mp->b_cont == NULL)
47083526Sxy150489 		return (IOC_INVAL);
47093526Sxy150489 
47107133Scc210113 	if (!e1000g_check_loopback_support(hw)) {
47117133Scc210113 		e1000g_log(NULL, CE_WARN,
47127133Scc210113 		    "Loopback is not supported on e1000g%d", Adapter->instance);
47137133Scc210113 		return (IOC_INVAL);
47147133Scc210113 	}
47157133Scc210113 
47163526Sxy150489 	switch (iocp->ioc_cmd) {
47173526Sxy150489 	default:
47183526Sxy150489 		return (IOC_INVAL);
47193526Sxy150489 
47203526Sxy150489 	case LB_GET_INFO_SIZE:
47213526Sxy150489 		size = sizeof (lb_info_sz_t);
47223526Sxy150489 		if (iocp->ioc_count != size)
47233526Sxy150489 			return (IOC_INVAL);
47243526Sxy150489 
47255082Syy150190 		rw_enter(&Adapter->chip_lock, RW_WRITER);
47265082Syy150190 		e1000g_get_phy_state(Adapter);
47275082Syy150190 
47285082Syy150190 		/*
47295082Syy150190 		 * Workaround for hardware faults. In order to get a stable
47305082Syy150190 		 * state of phy, we will wait for a specific interval and
47315082Syy150190 		 * try again. The time delay is an experiential value based
47325082Syy150190 		 * on our testing.
47335082Syy150190 		 */
47345082Syy150190 		msec_delay(100);
47355082Syy150190 		e1000g_get_phy_state(Adapter);
47365082Syy150190 		rw_exit(&Adapter->chip_lock);
47373526Sxy150489 
47383526Sxy150489 		value = sizeof (lb_normal);
47395082Syy150190 		if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
47405082Syy150190 		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
47416735Scc210113 		    (hw->phy.media_type == e1000_media_type_fiber) ||
47426735Scc210113 		    (hw->phy.media_type == e1000_media_type_internal_serdes)) {
47433526Sxy150489 			value += sizeof (lb_phy);
47444919Sxy150489 			switch (hw->mac.type) {
47453526Sxy150489 			case e1000_82571:
47463526Sxy150489 			case e1000_82572:
47477133Scc210113 			case e1000_80003es2lan:
47483526Sxy150489 				value += sizeof (lb_external1000);
47493526Sxy150489 				break;
47503526Sxy150489 			}
47513526Sxy150489 		}
47525082Syy150190 		if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
47535082Syy150190 		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS))
47543526Sxy150489 			value += sizeof (lb_external100);
47555082Syy150190 		if (Adapter->phy_status & MII_SR_10T_FD_CAPS)
47563526Sxy150489 			value += sizeof (lb_external10);
47573526Sxy150489 
47587426SChenliang.Xu@Sun.COM 		lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr;
47593526Sxy150489 		*lbsp = value;
47603526Sxy150489 		break;
47613526Sxy150489 
47623526Sxy150489 	case LB_GET_INFO:
47633526Sxy150489 		value = sizeof (lb_normal);
47645082Syy150190 		if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
47655082Syy150190 		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
47666735Scc210113 		    (hw->phy.media_type == e1000_media_type_fiber) ||
47676735Scc210113 		    (hw->phy.media_type == e1000_media_type_internal_serdes)) {
47683526Sxy150489 			value += sizeof (lb_phy);
47694919Sxy150489 			switch (hw->mac.type) {
47703526Sxy150489 			case e1000_82571:
47713526Sxy150489 			case e1000_82572:
47727133Scc210113 			case e1000_80003es2lan:
47733526Sxy150489 				value += sizeof (lb_external1000);
47743526Sxy150489 				break;
47753526Sxy150489 			}
47763526Sxy150489 		}
47775082Syy150190 		if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
47785082Syy150190 		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS))
47793526Sxy150489 			value += sizeof (lb_external100);
47805082Syy150190 		if (Adapter->phy_status & MII_SR_10T_FD_CAPS)
47813526Sxy150489 			value += sizeof (lb_external10);
47823526Sxy150489 
47833526Sxy150489 		size = value;
47843526Sxy150489 		if (iocp->ioc_count != size)
47853526Sxy150489 			return (IOC_INVAL);
47863526Sxy150489 
47873526Sxy150489 		value = 0;
47887426SChenliang.Xu@Sun.COM 		lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr;
47893526Sxy150489 		lbpp[value++] = lb_normal;
47905082Syy150190 		if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
47915082Syy150190 		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
47926735Scc210113 		    (hw->phy.media_type == e1000_media_type_fiber) ||
47936735Scc210113 		    (hw->phy.media_type == e1000_media_type_internal_serdes)) {
47943526Sxy150489 			lbpp[value++] = lb_phy;
47954919Sxy150489 			switch (hw->mac.type) {
47963526Sxy150489 			case e1000_82571:
47973526Sxy150489 			case e1000_82572:
47987133Scc210113 			case e1000_80003es2lan:
47993526Sxy150489 				lbpp[value++] = lb_external1000;
48003526Sxy150489 				break;
48013526Sxy150489 			}
48023526Sxy150489 		}
48035082Syy150190 		if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
48045082Syy150190 		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS))
48053526Sxy150489 			lbpp[value++] = lb_external100;
48065082Syy150190 		if (Adapter->phy_status & MII_SR_10T_FD_CAPS)
48073526Sxy150489 			lbpp[value++] = lb_external10;
48083526Sxy150489 		break;
48093526Sxy150489 
48103526Sxy150489 	case LB_GET_MODE:
48113526Sxy150489 		size = sizeof (uint32_t);
48123526Sxy150489 		if (iocp->ioc_count != size)
48133526Sxy150489 			return (IOC_INVAL);
48143526Sxy150489 
48157426SChenliang.Xu@Sun.COM 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
48163526Sxy150489 		*lbmp = Adapter->loopback_mode;
48173526Sxy150489 		break;
48183526Sxy150489 
48193526Sxy150489 	case LB_SET_MODE:
48203526Sxy150489 		size = 0;
48213526Sxy150489 		if (iocp->ioc_count != sizeof (uint32_t))
48223526Sxy150489 			return (IOC_INVAL);
48233526Sxy150489 
48247426SChenliang.Xu@Sun.COM 		lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
48253526Sxy150489 		if (!e1000g_set_loopback_mode(Adapter, *lbmp))
48263526Sxy150489 			return (IOC_INVAL);
48273526Sxy150489 		break;
48283526Sxy150489 	}
48293526Sxy150489 
48303526Sxy150489 	iocp->ioc_count = size;
48313526Sxy150489 	iocp->ioc_error = 0;
48323526Sxy150489 
48335273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
48345273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
48355273Sgl147354 		return (IOC_INVAL);
48365273Sgl147354 	}
48375273Sgl147354 
48383526Sxy150489 	return (IOC_REPLY);
48393526Sxy150489 }
48403526Sxy150489 
48413526Sxy150489 static boolean_t
48427133Scc210113 e1000g_check_loopback_support(struct e1000_hw *hw)
48437133Scc210113 {
48447133Scc210113 	switch (hw->mac.type) {
48457133Scc210113 	case e1000_82540:
48467133Scc210113 	case e1000_82545:
48477133Scc210113 	case e1000_82545_rev_3:
48487133Scc210113 	case e1000_82546:
48497133Scc210113 	case e1000_82546_rev_3:
48507133Scc210113 	case e1000_82541:
48517133Scc210113 	case e1000_82541_rev_2:
48527133Scc210113 	case e1000_82547:
48537133Scc210113 	case e1000_82547_rev_2:
48547133Scc210113 	case e1000_82571:
48557133Scc210113 	case e1000_82572:
48567133Scc210113 	case e1000_82573:
48578479SChenlu.Chen@Sun.COM 	case e1000_82574:
48587133Scc210113 	case e1000_80003es2lan:
48598479SChenlu.Chen@Sun.COM 	case e1000_ich9lan:
48608479SChenlu.Chen@Sun.COM 	case e1000_ich10lan:
48617133Scc210113 		return (B_TRUE);
48627133Scc210113 	}
48637133Scc210113 	return (B_FALSE);
48647133Scc210113 }
48657133Scc210113 
48667133Scc210113 static boolean_t
48673526Sxy150489 e1000g_set_loopback_mode(struct e1000g *Adapter, uint32_t mode)
48683526Sxy150489 {
48693526Sxy150489 	struct e1000_hw *hw;
48703526Sxy150489 	int i, times;
48715082Syy150190 	boolean_t link_up;
48723526Sxy150489 
48733526Sxy150489 	if (mode == Adapter->loopback_mode)
48743526Sxy150489 		return (B_TRUE);
48753526Sxy150489 
48764919Sxy150489 	hw = &Adapter->shared;
48773526Sxy150489 	times = 0;
48783526Sxy150489 
48795082Syy150190 	Adapter->loopback_mode = mode;
48805082Syy150190 
48815082Syy150190 	if (mode == E1000G_LB_NONE) {
48823526Sxy150489 		/* Reset the chip */
48836735Scc210113 		hw->phy.autoneg_wait_to_complete = B_TRUE;
48847656SSherry.Moore@Sun.COM 		(void) e1000g_reset_adapter(Adapter);
48856735Scc210113 		hw->phy.autoneg_wait_to_complete = B_FALSE;
48865082Syy150190 		return (B_TRUE);
48875082Syy150190 	}
48885082Syy150190 
48895082Syy150190 again:
48905082Syy150190 
48915082Syy150190 	rw_enter(&Adapter->chip_lock, RW_WRITER);
48925082Syy150190 
48935082Syy150190 	switch (mode) {
48945082Syy150190 	default:
48955082Syy150190 		rw_exit(&Adapter->chip_lock);
48965082Syy150190 		return (B_FALSE);
48973526Sxy150489 
48983526Sxy150489 	case E1000G_LB_EXTERNAL_1000:
48993526Sxy150489 		e1000g_set_external_loopback_1000(Adapter);
49003526Sxy150489 		break;
49013526Sxy150489 
49023526Sxy150489 	case E1000G_LB_EXTERNAL_100:
49033526Sxy150489 		e1000g_set_external_loopback_100(Adapter);
49043526Sxy150489 		break;
49053526Sxy150489 
49063526Sxy150489 	case E1000G_LB_EXTERNAL_10:
49073526Sxy150489 		e1000g_set_external_loopback_10(Adapter);
49083526Sxy150489 		break;
49093526Sxy150489 
49103526Sxy150489 	case E1000G_LB_INTERNAL_PHY:
49113526Sxy150489 		e1000g_set_internal_loopback(Adapter);
49123526Sxy150489 		break;
49133526Sxy150489 	}
49143526Sxy150489 
49153526Sxy150489 	times++;
49163526Sxy150489 
49175858Scc210113 	rw_exit(&Adapter->chip_lock);
49185858Scc210113 
49195082Syy150190 	/* Wait for link up */
49205082Syy150190 	for (i = (PHY_FORCE_LIMIT * 2); i > 0; i--)
49215082Syy150190 		msec_delay(100);
49225082Syy150190 
49235858Scc210113 	rw_enter(&Adapter->chip_lock, RW_WRITER);
49245858Scc210113 
49255082Syy150190 	link_up = e1000g_link_up(Adapter);
49265082Syy150190 
49275082Syy150190 	rw_exit(&Adapter->chip_lock);
49285082Syy150190 
49295082Syy150190 	if (!link_up) {
49305082Syy150190 		E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
49315082Syy150190 		    "Failed to get the link up");
49325082Syy150190 		if (times < 2) {
49335082Syy150190 			/* Reset the link */
49344919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
49355082Syy150190 			    "Reset the link ...");
49367656SSherry.Moore@Sun.COM 			(void) e1000g_reset_adapter(Adapter);
49375082Syy150190 			goto again;
49383526Sxy150489 		}
49393526Sxy150489 	}
49403526Sxy150489 
49413526Sxy150489 	return (B_TRUE);
49423526Sxy150489 }
49433526Sxy150489 
49443526Sxy150489 /*
49453526Sxy150489  * The following loopback settings are from Intel's technical
49463526Sxy150489  * document - "How To Loopback". All the register settings and
49473526Sxy150489  * time delay values are directly inherited from the document
49483526Sxy150489  * without more explanations available.
49493526Sxy150489  */
49503526Sxy150489 static void
49513526Sxy150489 e1000g_set_internal_loopback(struct e1000g *Adapter)
49523526Sxy150489 {
49533526Sxy150489 	struct e1000_hw *hw;
49543526Sxy150489 	uint32_t ctrl;
49553526Sxy150489 	uint32_t status;
49563526Sxy150489 	uint16_t phy_ctrl;
49578479SChenlu.Chen@Sun.COM 	uint16_t phy_reg;
49585082Syy150190 	uint32_t txcw;
49593526Sxy150489 
49604919Sxy150489 	hw = &Adapter->shared;
49613526Sxy150489 
49623526Sxy150489 	/* Disable Smart Power Down */
49633526Sxy150489 	phy_spd_state(hw, B_FALSE);
49643526Sxy150489 
49657426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl);
49663526Sxy150489 	phy_ctrl &= ~(MII_CR_AUTO_NEG_EN | MII_CR_SPEED_100 | MII_CR_SPEED_10);
49673526Sxy150489 	phy_ctrl |= MII_CR_FULL_DUPLEX | MII_CR_SPEED_1000;
49683526Sxy150489 
49694919Sxy150489 	switch (hw->mac.type) {
49703526Sxy150489 	case e1000_82540:
49713526Sxy150489 	case e1000_82545:
49723526Sxy150489 	case e1000_82545_rev_3:
49733526Sxy150489 	case e1000_82546:
49743526Sxy150489 	case e1000_82546_rev_3:
49753526Sxy150489 	case e1000_82573:
49763526Sxy150489 		/* Auto-MDI/MDIX off */
49777426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
49783526Sxy150489 		/* Reset PHY to update Auto-MDI/MDIX */
49797426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, PHY_CONTROL,
49804349Sxy150489 		    phy_ctrl | MII_CR_RESET | MII_CR_AUTO_NEG_EN);
49813526Sxy150489 		/* Reset PHY to auto-neg off and force 1000 */
49827426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, PHY_CONTROL,
49834349Sxy150489 		    phy_ctrl | MII_CR_RESET);
49845082Syy150190 		/*
49855082Syy150190 		 * Disable PHY receiver for 82540/545/546 and 82573 Family.
49865082Syy150190 		 * See comments above e1000g_set_internal_loopback() for the
49875082Syy150190 		 * background.
49885082Syy150190 		 */
49897426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, 29, 0x001F);
49907426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, 30, 0x8FFC);
49917426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, 29, 0x001A);
49927426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, 30, 0x8FF0);
49933526Sxy150489 		break;
49947133Scc210113 	case e1000_80003es2lan:
49957133Scc210113 		/* Force Link Up */
49967426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
49977426SChenliang.Xu@Sun.COM 		    0x1CC);
49987133Scc210113 		/* Sets PCS loopback at 1Gbs */
49997426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
50007426SChenliang.Xu@Sun.COM 		    0x1046);
50017133Scc210113 		break;
50023526Sxy150489 	}
50033526Sxy150489 
50048479SChenlu.Chen@Sun.COM 	/*
50058479SChenlu.Chen@Sun.COM 	 * The following registers should be set for e1000_phy_bm phy type.
50068479SChenlu.Chen@Sun.COM 	 * e1000_82574, e1000_ich10lan and some e1000_ich9lan use this phy.
50078479SChenlu.Chen@Sun.COM 	 * For others, we do not need to set these registers.
50088479SChenlu.Chen@Sun.COM 	 */
50098479SChenlu.Chen@Sun.COM 	if (hw->phy.type == e1000_phy_bm) {
50108479SChenlu.Chen@Sun.COM 		/* Set Default MAC Interface speed to 1GB */
50118850SMin.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_REG(2, 21), &phy_reg);
50128479SChenlu.Chen@Sun.COM 		phy_reg &= ~0x0007;
50138479SChenlu.Chen@Sun.COM 		phy_reg |= 0x006;
50148850SMin.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, PHY_REG(2, 21), phy_reg);
50158479SChenlu.Chen@Sun.COM 		/* Assert SW reset for above settings to take effect */
50168850SMin.Xu@Sun.COM 		(void) e1000_phy_commit(hw);
50178479SChenlu.Chen@Sun.COM 		msec_delay(1);
50188479SChenlu.Chen@Sun.COM 		/* Force Full Duplex */
50198850SMin.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_REG(769, 16), &phy_reg);
50208850SMin.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, PHY_REG(769, 16),
50218850SMin.Xu@Sun.COM 		    phy_reg | 0x000C);
50228479SChenlu.Chen@Sun.COM 		/* Set Link Up (in force link) */
50238850SMin.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_REG(776, 16), &phy_reg);
50248850SMin.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, PHY_REG(776, 16),
50258850SMin.Xu@Sun.COM 		    phy_reg | 0x0040);
50268479SChenlu.Chen@Sun.COM 		/* Force Link */
50278850SMin.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_REG(769, 16), &phy_reg);
50288850SMin.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, PHY_REG(769, 16),
50298850SMin.Xu@Sun.COM 		    phy_reg | 0x0040);
50308479SChenlu.Chen@Sun.COM 		/* Set Early Link Enable */
50318850SMin.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, PHY_REG(769, 20), &phy_reg);
50328850SMin.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, PHY_REG(769, 20),
50338850SMin.Xu@Sun.COM 		    phy_reg | 0x0400);
50348479SChenlu.Chen@Sun.COM 	}
50358479SChenlu.Chen@Sun.COM 
50363526Sxy150489 	/* Set loopback */
50377426SChenliang.Xu@Sun.COM 	(void) e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl | MII_CR_LOOPBACK);
50383526Sxy150489 
50393526Sxy150489 	msec_delay(250);
50403526Sxy150489 
50413526Sxy150489 	/* Now set up the MAC to the same speed/duplex as the PHY. */
50424919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
50433526Sxy150489 	ctrl &= ~E1000_CTRL_SPD_SEL;	/* Clear the speed sel bits */
50443526Sxy150489 	ctrl |= (E1000_CTRL_FRCSPD |	/* Set the Force Speed Bit */
50454349Sxy150489 	    E1000_CTRL_FRCDPX |		/* Set the Force Duplex Bit */
50464349Sxy150489 	    E1000_CTRL_SPD_1000 |	/* Force Speed to 1000 */
50474349Sxy150489 	    E1000_CTRL_FD);		/* Force Duplex to FULL */
50483526Sxy150489 
50494919Sxy150489 	switch (hw->mac.type) {
50503526Sxy150489 	case e1000_82540:
50513526Sxy150489 	case e1000_82545:
50523526Sxy150489 	case e1000_82545_rev_3:
50533526Sxy150489 	case e1000_82546:
50543526Sxy150489 	case e1000_82546_rev_3:
50553526Sxy150489 		/*
50563526Sxy150489 		 * For some serdes we'll need to commit the writes now
50573526Sxy150489 		 * so that the status is updated on link
50583526Sxy150489 		 */
50596735Scc210113 		if (hw->phy.media_type == e1000_media_type_internal_serdes) {
50604919Sxy150489 			E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
50613526Sxy150489 			msec_delay(100);
50624919Sxy150489 			ctrl = E1000_READ_REG(hw, E1000_CTRL);
50633526Sxy150489 		}
50643526Sxy150489 
50656735Scc210113 		if (hw->phy.media_type == e1000_media_type_copper) {
50663526Sxy150489 			/* Invert Loss of Signal */
50673526Sxy150489 			ctrl |= E1000_CTRL_ILOS;
50683526Sxy150489 		} else {
50693526Sxy150489 			/* Set ILOS on fiber nic if half duplex is detected */
50704919Sxy150489 			status = E1000_READ_REG(hw, E1000_STATUS);
50713526Sxy150489 			if ((status & E1000_STATUS_FD) == 0)
50723526Sxy150489 				ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU;
50733526Sxy150489 		}
50743526Sxy150489 		break;
50753526Sxy150489 
50763526Sxy150489 	case e1000_82571:
50773526Sxy150489 	case e1000_82572:
50785082Syy150190 		/*
50795082Syy150190 		 * The fiber/SerDes versions of this adapter do not contain an
50805082Syy150190 		 * accessible PHY. Therefore, loopback beyond MAC must be done
50815082Syy150190 		 * using SerDes analog loopback.
50825082Syy150190 		 */
50836735Scc210113 		if (hw->phy.media_type != e1000_media_type_copper) {
50845082Syy150190 			/* Disable autoneg by setting bit 31 of TXCW to zero */
50855082Syy150190 			txcw = E1000_READ_REG(hw, E1000_TXCW);
50865082Syy150190 			txcw &= ~((uint32_t)1 << 31);
50875082Syy150190 			E1000_WRITE_REG(hw, E1000_TXCW, txcw);
50885082Syy150190 
50895082Syy150190 			/*
50905082Syy150190 			 * Write 0x410 to Serdes Control register
50915082Syy150190 			 * to enable Serdes analog loopback
50925082Syy150190 			 */
50935082Syy150190 			E1000_WRITE_REG(hw, E1000_SCTL, 0x0410);
50945082Syy150190 			msec_delay(10);
50953526Sxy150489 		}
50968479SChenlu.Chen@Sun.COM 
50978479SChenlu.Chen@Sun.COM 		status = E1000_READ_REG(hw, E1000_STATUS);
50988479SChenlu.Chen@Sun.COM 		/* Set ILOS on fiber nic if half duplex is detected */
50998479SChenlu.Chen@Sun.COM 		if ((hw->phy.media_type == e1000_media_type_fiber) &&
51008479SChenlu.Chen@Sun.COM 		    ((status & E1000_STATUS_FD) == 0 ||
51018479SChenlu.Chen@Sun.COM 		    (status & E1000_STATUS_LU) == 0))
51028479SChenlu.Chen@Sun.COM 			ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU;
51038479SChenlu.Chen@Sun.COM 		else if (hw->phy.media_type == e1000_media_type_internal_serdes)
51048479SChenlu.Chen@Sun.COM 			ctrl |= E1000_CTRL_SLU;
51053526Sxy150489 		break;
51063526Sxy150489 
51073526Sxy150489 	case e1000_82573:
51083526Sxy150489 		ctrl |= E1000_CTRL_ILOS;
51098479SChenlu.Chen@Sun.COM 		break;
51108479SChenlu.Chen@Sun.COM 	case e1000_ich9lan:
51118479SChenlu.Chen@Sun.COM 	case e1000_ich10lan:
51128479SChenlu.Chen@Sun.COM 		ctrl |= E1000_CTRL_SLU;
51133526Sxy150489 		break;
51143526Sxy150489 	}
51158479SChenlu.Chen@Sun.COM 	if (hw->phy.type == e1000_phy_bm)
51168479SChenlu.Chen@Sun.COM 		ctrl |= E1000_CTRL_SLU | E1000_CTRL_ILOS;
51178479SChenlu.Chen@Sun.COM 
51188479SChenlu.Chen@Sun.COM 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
51193526Sxy150489 }
51203526Sxy150489 
51213526Sxy150489 static void
51223526Sxy150489 e1000g_set_external_loopback_1000(struct e1000g *Adapter)
51233526Sxy150489 {
51243526Sxy150489 	struct e1000_hw *hw;
51253526Sxy150489 	uint32_t rctl;
51263526Sxy150489 	uint32_t ctrl_ext;
51273526Sxy150489 	uint32_t ctrl;
51283526Sxy150489 	uint32_t status;
51293526Sxy150489 	uint32_t txcw;
51307133Scc210113 	uint16_t phydata;
51313526Sxy150489 
51324919Sxy150489 	hw = &Adapter->shared;
51333526Sxy150489 
51343526Sxy150489 	/* Disable Smart Power Down */
51353526Sxy150489 	phy_spd_state(hw, B_FALSE);
51363526Sxy150489 
51377133Scc210113 	switch (hw->mac.type) {
51387133Scc210113 	case e1000_82571:
51397133Scc210113 	case e1000_82572:
51407133Scc210113 		switch (hw->phy.media_type) {
51417133Scc210113 		case e1000_media_type_copper:
51427133Scc210113 			/* Force link up (Must be done before the PHY writes) */
51437133Scc210113 			ctrl = E1000_READ_REG(hw, E1000_CTRL);
51447133Scc210113 			ctrl |= E1000_CTRL_SLU;	/* Force Link Up */
51457133Scc210113 			E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
51467133Scc210113 
51477133Scc210113 			rctl = E1000_READ_REG(hw, E1000_RCTL);
51487133Scc210113 			rctl |= (E1000_RCTL_EN |
51497133Scc210113 			    E1000_RCTL_SBP |
51507133Scc210113 			    E1000_RCTL_UPE |
51517133Scc210113 			    E1000_RCTL_MPE |
51527133Scc210113 			    E1000_RCTL_LPE |
51537133Scc210113 			    E1000_RCTL_BAM);		/* 0x803E */
51547133Scc210113 			E1000_WRITE_REG(hw, E1000_RCTL, rctl);
51557133Scc210113 
51567133Scc210113 			ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
51577133Scc210113 			ctrl_ext |= (E1000_CTRL_EXT_SDP4_DATA |
51587133Scc210113 			    E1000_CTRL_EXT_SDP6_DATA |
51597133Scc210113 			    E1000_CTRL_EXT_SDP7_DATA |
51607133Scc210113 			    E1000_CTRL_EXT_SDP4_DIR |
51617133Scc210113 			    E1000_CTRL_EXT_SDP6_DIR |
51627133Scc210113 			    E1000_CTRL_EXT_SDP7_DIR);	/* 0x0DD0 */
51637133Scc210113 			E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
51647133Scc210113 
51657133Scc210113 			/*
51667133Scc210113 			 * This sequence tunes the PHY's SDP and no customer
51677133Scc210113 			 * settable values. For background, see comments above
51687133Scc210113 			 * e1000g_set_internal_loopback().
51697133Scc210113 			 */
51707426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x0, 0x140);
51717133Scc210113 			msec_delay(10);
51727426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x9, 0x1A00);
51737426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x12, 0xC10);
51747426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x12, 0x1C10);
51757426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x1F37, 0x76);
51767426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x1F33, 0x1);
51777426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x1F33, 0x0);
51787426SChenliang.Xu@Sun.COM 
51797426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x1F35, 0x65);
51807426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x1837, 0x3F7C);
51817426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x1437, 0x3FDC);
51827426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x1237, 0x3F7C);
51837426SChenliang.Xu@Sun.COM 			(void) e1000_write_phy_reg(hw, 0x1137, 0x3FDC);
51847133Scc210113 
51857133Scc210113 			msec_delay(50);
51867133Scc210113 			break;
51877133Scc210113 		case e1000_media_type_fiber:
51887133Scc210113 		case e1000_media_type_internal_serdes:
51897133Scc210113 			status = E1000_READ_REG(hw, E1000_STATUS);
51907133Scc210113 			if (((status & E1000_STATUS_LU) == 0) ||
51917133Scc210113 			    (hw->phy.media_type ==
51927133Scc210113 			    e1000_media_type_internal_serdes)) {
51937133Scc210113 				ctrl = E1000_READ_REG(hw, E1000_CTRL);
51947133Scc210113 				ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU;
51957133Scc210113 				E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
51967133Scc210113 			}
51977133Scc210113 
51987133Scc210113 			/* Disable autoneg by setting bit 31 of TXCW to zero */
51997133Scc210113 			txcw = E1000_READ_REG(hw, E1000_TXCW);
52007133Scc210113 			txcw &= ~((uint32_t)1 << 31);
52017133Scc210113 			E1000_WRITE_REG(hw, E1000_TXCW, txcw);
52027133Scc210113 
52037133Scc210113 			/*
52047133Scc210113 			 * Write 0x410 to Serdes Control register
52057133Scc210113 			 * to enable Serdes analog loopback
52067133Scc210113 			 */
52077133Scc210113 			E1000_WRITE_REG(hw, E1000_SCTL, 0x0410);
52087133Scc210113 			msec_delay(10);
52097133Scc210113 			break;
52107133Scc210113 		default:
52117133Scc210113 			break;
52127133Scc210113 		}
52133526Sxy150489 		break;
52148479SChenlu.Chen@Sun.COM 	case e1000_82574:
52157133Scc210113 	case e1000_80003es2lan:
52168479SChenlu.Chen@Sun.COM 	case e1000_ich9lan:
52178479SChenlu.Chen@Sun.COM 	case e1000_ich10lan:
52187426SChenliang.Xu@Sun.COM 		(void) e1000_read_phy_reg(hw, GG82563_REG(6, 16), &phydata);
52197426SChenliang.Xu@Sun.COM 		(void) e1000_write_phy_reg(hw, GG82563_REG(6, 16),
52207426SChenliang.Xu@Sun.COM 		    phydata | (1 << 5));
52217133Scc210113 		Adapter->param_adv_autoneg = 1;
52227133Scc210113 		Adapter->param_adv_1000fdx = 1;
52237426SChenliang.Xu@Sun.COM 		(void) e1000g_reset_link(Adapter);
52243526Sxy150489 		break;
52253526Sxy150489 	}
52263526Sxy150489 }
52273526Sxy150489 
52283526Sxy150489 static void
52293526Sxy150489 e1000g_set_external_loopback_100(struct e1000g *Adapter)
52303526Sxy150489 {
52313526Sxy150489 	struct e1000_hw *hw;
52323526Sxy150489 	uint32_t ctrl;
52333526Sxy150489 	uint16_t phy_ctrl;
52343526Sxy150489 
52354919Sxy150489 	hw = &Adapter->shared;
52363526Sxy150489 
52373526Sxy150489 	/* Disable Smart Power Down */
52383526Sxy150489 	phy_spd_state(hw, B_FALSE);
52393526Sxy150489 
52403526Sxy150489 	phy_ctrl = (MII_CR_FULL_DUPLEX |
52414349Sxy150489 	    MII_CR_SPEED_100);
52423526Sxy150489 
52433526Sxy150489 	/* Force 100/FD, reset PHY */
52447426SChenliang.Xu@Sun.COM 	(void) e1000_write_phy_reg(hw, PHY_CONTROL,
52454349Sxy150489 	    phy_ctrl | MII_CR_RESET);	/* 0xA100 */
52463526Sxy150489 	msec_delay(10);
52473526Sxy150489 
52483526Sxy150489 	/* Force 100/FD */
52497426SChenliang.Xu@Sun.COM 	(void) e1000_write_phy_reg(hw, PHY_CONTROL,
52504349Sxy150489 	    phy_ctrl);			/* 0x2100 */
52513526Sxy150489 	msec_delay(10);
52523526Sxy150489 
52533526Sxy150489 	/* Now setup the MAC to the same speed/duplex as the PHY. */
52544919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
52553526Sxy150489 	ctrl &= ~E1000_CTRL_SPD_SEL;	/* Clear the speed sel bits */
52563526Sxy150489 	ctrl |= (E1000_CTRL_SLU |	/* Force Link Up */
52574349Sxy150489 	    E1000_CTRL_FRCSPD |		/* Set the Force Speed Bit */
52584349Sxy150489 	    E1000_CTRL_FRCDPX |		/* Set the Force Duplex Bit */
52594349Sxy150489 	    E1000_CTRL_SPD_100 |	/* Force Speed to 100 */
52604349Sxy150489 	    E1000_CTRL_FD);		/* Force Duplex to FULL */
52613526Sxy150489 
52624919Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
52633526Sxy150489 }
52643526Sxy150489 
52653526Sxy150489 static void
52663526Sxy150489 e1000g_set_external_loopback_10(struct e1000g *Adapter)
52673526Sxy150489 {
52683526Sxy150489 	struct e1000_hw *hw;
52693526Sxy150489 	uint32_t ctrl;
52703526Sxy150489 	uint16_t phy_ctrl;
52713526Sxy150489 
52724919Sxy150489 	hw = &Adapter->shared;
52733526Sxy150489 
52743526Sxy150489 	/* Disable Smart Power Down */
52753526Sxy150489 	phy_spd_state(hw, B_FALSE);
52763526Sxy150489 
52773526Sxy150489 	phy_ctrl = (MII_CR_FULL_DUPLEX |
52784349Sxy150489 	    MII_CR_SPEED_10);
52793526Sxy150489 
52803526Sxy150489 	/* Force 10/FD, reset PHY */
52817426SChenliang.Xu@Sun.COM 	(void) e1000_write_phy_reg(hw, PHY_CONTROL,
52824349Sxy150489 	    phy_ctrl | MII_CR_RESET);	/* 0x8100 */
52833526Sxy150489 	msec_delay(10);
52843526Sxy150489 
52853526Sxy150489 	/* Force 10/FD */
52867426SChenliang.Xu@Sun.COM 	(void) e1000_write_phy_reg(hw, PHY_CONTROL,
52874349Sxy150489 	    phy_ctrl);			/* 0x0100 */
52883526Sxy150489 	msec_delay(10);
52893526Sxy150489 
52903526Sxy150489 	/* Now setup the MAC to the same speed/duplex as the PHY. */
52914919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
52923526Sxy150489 	ctrl &= ~E1000_CTRL_SPD_SEL;	/* Clear the speed sel bits */
52933526Sxy150489 	ctrl |= (E1000_CTRL_SLU |	/* Force Link Up */
52944349Sxy150489 	    E1000_CTRL_FRCSPD |		/* Set the Force Speed Bit */
52954349Sxy150489 	    E1000_CTRL_FRCDPX |		/* Set the Force Duplex Bit */
52964349Sxy150489 	    E1000_CTRL_SPD_10 |		/* Force Speed to 10 */
52974349Sxy150489 	    E1000_CTRL_FD);		/* Force Duplex to FULL */
52983526Sxy150489 
52994919Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
53003526Sxy150489 }
53013526Sxy150489 
53023526Sxy150489 #ifdef __sparc
53033526Sxy150489 static boolean_t
53043526Sxy150489 e1000g_find_mac_address(struct e1000g *Adapter)
53053526Sxy150489 {
53064919Sxy150489 	struct e1000_hw *hw = &Adapter->shared;
53073526Sxy150489 	uchar_t *bytes;
53083526Sxy150489 	struct ether_addr sysaddr;
53093526Sxy150489 	uint_t nelts;
53103526Sxy150489 	int err;
53113526Sxy150489 	boolean_t found = B_FALSE;
53123526Sxy150489 
53133526Sxy150489 	/*
53143526Sxy150489 	 * The "vendor's factory-set address" may already have
53153526Sxy150489 	 * been extracted from the chip, but if the property
53163526Sxy150489 	 * "local-mac-address" is set we use that instead.
53173526Sxy150489 	 *
53183526Sxy150489 	 * We check whether it looks like an array of 6
53193526Sxy150489 	 * bytes (which it should, if OBP set it).  If we can't
53203526Sxy150489 	 * make sense of it this way, we'll ignore it.
53213526Sxy150489 	 */
53223526Sxy150489 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip,
53233526Sxy150489 	    DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts);
53243526Sxy150489 	if (err == DDI_PROP_SUCCESS) {
53253526Sxy150489 		if (nelts == ETHERADDRL) {
53263526Sxy150489 			while (nelts--)
53274919Sxy150489 				hw->mac.addr[nelts] = bytes[nelts];
53283526Sxy150489 			found = B_TRUE;
53293526Sxy150489 		}
53303526Sxy150489 		ddi_prop_free(bytes);
53313526Sxy150489 	}
53323526Sxy150489 
53333526Sxy150489 	/*
53343526Sxy150489 	 * Look up the OBP property "local-mac-address?". If the user has set
53353526Sxy150489 	 * 'local-mac-address? = false', use "the system address" instead.
53363526Sxy150489 	 */
53373526Sxy150489 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip, 0,
53383526Sxy150489 	    "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) {
53393526Sxy150489 		if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) {
53403526Sxy150489 			if (localetheraddr(NULL, &sysaddr) != 0) {
53414919Sxy150489 				bcopy(&sysaddr, hw->mac.addr, ETHERADDRL);
53423526Sxy150489 				found = B_TRUE;
53433526Sxy150489 			}
53443526Sxy150489 		}
53453526Sxy150489 		ddi_prop_free(bytes);
53463526Sxy150489 	}
53473526Sxy150489 
53483526Sxy150489 	/*
53493526Sxy150489 	 * Finally(!), if there's a valid "mac-address" property (created
53503526Sxy150489 	 * if we netbooted from this interface), we must use this instead
53513526Sxy150489 	 * of any of the above to ensure that the NFS/install server doesn't
53523526Sxy150489 	 * get confused by the address changing as Solaris takes over!
53533526Sxy150489 	 */
53543526Sxy150489 	err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip,
53553526Sxy150489 	    DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts);
53563526Sxy150489 	if (err == DDI_PROP_SUCCESS) {
53573526Sxy150489 		if (nelts == ETHERADDRL) {
53583526Sxy150489 			while (nelts--)
53594919Sxy150489 				hw->mac.addr[nelts] = bytes[nelts];
53603526Sxy150489 			found = B_TRUE;
53613526Sxy150489 		}
53623526Sxy150489 		ddi_prop_free(bytes);
53633526Sxy150489 	}
53643526Sxy150489 
53653526Sxy150489 	if (found) {
53664919Sxy150489 		bcopy(hw->mac.addr, hw->mac.perm_addr,
53673526Sxy150489 		    ETHERADDRL);
53683526Sxy150489 	}
53693526Sxy150489 
53703526Sxy150489 	return (found);
53713526Sxy150489 }
53723526Sxy150489 #endif
53733526Sxy150489 
53743526Sxy150489 static int
53753526Sxy150489 e1000g_add_intrs(struct e1000g *Adapter)
53763526Sxy150489 {
53773526Sxy150489 	dev_info_t *devinfo;
53783526Sxy150489 	int intr_types;
53793526Sxy150489 	int rc;
53803526Sxy150489 
53813526Sxy150489 	devinfo = Adapter->dip;
53823526Sxy150489 
53833526Sxy150489 	/* Get supported interrupt types */
53843526Sxy150489 	rc = ddi_intr_get_supported_types(devinfo, &intr_types);
53853526Sxy150489 
53863526Sxy150489 	if (rc != DDI_SUCCESS) {
53874919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
53883526Sxy150489 		    "Get supported interrupt types failed: %d\n", rc);
53893526Sxy150489 		return (DDI_FAILURE);
53903526Sxy150489 	}
53913526Sxy150489 
53923526Sxy150489 	/*
53933526Sxy150489 	 * Based on Intel Technical Advisory document (TA-160), there are some
53943526Sxy150489 	 * cases where some older Intel PCI-X NICs may "advertise" to the OS
53953526Sxy150489 	 * that it supports MSI, but in fact has problems.
53963526Sxy150489 	 * So we should only enable MSI for PCI-E NICs and disable MSI for old
53973526Sxy150489 	 * PCI/PCI-X NICs.
53983526Sxy150489 	 */
53994919Sxy150489 	if (Adapter->shared.mac.type < e1000_82571)
54006986Smx205022 		Adapter->msi_enable = B_FALSE;
54016986Smx205022 
54026986Smx205022 	if ((intr_types & DDI_INTR_TYPE_MSI) && Adapter->msi_enable) {
54033526Sxy150489 		rc = e1000g_intr_add(Adapter, DDI_INTR_TYPE_MSI);
54043526Sxy150489 
54053526Sxy150489 		if (rc != DDI_SUCCESS) {
54064919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
54073526Sxy150489 			    "Add MSI failed, trying Legacy interrupts\n");
54083526Sxy150489 		} else {
54093526Sxy150489 			Adapter->intr_type = DDI_INTR_TYPE_MSI;
54103526Sxy150489 		}
54113526Sxy150489 	}
54123526Sxy150489 
54133526Sxy150489 	if ((Adapter->intr_type == 0) &&
54143526Sxy150489 	    (intr_types & DDI_INTR_TYPE_FIXED)) {
54153526Sxy150489 		rc = e1000g_intr_add(Adapter, DDI_INTR_TYPE_FIXED);
54163526Sxy150489 
54173526Sxy150489 		if (rc != DDI_SUCCESS) {
54184919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
54193526Sxy150489 			    "Add Legacy interrupts failed\n");
54203526Sxy150489 			return (DDI_FAILURE);
54213526Sxy150489 		}
54223526Sxy150489 
54233526Sxy150489 		Adapter->intr_type = DDI_INTR_TYPE_FIXED;
54243526Sxy150489 	}
54253526Sxy150489 
54263526Sxy150489 	if (Adapter->intr_type == 0) {
54274919Sxy150489 		E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL,
54283526Sxy150489 		    "No interrupts registered\n");
54293526Sxy150489 		return (DDI_FAILURE);
54303526Sxy150489 	}
54313526Sxy150489 
54323526Sxy150489 	return (DDI_SUCCESS);
54333526Sxy150489 }
54343526Sxy150489 
54353526Sxy150489 /*
54363526Sxy150489  * e1000g_intr_add() handles MSI/Legacy interrupts
54373526Sxy150489  */
54383526Sxy150489 static int
54393526Sxy150489 e1000g_intr_add(struct e1000g *Adapter, int intr_type)
54403526Sxy150489 {
54413526Sxy150489 	dev_info_t *devinfo;
54423526Sxy150489 	int count, avail, actual;
54433526Sxy150489 	int x, y, rc, inum = 0;
54443526Sxy150489 	int flag;
54453526Sxy150489 	ddi_intr_handler_t *intr_handler;
54463526Sxy150489 
54473526Sxy150489 	devinfo = Adapter->dip;
54483526Sxy150489 
54493526Sxy150489 	/* get number of interrupts */
54503526Sxy150489 	rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
54513526Sxy150489 	if ((rc != DDI_SUCCESS) || (count == 0)) {
54524919Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL,
54533526Sxy150489 		    "Get interrupt number failed. Return: %d, count: %d\n",
54543526Sxy150489 		    rc, count);
54553526Sxy150489 		return (DDI_FAILURE);
54563526Sxy150489 	}
54573526Sxy150489 
54583526Sxy150489 	/* get number of available interrupts */
54593526Sxy150489 	rc = ddi_intr_get_navail(devinfo, intr_type, &avail);
54603526Sxy150489 	if ((rc != DDI_SUCCESS) || (avail == 0)) {
54614919Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL,
54623526Sxy150489 		    "Get interrupt available number failed. "
54633526Sxy150489 		    "Return: %d, available: %d\n", rc, avail);
54643526Sxy150489 		return (DDI_FAILURE);
54653526Sxy150489 	}
54663526Sxy150489 
54673526Sxy150489 	if (avail < count) {
54684919Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL,
54693526Sxy150489 		    "Interrupts count: %d, available: %d\n",
54703526Sxy150489 		    count, avail);
54713526Sxy150489 	}
54723526Sxy150489 
54733526Sxy150489 	/* Allocate an array of interrupt handles */
54743526Sxy150489 	Adapter->intr_size = count * sizeof (ddi_intr_handle_t);
54753526Sxy150489 	Adapter->htable = kmem_alloc(Adapter->intr_size, KM_SLEEP);
54763526Sxy150489 
54773526Sxy150489 	/* Set NORMAL behavior for both MSI and FIXED interrupt */
54783526Sxy150489 	flag = DDI_INTR_ALLOC_NORMAL;
54793526Sxy150489 
54803526Sxy150489 	/* call ddi_intr_alloc() */
54813526Sxy150489 	rc = ddi_intr_alloc(devinfo, Adapter->htable, intr_type, inum,
54823526Sxy150489 	    count, &actual, flag);
54833526Sxy150489 
54843526Sxy150489 	if ((rc != DDI_SUCCESS) || (actual == 0)) {
54854919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
54863526Sxy150489 		    "Allocate interrupts failed: %d\n", rc);
54873526Sxy150489 
54883526Sxy150489 		kmem_free(Adapter->htable, Adapter->intr_size);
54893526Sxy150489 		return (DDI_FAILURE);
54903526Sxy150489 	}
54913526Sxy150489 
54923526Sxy150489 	if (actual < count) {
54934919Sxy150489 		E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL,
54943526Sxy150489 		    "Interrupts requested: %d, received: %d\n",
54953526Sxy150489 		    count, actual);
54963526Sxy150489 	}
54973526Sxy150489 
54983526Sxy150489 	Adapter->intr_cnt = actual;
54993526Sxy150489 
55003526Sxy150489 	/* Get priority for first msi, assume remaining are all the same */
55013526Sxy150489 	rc = ddi_intr_get_pri(Adapter->htable[0], &Adapter->intr_pri);
55023526Sxy150489 
55033526Sxy150489 	if (rc != DDI_SUCCESS) {
55044919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
55053526Sxy150489 		    "Get interrupt priority failed: %d\n", rc);
55063526Sxy150489 
55073526Sxy150489 		/* Free already allocated intr */
55083526Sxy150489 		for (y = 0; y < actual; y++)
55093526Sxy150489 			(void) ddi_intr_free(Adapter->htable[y]);
55103526Sxy150489 
55113526Sxy150489 		kmem_free(Adapter->htable, Adapter->intr_size);
55123526Sxy150489 		return (DDI_FAILURE);
55133526Sxy150489 	}
55143526Sxy150489 
55153526Sxy150489 	/*
55163526Sxy150489 	 * In Legacy Interrupt mode, for PCI-Express adapters, we should
55173526Sxy150489 	 * use the interrupt service routine e1000g_intr_pciexpress()
55183526Sxy150489 	 * to avoid interrupt stealing when sharing interrupt with other
55193526Sxy150489 	 * devices.
55203526Sxy150489 	 */
55214919Sxy150489 	if (Adapter->shared.mac.type < e1000_82571)
55223526Sxy150489 		intr_handler = (ddi_intr_handler_t *)e1000g_intr;
55233526Sxy150489 	else
55243526Sxy150489 		intr_handler = (ddi_intr_handler_t *)e1000g_intr_pciexpress;
55253526Sxy150489 
55263526Sxy150489 	/* Call ddi_intr_add_handler() */
55273526Sxy150489 	for (x = 0; x < actual; x++) {
55283526Sxy150489 		rc = ddi_intr_add_handler(Adapter->htable[x],
55293526Sxy150489 		    intr_handler, (caddr_t)Adapter, NULL);
55303526Sxy150489 
55313526Sxy150489 		if (rc != DDI_SUCCESS) {
55324919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
55333526Sxy150489 			    "Add interrupt handler failed: %d\n", rc);
55343526Sxy150489 
55353526Sxy150489 			/* Remove already added handler */
55363526Sxy150489 			for (y = 0; y < x; y++)
55373526Sxy150489 				(void) ddi_intr_remove_handler(
55383526Sxy150489 				    Adapter->htable[y]);
55393526Sxy150489 
55403526Sxy150489 			/* Free already allocated intr */
55413526Sxy150489 			for (y = 0; y < actual; y++)
55423526Sxy150489 				(void) ddi_intr_free(Adapter->htable[y]);
55433526Sxy150489 
55443526Sxy150489 			kmem_free(Adapter->htable, Adapter->intr_size);
55453526Sxy150489 			return (DDI_FAILURE);
55463526Sxy150489 		}
55473526Sxy150489 	}
55483526Sxy150489 
55493526Sxy150489 	rc = ddi_intr_get_cap(Adapter->htable[0], &Adapter->intr_cap);
55503526Sxy150489 
55513526Sxy150489 	if (rc != DDI_SUCCESS) {
55524919Sxy150489 		E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
55533526Sxy150489 		    "Get interrupt cap failed: %d\n", rc);
55543526Sxy150489 
55553526Sxy150489 		/* Free already allocated intr */
55563526Sxy150489 		for (y = 0; y < actual; y++) {
55573526Sxy150489 			(void) ddi_intr_remove_handler(Adapter->htable[y]);
55583526Sxy150489 			(void) ddi_intr_free(Adapter->htable[y]);
55593526Sxy150489 		}
55603526Sxy150489 
55613526Sxy150489 		kmem_free(Adapter->htable, Adapter->intr_size);
55623526Sxy150489 		return (DDI_FAILURE);
55633526Sxy150489 	}
55643526Sxy150489 
55653526Sxy150489 	return (DDI_SUCCESS);
55663526Sxy150489 }
55673526Sxy150489 
55683526Sxy150489 static int
55693526Sxy150489 e1000g_rem_intrs(struct e1000g *Adapter)
55703526Sxy150489 {
55713526Sxy150489 	int x;
55723526Sxy150489 	int rc;
55733526Sxy150489 
55743526Sxy150489 	for (x = 0; x < Adapter->intr_cnt; x++) {
55753526Sxy150489 		rc = ddi_intr_remove_handler(Adapter->htable[x]);
55763526Sxy150489 		if (rc != DDI_SUCCESS) {
55774919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
55783526Sxy150489 			    "Remove intr handler failed: %d\n", rc);
55793526Sxy150489 			return (DDI_FAILURE);
55803526Sxy150489 		}
55813526Sxy150489 
55823526Sxy150489 		rc = ddi_intr_free(Adapter->htable[x]);
55833526Sxy150489 		if (rc != DDI_SUCCESS) {
55844919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
55853526Sxy150489 			    "Free intr failed: %d\n", rc);
55863526Sxy150489 			return (DDI_FAILURE);
55873526Sxy150489 		}
55883526Sxy150489 	}
55893526Sxy150489 
55903526Sxy150489 	kmem_free(Adapter->htable, Adapter->intr_size);
55913526Sxy150489 
55923526Sxy150489 	return (DDI_SUCCESS);
55933526Sxy150489 }
55943526Sxy150489 
55953526Sxy150489 static int
55963526Sxy150489 e1000g_enable_intrs(struct e1000g *Adapter)
55973526Sxy150489 {
55983526Sxy150489 	int x;
55993526Sxy150489 	int rc;
56003526Sxy150489 
56013526Sxy150489 	/* Enable interrupts */
56023526Sxy150489 	if (Adapter->intr_cap & DDI_INTR_FLAG_BLOCK) {
56033526Sxy150489 		/* Call ddi_intr_block_enable() for MSI */
56043526Sxy150489 		rc = ddi_intr_block_enable(Adapter->htable,
56053526Sxy150489 		    Adapter->intr_cnt);
56063526Sxy150489 		if (rc != DDI_SUCCESS) {
56074919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
56083526Sxy150489 			    "Enable block intr failed: %d\n", rc);
56093526Sxy150489 			return (DDI_FAILURE);
56103526Sxy150489 		}
56113526Sxy150489 	} else {
56123526Sxy150489 		/* Call ddi_intr_enable() for Legacy/MSI non block enable */
56133526Sxy150489 		for (x = 0; x < Adapter->intr_cnt; x++) {
56143526Sxy150489 			rc = ddi_intr_enable(Adapter->htable[x]);
56153526Sxy150489 			if (rc != DDI_SUCCESS) {
56164919Sxy150489 				E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
56173526Sxy150489 				    "Enable intr failed: %d\n", rc);
56183526Sxy150489 				return (DDI_FAILURE);
56193526Sxy150489 			}
56203526Sxy150489 		}
56213526Sxy150489 	}
56223526Sxy150489 
56233526Sxy150489 	return (DDI_SUCCESS);
56243526Sxy150489 }
56253526Sxy150489 
56263526Sxy150489 static int
56273526Sxy150489 e1000g_disable_intrs(struct e1000g *Adapter)
56283526Sxy150489 {
56293526Sxy150489 	int x;
56303526Sxy150489 	int rc;
56313526Sxy150489 
56323526Sxy150489 	/* Disable all interrupts */
56333526Sxy150489 	if (Adapter->intr_cap & DDI_INTR_FLAG_BLOCK) {
56343526Sxy150489 		rc = ddi_intr_block_disable(Adapter->htable,
56353526Sxy150489 		    Adapter->intr_cnt);
56363526Sxy150489 		if (rc != DDI_SUCCESS) {
56374919Sxy150489 			E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
56383526Sxy150489 			    "Disable block intr failed: %d\n", rc);
56393526Sxy150489 			return (DDI_FAILURE);
56403526Sxy150489 		}
56413526Sxy150489 	} else {
56423526Sxy150489 		for (x = 0; x < Adapter->intr_cnt; x++) {
56433526Sxy150489 			rc = ddi_intr_disable(Adapter->htable[x]);
56443526Sxy150489 			if (rc != DDI_SUCCESS) {
56454919Sxy150489 				E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
56463526Sxy150489 				    "Disable intr failed: %d\n", rc);
56473526Sxy150489 				return (DDI_FAILURE);
56483526Sxy150489 			}
56493526Sxy150489 		}
56503526Sxy150489 	}
56513526Sxy150489 
56523526Sxy150489 	return (DDI_SUCCESS);
56533526Sxy150489 }
56545082Syy150190 
56555082Syy150190 /*
56565082Syy150190  * e1000g_get_phy_state - get the state of PHY registers, save in the adapter
56575082Syy150190  */
56585082Syy150190 static void
56595082Syy150190 e1000g_get_phy_state(struct e1000g *Adapter)
56605082Syy150190 {
56615082Syy150190 	struct e1000_hw *hw = &Adapter->shared;
56625082Syy150190 
56637426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_CONTROL, &Adapter->phy_ctrl);
56647426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_STATUS, &Adapter->phy_status);
56657426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &Adapter->phy_an_adv);
56667426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &Adapter->phy_an_exp);
56677426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_EXT_STATUS, &Adapter->phy_ext_status);
56687426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_1000T_CTRL, &Adapter->phy_1000t_ctrl);
56697426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_1000T_STATUS,
56707426SChenliang.Xu@Sun.COM 	    &Adapter->phy_1000t_status);
56717426SChenliang.Xu@Sun.COM 	(void) e1000_read_phy_reg(hw, PHY_LP_ABILITY, &Adapter->phy_lp_able);
56726394Scc210113 
56736394Scc210113 	Adapter->param_autoneg_cap =
56746394Scc210113 	    (Adapter->phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0;
56756394Scc210113 	Adapter->param_pause_cap =
56766394Scc210113 	    (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
56776394Scc210113 	Adapter->param_asym_pause_cap =
56786394Scc210113 	    (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
56796394Scc210113 	Adapter->param_1000fdx_cap =
56806394Scc210113 	    ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
56816394Scc210113 	    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0;
56826394Scc210113 	Adapter->param_1000hdx_cap =
56836394Scc210113 	    ((Adapter->phy_ext_status & IEEE_ESR_1000T_HD_CAPS) ||
56846394Scc210113 	    (Adapter->phy_ext_status & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0;
56856394Scc210113 	Adapter->param_100t4_cap =
56866394Scc210113 	    (Adapter->phy_status & MII_SR_100T4_CAPS) ? 1 : 0;
56876394Scc210113 	Adapter->param_100fdx_cap =
56886394Scc210113 	    ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
56896394Scc210113 	    (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0;
56906394Scc210113 	Adapter->param_100hdx_cap =
56916394Scc210113 	    ((Adapter->phy_status & MII_SR_100X_HD_CAPS) ||
56926394Scc210113 	    (Adapter->phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0;
56936394Scc210113 	Adapter->param_10fdx_cap =
56946394Scc210113 	    (Adapter->phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0;
56956394Scc210113 	Adapter->param_10hdx_cap =
56966394Scc210113 	    (Adapter->phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0;
56976394Scc210113 
56986394Scc210113 	Adapter->param_adv_autoneg = hw->mac.autoneg;
56996394Scc210113 	Adapter->param_adv_pause =
57006394Scc210113 	    (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
57016394Scc210113 	Adapter->param_adv_asym_pause =
57026394Scc210113 	    (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
57036394Scc210113 	Adapter->param_adv_1000hdx =
57046394Scc210113 	    (Adapter->phy_1000t_ctrl & CR_1000T_HD_CAPS) ? 1 : 0;
57056394Scc210113 	Adapter->param_adv_100t4 =
57066394Scc210113 	    (Adapter->phy_an_adv & NWAY_AR_100T4_CAPS) ? 1 : 0;
57076394Scc210113 	if (Adapter->param_adv_autoneg == 1) {
57086394Scc210113 		Adapter->param_adv_1000fdx =
57096394Scc210113 		    (Adapter->phy_1000t_ctrl & CR_1000T_FD_CAPS) ? 1 : 0;
57106394Scc210113 		Adapter->param_adv_100fdx =
57116394Scc210113 		    (Adapter->phy_an_adv & NWAY_AR_100TX_FD_CAPS) ? 1 : 0;
57126394Scc210113 		Adapter->param_adv_100hdx =
57136394Scc210113 		    (Adapter->phy_an_adv & NWAY_AR_100TX_HD_CAPS) ? 1 : 0;
57146394Scc210113 		Adapter->param_adv_10fdx =
57156394Scc210113 		    (Adapter->phy_an_adv & NWAY_AR_10T_FD_CAPS) ? 1 : 0;
57166394Scc210113 		Adapter->param_adv_10hdx =
57176394Scc210113 		    (Adapter->phy_an_adv & NWAY_AR_10T_HD_CAPS) ? 1 : 0;
57186394Scc210113 	}
57196394Scc210113 
57206394Scc210113 	Adapter->param_lp_autoneg =
57216394Scc210113 	    (Adapter->phy_an_exp & NWAY_ER_LP_NWAY_CAPS) ? 1 : 0;
57226394Scc210113 	Adapter->param_lp_pause =
57236394Scc210113 	    (Adapter->phy_lp_able & NWAY_LPAR_PAUSE) ? 1 : 0;
57246394Scc210113 	Adapter->param_lp_asym_pause =
57256394Scc210113 	    (Adapter->phy_lp_able & NWAY_LPAR_ASM_DIR) ? 1 : 0;
57266394Scc210113 	Adapter->param_lp_1000fdx =
57276394Scc210113 	    (Adapter->phy_1000t_status & SR_1000T_LP_FD_CAPS) ? 1 : 0;
57286394Scc210113 	Adapter->param_lp_1000hdx =
57296394Scc210113 	    (Adapter->phy_1000t_status & SR_1000T_LP_HD_CAPS) ? 1 : 0;
57306394Scc210113 	Adapter->param_lp_100t4 =
57316394Scc210113 	    (Adapter->phy_lp_able & NWAY_LPAR_100T4_CAPS) ? 1 : 0;
57326394Scc210113 	Adapter->param_lp_100fdx =
57336394Scc210113 	    (Adapter->phy_lp_able & NWAY_LPAR_100TX_FD_CAPS) ? 1 : 0;
57346394Scc210113 	Adapter->param_lp_100hdx =
57356394Scc210113 	    (Adapter->phy_lp_able & NWAY_LPAR_100TX_HD_CAPS) ? 1 : 0;
57366394Scc210113 	Adapter->param_lp_10fdx =
57376394Scc210113 	    (Adapter->phy_lp_able & NWAY_LPAR_10T_FD_CAPS) ? 1 : 0;
57386394Scc210113 	Adapter->param_lp_10hdx =
57396394Scc210113 	    (Adapter->phy_lp_able & NWAY_LPAR_10T_HD_CAPS) ? 1 : 0;
57405082Syy150190 }
57415273Sgl147354 
57425273Sgl147354 /*
57435273Sgl147354  * FMA support
57445273Sgl147354  */
57455273Sgl147354 
57465273Sgl147354 int
57475273Sgl147354 e1000g_check_acc_handle(ddi_acc_handle_t handle)
57485273Sgl147354 {
57495273Sgl147354 	ddi_fm_error_t de;
57505273Sgl147354 
57515273Sgl147354 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
57525273Sgl147354 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
57535273Sgl147354 	return (de.fme_status);
57545273Sgl147354 }
57555273Sgl147354 
57565273Sgl147354 int
57575273Sgl147354 e1000g_check_dma_handle(ddi_dma_handle_t handle)
57585273Sgl147354 {
57595273Sgl147354 	ddi_fm_error_t de;
57605273Sgl147354 
57615273Sgl147354 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
57625273Sgl147354 	return (de.fme_status);
57635273Sgl147354 }
57645273Sgl147354 
57655273Sgl147354 /*
57665273Sgl147354  * The IO fault service error handling callback function
57675273Sgl147354  */
57687426SChenliang.Xu@Sun.COM /* ARGSUSED2 */
57695273Sgl147354 static int
57705273Sgl147354 e1000g_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
57715273Sgl147354 {
57725273Sgl147354 	/*
57735273Sgl147354 	 * as the driver can always deal with an error in any dma or
57745273Sgl147354 	 * access handle, we can just return the fme_status value.
57755273Sgl147354 	 */
57765273Sgl147354 	pci_ereport_post(dip, err, NULL);
57775273Sgl147354 	return (err->fme_status);
57785273Sgl147354 }
57795273Sgl147354 
57805273Sgl147354 static void
57815273Sgl147354 e1000g_fm_init(struct e1000g *Adapter)
57825273Sgl147354 {
57835273Sgl147354 	ddi_iblock_cookie_t iblk;
57845273Sgl147354 	int fma_acc_flag, fma_dma_flag;
57855273Sgl147354 
57865273Sgl147354 	/* Only register with IO Fault Services if we have some capability */
57875273Sgl147354 	if (Adapter->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
57885273Sgl147354 		e1000g_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
57895273Sgl147354 		fma_acc_flag = 1;
57905273Sgl147354 	} else {
57915273Sgl147354 		e1000g_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
57925273Sgl147354 		fma_acc_flag = 0;
57935273Sgl147354 	}
57945273Sgl147354 
57955273Sgl147354 	if (Adapter->fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
57965273Sgl147354 		fma_dma_flag = 1;
57975273Sgl147354 	} else {
57985273Sgl147354 		fma_dma_flag = 0;
57995273Sgl147354 	}
58005273Sgl147354 
58015273Sgl147354 	(void) e1000g_set_fma_flags(Adapter, fma_acc_flag, fma_dma_flag);
58025273Sgl147354 
58035273Sgl147354 	if (Adapter->fm_capabilities) {
58045273Sgl147354 
58055273Sgl147354 		/* Register capabilities with IO Fault Services */
58065273Sgl147354 		ddi_fm_init(Adapter->dip, &Adapter->fm_capabilities, &iblk);
58075273Sgl147354 
58085273Sgl147354 		/*
58095273Sgl147354 		 * Initialize pci ereport capabilities if ereport capable
58105273Sgl147354 		 */
58115273Sgl147354 		if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities) ||
58125273Sgl147354 		    DDI_FM_ERRCB_CAP(Adapter->fm_capabilities))
58135273Sgl147354 			pci_ereport_setup(Adapter->dip);
58145273Sgl147354 
58155273Sgl147354 		/*
58165273Sgl147354 		 * Register error callback if error callback capable
58175273Sgl147354 		 */
58185273Sgl147354 		if (DDI_FM_ERRCB_CAP(Adapter->fm_capabilities))
58195273Sgl147354 			ddi_fm_handler_register(Adapter->dip,
58205273Sgl147354 			    e1000g_fm_error_cb, (void*) Adapter);
58215273Sgl147354 	}
58225273Sgl147354 }
58235273Sgl147354 
58245273Sgl147354 static void
58255273Sgl147354 e1000g_fm_fini(struct e1000g *Adapter)
58265273Sgl147354 {
58275273Sgl147354 	/* Only unregister FMA capabilities if we registered some */
58285273Sgl147354 	if (Adapter->fm_capabilities) {
58295273Sgl147354 
58305273Sgl147354 		/*
58315273Sgl147354 		 * Release any resources allocated by pci_ereport_setup()
58325273Sgl147354 		 */
58335273Sgl147354 		if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities) ||
58345273Sgl147354 		    DDI_FM_ERRCB_CAP(Adapter->fm_capabilities))
58355273Sgl147354 			pci_ereport_teardown(Adapter->dip);
58365273Sgl147354 
58375273Sgl147354 		/*
58385273Sgl147354 		 * Un-register error callback if error callback capable
58395273Sgl147354 		 */
58405273Sgl147354 		if (DDI_FM_ERRCB_CAP(Adapter->fm_capabilities))
58415273Sgl147354 			ddi_fm_handler_unregister(Adapter->dip);
58425273Sgl147354 
58435273Sgl147354 		/* Unregister from IO Fault Services */
5844*8949SChangqing.Li@Sun.COM 		mutex_enter(&e1000g_rx_detach_lock);
58455273Sgl147354 		ddi_fm_fini(Adapter->dip);
5846*8949SChangqing.Li@Sun.COM 		if (Adapter->priv_dip != NULL) {
5847*8949SChangqing.Li@Sun.COM 			DEVI(Adapter->priv_dip)->devi_fmhdl = NULL;
5848*8949SChangqing.Li@Sun.COM 		}
5849*8949SChangqing.Li@Sun.COM 		mutex_exit(&e1000g_rx_detach_lock);
58505273Sgl147354 	}
58515273Sgl147354 }
58525273Sgl147354 
58535273Sgl147354 void
58545273Sgl147354 e1000g_fm_ereport(struct e1000g *Adapter, char *detail)
58555273Sgl147354 {
58565273Sgl147354 	uint64_t ena;
58575273Sgl147354 	char buf[FM_MAX_CLASS];
58585273Sgl147354 
58595273Sgl147354 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
58605273Sgl147354 	ena = fm_ena_generate(0, FM_ENA_FMT1);
58615273Sgl147354 	if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities)) {
58625273Sgl147354 		ddi_fm_ereport_post(Adapter->dip, buf, ena, DDI_NOSLEEP,
58635273Sgl147354 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
58645273Sgl147354 	}
58655273Sgl147354 }
58666512Ssowmini 
58677656SSherry.Moore@Sun.COM /*
58687656SSherry.Moore@Sun.COM  * quiesce(9E) entry point.
58697656SSherry.Moore@Sun.COM  *
58707656SSherry.Moore@Sun.COM  * This function is called when the system is single-threaded at high
58717656SSherry.Moore@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
58727656SSherry.Moore@Sun.COM  * blocked.
58737656SSherry.Moore@Sun.COM  *
58747656SSherry.Moore@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
58757656SSherry.Moore@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
58767656SSherry.Moore@Sun.COM  */
58777656SSherry.Moore@Sun.COM static int
58787656SSherry.Moore@Sun.COM e1000g_quiesce(dev_info_t *devinfo)
58797656SSherry.Moore@Sun.COM {
58807656SSherry.Moore@Sun.COM 	struct e1000g *Adapter;
58817656SSherry.Moore@Sun.COM 
58827656SSherry.Moore@Sun.COM 	Adapter = (struct e1000g *)ddi_get_driver_private(devinfo);
58837656SSherry.Moore@Sun.COM 
58847656SSherry.Moore@Sun.COM 	if (Adapter == NULL)
58857656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
58867656SSherry.Moore@Sun.COM 
58877656SSherry.Moore@Sun.COM 	e1000g_clear_all_interrupts(Adapter);
58887656SSherry.Moore@Sun.COM 
58897656SSherry.Moore@Sun.COM 	(void) e1000_reset_hw(&Adapter->shared);
58907656SSherry.Moore@Sun.COM 
58917656SSherry.Moore@Sun.COM 	/* Setup our HW Tx Head & Tail descriptor pointers */
58927656SSherry.Moore@Sun.COM 	E1000_WRITE_REG(&Adapter->shared, E1000_TDH(0), 0);
58937656SSherry.Moore@Sun.COM 	E1000_WRITE_REG(&Adapter->shared, E1000_TDT(0), 0);
58947656SSherry.Moore@Sun.COM 
58957656SSherry.Moore@Sun.COM 	/* Setup our HW Rx Head & Tail descriptor pointers */
58967656SSherry.Moore@Sun.COM 	E1000_WRITE_REG(&Adapter->shared, E1000_RDH(0), 0);
58977656SSherry.Moore@Sun.COM 	E1000_WRITE_REG(&Adapter->shared, E1000_RDT(0), 0);
58987656SSherry.Moore@Sun.COM 
58997656SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
59007656SSherry.Moore@Sun.COM }
59017656SSherry.Moore@Sun.COM 
59026512Ssowmini static int
59036512Ssowmini e1000g_get_def_val(struct e1000g *Adapter, mac_prop_id_t pr_num,
59046512Ssowmini     uint_t pr_valsize, void *pr_val)
59056512Ssowmini {
59066512Ssowmini 	link_flowctrl_t fl;
59076512Ssowmini 	int err = 0;
59086512Ssowmini 
59096512Ssowmini 	ASSERT(pr_valsize > 0);
59106512Ssowmini 	switch (pr_num) {
59116789Sam223141 	case MAC_PROP_AUTONEG:
59126512Ssowmini 		*(uint8_t *)pr_val =
59136512Ssowmini 		    ((Adapter->phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0);
59146512Ssowmini 		break;
59156789Sam223141 	case MAC_PROP_FLOWCTRL:
59166512Ssowmini 		if (pr_valsize < sizeof (link_flowctrl_t))
59176512Ssowmini 			return (EINVAL);
59186512Ssowmini 		fl = LINK_FLOWCTRL_BI;
59196512Ssowmini 		bcopy(&fl, pr_val, sizeof (fl));
59206512Ssowmini 		break;
59216789Sam223141 	case MAC_PROP_ADV_1000FDX_CAP:
59226789Sam223141 	case MAC_PROP_EN_1000FDX_CAP:
59236512Ssowmini 		*(uint8_t *)pr_val =
59246512Ssowmini 		    ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
59256512Ssowmini 		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0;
59266512Ssowmini 		break;
59276789Sam223141 	case MAC_PROP_ADV_1000HDX_CAP:
59286789Sam223141 	case MAC_PROP_EN_1000HDX_CAP:
59296512Ssowmini 		*(uint8_t *)pr_val =
59306512Ssowmini 		    ((Adapter->phy_ext_status & IEEE_ESR_1000T_HD_CAPS) ||
59316512Ssowmini 		    (Adapter->phy_ext_status & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0;
59326512Ssowmini 		break;
59336789Sam223141 	case MAC_PROP_ADV_100FDX_CAP:
59346789Sam223141 	case MAC_PROP_EN_100FDX_CAP:
59356512Ssowmini 		*(uint8_t *)pr_val =
59366512Ssowmini 		    ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
59376512Ssowmini 		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0;
59387426SChenliang.Xu@Sun.COM 		break;
59396789Sam223141 	case MAC_PROP_ADV_100HDX_CAP:
59406789Sam223141 	case MAC_PROP_EN_100HDX_CAP:
59416512Ssowmini 		*(uint8_t *)pr_val =
59426512Ssowmini 		    ((Adapter->phy_status & MII_SR_100X_HD_CAPS) ||
59436512Ssowmini 		    (Adapter->phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0;
59446512Ssowmini 		break;
59456789Sam223141 	case MAC_PROP_ADV_10FDX_CAP:
59466789Sam223141 	case MAC_PROP_EN_10FDX_CAP:
59476512Ssowmini 		*(uint8_t *)pr_val =
59486512Ssowmini 		    (Adapter->phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0;
59496512Ssowmini 		break;
59506789Sam223141 	case MAC_PROP_ADV_10HDX_CAP:
59516789Sam223141 	case MAC_PROP_EN_10HDX_CAP:
59526512Ssowmini 		*(uint8_t *)pr_val =
59536512Ssowmini 		    (Adapter->phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0;
59546512Ssowmini 		break;
59556512Ssowmini 	default:
59566512Ssowmini 		err = ENOTSUP;
59576512Ssowmini 		break;
59586512Ssowmini 	}
59596512Ssowmini 	return (err);
59606512Ssowmini }
59616512Ssowmini 
59626512Ssowmini /*
59636512Ssowmini  * synchronize the adv* and en* parameters.
59646512Ssowmini  *
59656512Ssowmini  * See comments in <sys/dld.h> for details of the *_en_*
59666512Ssowmini  * parameters. The usage of ndd for setting adv parameters will
59676512Ssowmini  * synchronize all the en parameters with the e1000g parameters,
59687607STed.You@Sun.COM  * implicitly disabling any settings made via dladm.
59696512Ssowmini  */
59706512Ssowmini static void
59716512Ssowmini e1000g_param_sync(struct e1000g *Adapter)
59726512Ssowmini {
59736512Ssowmini 	Adapter->param_en_1000fdx = Adapter->param_adv_1000fdx;
59746512Ssowmini 	Adapter->param_en_1000hdx = Adapter->param_adv_1000hdx;
59756512Ssowmini 	Adapter->param_en_100fdx = Adapter->param_adv_100fdx;
59766512Ssowmini 	Adapter->param_en_100hdx = Adapter->param_adv_100hdx;
59776512Ssowmini 	Adapter->param_en_10fdx = Adapter->param_adv_10fdx;
59786512Ssowmini 	Adapter->param_en_10hdx = Adapter->param_adv_10hdx;
59796512Ssowmini }
59807607STed.You@Sun.COM 
59817607STed.You@Sun.COM /*
59827607STed.You@Sun.COM  * e1000g_get_driver_control - tell manageability firmware that the driver
59837607STed.You@Sun.COM  * has control.
59847607STed.You@Sun.COM  */
59857607STed.You@Sun.COM static void
59867607STed.You@Sun.COM e1000g_get_driver_control(struct e1000_hw *hw)
59877607STed.You@Sun.COM {
59887607STed.You@Sun.COM 	uint32_t ctrl_ext;
59897607STed.You@Sun.COM 	uint32_t swsm;
59907607STed.You@Sun.COM 
59917607STed.You@Sun.COM 	/* tell manageability firmware the driver has taken over */
59927607STed.You@Sun.COM 	switch (hw->mac.type) {
59937607STed.You@Sun.COM 	case e1000_82573:
59947607STed.You@Sun.COM 		swsm = E1000_READ_REG(hw, E1000_SWSM);
59957607STed.You@Sun.COM 		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_DRV_LOAD);
59967607STed.You@Sun.COM 		break;
59977607STed.You@Sun.COM 	case e1000_82571:
59987607STed.You@Sun.COM 	case e1000_82572:
59997607STed.You@Sun.COM 	case e1000_82574:
60007607STed.You@Sun.COM 	case e1000_80003es2lan:
60017607STed.You@Sun.COM 	case e1000_ich8lan:
60027607STed.You@Sun.COM 	case e1000_ich9lan:
60037607STed.You@Sun.COM 	case e1000_ich10lan:
60047607STed.You@Sun.COM 		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
60057607STed.You@Sun.COM 		E1000_WRITE_REG(hw, E1000_CTRL_EXT,
60067607STed.You@Sun.COM 		    ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
60077607STed.You@Sun.COM 		break;
60087607STed.You@Sun.COM 	default:
60097607STed.You@Sun.COM 		/* no manageability firmware: do nothing */
60107607STed.You@Sun.COM 		break;
60117607STed.You@Sun.COM 	}
60127607STed.You@Sun.COM }
60137607STed.You@Sun.COM 
60147607STed.You@Sun.COM /*
60157607STed.You@Sun.COM  * e1000g_release_driver_control - tell manageability firmware that the driver
60167607STed.You@Sun.COM  * has released control.
60177607STed.You@Sun.COM  */
60187607STed.You@Sun.COM static void
60197607STed.You@Sun.COM e1000g_release_driver_control(struct e1000_hw *hw)
60207607STed.You@Sun.COM {
60217607STed.You@Sun.COM 	uint32_t ctrl_ext;
60227607STed.You@Sun.COM 	uint32_t swsm;
60237607STed.You@Sun.COM 
60247607STed.You@Sun.COM 	/* tell manageability firmware the driver has released control */
60257607STed.You@Sun.COM 	switch (hw->mac.type) {
60267607STed.You@Sun.COM 	case e1000_82573:
60277607STed.You@Sun.COM 		swsm = E1000_READ_REG(hw, E1000_SWSM);
60287607STed.You@Sun.COM 		E1000_WRITE_REG(hw, E1000_SWSM, swsm & ~E1000_SWSM_DRV_LOAD);
60297607STed.You@Sun.COM 		break;
60307607STed.You@Sun.COM 	case e1000_82571:
60317607STed.You@Sun.COM 	case e1000_82572:
60327607STed.You@Sun.COM 	case e1000_82574:
60337607STed.You@Sun.COM 	case e1000_80003es2lan:
60347607STed.You@Sun.COM 	case e1000_ich8lan:
60357607STed.You@Sun.COM 	case e1000_ich9lan:
60367607STed.You@Sun.COM 	case e1000_ich10lan:
60377607STed.You@Sun.COM 		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
60387607STed.You@Sun.COM 		E1000_WRITE_REG(hw, E1000_CTRL_EXT,
60397607STed.You@Sun.COM 		    ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
60407607STed.You@Sun.COM 		break;
60417607STed.You@Sun.COM 	default:
60427607STed.You@Sun.COM 		/* no manageability firmware: do nothing */
60437607STed.You@Sun.COM 		break;
60447607STed.You@Sun.COM 	}
60457607STed.You@Sun.COM }
60467722SShuguo.Yang@Sun.COM 
60477722SShuguo.Yang@Sun.COM /*
60487722SShuguo.Yang@Sun.COM  * Restore e1000g promiscuous mode.
60497722SShuguo.Yang@Sun.COM  */
60507722SShuguo.Yang@Sun.COM static void
60517722SShuguo.Yang@Sun.COM e1000g_restore_promisc(struct e1000g *Adapter)
60527722SShuguo.Yang@Sun.COM {
60537722SShuguo.Yang@Sun.COM 	if (Adapter->e1000g_promisc) {
60547722SShuguo.Yang@Sun.COM 		uint32_t rctl;
60557722SShuguo.Yang@Sun.COM 
60567722SShuguo.Yang@Sun.COM 		rctl = E1000_READ_REG(&Adapter->shared, E1000_RCTL);
60577722SShuguo.Yang@Sun.COM 		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_BAM);
60587722SShuguo.Yang@Sun.COM 		E1000_WRITE_REG(&Adapter->shared, E1000_RCTL, rctl);
60597722SShuguo.Yang@Sun.COM 	}
60607722SShuguo.Yang@Sun.COM }
6061