108057504Sxy150489 /* 208057504Sxy150489 * This file is provided under a CDDLv1 license. When using or 308057504Sxy150489 * redistributing this file, you may do so under this license. 408057504Sxy150489 * In redistributing this file this license must be included 508057504Sxy150489 * and no other modification of this header file is permitted. 608057504Sxy150489 * 708057504Sxy150489 * CDDL LICENSE SUMMARY 808057504Sxy150489 * 9d5c3073dSchenlu chen - Sun Microsystems - Beijing China * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved. 1008057504Sxy150489 * 1108057504Sxy150489 * The contents of this file are subject to the terms of Version 1208057504Sxy150489 * 1.0 of the Common Development and Distribution License (the "License"). 1308057504Sxy150489 * 1408057504Sxy150489 * You should have received a copy of the License with this software. 1508057504Sxy150489 * You can obtain a copy of the License at 1608057504Sxy150489 * http://www.opensolaris.org/os/licensing. 1708057504Sxy150489 * See the License for the specific language governing permissions 1808057504Sxy150489 * and limitations under the License. 1908057504Sxy150489 */ 2008057504Sxy150489 2108057504Sxy150489 /* 223fb4efefSchangqing li - Sun Microsystems - Beijing China * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2308057504Sxy150489 */ 2408057504Sxy150489 2508057504Sxy150489 /* 2659e72b15SGarrett D'Amore * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. 27b7c47e8cSHans Rosenfeld * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 28*b142f83dSRobert Mustacchi * Copyright (c) 2017, Joyent, Inc. 29dab7de2dSGarrett D'Amore */ 30dab7de2dSGarrett D'Amore 31dab7de2dSGarrett D'Amore /* 3208057504Sxy150489 * ********************************************************************** 3308057504Sxy150489 * * 3408057504Sxy150489 * Module Name: * 3508057504Sxy150489 * e1000g_main.c * 3608057504Sxy150489 * * 3708057504Sxy150489 * Abstract: * 3825f2d433Sxy150489 * This file contains the interface routines for the solaris OS. * 3925f2d433Sxy150489 * It has all DDI entry point routines and GLD entry point routines. * 4008057504Sxy150489 * * 4125f2d433Sxy150489 * This file also contains routines that take care of initialization * 4225f2d433Sxy150489 * uninit routine and interrupt routine. * 4308057504Sxy150489 * * 4408057504Sxy150489 * ********************************************************************** 4508057504Sxy150489 */ 4608057504Sxy150489 4708057504Sxy150489 #include <sys/dlpi.h> 4808057504Sxy150489 #include <sys/mac.h> 4908057504Sxy150489 #include "e1000g_sw.h" 5008057504Sxy150489 #include "e1000g_debug.h" 5108057504Sxy150489 5219397407SSherry Moore static char ident[] = "Intel PRO/1000 Ethernet"; 533fb4efefSchangqing li - Sun Microsystems - Beijing China /* LINTED E_STATIC_UNUSED */ 543fb4efefSchangqing li - Sun Microsystems - Beijing China static char e1000g_version[] = "Driver Ver. 5.3.24"; 5508057504Sxy150489 5608057504Sxy150489 /* 5708057504Sxy150489 * Proto types for DDI entry points 5808057504Sxy150489 */ 5925f2d433Sxy150489 static int e1000g_attach(dev_info_t *, ddi_attach_cmd_t); 6025f2d433Sxy150489 static int e1000g_detach(dev_info_t *, ddi_detach_cmd_t); 6119397407SSherry Moore static int e1000g_quiesce(dev_info_t *); 6208057504Sxy150489 6308057504Sxy150489 /* 6408057504Sxy150489 * init and intr routines prototype 6508057504Sxy150489 */ 6625f2d433Sxy150489 static int e1000g_resume(dev_info_t *); 6725f2d433Sxy150489 static int e1000g_suspend(dev_info_t *); 6808057504Sxy150489 static uint_t e1000g_intr_pciexpress(caddr_t); 6908057504Sxy150489 static uint_t e1000g_intr(caddr_t); 7008057504Sxy150489 static void e1000g_intr_work(struct e1000g *, uint32_t); 7108057504Sxy150489 #pragma inline(e1000g_intr_work) 7208057504Sxy150489 static int e1000g_init(struct e1000g *); 7325f2d433Sxy150489 static int e1000g_start(struct e1000g *, boolean_t); 7425f2d433Sxy150489 static void e1000g_stop(struct e1000g *, boolean_t); 7508057504Sxy150489 static int e1000g_m_start(void *); 7608057504Sxy150489 static void e1000g_m_stop(void *); 7708057504Sxy150489 static int e1000g_m_promisc(void *, boolean_t); 7808057504Sxy150489 static boolean_t e1000g_m_getcapab(void *, mac_capab_t, void *); 7908057504Sxy150489 static int e1000g_m_multicst(void *, boolean_t, const uint8_t *); 8008057504Sxy150489 static void e1000g_m_ioctl(void *, queue_t *, mblk_t *); 819ce7e93cScc210113 static int e1000g_m_setprop(void *, const char *, mac_prop_id_t, 829ce7e93cScc210113 uint_t, const void *); 839ce7e93cScc210113 static int e1000g_m_getprop(void *, const char *, mac_prop_id_t, 840dc2366fSVenugopal Iyer uint_t, void *); 850dc2366fSVenugopal Iyer static void e1000g_m_propinfo(void *, const char *, mac_prop_id_t, 860dc2366fSVenugopal Iyer mac_prop_info_handle_t); 879ce7e93cScc210113 static int e1000g_set_priv_prop(struct e1000g *, const char *, uint_t, 889ce7e93cScc210113 const void *); 890dc2366fSVenugopal Iyer static int e1000g_get_priv_prop(struct e1000g *, const char *, uint_t, void *); 9025f2d433Sxy150489 static void e1000g_init_locks(struct e1000g *); 9125f2d433Sxy150489 static void e1000g_destroy_locks(struct e1000g *); 9225f2d433Sxy150489 static int e1000g_identify_hardware(struct e1000g *); 9325f2d433Sxy150489 static int e1000g_regs_map(struct e1000g *); 9425f2d433Sxy150489 static int e1000g_set_driver_params(struct e1000g *); 959ce7e93cScc210113 static void e1000g_set_bufsize(struct e1000g *); 9625f2d433Sxy150489 static int e1000g_register_mac(struct e1000g *); 9725f2d433Sxy150489 static boolean_t e1000g_rx_drain(struct e1000g *); 9825f2d433Sxy150489 static boolean_t e1000g_tx_drain(struct e1000g *); 9925f2d433Sxy150489 static void e1000g_init_unicst(struct e1000g *); 100da14cebeSEric Cheng static int e1000g_unicst_set(struct e1000g *, const uint8_t *, int); 10154e0d7a5SMiles Xu, Sun Microsystems static int e1000g_alloc_rx_data(struct e1000g *); 1020c56b8d9Schangqing li - Sun Microsystems - Beijing China static void e1000g_release_multicast(struct e1000g *); 103caf05df5SMiles Xu, Sun Microsystems static void e1000g_pch_limits(struct e1000g *); 104caf05df5SMiles Xu, Sun Microsystems static uint32_t e1000g_mtu2maxframe(uint32_t); 10508057504Sxy150489 10608057504Sxy150489 /* 10708057504Sxy150489 * Local routines 10808057504Sxy150489 */ 10919397407SSherry Moore static boolean_t e1000g_reset_adapter(struct e1000g *); 11025f2d433Sxy150489 static void e1000g_tx_clean(struct e1000g *); 11125f2d433Sxy150489 static void e1000g_rx_clean(struct e1000g *); 1127941757cSxy150489 static void e1000g_link_timer(void *); 11325f2d433Sxy150489 static void e1000g_local_timer(void *); 1147941757cSxy150489 static boolean_t e1000g_link_check(struct e1000g *); 11508057504Sxy150489 static boolean_t e1000g_stall_check(struct e1000g *); 11608057504Sxy150489 static void e1000g_smartspeed(struct e1000g *); 11725f2d433Sxy150489 static void e1000g_get_conf(struct e1000g *); 1181bc1c721Sguoqing zhu - Sun Microsystems - Beijing China static boolean_t e1000g_get_prop(struct e1000g *, char *, int, int, int, 1191bc1c721Sguoqing zhu - Sun Microsystems - Beijing China int *); 12025f2d433Sxy150489 static void enable_watchdog_timer(struct e1000g *); 12125f2d433Sxy150489 static void disable_watchdog_timer(struct e1000g *); 12225f2d433Sxy150489 static void start_watchdog_timer(struct e1000g *); 12325f2d433Sxy150489 static void restart_watchdog_timer(struct e1000g *); 12425f2d433Sxy150489 static void stop_watchdog_timer(struct e1000g *); 12525f2d433Sxy150489 static void stop_link_timer(struct e1000g *); 12625f2d433Sxy150489 static void stop_82547_timer(e1000g_tx_ring_t *); 12725f2d433Sxy150489 static void e1000g_force_speed_duplex(struct e1000g *); 128caf05df5SMiles Xu, Sun Microsystems static void e1000g_setup_max_mtu(struct e1000g *); 12925f2d433Sxy150489 static void e1000g_get_max_frame_size(struct e1000g *); 13025f2d433Sxy150489 static boolean_t is_valid_mac_addr(uint8_t *); 13108057504Sxy150489 static void e1000g_unattach(dev_info_t *, struct e1000g *); 1323f64cd55Sguoqing zhu - Sun Microsystems - Beijing China static int e1000g_get_bar_info(dev_info_t *, int, bar_info_t *); 13325f2d433Sxy150489 #ifdef E1000G_DEBUG 13425f2d433Sxy150489 static void e1000g_ioc_peek_reg(struct e1000g *, e1000g_peekpoke_t *); 13525f2d433Sxy150489 static void e1000g_ioc_poke_reg(struct e1000g *, e1000g_peekpoke_t *); 13625f2d433Sxy150489 static void e1000g_ioc_peek_mem(struct e1000g *, e1000g_peekpoke_t *); 13725f2d433Sxy150489 static void e1000g_ioc_poke_mem(struct e1000g *, e1000g_peekpoke_t *); 13825f2d433Sxy150489 static enum ioc_reply e1000g_pp_ioctl(struct e1000g *, 13925f2d433Sxy150489 struct iocblk *, mblk_t *); 14025f2d433Sxy150489 #endif 14125f2d433Sxy150489 static enum ioc_reply e1000g_loopback_ioctl(struct e1000g *, 14225f2d433Sxy150489 struct iocblk *, mblk_t *); 143a2e9a830Scc210113 static boolean_t e1000g_check_loopback_support(struct e1000_hw *); 14425f2d433Sxy150489 static boolean_t e1000g_set_loopback_mode(struct e1000g *, uint32_t); 14525f2d433Sxy150489 static void e1000g_set_internal_loopback(struct e1000g *); 14625f2d433Sxy150489 static void e1000g_set_external_loopback_1000(struct e1000g *); 14725f2d433Sxy150489 static void e1000g_set_external_loopback_100(struct e1000g *); 14825f2d433Sxy150489 static void e1000g_set_external_loopback_10(struct e1000g *); 14925f2d433Sxy150489 static int e1000g_add_intrs(struct e1000g *); 15025f2d433Sxy150489 static int e1000g_intr_add(struct e1000g *, int); 15125f2d433Sxy150489 static int e1000g_rem_intrs(struct e1000g *); 15225f2d433Sxy150489 static int e1000g_enable_intrs(struct e1000g *); 15325f2d433Sxy150489 static int e1000g_disable_intrs(struct e1000g *); 15425f2d433Sxy150489 static boolean_t e1000g_link_up(struct e1000g *); 15508057504Sxy150489 #ifdef __sparc 15625f2d433Sxy150489 static boolean_t e1000g_find_mac_address(struct e1000g *); 15708057504Sxy150489 #endif 1584914a7d0Syy150190 static void e1000g_get_phy_state(struct e1000g *); 1599b6541b3Sgl147354 static int e1000g_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, 1609b6541b3Sgl147354 const void *impl_data); 1619b6541b3Sgl147354 static void e1000g_fm_init(struct e1000g *Adapter); 1629b6541b3Sgl147354 static void e1000g_fm_fini(struct e1000g *Adapter); 1634045d941Ssowmini static void e1000g_param_sync(struct e1000g *); 1644d737963Sxiangtao you - Sun Microsystems - Beijing China static void e1000g_get_driver_control(struct e1000_hw *); 1654d737963Sxiangtao you - Sun Microsystems - Beijing China static void e1000g_release_driver_control(struct e1000_hw *); 166bb184967SShu-Guo Yang static void e1000g_restore_promisc(struct e1000g *Adapter); 1674045d941Ssowmini 1680dc2366fSVenugopal Iyer char *e1000g_priv_props[] = { 1690dc2366fSVenugopal Iyer "_tx_bcopy_threshold", 1700dc2366fSVenugopal Iyer "_tx_interrupt_enable", 1710dc2366fSVenugopal Iyer "_tx_intr_delay", 1720dc2366fSVenugopal Iyer "_tx_intr_abs_delay", 1730dc2366fSVenugopal Iyer "_rx_bcopy_threshold", 1740dc2366fSVenugopal Iyer "_max_num_rcv_packets", 1750dc2366fSVenugopal Iyer "_rx_intr_delay", 1760dc2366fSVenugopal Iyer "_rx_intr_abs_delay", 1770dc2366fSVenugopal Iyer "_intr_throttling_rate", 1780dc2366fSVenugopal Iyer "_intr_adaptive", 1790dc2366fSVenugopal Iyer "_adv_pause_cap", 1800dc2366fSVenugopal Iyer "_adv_asym_pause_cap", 1810dc2366fSVenugopal Iyer NULL 1824045d941Ssowmini }; 18308057504Sxy150489 18408057504Sxy150489 static struct cb_ops cb_ws_ops = { 18508057504Sxy150489 nulldev, /* cb_open */ 18608057504Sxy150489 nulldev, /* cb_close */ 18708057504Sxy150489 nodev, /* cb_strategy */ 18808057504Sxy150489 nodev, /* cb_print */ 18908057504Sxy150489 nodev, /* cb_dump */ 19008057504Sxy150489 nodev, /* cb_read */ 19108057504Sxy150489 nodev, /* cb_write */ 19208057504Sxy150489 nodev, /* cb_ioctl */ 19308057504Sxy150489 nodev, /* cb_devmap */ 19408057504Sxy150489 nodev, /* cb_mmap */ 19508057504Sxy150489 nodev, /* cb_segmap */ 19608057504Sxy150489 nochpoll, /* cb_chpoll */ 19708057504Sxy150489 ddi_prop_op, /* cb_prop_op */ 19808057504Sxy150489 NULL, /* cb_stream */ 19908057504Sxy150489 D_MP | D_HOTPLUG, /* cb_flag */ 20008057504Sxy150489 CB_REV, /* cb_rev */ 20108057504Sxy150489 nodev, /* cb_aread */ 20208057504Sxy150489 nodev /* cb_awrite */ 20308057504Sxy150489 }; 20408057504Sxy150489 20508057504Sxy150489 static struct dev_ops ws_ops = { 20608057504Sxy150489 DEVO_REV, /* devo_rev */ 20708057504Sxy150489 0, /* devo_refcnt */ 20808057504Sxy150489 NULL, /* devo_getinfo */ 20908057504Sxy150489 nulldev, /* devo_identify */ 21008057504Sxy150489 nulldev, /* devo_probe */ 21125f2d433Sxy150489 e1000g_attach, /* devo_attach */ 21225f2d433Sxy150489 e1000g_detach, /* devo_detach */ 21308057504Sxy150489 nodev, /* devo_reset */ 21408057504Sxy150489 &cb_ws_ops, /* devo_cb_ops */ 21508057504Sxy150489 NULL, /* devo_bus_ops */ 21619397407SSherry Moore ddi_power, /* devo_power */ 21719397407SSherry Moore e1000g_quiesce /* devo_quiesce */ 21808057504Sxy150489 }; 21908057504Sxy150489 22008057504Sxy150489 static struct modldrv modldrv = { 22108057504Sxy150489 &mod_driverops, /* Type of module. This one is a driver */ 22208057504Sxy150489 ident, /* Discription string */ 22308057504Sxy150489 &ws_ops, /* driver ops */ 22408057504Sxy150489 }; 22508057504Sxy150489 22608057504Sxy150489 static struct modlinkage modlinkage = { 22708057504Sxy150489 MODREV_1, &modldrv, NULL 22808057504Sxy150489 }; 22908057504Sxy150489 23025f2d433Sxy150489 /* Access attributes for register mapping */ 23125f2d433Sxy150489 static ddi_device_acc_attr_t e1000g_regs_acc_attr = { 232837c1ac4SStephen Hanson DDI_DEVICE_ATTR_V1, 23308057504Sxy150489 DDI_STRUCTURE_LE_ACC, 23408057504Sxy150489 DDI_STRICTORDER_ACC, 2359b6541b3Sgl147354 DDI_FLAGERR_ACC 23608057504Sxy150489 }; 23708057504Sxy150489 2389ce7e93cScc210113 #define E1000G_M_CALLBACK_FLAGS \ 2390dc2366fSVenugopal Iyer (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 24008057504Sxy150489 24108057504Sxy150489 static mac_callbacks_t e1000g_m_callbacks = { 24208057504Sxy150489 E1000G_M_CALLBACK_FLAGS, 24308057504Sxy150489 e1000g_m_stat, 24408057504Sxy150489 e1000g_m_start, 24508057504Sxy150489 e1000g_m_stop, 24608057504Sxy150489 e1000g_m_promisc, 24708057504Sxy150489 e1000g_m_multicst, 24847b7744cSyy150190 NULL, 249da14cebeSEric Cheng e1000g_m_tx, 2500dc2366fSVenugopal Iyer NULL, 25108057504Sxy150489 e1000g_m_ioctl, 2529ce7e93cScc210113 e1000g_m_getcapab, 2539ce7e93cScc210113 NULL, 2549ce7e93cScc210113 NULL, 2559ce7e93cScc210113 e1000g_m_setprop, 2560dc2366fSVenugopal Iyer e1000g_m_getprop, 2570dc2366fSVenugopal Iyer e1000g_m_propinfo 25808057504Sxy150489 }; 25908057504Sxy150489 26008057504Sxy150489 /* 26108057504Sxy150489 * Global variables 26208057504Sxy150489 */ 2633fb4efefSchangqing li - Sun Microsystems - Beijing China uint32_t e1000g_jumbo_mtu = MAXIMUM_MTU_9K; 26408057504Sxy150489 uint32_t e1000g_mblks_pending = 0; 26508057504Sxy150489 /* 2668bfe3c7bSyy150190 * Workaround for Dynamic Reconfiguration support, for x86 platform only. 2670f70fbf8Sxy150489 * Here we maintain a private dev_info list if e1000g_force_detach is 2680f70fbf8Sxy150489 * enabled. If we force the driver to detach while there are still some 2690f70fbf8Sxy150489 * rx buffers retained in the upper layer, we have to keep a copy of the 2700f70fbf8Sxy150489 * dev_info. In some cases (Dynamic Reconfiguration), the dev_info data 2710f70fbf8Sxy150489 * structure will be freed after the driver is detached. However when we 2720f70fbf8Sxy150489 * finally free those rx buffers released by the upper layer, we need to 2730f70fbf8Sxy150489 * refer to the dev_info to free the dma buffers. So we save a copy of 2748bfe3c7bSyy150190 * the dev_info for this purpose. On x86 platform, we assume this copy 2758bfe3c7bSyy150190 * of dev_info is always valid, but on SPARC platform, it could be invalid 2768bfe3c7bSyy150190 * after the system board level DR operation. For this reason, the global 2778bfe3c7bSyy150190 * variable e1000g_force_detach must be B_FALSE on SPARC platform. 2780f70fbf8Sxy150489 */ 2798bfe3c7bSyy150190 #ifdef __sparc 2808bfe3c7bSyy150190 boolean_t e1000g_force_detach = B_FALSE; 2818bfe3c7bSyy150190 #else 2828bfe3c7bSyy150190 boolean_t e1000g_force_detach = B_TRUE; 2838bfe3c7bSyy150190 #endif 2840f70fbf8Sxy150489 private_devi_list_t *e1000g_private_devi_list = NULL; 2858bfe3c7bSyy150190 2860f70fbf8Sxy150489 /* 28754e0d7a5SMiles Xu, Sun Microsystems * The mutex e1000g_rx_detach_lock is defined to protect the processing of 28854e0d7a5SMiles Xu, Sun Microsystems * the private dev_info list, and to serialize the processing of rx buffer 28954e0d7a5SMiles Xu, Sun Microsystems * freeing and rx buffer recycling. 29008057504Sxy150489 */ 29154e0d7a5SMiles Xu, Sun Microsystems kmutex_t e1000g_rx_detach_lock; 29208057504Sxy150489 /* 29308057504Sxy150489 * The rwlock e1000g_dma_type_lock is defined to protect the global flag 29408057504Sxy150489 * e1000g_dma_type. For SPARC, the initial value of the flag is "USE_DVMA". 29508057504Sxy150489 * If there are many e1000g instances, the system may run out of DVMA 29608057504Sxy150489 * resources during the initialization of the instances, then the flag will 29708057504Sxy150489 * be changed to "USE_DMA". Because different e1000g instances are initialized 29808057504Sxy150489 * in parallel, we need to use this lock to protect the flag. 29908057504Sxy150489 */ 30008057504Sxy150489 krwlock_t e1000g_dma_type_lock; 30108057504Sxy150489 302a2e9a830Scc210113 /* 303a2e9a830Scc210113 * The 82546 chipset is a dual-port device, both the ports share one eeprom. 304a2e9a830Scc210113 * Based on the information from Intel, the 82546 chipset has some hardware 305a2e9a830Scc210113 * problem. When one port is being reset and the other port is trying to 306a2e9a830Scc210113 * access the eeprom, it could cause system hang or panic. To workaround this 307a2e9a830Scc210113 * hardware problem, we use a global mutex to prevent such operations from 308a2e9a830Scc210113 * happening simultaneously on different instances. This workaround is applied 309a2e9a830Scc210113 * to all the devices supported by this driver. 310a2e9a830Scc210113 */ 311a2e9a830Scc210113 kmutex_t e1000g_nvm_lock; 31208057504Sxy150489 31308057504Sxy150489 /* 31408057504Sxy150489 * Loadable module configuration entry points for the driver 31508057504Sxy150489 */ 31608057504Sxy150489 31708057504Sxy150489 /* 31825f2d433Sxy150489 * _init - module initialization 31908057504Sxy150489 */ 32008057504Sxy150489 int 32108057504Sxy150489 _init(void) 32208057504Sxy150489 { 32308057504Sxy150489 int status; 32408057504Sxy150489 32508057504Sxy150489 mac_init_ops(&ws_ops, WSNAME); 32608057504Sxy150489 status = mod_install(&modlinkage); 32708057504Sxy150489 if (status != DDI_SUCCESS) 32808057504Sxy150489 mac_fini_ops(&ws_ops); 32908057504Sxy150489 else { 33054e0d7a5SMiles Xu, Sun Microsystems mutex_init(&e1000g_rx_detach_lock, NULL, MUTEX_DRIVER, NULL); 33108057504Sxy150489 rw_init(&e1000g_dma_type_lock, NULL, RW_DRIVER, NULL); 332a2e9a830Scc210113 mutex_init(&e1000g_nvm_lock, NULL, MUTEX_DRIVER, NULL); 33308057504Sxy150489 } 33408057504Sxy150489 33508057504Sxy150489 return (status); 33608057504Sxy150489 } 33708057504Sxy150489 33808057504Sxy150489 /* 33925f2d433Sxy150489 * _fini - module finalization 34008057504Sxy150489 */ 34108057504Sxy150489 int 34208057504Sxy150489 _fini(void) 34308057504Sxy150489 { 34408057504Sxy150489 int status; 34508057504Sxy150489 34654e0d7a5SMiles Xu, Sun Microsystems if (e1000g_mblks_pending != 0) 34708057504Sxy150489 return (EBUSY); 34808057504Sxy150489 34908057504Sxy150489 status = mod_remove(&modlinkage); 35008057504Sxy150489 if (status == DDI_SUCCESS) { 35108057504Sxy150489 mac_fini_ops(&ws_ops); 3520f70fbf8Sxy150489 3530f70fbf8Sxy150489 if (e1000g_force_detach) { 3540f70fbf8Sxy150489 private_devi_list_t *devi_node; 3550f70fbf8Sxy150489 35654e0d7a5SMiles Xu, Sun Microsystems mutex_enter(&e1000g_rx_detach_lock); 3570f70fbf8Sxy150489 while (e1000g_private_devi_list != NULL) { 3580f70fbf8Sxy150489 devi_node = e1000g_private_devi_list; 3590f70fbf8Sxy150489 e1000g_private_devi_list = 3600f70fbf8Sxy150489 e1000g_private_devi_list->next; 3610f70fbf8Sxy150489 3620f70fbf8Sxy150489 kmem_free(devi_node->priv_dip, 3630f70fbf8Sxy150489 sizeof (struct dev_info)); 3640f70fbf8Sxy150489 kmem_free(devi_node, 3650f70fbf8Sxy150489 sizeof (private_devi_list_t)); 3660f70fbf8Sxy150489 } 36754e0d7a5SMiles Xu, Sun Microsystems mutex_exit(&e1000g_rx_detach_lock); 3680f70fbf8Sxy150489 } 3690f70fbf8Sxy150489 37054e0d7a5SMiles Xu, Sun Microsystems mutex_destroy(&e1000g_rx_detach_lock); 37108057504Sxy150489 rw_destroy(&e1000g_dma_type_lock); 372a2e9a830Scc210113 mutex_destroy(&e1000g_nvm_lock); 37308057504Sxy150489 } 37408057504Sxy150489 37508057504Sxy150489 return (status); 37608057504Sxy150489 } 37708057504Sxy150489 37808057504Sxy150489 /* 37925f2d433Sxy150489 * _info - module information 38008057504Sxy150489 */ 38108057504Sxy150489 int 38208057504Sxy150489 _info(struct modinfo *modinfop) 38308057504Sxy150489 { 38408057504Sxy150489 return (mod_info(&modlinkage, modinfop)); 38508057504Sxy150489 } 38608057504Sxy150489 38708057504Sxy150489 /* 38825f2d433Sxy150489 * e1000g_attach - driver attach 38925f2d433Sxy150489 * 39025f2d433Sxy150489 * This function is the device-specific initialization entry 39125f2d433Sxy150489 * point. This entry point is required and must be written. 39225f2d433Sxy150489 * The DDI_ATTACH command must be provided in the attach entry 39325f2d433Sxy150489 * point. When attach() is called with cmd set to DDI_ATTACH, 39425f2d433Sxy150489 * all normal kernel services (such as kmem_alloc(9F)) are 39525f2d433Sxy150489 * available for use by the driver. 39625f2d433Sxy150489 * 39725f2d433Sxy150489 * The attach() function will be called once for each instance 39825f2d433Sxy150489 * of the device on the system with cmd set to DDI_ATTACH. 39925f2d433Sxy150489 * Until attach() succeeds, the only driver entry points which 40025f2d433Sxy150489 * may be called are open(9E) and getinfo(9E). 40108057504Sxy150489 */ 40208057504Sxy150489 static int 40325f2d433Sxy150489 e1000g_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 40408057504Sxy150489 { 40508057504Sxy150489 struct e1000g *Adapter; 40608057504Sxy150489 struct e1000_hw *hw; 40725f2d433Sxy150489 struct e1000g_osdep *osdep; 40808057504Sxy150489 int instance; 40908057504Sxy150489 41008057504Sxy150489 switch (cmd) { 41108057504Sxy150489 default: 41208057504Sxy150489 e1000g_log(NULL, CE_WARN, 41325f2d433Sxy150489 "Unsupported command send to e1000g_attach... "); 41408057504Sxy150489 return (DDI_FAILURE); 41508057504Sxy150489 41608057504Sxy150489 case DDI_RESUME: 41708057504Sxy150489 return (e1000g_resume(devinfo)); 41808057504Sxy150489 41908057504Sxy150489 case DDI_ATTACH: 42008057504Sxy150489 break; 42108057504Sxy150489 } 42208057504Sxy150489 42308057504Sxy150489 /* 42408057504Sxy150489 * get device instance number 42508057504Sxy150489 */ 42608057504Sxy150489 instance = ddi_get_instance(devinfo); 42708057504Sxy150489 42808057504Sxy150489 /* 42908057504Sxy150489 * Allocate soft data structure 43008057504Sxy150489 */ 43108057504Sxy150489 Adapter = 43208057504Sxy150489 (struct e1000g *)kmem_zalloc(sizeof (*Adapter), KM_SLEEP); 43308057504Sxy150489 43408057504Sxy150489 Adapter->dip = devinfo; 43525f2d433Sxy150489 Adapter->instance = instance; 43608057504Sxy150489 Adapter->tx_ring->adapter = Adapter; 43708057504Sxy150489 Adapter->rx_ring->adapter = Adapter; 43808057504Sxy150489 43925f2d433Sxy150489 hw = &Adapter->shared; 44025f2d433Sxy150489 osdep = &Adapter->osdep; 44125f2d433Sxy150489 hw->back = osdep; 44225f2d433Sxy150489 osdep->adapter = Adapter; 44325f2d433Sxy150489 44408057504Sxy150489 ddi_set_driver_private(devinfo, (caddr_t)Adapter); 44508057504Sxy150489 44608057504Sxy150489 /* 4479b6541b3Sgl147354 * Initialize for fma support 4489b6541b3Sgl147354 */ 4491bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "fm-capable", 4509b6541b3Sgl147354 0, 0x0f, 4519b6541b3Sgl147354 DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 4521bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE, 4531bc1c721Sguoqing zhu - Sun Microsystems - Beijing China &Adapter->fm_capabilities); 4549b6541b3Sgl147354 e1000g_fm_init(Adapter); 4559b6541b3Sgl147354 Adapter->attach_progress |= ATTACH_PROGRESS_FMINIT; 4569b6541b3Sgl147354 4579b6541b3Sgl147354 /* 45808057504Sxy150489 * PCI Configure 45908057504Sxy150489 */ 46025f2d433Sxy150489 if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) { 46125f2d433Sxy150489 e1000g_log(Adapter, CE_WARN, "PCI configuration failed"); 46225f2d433Sxy150489 goto attach_fail; 46325f2d433Sxy150489 } 46425f2d433Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG; 46525f2d433Sxy150489 46625f2d433Sxy150489 /* 46725f2d433Sxy150489 * Setup hardware 46825f2d433Sxy150489 */ 46925f2d433Sxy150489 if (e1000g_identify_hardware(Adapter) != DDI_SUCCESS) { 47025f2d433Sxy150489 e1000g_log(Adapter, CE_WARN, "Identify hardware failed"); 47108057504Sxy150489 goto attach_fail; 47208057504Sxy150489 } 47308057504Sxy150489 47425f2d433Sxy150489 /* 47525f2d433Sxy150489 * Map in the device registers. 47625f2d433Sxy150489 */ 47725f2d433Sxy150489 if (e1000g_regs_map(Adapter) != DDI_SUCCESS) { 47825f2d433Sxy150489 e1000g_log(Adapter, CE_WARN, "Mapping registers failed"); 47925f2d433Sxy150489 goto attach_fail; 48025f2d433Sxy150489 } 48125f2d433Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_REGS_MAP; 48208057504Sxy150489 48308057504Sxy150489 /* 48408057504Sxy150489 * Initialize driver parameters 48508057504Sxy150489 */ 48608057504Sxy150489 if (e1000g_set_driver_params(Adapter) != DDI_SUCCESS) { 48708057504Sxy150489 goto attach_fail; 48808057504Sxy150489 } 48925f2d433Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_SETUP; 49008057504Sxy150489 4919b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.cfg_handle) != DDI_FM_OK) { 4929b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 4939b6541b3Sgl147354 goto attach_fail; 4949b6541b3Sgl147354 } 4959b6541b3Sgl147354 49608057504Sxy150489 /* 497c124a83eSRobert Mustacchi * Disable ULP support 498c124a83eSRobert Mustacchi */ 499c124a83eSRobert Mustacchi (void) e1000_disable_ulp_lpt_lp(hw, TRUE); 500c124a83eSRobert Mustacchi 501c124a83eSRobert Mustacchi /* 50208057504Sxy150489 * Initialize interrupts 50308057504Sxy150489 */ 50408057504Sxy150489 if (e1000g_add_intrs(Adapter) != DDI_SUCCESS) { 50508057504Sxy150489 e1000g_log(Adapter, CE_WARN, "Add interrupts failed"); 50608057504Sxy150489 goto attach_fail; 50708057504Sxy150489 } 50825f2d433Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 50908057504Sxy150489 51008057504Sxy150489 /* 51108057504Sxy150489 * Initialize mutex's for this device. 51208057504Sxy150489 * Do this before enabling the interrupt handler and 51308057504Sxy150489 * register the softint to avoid the condition where 51408057504Sxy150489 * interrupt handler can try using uninitialized mutex 51508057504Sxy150489 */ 51608057504Sxy150489 e1000g_init_locks(Adapter); 51708057504Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_LOCKS; 51808057504Sxy150489 51908057504Sxy150489 /* 52008057504Sxy150489 * Initialize Driver Counters 52108057504Sxy150489 */ 52225f2d433Sxy150489 if (e1000g_init_stats(Adapter) != DDI_SUCCESS) { 52308057504Sxy150489 e1000g_log(Adapter, CE_WARN, "Init stats failed"); 52408057504Sxy150489 goto attach_fail; 52508057504Sxy150489 } 52608057504Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_KSTATS; 52708057504Sxy150489 52808057504Sxy150489 /* 52908057504Sxy150489 * Initialize chip hardware and software structures 53008057504Sxy150489 */ 531d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 53208057504Sxy150489 if (e1000g_init(Adapter) != DDI_SUCCESS) { 533d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 53408057504Sxy150489 e1000g_log(Adapter, CE_WARN, "Adapter initialization failed"); 53508057504Sxy150489 goto attach_fail; 53608057504Sxy150489 } 537d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 53808057504Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_INIT; 53908057504Sxy150489 54008057504Sxy150489 /* 54108057504Sxy150489 * Register the driver to the MAC 54208057504Sxy150489 */ 54308057504Sxy150489 if (e1000g_register_mac(Adapter) != DDI_SUCCESS) { 54408057504Sxy150489 e1000g_log(Adapter, CE_WARN, "Register MAC failed"); 54508057504Sxy150489 goto attach_fail; 54608057504Sxy150489 } 54725f2d433Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_MAC; 54808057504Sxy150489 54908057504Sxy150489 /* 55008057504Sxy150489 * Now that mutex locks are initialized, and the chip is also 55108057504Sxy150489 * initialized, enable interrupts. 55208057504Sxy150489 */ 55308057504Sxy150489 if (e1000g_enable_intrs(Adapter) != DDI_SUCCESS) { 55408057504Sxy150489 e1000g_log(Adapter, CE_WARN, "Enable DDI interrupts failed"); 55508057504Sxy150489 goto attach_fail; 55608057504Sxy150489 } 55725f2d433Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 55808057504Sxy150489 559ea6b684aSyy150190 /* 560ea6b684aSyy150190 * If e1000g_force_detach is enabled, in global private dip list, 561ea6b684aSyy150190 * we will create a new entry, which maintains the priv_dip for DR 562ea6b684aSyy150190 * supports after driver detached. 563ea6b684aSyy150190 */ 564ea6b684aSyy150190 if (e1000g_force_detach) { 565ea6b684aSyy150190 private_devi_list_t *devi_node; 566ea6b684aSyy150190 567ea6b684aSyy150190 Adapter->priv_dip = 568ea6b684aSyy150190 kmem_zalloc(sizeof (struct dev_info), KM_SLEEP); 569ea6b684aSyy150190 bcopy(DEVI(devinfo), DEVI(Adapter->priv_dip), 570ea6b684aSyy150190 sizeof (struct dev_info)); 571ea6b684aSyy150190 572ea6b684aSyy150190 devi_node = 573ea6b684aSyy150190 kmem_zalloc(sizeof (private_devi_list_t), KM_SLEEP); 574ea6b684aSyy150190 57554e0d7a5SMiles Xu, Sun Microsystems mutex_enter(&e1000g_rx_detach_lock); 576ea6b684aSyy150190 devi_node->priv_dip = Adapter->priv_dip; 577ea6b684aSyy150190 devi_node->flag = E1000G_PRIV_DEVI_ATTACH; 57854e0d7a5SMiles Xu, Sun Microsystems devi_node->pending_rx_count = 0; 57954e0d7a5SMiles Xu, Sun Microsystems 58054e0d7a5SMiles Xu, Sun Microsystems Adapter->priv_devi_node = devi_node; 58154e0d7a5SMiles Xu, Sun Microsystems 58254e0d7a5SMiles Xu, Sun Microsystems if (e1000g_private_devi_list == NULL) { 58354e0d7a5SMiles Xu, Sun Microsystems devi_node->prev = NULL; 58454e0d7a5SMiles Xu, Sun Microsystems devi_node->next = NULL; 585ea6b684aSyy150190 e1000g_private_devi_list = devi_node; 58654e0d7a5SMiles Xu, Sun Microsystems } else { 58754e0d7a5SMiles Xu, Sun Microsystems devi_node->prev = NULL; 58854e0d7a5SMiles Xu, Sun Microsystems devi_node->next = e1000g_private_devi_list; 58954e0d7a5SMiles Xu, Sun Microsystems e1000g_private_devi_list->prev = devi_node; 59054e0d7a5SMiles Xu, Sun Microsystems e1000g_private_devi_list = devi_node; 59154e0d7a5SMiles Xu, Sun Microsystems } 59254e0d7a5SMiles Xu, Sun Microsystems mutex_exit(&e1000g_rx_detach_lock); 593ea6b684aSyy150190 } 594ea6b684aSyy150190 595d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state = E1000G_INITIALIZED; 59608057504Sxy150489 return (DDI_SUCCESS); 59708057504Sxy150489 59808057504Sxy150489 attach_fail: 59908057504Sxy150489 e1000g_unattach(devinfo, Adapter); 60008057504Sxy150489 return (DDI_FAILURE); 60108057504Sxy150489 } 60208057504Sxy150489 60308057504Sxy150489 static int 60408057504Sxy150489 e1000g_register_mac(struct e1000g *Adapter) 60508057504Sxy150489 { 60625f2d433Sxy150489 struct e1000_hw *hw = &Adapter->shared; 60708057504Sxy150489 mac_register_t *mac; 60808057504Sxy150489 int err; 60908057504Sxy150489 61008057504Sxy150489 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 61108057504Sxy150489 return (DDI_FAILURE); 61225f2d433Sxy150489 61308057504Sxy150489 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 61408057504Sxy150489 mac->m_driver = Adapter; 61508057504Sxy150489 mac->m_dip = Adapter->dip; 61625f2d433Sxy150489 mac->m_src_addr = hw->mac.addr; 61708057504Sxy150489 mac->m_callbacks = &e1000g_m_callbacks; 61808057504Sxy150489 mac->m_min_sdu = 0; 6199ce7e93cScc210113 mac->m_max_sdu = Adapter->default_mtu; 620d62bc4baSyz147064 mac->m_margin = VLAN_TAGSZ; 6214045d941Ssowmini mac->m_priv_props = e1000g_priv_props; 622da14cebeSEric Cheng mac->m_v12n = MAC_VIRT_LEVEL1; 62325f2d433Sxy150489 62408057504Sxy150489 err = mac_register(mac, &Adapter->mh); 62508057504Sxy150489 mac_free(mac); 62625f2d433Sxy150489 62708057504Sxy150489 return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 62808057504Sxy150489 } 62908057504Sxy150489 63008057504Sxy150489 static int 63125f2d433Sxy150489 e1000g_identify_hardware(struct e1000g *Adapter) 63225f2d433Sxy150489 { 63325f2d433Sxy150489 struct e1000_hw *hw = &Adapter->shared; 63425f2d433Sxy150489 struct e1000g_osdep *osdep = &Adapter->osdep; 63525f2d433Sxy150489 63625f2d433Sxy150489 /* Get the device id */ 63725f2d433Sxy150489 hw->vendor_id = 63825f2d433Sxy150489 pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID); 63925f2d433Sxy150489 hw->device_id = 64025f2d433Sxy150489 pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID); 64125f2d433Sxy150489 hw->revision_id = 64225f2d433Sxy150489 pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID); 64325f2d433Sxy150489 hw->subsystem_device_id = 64425f2d433Sxy150489 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID); 64525f2d433Sxy150489 hw->subsystem_vendor_id = 64625f2d433Sxy150489 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID); 64725f2d433Sxy150489 64825f2d433Sxy150489 if (e1000_set_mac_type(hw) != E1000_SUCCESS) { 64925f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 65025f2d433Sxy150489 "MAC type could not be set properly."); 65125f2d433Sxy150489 return (DDI_FAILURE); 65225f2d433Sxy150489 } 65325f2d433Sxy150489 65425f2d433Sxy150489 return (DDI_SUCCESS); 65525f2d433Sxy150489 } 65625f2d433Sxy150489 65725f2d433Sxy150489 static int 65825f2d433Sxy150489 e1000g_regs_map(struct e1000g *Adapter) 65925f2d433Sxy150489 { 66025f2d433Sxy150489 dev_info_t *devinfo = Adapter->dip; 66125f2d433Sxy150489 struct e1000_hw *hw = &Adapter->shared; 66225f2d433Sxy150489 struct e1000g_osdep *osdep = &Adapter->osdep; 66325f2d433Sxy150489 off_t mem_size; 6643f64cd55Sguoqing zhu - Sun Microsystems - Beijing China bar_info_t bar_info; 6653f64cd55Sguoqing zhu - Sun Microsystems - Beijing China int offset, rnumber; 66625f2d433Sxy150489 6673f64cd55Sguoqing zhu - Sun Microsystems - Beijing China rnumber = ADAPTER_REG_SET; 6684d737963Sxiangtao you - Sun Microsystems - Beijing China /* Get size of adapter register memory */ 6693f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (ddi_dev_regsize(devinfo, rnumber, &mem_size) != 6704d737963Sxiangtao you - Sun Microsystems - Beijing China DDI_SUCCESS) { 67125f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 67225f2d433Sxy150489 "ddi_dev_regsize for registers failed"); 67325f2d433Sxy150489 return (DDI_FAILURE); 67425f2d433Sxy150489 } 67525f2d433Sxy150489 6764d737963Sxiangtao you - Sun Microsystems - Beijing China /* Map adapter register memory */ 6773f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if ((ddi_regs_map_setup(devinfo, rnumber, 67825f2d433Sxy150489 (caddr_t *)&hw->hw_addr, 0, mem_size, &e1000g_regs_acc_attr, 67925f2d433Sxy150489 &osdep->reg_handle)) != DDI_SUCCESS) { 68025f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 68125f2d433Sxy150489 "ddi_regs_map_setup for registers failed"); 68225f2d433Sxy150489 goto regs_map_fail; 68325f2d433Sxy150489 } 68425f2d433Sxy150489 68525f2d433Sxy150489 /* ICH needs to map flash memory */ 6863f64cd55Sguoqing zhu - Sun Microsystems - Beijing China switch (hw->mac.type) { 6873f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_ich8lan: 6883f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_ich9lan: 6893f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_ich10lan: 6903f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_pchlan: 691dab7de2dSGarrett D'Amore case e1000_pch2lan: 69275eba5b6SRobert Mustacchi case e1000_pch_lpt: 6933f64cd55Sguoqing zhu - Sun Microsystems - Beijing China rnumber = ICH_FLASH_REG_SET; 6943f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 69525f2d433Sxy150489 /* get flash size */ 6963f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (ddi_dev_regsize(devinfo, rnumber, 69725f2d433Sxy150489 &mem_size) != DDI_SUCCESS) { 69825f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 69925f2d433Sxy150489 "ddi_dev_regsize for ICH flash failed"); 70025f2d433Sxy150489 goto regs_map_fail; 70125f2d433Sxy150489 } 70225f2d433Sxy150489 70325f2d433Sxy150489 /* map flash in */ 7043f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (ddi_regs_map_setup(devinfo, rnumber, 70525f2d433Sxy150489 (caddr_t *)&hw->flash_address, 0, 70625f2d433Sxy150489 mem_size, &e1000g_regs_acc_attr, 70725f2d433Sxy150489 &osdep->ich_flash_handle) != DDI_SUCCESS) { 70825f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 70925f2d433Sxy150489 "ddi_regs_map_setup for ICH flash failed"); 71025f2d433Sxy150489 goto regs_map_fail; 71125f2d433Sxy150489 } 7123f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 71342cc51e0SRobert Mustacchi case e1000_pch_spt: 71442cc51e0SRobert Mustacchi /* 71542cc51e0SRobert Mustacchi * On the SPT, the device flash is actually in BAR0, not a 71642cc51e0SRobert Mustacchi * separate BAR. Therefore we end up setting the 71742cc51e0SRobert Mustacchi * ich_flash_handle to be the same as the register handle. 71842cc51e0SRobert Mustacchi * We mark the same to reduce the confusion in the other 71942cc51e0SRobert Mustacchi * functions and macros. Though this does make the set up and 72042cc51e0SRobert Mustacchi * tear-down path slightly more complicated. 72142cc51e0SRobert Mustacchi */ 72242cc51e0SRobert Mustacchi osdep->ich_flash_handle = osdep->reg_handle; 72342cc51e0SRobert Mustacchi hw->flash_address = hw->hw_addr; 7243f64cd55Sguoqing zhu - Sun Microsystems - Beijing China default: 7253f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 7263f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 7273f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 7283f64cd55Sguoqing zhu - Sun Microsystems - Beijing China /* map io space */ 7293f64cd55Sguoqing zhu - Sun Microsystems - Beijing China switch (hw->mac.type) { 7303f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_82544: 7313f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_82540: 7323f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_82545: 7333f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_82546: 7343f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_82541: 7353f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case e1000_82541_rev_2: 7363f64cd55Sguoqing zhu - Sun Microsystems - Beijing China /* find the IO bar */ 7373f64cd55Sguoqing zhu - Sun Microsystems - Beijing China rnumber = -1; 7383f64cd55Sguoqing zhu - Sun Microsystems - Beijing China for (offset = PCI_CONF_BASE1; 7393f64cd55Sguoqing zhu - Sun Microsystems - Beijing China offset <= PCI_CONF_BASE5; offset += 4) { 7403f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (e1000g_get_bar_info(devinfo, offset, &bar_info) 7413f64cd55Sguoqing zhu - Sun Microsystems - Beijing China != DDI_SUCCESS) 7423f64cd55Sguoqing zhu - Sun Microsystems - Beijing China continue; 7433f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (bar_info.type == E1000G_BAR_IO) { 7443f64cd55Sguoqing zhu - Sun Microsystems - Beijing China rnumber = bar_info.rnumber; 7453f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 7463f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 7473f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 7483f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 7493f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (rnumber < 0) { 7503f64cd55Sguoqing zhu - Sun Microsystems - Beijing China E1000G_DEBUGLOG_0(Adapter, CE_WARN, 7513f64cd55Sguoqing zhu - Sun Microsystems - Beijing China "No io space is found"); 7523f64cd55Sguoqing zhu - Sun Microsystems - Beijing China goto regs_map_fail; 7533f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 7543f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 7553f64cd55Sguoqing zhu - Sun Microsystems - Beijing China /* get io space size */ 7563f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (ddi_dev_regsize(devinfo, rnumber, 7573f64cd55Sguoqing zhu - Sun Microsystems - Beijing China &mem_size) != DDI_SUCCESS) { 7583f64cd55Sguoqing zhu - Sun Microsystems - Beijing China E1000G_DEBUGLOG_0(Adapter, CE_WARN, 7593f64cd55Sguoqing zhu - Sun Microsystems - Beijing China "ddi_dev_regsize for io space failed"); 7603f64cd55Sguoqing zhu - Sun Microsystems - Beijing China goto regs_map_fail; 7613f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 7623f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 7633f64cd55Sguoqing zhu - Sun Microsystems - Beijing China /* map io space */ 7643f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if ((ddi_regs_map_setup(devinfo, rnumber, 7653f64cd55Sguoqing zhu - Sun Microsystems - Beijing China (caddr_t *)&hw->io_base, 0, mem_size, 7663f64cd55Sguoqing zhu - Sun Microsystems - Beijing China &e1000g_regs_acc_attr, 7673f64cd55Sguoqing zhu - Sun Microsystems - Beijing China &osdep->io_reg_handle)) != DDI_SUCCESS) { 7683f64cd55Sguoqing zhu - Sun Microsystems - Beijing China E1000G_DEBUGLOG_0(Adapter, CE_WARN, 7693f64cd55Sguoqing zhu - Sun Microsystems - Beijing China "ddi_regs_map_setup for io space failed"); 7703f64cd55Sguoqing zhu - Sun Microsystems - Beijing China goto regs_map_fail; 7713f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 7723f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 7733f64cd55Sguoqing zhu - Sun Microsystems - Beijing China default: 7743f64cd55Sguoqing zhu - Sun Microsystems - Beijing China hw->io_base = 0; 7753f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 77625f2d433Sxy150489 } 77725f2d433Sxy150489 77825f2d433Sxy150489 return (DDI_SUCCESS); 77925f2d433Sxy150489 78025f2d433Sxy150489 regs_map_fail: 78125f2d433Sxy150489 if (osdep->reg_handle != NULL) 78225f2d433Sxy150489 ddi_regs_map_free(&osdep->reg_handle); 78342cc51e0SRobert Mustacchi if (osdep->ich_flash_handle != NULL && hw->mac.type != e1000_pch_spt) 7843f64cd55Sguoqing zhu - Sun Microsystems - Beijing China ddi_regs_map_free(&osdep->ich_flash_handle); 78525f2d433Sxy150489 return (DDI_FAILURE); 78625f2d433Sxy150489 } 78725f2d433Sxy150489 78825f2d433Sxy150489 static int 78908057504Sxy150489 e1000g_set_driver_params(struct e1000g *Adapter) 79008057504Sxy150489 { 79108057504Sxy150489 struct e1000_hw *hw; 79208057504Sxy150489 79325f2d433Sxy150489 hw = &Adapter->shared; 79408057504Sxy150489 79525f2d433Sxy150489 /* Set MAC type and initialize hardware functions */ 79625f2d433Sxy150489 if (e1000_setup_init_funcs(hw, B_TRUE) != E1000_SUCCESS) { 79725f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 79825f2d433Sxy150489 "Could not setup hardware functions"); 79908057504Sxy150489 return (DDI_FAILURE); 80008057504Sxy150489 } 80108057504Sxy150489 80225f2d433Sxy150489 /* Get bus information */ 80325f2d433Sxy150489 if (e1000_get_bus_info(hw) != E1000_SUCCESS) { 80425f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 80525f2d433Sxy150489 "Could not get bus information"); 80608057504Sxy150489 return (DDI_FAILURE); 80708057504Sxy150489 } 80808057504Sxy150489 80925f2d433Sxy150489 e1000_read_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->bus.pci_cmd_word); 81008057504Sxy150489 81125f2d433Sxy150489 hw->mac.autoneg_failed = B_TRUE; 81225f2d433Sxy150489 813592a4d85Scc210113 /* Set the autoneg_wait_to_complete flag to B_FALSE */ 814592a4d85Scc210113 hw->phy.autoneg_wait_to_complete = B_FALSE; 81508057504Sxy150489 81608057504Sxy150489 /* Adaptive IFS related changes */ 81725f2d433Sxy150489 hw->mac.adaptive_ifs = B_TRUE; 81808057504Sxy150489 81925f2d433Sxy150489 /* Enable phy init script for IGP phy of 82541/82547 */ 82025f2d433Sxy150489 if ((hw->mac.type == e1000_82547) || 82125f2d433Sxy150489 (hw->mac.type == e1000_82541) || 82225f2d433Sxy150489 (hw->mac.type == e1000_82547_rev_2) || 82325f2d433Sxy150489 (hw->mac.type == e1000_82541_rev_2)) 82425f2d433Sxy150489 e1000_init_script_state_82541(hw, B_TRUE); 82508057504Sxy150489 82625f2d433Sxy150489 /* Enable the TTL workaround for 82541/82547 */ 82725f2d433Sxy150489 e1000_set_ttl_workaround_state_82541(hw, B_TRUE); 82808057504Sxy150489 8295633182fSyy150190 #ifdef __sparc 8305633182fSyy150190 Adapter->strip_crc = B_TRUE; 8315633182fSyy150190 #else 8325633182fSyy150190 Adapter->strip_crc = B_FALSE; 8335633182fSyy150190 #endif 8345633182fSyy150190 835caf05df5SMiles Xu, Sun Microsystems /* setup the maximum MTU size of the chip */ 836caf05df5SMiles Xu, Sun Microsystems e1000g_setup_max_mtu(Adapter); 837caf05df5SMiles Xu, Sun Microsystems 83825f2d433Sxy150489 /* Get speed/duplex settings in conf file */ 83925f2d433Sxy150489 hw->mac.forced_speed_duplex = ADVERTISE_100_FULL; 84025f2d433Sxy150489 hw->phy.autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; 84108057504Sxy150489 e1000g_force_speed_duplex(Adapter); 84208057504Sxy150489 84325f2d433Sxy150489 /* Get Jumbo Frames settings in conf file */ 84408057504Sxy150489 e1000g_get_max_frame_size(Adapter); 84508057504Sxy150489 8461bc1c721Sguoqing zhu - Sun Microsystems - Beijing China /* Get conf file properties */ 8471bc1c721Sguoqing zhu - Sun Microsystems - Beijing China e1000g_get_conf(Adapter); 8481bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 849caf05df5SMiles Xu, Sun Microsystems /* enforce PCH limits */ 850caf05df5SMiles Xu, Sun Microsystems e1000g_pch_limits(Adapter); 851caf05df5SMiles Xu, Sun Microsystems 85208057504Sxy150489 /* Set Rx/Tx buffer size */ 8539ce7e93cScc210113 e1000g_set_bufsize(Adapter); 85408057504Sxy150489 85508057504Sxy150489 /* Master Latency Timer */ 85625f2d433Sxy150489 Adapter->master_latency_timer = DEFAULT_MASTER_LATENCY_TIMER; 85708057504Sxy150489 85808057504Sxy150489 /* copper options */ 859592a4d85Scc210113 if (hw->phy.media_type == e1000_media_type_copper) { 86025f2d433Sxy150489 hw->phy.mdix = 0; /* AUTO_ALL_MODES */ 86125f2d433Sxy150489 hw->phy.disable_polarity_correction = B_FALSE; 86225f2d433Sxy150489 hw->phy.ms_type = e1000_ms_hw_default; /* E1000_MASTER_SLAVE */ 86308057504Sxy150489 } 86408057504Sxy150489 86525f2d433Sxy150489 /* The initial link state should be "unknown" */ 8667941757cSxy150489 Adapter->link_state = LINK_STATE_UNKNOWN; 8677941757cSxy150489 86847b7744cSyy150190 /* Initialize rx parameters */ 86947b7744cSyy150190 Adapter->rx_intr_delay = DEFAULT_RX_INTR_DELAY; 87047b7744cSyy150190 Adapter->rx_intr_abs_delay = DEFAULT_RX_INTR_ABS_DELAY; 87147b7744cSyy150190 87225f2d433Sxy150489 /* Initialize tx parameters */ 87325f2d433Sxy150489 Adapter->tx_intr_enable = DEFAULT_TX_INTR_ENABLE; 87425f2d433Sxy150489 Adapter->tx_bcopy_thresh = DEFAULT_TX_BCOPY_THRESHOLD; 87547b7744cSyy150190 Adapter->tx_intr_delay = DEFAULT_TX_INTR_DELAY; 87647b7744cSyy150190 Adapter->tx_intr_abs_delay = DEFAULT_TX_INTR_ABS_DELAY; 87725f2d433Sxy150489 87825f2d433Sxy150489 /* Initialize rx parameters */ 87925f2d433Sxy150489 Adapter->rx_bcopy_thresh = DEFAULT_RX_BCOPY_THRESHOLD; 88025f2d433Sxy150489 88108057504Sxy150489 return (DDI_SUCCESS); 88208057504Sxy150489 } 88308057504Sxy150489 8849ce7e93cScc210113 static void 885caf05df5SMiles Xu, Sun Microsystems e1000g_setup_max_mtu(struct e1000g *Adapter) 886caf05df5SMiles Xu, Sun Microsystems { 887caf05df5SMiles Xu, Sun Microsystems struct e1000_mac_info *mac = &Adapter->shared.mac; 888caf05df5SMiles Xu, Sun Microsystems struct e1000_phy_info *phy = &Adapter->shared.phy; 889caf05df5SMiles Xu, Sun Microsystems 890caf05df5SMiles Xu, Sun Microsystems switch (mac->type) { 891caf05df5SMiles Xu, Sun Microsystems /* types that do not support jumbo frames */ 892caf05df5SMiles Xu, Sun Microsystems case e1000_ich8lan: 893caf05df5SMiles Xu, Sun Microsystems case e1000_82573: 894caf05df5SMiles Xu, Sun Microsystems case e1000_82583: 895caf05df5SMiles Xu, Sun Microsystems Adapter->max_mtu = ETHERMTU; 896caf05df5SMiles Xu, Sun Microsystems break; 897caf05df5SMiles Xu, Sun Microsystems /* ich9 supports jumbo frames except on one phy type */ 898caf05df5SMiles Xu, Sun Microsystems case e1000_ich9lan: 899caf05df5SMiles Xu, Sun Microsystems if (phy->type == e1000_phy_ife) 900caf05df5SMiles Xu, Sun Microsystems Adapter->max_mtu = ETHERMTU; 901caf05df5SMiles Xu, Sun Microsystems else 902caf05df5SMiles Xu, Sun Microsystems Adapter->max_mtu = MAXIMUM_MTU_9K; 903caf05df5SMiles Xu, Sun Microsystems break; 904caf05df5SMiles Xu, Sun Microsystems /* pch can do jumbo frames up to 4K */ 905caf05df5SMiles Xu, Sun Microsystems case e1000_pchlan: 906caf05df5SMiles Xu, Sun Microsystems Adapter->max_mtu = MAXIMUM_MTU_4K; 907caf05df5SMiles Xu, Sun Microsystems break; 908dab7de2dSGarrett D'Amore /* pch2 can do jumbo frames up to 9K */ 909dab7de2dSGarrett D'Amore case e1000_pch2lan: 91075eba5b6SRobert Mustacchi case e1000_pch_lpt: 91142cc51e0SRobert Mustacchi case e1000_pch_spt: 912dab7de2dSGarrett D'Amore Adapter->max_mtu = MAXIMUM_MTU_9K; 913dab7de2dSGarrett D'Amore break; 914caf05df5SMiles Xu, Sun Microsystems /* types with a special limit */ 915caf05df5SMiles Xu, Sun Microsystems case e1000_82571: 916caf05df5SMiles Xu, Sun Microsystems case e1000_82572: 917caf05df5SMiles Xu, Sun Microsystems case e1000_82574: 918caf05df5SMiles Xu, Sun Microsystems case e1000_80003es2lan: 919caf05df5SMiles Xu, Sun Microsystems case e1000_ich10lan: 9203fb4efefSchangqing li - Sun Microsystems - Beijing China if (e1000g_jumbo_mtu >= ETHERMTU && 9213fb4efefSchangqing li - Sun Microsystems - Beijing China e1000g_jumbo_mtu <= MAXIMUM_MTU_9K) { 9223fb4efefSchangqing li - Sun Microsystems - Beijing China Adapter->max_mtu = e1000g_jumbo_mtu; 9233fb4efefSchangqing li - Sun Microsystems - Beijing China } else { 924caf05df5SMiles Xu, Sun Microsystems Adapter->max_mtu = MAXIMUM_MTU_9K; 9253fb4efefSchangqing li - Sun Microsystems - Beijing China } 926caf05df5SMiles Xu, Sun Microsystems break; 927caf05df5SMiles Xu, Sun Microsystems /* default limit is 16K */ 928caf05df5SMiles Xu, Sun Microsystems default: 929caf05df5SMiles Xu, Sun Microsystems Adapter->max_mtu = FRAME_SIZE_UPTO_16K - 9303fb4efefSchangqing li - Sun Microsystems - Beijing China sizeof (struct ether_vlan_header) - ETHERFCSL; 931caf05df5SMiles Xu, Sun Microsystems break; 932caf05df5SMiles Xu, Sun Microsystems } 933caf05df5SMiles Xu, Sun Microsystems } 934caf05df5SMiles Xu, Sun Microsystems 935caf05df5SMiles Xu, Sun Microsystems static void 9369ce7e93cScc210113 e1000g_set_bufsize(struct e1000g *Adapter) 9379ce7e93cScc210113 { 9389ce7e93cScc210113 struct e1000_mac_info *mac = &Adapter->shared.mac; 9399ce7e93cScc210113 uint64_t rx_size; 9409ce7e93cScc210113 uint64_t tx_size; 9419ce7e93cScc210113 9429ce7e93cScc210113 dev_info_t *devinfo = Adapter->dip; 94343a17687SMiles Xu, Sun Microsystems #ifdef __sparc 9449ce7e93cScc210113 ulong_t iommu_pagesize; 94543a17687SMiles Xu, Sun Microsystems #endif 9469ce7e93cScc210113 /* Get the system page size */ 9479ce7e93cScc210113 Adapter->sys_page_sz = ddi_ptob(devinfo, (ulong_t)1); 94843a17687SMiles Xu, Sun Microsystems 94943a17687SMiles Xu, Sun Microsystems #ifdef __sparc 9509ce7e93cScc210113 iommu_pagesize = dvma_pagesize(devinfo); 9519ce7e93cScc210113 if (iommu_pagesize != 0) { 9529ce7e93cScc210113 if (Adapter->sys_page_sz == iommu_pagesize) { 9539ce7e93cScc210113 if (iommu_pagesize > 0x4000) 9549ce7e93cScc210113 Adapter->sys_page_sz = 0x4000; 9559ce7e93cScc210113 } else { 9569ce7e93cScc210113 if (Adapter->sys_page_sz > iommu_pagesize) 9579ce7e93cScc210113 Adapter->sys_page_sz = iommu_pagesize; 9589ce7e93cScc210113 } 9599ce7e93cScc210113 } 960c7770590Smx205022 if (Adapter->lso_enable) { 961c7770590Smx205022 Adapter->dvma_page_num = E1000_LSO_MAXLEN / 962c7770590Smx205022 Adapter->sys_page_sz + E1000G_DEFAULT_DVMA_PAGE_NUM; 963c7770590Smx205022 } else { 964592a4d85Scc210113 Adapter->dvma_page_num = Adapter->max_frame_size / 9659ce7e93cScc210113 Adapter->sys_page_sz + E1000G_DEFAULT_DVMA_PAGE_NUM; 966c7770590Smx205022 } 9679ce7e93cScc210113 ASSERT(Adapter->dvma_page_num >= E1000G_DEFAULT_DVMA_PAGE_NUM); 9689ce7e93cScc210113 #endif 9699ce7e93cScc210113 970592a4d85Scc210113 Adapter->min_frame_size = ETHERMIN + ETHERFCSL; 9719ce7e93cScc210113 9723d15c084Schenlu chen - Sun Microsystems - Beijing China if (Adapter->mem_workaround_82546 && 9733d15c084Schenlu chen - Sun Microsystems - Beijing China ((mac->type == e1000_82545) || 974ede5269eSchenlu chen - Sun Microsystems - Beijing China (mac->type == e1000_82546) || 9753d15c084Schenlu chen - Sun Microsystems - Beijing China (mac->type == e1000_82546_rev_3))) { 9763fb4efefSchangqing li - Sun Microsystems - Beijing China Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_2K; 977ede5269eSchenlu chen - Sun Microsystems - Beijing China } else { 9783fb4efefSchangqing li - Sun Microsystems - Beijing China rx_size = Adapter->max_frame_size; 979ede5269eSchenlu chen - Sun Microsystems - Beijing China if ((rx_size > FRAME_SIZE_UPTO_2K) && 980ede5269eSchenlu chen - Sun Microsystems - Beijing China (rx_size <= FRAME_SIZE_UPTO_4K)) 9819ce7e93cScc210113 Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_4K; 9829ce7e93cScc210113 else if ((rx_size > FRAME_SIZE_UPTO_4K) && 9839ce7e93cScc210113 (rx_size <= FRAME_SIZE_UPTO_8K)) 9849ce7e93cScc210113 Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_8K; 9859ce7e93cScc210113 else if ((rx_size > FRAME_SIZE_UPTO_8K) && 9869ce7e93cScc210113 (rx_size <= FRAME_SIZE_UPTO_16K)) 9879ce7e93cScc210113 Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_16K; 9889ce7e93cScc210113 else 9899ce7e93cScc210113 Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_2K; 990ede5269eSchenlu chen - Sun Microsystems - Beijing China } 9913fb4efefSchangqing li - Sun Microsystems - Beijing China Adapter->rx_buffer_size += E1000G_IPALIGNROOM; 9929ce7e93cScc210113 993592a4d85Scc210113 tx_size = Adapter->max_frame_size; 9949ce7e93cScc210113 if ((tx_size > FRAME_SIZE_UPTO_2K) && (tx_size <= FRAME_SIZE_UPTO_4K)) 9959ce7e93cScc210113 Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_4K; 9969ce7e93cScc210113 else if ((tx_size > FRAME_SIZE_UPTO_4K) && 9979ce7e93cScc210113 (tx_size <= FRAME_SIZE_UPTO_8K)) 9989ce7e93cScc210113 Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_8K; 9999ce7e93cScc210113 else if ((tx_size > FRAME_SIZE_UPTO_8K) && 10009ce7e93cScc210113 (tx_size <= FRAME_SIZE_UPTO_16K)) 10019ce7e93cScc210113 Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_16K; 10029ce7e93cScc210113 else 10039ce7e93cScc210113 Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_2K; 10049ce7e93cScc210113 10059ce7e93cScc210113 /* 10069ce7e93cScc210113 * For Wiseman adapters we have an requirement of having receive 10079ce7e93cScc210113 * buffers aligned at 256 byte boundary. Since Livengood does not 10089ce7e93cScc210113 * require this and forcing it for all hardwares will have 10099ce7e93cScc210113 * performance implications, I am making it applicable only for 10109ce7e93cScc210113 * Wiseman and for Jumbo frames enabled mode as rest of the time, 10119ce7e93cScc210113 * it is okay to have normal frames...but it does involve a 10129ce7e93cScc210113 * potential risk where we may loose data if buffer is not 10139ce7e93cScc210113 * aligned...so all wiseman boards to have 256 byte aligned 10149ce7e93cScc210113 * buffers 10159ce7e93cScc210113 */ 10169ce7e93cScc210113 if (mac->type < e1000_82543) 10179ce7e93cScc210113 Adapter->rx_buf_align = RECEIVE_BUFFER_ALIGN_SIZE; 10189ce7e93cScc210113 else 10199ce7e93cScc210113 Adapter->rx_buf_align = 1; 10209ce7e93cScc210113 } 10219ce7e93cScc210113 102208057504Sxy150489 /* 102325f2d433Sxy150489 * e1000g_detach - driver detach 102425f2d433Sxy150489 * 102525f2d433Sxy150489 * The detach() function is the complement of the attach routine. 102625f2d433Sxy150489 * If cmd is set to DDI_DETACH, detach() is used to remove the 102725f2d433Sxy150489 * state associated with a given instance of a device node 102825f2d433Sxy150489 * prior to the removal of that instance from the system. 102925f2d433Sxy150489 * 103025f2d433Sxy150489 * The detach() function will be called once for each instance 103125f2d433Sxy150489 * of the device for which there has been a successful attach() 103225f2d433Sxy150489 * once there are no longer any opens on the device. 103325f2d433Sxy150489 * 103425f2d433Sxy150489 * Interrupts routine are disabled, All memory allocated by this 103525f2d433Sxy150489 * driver are freed. 103608057504Sxy150489 */ 103708057504Sxy150489 static int 103825f2d433Sxy150489 e1000g_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 103908057504Sxy150489 { 104008057504Sxy150489 struct e1000g *Adapter; 1041ea6b684aSyy150190 boolean_t rx_drain; 104208057504Sxy150489 104308057504Sxy150489 switch (cmd) { 104408057504Sxy150489 default: 104508057504Sxy150489 return (DDI_FAILURE); 104608057504Sxy150489 104708057504Sxy150489 case DDI_SUSPEND: 104808057504Sxy150489 return (e1000g_suspend(devinfo)); 104908057504Sxy150489 105008057504Sxy150489 case DDI_DETACH: 105108057504Sxy150489 break; 105208057504Sxy150489 } 105308057504Sxy150489 105408057504Sxy150489 Adapter = (struct e1000g *)ddi_get_driver_private(devinfo); 105508057504Sxy150489 if (Adapter == NULL) 105608057504Sxy150489 return (DDI_FAILURE); 105708057504Sxy150489 1058da14cebeSEric Cheng rx_drain = e1000g_rx_drain(Adapter); 1059da14cebeSEric Cheng if (!rx_drain && !e1000g_force_detach) 1060da14cebeSEric Cheng return (DDI_FAILURE); 1061da14cebeSEric Cheng 106225f2d433Sxy150489 if (mac_unregister(Adapter->mh) != 0) { 106325f2d433Sxy150489 e1000g_log(Adapter, CE_WARN, "Unregister MAC failed"); 106425f2d433Sxy150489 return (DDI_FAILURE); 106525f2d433Sxy150489 } 106625f2d433Sxy150489 Adapter->attach_progress &= ~ATTACH_PROGRESS_MAC; 106725f2d433Sxy150489 1068d5c3073dSchenlu chen - Sun Microsystems - Beijing China ASSERT(!(Adapter->e1000g_state & E1000G_STARTED)); 1069ea6b684aSyy150190 107054e0d7a5SMiles Xu, Sun Microsystems if (!e1000g_force_detach && !rx_drain) 107154e0d7a5SMiles Xu, Sun Microsystems return (DDI_FAILURE); 107208057504Sxy150489 107308057504Sxy150489 e1000g_unattach(devinfo, Adapter); 107408057504Sxy150489 107508057504Sxy150489 return (DDI_SUCCESS); 107608057504Sxy150489 } 107708057504Sxy150489 1078ea6b684aSyy150190 /* 1079ea6b684aSyy150190 * e1000g_free_priv_devi_node - free a priv_dip entry for driver instance 1080ea6b684aSyy150190 */ 108154e0d7a5SMiles Xu, Sun Microsystems void 108254e0d7a5SMiles Xu, Sun Microsystems e1000g_free_priv_devi_node(private_devi_list_t *devi_node) 1083ea6b684aSyy150190 { 1084ea6b684aSyy150190 ASSERT(e1000g_private_devi_list != NULL); 108554e0d7a5SMiles Xu, Sun Microsystems ASSERT(devi_node != NULL); 1086ea6b684aSyy150190 108754e0d7a5SMiles Xu, Sun Microsystems if (devi_node->prev != NULL) 108854e0d7a5SMiles Xu, Sun Microsystems devi_node->prev->next = devi_node->next; 108954e0d7a5SMiles Xu, Sun Microsystems if (devi_node->next != NULL) 109054e0d7a5SMiles Xu, Sun Microsystems devi_node->next->prev = devi_node->prev; 109154e0d7a5SMiles Xu, Sun Microsystems if (devi_node == e1000g_private_devi_list) 109254e0d7a5SMiles Xu, Sun Microsystems e1000g_private_devi_list = devi_node->next; 109354e0d7a5SMiles Xu, Sun Microsystems 1094ea6b684aSyy150190 kmem_free(devi_node->priv_dip, 1095ea6b684aSyy150190 sizeof (struct dev_info)); 1096ea6b684aSyy150190 kmem_free(devi_node, 1097ea6b684aSyy150190 sizeof (private_devi_list_t)); 1098ea6b684aSyy150190 } 1099ea6b684aSyy150190 110008057504Sxy150489 static void 110108057504Sxy150489 e1000g_unattach(dev_info_t *devinfo, struct e1000g *Adapter) 110208057504Sxy150489 { 110354e0d7a5SMiles Xu, Sun Microsystems private_devi_list_t *devi_node; 1104a2e9a830Scc210113 int result; 1105a2e9a830Scc210113 1106*b142f83dSRobert Mustacchi if (Adapter->e1000g_blink != NULL) { 1107*b142f83dSRobert Mustacchi ddi_periodic_delete(Adapter->e1000g_blink); 1108*b142f83dSRobert Mustacchi Adapter->e1000g_blink = NULL; 1109*b142f83dSRobert Mustacchi } 1110*b142f83dSRobert Mustacchi 111125f2d433Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 111208057504Sxy150489 (void) e1000g_disable_intrs(Adapter); 111308057504Sxy150489 } 111408057504Sxy150489 111525f2d433Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_MAC) { 111608057504Sxy150489 (void) mac_unregister(Adapter->mh); 111708057504Sxy150489 } 111808057504Sxy150489 111925f2d433Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 112008057504Sxy150489 (void) e1000g_rem_intrs(Adapter); 112108057504Sxy150489 } 112208057504Sxy150489 112325f2d433Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_SETUP) { 112408057504Sxy150489 (void) ddi_prop_remove_all(devinfo); 112508057504Sxy150489 } 112608057504Sxy150489 112708057504Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_KSTATS) { 112808057504Sxy150489 kstat_delete((kstat_t *)Adapter->e1000g_ksp); 112908057504Sxy150489 } 113008057504Sxy150489 113108057504Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_INIT) { 113225f2d433Sxy150489 stop_link_timer(Adapter); 1133a2e9a830Scc210113 1134a2e9a830Scc210113 mutex_enter(&e1000g_nvm_lock); 1135a2e9a830Scc210113 result = e1000_reset_hw(&Adapter->shared); 1136a2e9a830Scc210113 mutex_exit(&e1000g_nvm_lock); 1137a2e9a830Scc210113 1138a2e9a830Scc210113 if (result != E1000_SUCCESS) { 11399b6541b3Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 11409b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 11419b6541b3Sgl147354 } 114208057504Sxy150489 } 114308057504Sxy150489 11440c56b8d9Schangqing li - Sun Microsystems - Beijing China e1000g_release_multicast(Adapter); 11450c56b8d9Schangqing li - Sun Microsystems - Beijing China 114625f2d433Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_REGS_MAP) { 114725f2d433Sxy150489 if (Adapter->osdep.reg_handle != NULL) 114825f2d433Sxy150489 ddi_regs_map_free(&Adapter->osdep.reg_handle); 114942cc51e0SRobert Mustacchi if (Adapter->osdep.ich_flash_handle != NULL && 115042cc51e0SRobert Mustacchi Adapter->shared.mac.type != e1000_pch_spt) 115125f2d433Sxy150489 ddi_regs_map_free(&Adapter->osdep.ich_flash_handle); 11523f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->osdep.io_reg_handle != NULL) 11533f64cd55Sguoqing zhu - Sun Microsystems - Beijing China ddi_regs_map_free(&Adapter->osdep.io_reg_handle); 115408057504Sxy150489 } 115508057504Sxy150489 115625f2d433Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) { 115725f2d433Sxy150489 if (Adapter->osdep.cfg_handle != NULL) 115825f2d433Sxy150489 pci_config_teardown(&Adapter->osdep.cfg_handle); 115908057504Sxy150489 } 116008057504Sxy150489 116108057504Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_LOCKS) { 116208057504Sxy150489 e1000g_destroy_locks(Adapter); 116308057504Sxy150489 } 116408057504Sxy150489 11659b6541b3Sgl147354 if (Adapter->attach_progress & ATTACH_PROGRESS_FMINIT) { 11669b6541b3Sgl147354 e1000g_fm_fini(Adapter); 11679b6541b3Sgl147354 } 11689b6541b3Sgl147354 116954e0d7a5SMiles Xu, Sun Microsystems mutex_enter(&e1000g_rx_detach_lock); 1170cb5cd232SMiles Xu, Sun Microsystems if (e1000g_force_detach && (Adapter->priv_devi_node != NULL)) { 117154e0d7a5SMiles Xu, Sun Microsystems devi_node = Adapter->priv_devi_node; 117254e0d7a5SMiles Xu, Sun Microsystems devi_node->flag |= E1000G_PRIV_DEVI_DETACH; 117354e0d7a5SMiles Xu, Sun Microsystems 117454e0d7a5SMiles Xu, Sun Microsystems if (devi_node->pending_rx_count == 0) { 117554e0d7a5SMiles Xu, Sun Microsystems e1000g_free_priv_devi_node(devi_node); 117654e0d7a5SMiles Xu, Sun Microsystems } 117754e0d7a5SMiles Xu, Sun Microsystems } 117854e0d7a5SMiles Xu, Sun Microsystems mutex_exit(&e1000g_rx_detach_lock); 117954e0d7a5SMiles Xu, Sun Microsystems 118008057504Sxy150489 kmem_free((caddr_t)Adapter, sizeof (struct e1000g)); 118108057504Sxy150489 118208057504Sxy150489 /* 118308057504Sxy150489 * Another hotplug spec requirement, 118408057504Sxy150489 * run ddi_set_driver_private(devinfo, null); 118508057504Sxy150489 */ 118608057504Sxy150489 ddi_set_driver_private(devinfo, NULL); 118708057504Sxy150489 } 118808057504Sxy150489 11893f64cd55Sguoqing zhu - Sun Microsystems - Beijing China /* 11903f64cd55Sguoqing zhu - Sun Microsystems - Beijing China * Get the BAR type and rnumber for a given PCI BAR offset 11913f64cd55Sguoqing zhu - Sun Microsystems - Beijing China */ 11923f64cd55Sguoqing zhu - Sun Microsystems - Beijing China static int 11933f64cd55Sguoqing zhu - Sun Microsystems - Beijing China e1000g_get_bar_info(dev_info_t *dip, int bar_offset, bar_info_t *bar_info) 11943f64cd55Sguoqing zhu - Sun Microsystems - Beijing China { 11953f64cd55Sguoqing zhu - Sun Microsystems - Beijing China pci_regspec_t *regs; 11963f64cd55Sguoqing zhu - Sun Microsystems - Beijing China uint_t regs_length; 119772d5682dSGuoqing Zhu int type, rnumber, rcount; 11983f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 11993f64cd55Sguoqing zhu - Sun Microsystems - Beijing China ASSERT((bar_offset >= PCI_CONF_BASE0) && 12003f64cd55Sguoqing zhu - Sun Microsystems - Beijing China (bar_offset <= PCI_CONF_BASE5)); 12013f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 12023f64cd55Sguoqing zhu - Sun Microsystems - Beijing China /* 12033f64cd55Sguoqing zhu - Sun Microsystems - Beijing China * Get the DDI "reg" property 12043f64cd55Sguoqing zhu - Sun Microsystems - Beijing China */ 12053f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 12063f64cd55Sguoqing zhu - Sun Microsystems - Beijing China DDI_PROP_DONTPASS, "reg", (int **)®s, 12073f64cd55Sguoqing zhu - Sun Microsystems - Beijing China ®s_length) != DDI_PROP_SUCCESS) { 12083f64cd55Sguoqing zhu - Sun Microsystems - Beijing China return (DDI_FAILURE); 12093f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 12103f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 121172d5682dSGuoqing Zhu rcount = regs_length * sizeof (int) / sizeof (pci_regspec_t); 12123f64cd55Sguoqing zhu - Sun Microsystems - Beijing China /* 12133f64cd55Sguoqing zhu - Sun Microsystems - Beijing China * Check the BAR offset 12143f64cd55Sguoqing zhu - Sun Microsystems - Beijing China */ 121572d5682dSGuoqing Zhu for (rnumber = 0; rnumber < rcount; ++rnumber) { 12163f64cd55Sguoqing zhu - Sun Microsystems - Beijing China if (PCI_REG_REG_G(regs[rnumber].pci_phys_hi) == bar_offset) { 12173f64cd55Sguoqing zhu - Sun Microsystems - Beijing China type = regs[rnumber].pci_phys_hi & PCI_ADDR_MASK; 12183f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 12193f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 12203f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 12213f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 12223f64cd55Sguoqing zhu - Sun Microsystems - Beijing China ddi_prop_free(regs); 12233f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 122472d5682dSGuoqing Zhu if (rnumber >= rcount) 12253f64cd55Sguoqing zhu - Sun Microsystems - Beijing China return (DDI_FAILURE); 12263f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 12273f64cd55Sguoqing zhu - Sun Microsystems - Beijing China switch (type) { 12283f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case PCI_ADDR_CONFIG: 12293f64cd55Sguoqing zhu - Sun Microsystems - Beijing China bar_info->type = E1000G_BAR_CONFIG; 12303f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 12313f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case PCI_ADDR_IO: 12323f64cd55Sguoqing zhu - Sun Microsystems - Beijing China bar_info->type = E1000G_BAR_IO; 12333f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 12343f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case PCI_ADDR_MEM32: 12353f64cd55Sguoqing zhu - Sun Microsystems - Beijing China bar_info->type = E1000G_BAR_MEM32; 12363f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 12373f64cd55Sguoqing zhu - Sun Microsystems - Beijing China case PCI_ADDR_MEM64: 12383f64cd55Sguoqing zhu - Sun Microsystems - Beijing China bar_info->type = E1000G_BAR_MEM64; 12393f64cd55Sguoqing zhu - Sun Microsystems - Beijing China break; 12403f64cd55Sguoqing zhu - Sun Microsystems - Beijing China default: 12413f64cd55Sguoqing zhu - Sun Microsystems - Beijing China return (DDI_FAILURE); 12423f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 12433f64cd55Sguoqing zhu - Sun Microsystems - Beijing China bar_info->rnumber = rnumber; 12443f64cd55Sguoqing zhu - Sun Microsystems - Beijing China return (DDI_SUCCESS); 12453f64cd55Sguoqing zhu - Sun Microsystems - Beijing China } 12463f64cd55Sguoqing zhu - Sun Microsystems - Beijing China 124708057504Sxy150489 static void 124808057504Sxy150489 e1000g_init_locks(struct e1000g *Adapter) 124908057504Sxy150489 { 125008057504Sxy150489 e1000g_tx_ring_t *tx_ring; 125108057504Sxy150489 e1000g_rx_ring_t *rx_ring; 125208057504Sxy150489 125308057504Sxy150489 rw_init(&Adapter->chip_lock, NULL, 125408057504Sxy150489 RW_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 125525f2d433Sxy150489 mutex_init(&Adapter->link_lock, NULL, 125608057504Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 125725f2d433Sxy150489 mutex_init(&Adapter->watchdog_lock, NULL, 125808057504Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 125908057504Sxy150489 126008057504Sxy150489 tx_ring = Adapter->tx_ring; 126108057504Sxy150489 126208057504Sxy150489 mutex_init(&tx_ring->tx_lock, NULL, 126308057504Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 126408057504Sxy150489 mutex_init(&tx_ring->usedlist_lock, NULL, 126508057504Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 126608057504Sxy150489 mutex_init(&tx_ring->freelist_lock, NULL, 126708057504Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 126808057504Sxy150489 126908057504Sxy150489 rx_ring = Adapter->rx_ring; 127008057504Sxy150489 1271b61028f6Sxiangtao you - Sun Microsystems - Beijing China mutex_init(&rx_ring->rx_lock, NULL, 1272b61028f6Sxiangtao you - Sun Microsystems - Beijing China MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 1273*b142f83dSRobert Mustacchi 1274*b142f83dSRobert Mustacchi mutex_init(&Adapter->e1000g_led_lock, NULL, 1275*b142f83dSRobert Mustacchi MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 127608057504Sxy150489 } 127708057504Sxy150489 127808057504Sxy150489 static void 127908057504Sxy150489 e1000g_destroy_locks(struct e1000g *Adapter) 128008057504Sxy150489 { 128108057504Sxy150489 e1000g_tx_ring_t *tx_ring; 128208057504Sxy150489 e1000g_rx_ring_t *rx_ring; 128308057504Sxy150489 1284*b142f83dSRobert Mustacchi mutex_destroy(&Adapter->e1000g_led_lock); 1285*b142f83dSRobert Mustacchi 128608057504Sxy150489 tx_ring = Adapter->tx_ring; 128708057504Sxy150489 mutex_destroy(&tx_ring->tx_lock); 128808057504Sxy150489 mutex_destroy(&tx_ring->usedlist_lock); 128908057504Sxy150489 mutex_destroy(&tx_ring->freelist_lock); 129008057504Sxy150489 129108057504Sxy150489 rx_ring = Adapter->rx_ring; 1292b61028f6Sxiangtao you - Sun Microsystems - Beijing China mutex_destroy(&rx_ring->rx_lock); 129308057504Sxy150489 129425f2d433Sxy150489 mutex_destroy(&Adapter->link_lock); 129525f2d433Sxy150489 mutex_destroy(&Adapter->watchdog_lock); 129608057504Sxy150489 rw_destroy(&Adapter->chip_lock); 1297caf05df5SMiles Xu, Sun Microsystems 1298caf05df5SMiles Xu, Sun Microsystems /* destory mutex initialized in shared code */ 1299caf05df5SMiles Xu, Sun Microsystems e1000_destroy_hw_mutex(&Adapter->shared); 130008057504Sxy150489 } 130108057504Sxy150489 130208057504Sxy150489 static int 130308057504Sxy150489 e1000g_resume(dev_info_t *devinfo) 130408057504Sxy150489 { 130508057504Sxy150489 struct e1000g *Adapter; 130608057504Sxy150489 130708057504Sxy150489 Adapter = (struct e1000g *)ddi_get_driver_private(devinfo); 130808057504Sxy150489 if (Adapter == NULL) 1309d5c3073dSchenlu chen - Sun Microsystems - Beijing China e1000g_log(Adapter, CE_PANIC, 1310d5c3073dSchenlu chen - Sun Microsystems - Beijing China "Instance pointer is null\n"); 131108057504Sxy150489 1312d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->dip != devinfo) 1313d5c3073dSchenlu chen - Sun Microsystems - Beijing China e1000g_log(Adapter, CE_PANIC, 1314d5c3073dSchenlu chen - Sun Microsystems - Beijing China "Devinfo is not the same as saved devinfo\n"); 1315d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1316d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 1317d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1318d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_STARTED) { 1319d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (e1000g_start(Adapter, B_FALSE) != DDI_SUCCESS) { 1320d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 1321d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* 1322d5c3073dSchenlu chen - Sun Microsystems - Beijing China * We note the failure, but return success, as the 1323d5c3073dSchenlu chen - Sun Microsystems - Beijing China * system is still usable without this controller. 1324d5c3073dSchenlu chen - Sun Microsystems - Beijing China */ 1325d5c3073dSchenlu chen - Sun Microsystems - Beijing China e1000g_log(Adapter, CE_WARN, 1326d5c3073dSchenlu chen - Sun Microsystems - Beijing China "e1000g_resume: failed to restart controller\n"); 1327d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (DDI_SUCCESS); 1328d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 1329d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Enable and start the watchdog timer */ 1330d5c3073dSchenlu chen - Sun Microsystems - Beijing China enable_watchdog_timer(Adapter); 1331d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 1332d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1333d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state &= ~E1000G_SUSPENDED; 1334d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1335d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 133608057504Sxy150489 133708057504Sxy150489 return (DDI_SUCCESS); 133808057504Sxy150489 } 133908057504Sxy150489 134008057504Sxy150489 static int 134108057504Sxy150489 e1000g_suspend(dev_info_t *devinfo) 134208057504Sxy150489 { 134308057504Sxy150489 struct e1000g *Adapter; 134408057504Sxy150489 134508057504Sxy150489 Adapter = (struct e1000g *)ddi_get_driver_private(devinfo); 134608057504Sxy150489 if (Adapter == NULL) 134708057504Sxy150489 return (DDI_FAILURE); 134808057504Sxy150489 1349d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 1350d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1351d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state |= E1000G_SUSPENDED; 1352d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1353d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* if the port isn't plumbed, we can simply return */ 1354d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (!(Adapter->e1000g_state & E1000G_STARTED)) { 1355d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 1356d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (DDI_SUCCESS); 1357d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 1358d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1359d5c3073dSchenlu chen - Sun Microsystems - Beijing China e1000g_stop(Adapter, B_FALSE); 1360d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1361d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 1362d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1363d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Disable and stop all the timers */ 1364d5c3073dSchenlu chen - Sun Microsystems - Beijing China disable_watchdog_timer(Adapter); 1365d5c3073dSchenlu chen - Sun Microsystems - Beijing China stop_link_timer(Adapter); 1366d5c3073dSchenlu chen - Sun Microsystems - Beijing China stop_82547_timer(Adapter->tx_ring); 136708057504Sxy150489 136808057504Sxy150489 return (DDI_SUCCESS); 136908057504Sxy150489 } 137008057504Sxy150489 137108057504Sxy150489 static int 137208057504Sxy150489 e1000g_init(struct e1000g *Adapter) 137308057504Sxy150489 { 137408057504Sxy150489 uint32_t pba; 137525f2d433Sxy150489 uint32_t high_water; 137608057504Sxy150489 struct e1000_hw *hw; 13777941757cSxy150489 clock_t link_timeout; 1378a2e9a830Scc210113 int result; 137908057504Sxy150489 138025f2d433Sxy150489 hw = &Adapter->shared; 138108057504Sxy150489 138208057504Sxy150489 /* 138308057504Sxy150489 * reset to put the hardware in a known state 138408057504Sxy150489 * before we try to do anything with the eeprom 138508057504Sxy150489 */ 1386a2e9a830Scc210113 mutex_enter(&e1000g_nvm_lock); 1387a2e9a830Scc210113 result = e1000_reset_hw(hw); 1388a2e9a830Scc210113 mutex_exit(&e1000g_nvm_lock); 1389a2e9a830Scc210113 1390a2e9a830Scc210113 if (result != E1000_SUCCESS) { 13919b6541b3Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 13929b6541b3Sgl147354 goto init_fail; 13939b6541b3Sgl147354 } 139408057504Sxy150489 1395a2e9a830Scc210113 mutex_enter(&e1000g_nvm_lock); 1396a2e9a830Scc210113 result = e1000_validate_nvm_checksum(hw); 1397a2e9a830Scc210113 if (result < E1000_SUCCESS) { 13987941757cSxy150489 /* 13997941757cSxy150489 * Some PCI-E parts fail the first check due to 14007941757cSxy150489 * the link being in sleep state. Call it again, 14017941757cSxy150489 * if it fails a second time its a real issue. 14027941757cSxy150489 */ 1403a2e9a830Scc210113 result = e1000_validate_nvm_checksum(hw); 1404a2e9a830Scc210113 } 1405a2e9a830Scc210113 mutex_exit(&e1000g_nvm_lock); 1406a2e9a830Scc210113 1407a2e9a830Scc210113 if (result < E1000_SUCCESS) { 14087941757cSxy150489 e1000g_log(Adapter, CE_WARN, 140925f2d433Sxy150489 "Invalid NVM checksum. Please contact " 141025f2d433Sxy150489 "the vendor to update the NVM."); 14119b6541b3Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 141208057504Sxy150489 goto init_fail; 141308057504Sxy150489 } 141408057504Sxy150489 1415a2e9a830Scc210113 result = 0; 141608057504Sxy150489 #ifdef __sparc 141708057504Sxy150489 /* 14184d737963Sxiangtao you - Sun Microsystems - Beijing China * First, we try to get the local ethernet address from OBP. If 1419a2e9a830Scc210113 * failed, then we get it from the EEPROM of NIC card. 142008057504Sxy150489 */ 1421a2e9a830Scc210113 result = e1000g_find_mac_address(Adapter); 142208057504Sxy150489 #endif 1423a2e9a830Scc210113 /* Get the local ethernet address. */ 1424a2e9a830Scc210113 if (!result) { 1425a2e9a830Scc210113 mutex_enter(&e1000g_nvm_lock); 142635ae85e6Scc210113 result = e1000_read_mac_addr(hw); 1427a2e9a830Scc210113 mutex_exit(&e1000g_nvm_lock); 1428a2e9a830Scc210113 } 1429a2e9a830Scc210113 1430a2e9a830Scc210113 if (result < E1000_SUCCESS) { 1431a2e9a830Scc210113 e1000g_log(Adapter, CE_WARN, "Read mac addr failed"); 1432a2e9a830Scc210113 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 1433a2e9a830Scc210113 goto init_fail; 1434a2e9a830Scc210113 } 143508057504Sxy150489 143608057504Sxy150489 /* check for valid mac address */ 143725f2d433Sxy150489 if (!is_valid_mac_addr(hw->mac.addr)) { 143808057504Sxy150489 e1000g_log(Adapter, CE_WARN, "Invalid mac addr"); 14399b6541b3Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 144008057504Sxy150489 goto init_fail; 144108057504Sxy150489 } 144208057504Sxy150489 144325f2d433Sxy150489 /* Set LAA state for 82571 chipset */ 144425f2d433Sxy150489 e1000_set_laa_state_82571(hw, B_TRUE); 144508057504Sxy150489 144608057504Sxy150489 /* Master Latency Timer implementation */ 144725f2d433Sxy150489 if (Adapter->master_latency_timer) { 144825f2d433Sxy150489 pci_config_put8(Adapter->osdep.cfg_handle, 144925f2d433Sxy150489 PCI_CONF_LATENCY_TIMER, Adapter->master_latency_timer); 145008057504Sxy150489 } 145108057504Sxy150489 145225f2d433Sxy150489 if (hw->mac.type < e1000_82547) { 145308057504Sxy150489 /* 145408057504Sxy150489 * Total FIFO is 64K 145508057504Sxy150489 */ 1456592a4d85Scc210113 if (Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) 145708057504Sxy150489 pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */ 145808057504Sxy150489 else 145908057504Sxy150489 pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */ 146035ae85e6Scc210113 } else if ((hw->mac.type == e1000_82571) || 146135ae85e6Scc210113 (hw->mac.type == e1000_82572) || 146235ae85e6Scc210113 (hw->mac.type == e1000_80003es2lan)) { 146308057504Sxy150489 /* 146408057504Sxy150489 * Total FIFO is 48K 146508057504Sxy150489 */ 1466592a4d85Scc210113 if (Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) 146708057504Sxy150489 pba = E1000_PBA_30K; /* 30K for Rx, 18K for Tx */ 146808057504Sxy150489 else 146908057504Sxy150489 pba = E1000_PBA_38K; /* 38K for Rx, 10K for Tx */ 14704d737963Sxiangtao you - Sun Microsystems - Beijing China } else if (hw->mac.type == e1000_82573) { 14714d737963Sxiangtao you - Sun Microsystems - Beijing China pba = E1000_PBA_20K; /* 20K for Rx, 12K for Tx */ 14724d737963Sxiangtao you - Sun Microsystems - Beijing China } else if (hw->mac.type == e1000_82574) { 14734d737963Sxiangtao you - Sun Microsystems - Beijing China /* Keep adapter default: 20K for Rx, 20K for Tx */ 14744d737963Sxiangtao you - Sun Microsystems - Beijing China pba = E1000_READ_REG(hw, E1000_PBA); 147525f2d433Sxy150489 } else if (hw->mac.type == e1000_ich8lan) { 147608057504Sxy150489 pba = E1000_PBA_8K; /* 8K for Rx, 12K for Tx */ 147725f2d433Sxy150489 } else if (hw->mac.type == e1000_ich9lan) { 14784d737963Sxiangtao you - Sun Microsystems - Beijing China pba = E1000_PBA_10K; 14794d737963Sxiangtao you - Sun Microsystems - Beijing China } else if (hw->mac.type == e1000_ich10lan) { 14804d737963Sxiangtao you - Sun Microsystems - Beijing China pba = E1000_PBA_10K; 1481caf05df5SMiles Xu, Sun Microsystems } else if (hw->mac.type == e1000_pchlan) { 1482caf05df5SMiles Xu, Sun Microsystems pba = E1000_PBA_26K; 1483dab7de2dSGarrett D'Amore } else if (hw->mac.type == e1000_pch2lan) { 1484dab7de2dSGarrett D'Amore pba = E1000_PBA_26K; 148575eba5b6SRobert Mustacchi } else if (hw->mac.type == e1000_pch_lpt) { 148675eba5b6SRobert Mustacchi pba = E1000_PBA_26K; 148742cc51e0SRobert Mustacchi } else if (hw->mac.type == e1000_pch_spt) { 148842cc51e0SRobert Mustacchi pba = E1000_PBA_26K; 148908057504Sxy150489 } else { 149008057504Sxy150489 /* 149108057504Sxy150489 * Total FIFO is 40K 149208057504Sxy150489 */ 1493592a4d85Scc210113 if (Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) 149408057504Sxy150489 pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */ 149508057504Sxy150489 else 149608057504Sxy150489 pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */ 149708057504Sxy150489 } 149825f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_PBA, pba); 149908057504Sxy150489 150008057504Sxy150489 /* 150108057504Sxy150489 * These parameters set thresholds for the adapter's generation(Tx) 150208057504Sxy150489 * and response(Rx) to Ethernet PAUSE frames. These are just threshold 150308057504Sxy150489 * settings. Flow control is enabled or disabled in the configuration 150408057504Sxy150489 * file. 150508057504Sxy150489 * High-water mark is set down from the top of the rx fifo (not 150608057504Sxy150489 * sensitive to max_frame_size) and low-water is set just below 150708057504Sxy150489 * high-water mark. 150825f2d433Sxy150489 * The high water mark must be low enough to fit one full frame above 150925f2d433Sxy150489 * it in the rx FIFO. Should be the lower of: 151025f2d433Sxy150489 * 90% of the Rx FIFO size and the full Rx FIFO size minus the early 151125f2d433Sxy150489 * receive size (assuming ERT set to E1000_ERT_2048), or the full 151225f2d433Sxy150489 * Rx FIFO size minus one full frame. 151308057504Sxy150489 */ 151425f2d433Sxy150489 high_water = min(((pba << 10) * 9 / 10), 1515d5c3073dSchenlu chen - Sun Microsystems - Beijing China ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574 || 1516d5c3073dSchenlu chen - Sun Microsystems - Beijing China hw->mac.type == e1000_ich9lan || hw->mac.type == e1000_ich10lan) ? 151725f2d433Sxy150489 ((pba << 10) - (E1000_ERT_2048 << 3)) : 1518592a4d85Scc210113 ((pba << 10) - Adapter->max_frame_size))); 151925f2d433Sxy150489 1520592a4d85Scc210113 hw->fc.high_water = high_water & 0xFFF8; 1521592a4d85Scc210113 hw->fc.low_water = hw->fc.high_water - 8; 152225f2d433Sxy150489 152325f2d433Sxy150489 if (hw->mac.type == e1000_80003es2lan) 1524592a4d85Scc210113 hw->fc.pause_time = 0xFFFF; 152525f2d433Sxy150489 else 1526592a4d85Scc210113 hw->fc.pause_time = E1000_FC_PAUSE_TIME; 1527592a4d85Scc210113 hw->fc.send_xon = B_TRUE; 152808057504Sxy150489 152908057504Sxy150489 /* 153008057504Sxy150489 * Reset the adapter hardware the second time. 153108057504Sxy150489 */ 1532a2e9a830Scc210113 mutex_enter(&e1000g_nvm_lock); 1533a2e9a830Scc210113 result = e1000_reset_hw(hw); 1534a2e9a830Scc210113 mutex_exit(&e1000g_nvm_lock); 1535a2e9a830Scc210113 1536a2e9a830Scc210113 if (result != E1000_SUCCESS) { 15379b6541b3Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 15389b6541b3Sgl147354 goto init_fail; 15399b6541b3Sgl147354 } 154008057504Sxy150489 154108057504Sxy150489 /* disable wakeup control by default */ 154225f2d433Sxy150489 if (hw->mac.type >= e1000_82544) 154325f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_WUC, 0); 154408057504Sxy150489 1545ede5269eSchenlu chen - Sun Microsystems - Beijing China /* 1546ede5269eSchenlu chen - Sun Microsystems - Beijing China * MWI should be disabled on 82546. 1547ede5269eSchenlu chen - Sun Microsystems - Beijing China */ 1548ede5269eSchenlu chen - Sun Microsystems - Beijing China if (hw->mac.type == e1000_82546) 1549ede5269eSchenlu chen - Sun Microsystems - Beijing China e1000_pci_clear_mwi(hw); 1550ede5269eSchenlu chen - Sun Microsystems - Beijing China else 155108057504Sxy150489 e1000_pci_set_mwi(hw); 155208057504Sxy150489 155308057504Sxy150489 /* 155408057504Sxy150489 * Configure/Initialize hardware 155508057504Sxy150489 */ 1556a2e9a830Scc210113 mutex_enter(&e1000g_nvm_lock); 1557a2e9a830Scc210113 result = e1000_init_hw(hw); 1558a2e9a830Scc210113 mutex_exit(&e1000g_nvm_lock); 1559a2e9a830Scc210113 1560a2e9a830Scc210113 if (result < E1000_SUCCESS) { 156108057504Sxy150489 e1000g_log(Adapter, CE_WARN, "Initialize hw failed"); 15629b6541b3Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 156308057504Sxy150489 goto init_fail; 156408057504Sxy150489 } 156508057504Sxy150489 1566b61028f6Sxiangtao you - Sun Microsystems - Beijing China /* 1567b61028f6Sxiangtao you - Sun Microsystems - Beijing China * Restore LED settings to the default from EEPROM 1568b61028f6Sxiangtao you - Sun Microsystems - Beijing China * to meet the standard for Sun platforms. 1569b61028f6Sxiangtao you - Sun Microsystems - Beijing China */ 1570b61028f6Sxiangtao you - Sun Microsystems - Beijing China (void) e1000_cleanup_led(hw); 1571b61028f6Sxiangtao you - Sun Microsystems - Beijing China 157208057504Sxy150489 /* Disable Smart Power Down */ 157308057504Sxy150489 phy_spd_state(hw, B_FALSE); 157408057504Sxy150489 15754914a7d0Syy150190 /* Make sure driver has control */ 15764914a7d0Syy150190 e1000g_get_driver_control(hw); 15774914a7d0Syy150190 157808057504Sxy150489 /* 157908057504Sxy150489 * Initialize unicast addresses. 158008057504Sxy150489 */ 158108057504Sxy150489 e1000g_init_unicst(Adapter); 158208057504Sxy150489 158308057504Sxy150489 /* 158408057504Sxy150489 * Setup and initialize the mctable structures. After this routine 158508057504Sxy150489 * completes Multicast table will be set 158608057504Sxy150489 */ 1587caf05df5SMiles Xu, Sun Microsystems e1000_update_mc_addr_list(hw, 1588caf05df5SMiles Xu, Sun Microsystems (uint8_t *)Adapter->mcast_table, Adapter->mcast_count); 158925f2d433Sxy150489 msec_delay(5); 159008057504Sxy150489 159108057504Sxy150489 /* 159208057504Sxy150489 * Implement Adaptive IFS 159308057504Sxy150489 */ 159408057504Sxy150489 e1000_reset_adaptive(hw); 159508057504Sxy150489 159608057504Sxy150489 /* Setup Interrupt Throttling Register */ 159747b7744cSyy150190 if (hw->mac.type >= e1000_82540) { 159825f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_ITR, Adapter->intr_throttling_rate); 159947b7744cSyy150190 } else 160047b7744cSyy150190 Adapter->intr_adaptive = B_FALSE; 160108057504Sxy150489 16027941757cSxy150489 /* Start the timer for link setup */ 160325f2d433Sxy150489 if (hw->mac.autoneg) 160425f2d433Sxy150489 link_timeout = PHY_AUTO_NEG_LIMIT * drv_usectohz(100000); 16057941757cSxy150489 else 160625f2d433Sxy150489 link_timeout = PHY_FORCE_LIMIT * drv_usectohz(100000); 16077941757cSxy150489 160825f2d433Sxy150489 mutex_enter(&Adapter->link_lock); 1609592a4d85Scc210113 if (hw->phy.autoneg_wait_to_complete) { 16107941757cSxy150489 Adapter->link_complete = B_TRUE; 161108057504Sxy150489 } else { 16127941757cSxy150489 Adapter->link_complete = B_FALSE; 16137941757cSxy150489 Adapter->link_tid = timeout(e1000g_link_timer, 16147941757cSxy150489 (void *)Adapter, link_timeout); 161508057504Sxy150489 } 161625f2d433Sxy150489 mutex_exit(&Adapter->link_lock); 161708057504Sxy150489 16184914a7d0Syy150190 /* Save the state of the phy */ 16194914a7d0Syy150190 e1000g_get_phy_state(Adapter); 16204914a7d0Syy150190 16214045d941Ssowmini e1000g_param_sync(Adapter); 16224045d941Ssowmini 162308057504Sxy150489 Adapter->init_count++; 162408057504Sxy150489 16259b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.cfg_handle) != DDI_FM_OK) { 16269b6541b3Sgl147354 goto init_fail; 16279b6541b3Sgl147354 } 16289b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 16299b6541b3Sgl147354 goto init_fail; 16309b6541b3Sgl147354 } 16319b6541b3Sgl147354 1632da14cebeSEric Cheng Adapter->poll_mode = e1000g_poll_mode; 1633da14cebeSEric Cheng 163408057504Sxy150489 return (DDI_SUCCESS); 163508057504Sxy150489 163608057504Sxy150489 init_fail: 16379b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 163808057504Sxy150489 return (DDI_FAILURE); 163908057504Sxy150489 } 164008057504Sxy150489 164154e0d7a5SMiles Xu, Sun Microsystems static int 164254e0d7a5SMiles Xu, Sun Microsystems e1000g_alloc_rx_data(struct e1000g *Adapter) 164354e0d7a5SMiles Xu, Sun Microsystems { 164454e0d7a5SMiles Xu, Sun Microsystems e1000g_rx_ring_t *rx_ring; 164554e0d7a5SMiles Xu, Sun Microsystems e1000g_rx_data_t *rx_data; 164654e0d7a5SMiles Xu, Sun Microsystems 164754e0d7a5SMiles Xu, Sun Microsystems rx_ring = Adapter->rx_ring; 164854e0d7a5SMiles Xu, Sun Microsystems 164954e0d7a5SMiles Xu, Sun Microsystems rx_data = kmem_zalloc(sizeof (e1000g_rx_data_t), KM_NOSLEEP); 165054e0d7a5SMiles Xu, Sun Microsystems 165154e0d7a5SMiles Xu, Sun Microsystems if (rx_data == NULL) 165254e0d7a5SMiles Xu, Sun Microsystems return (DDI_FAILURE); 165354e0d7a5SMiles Xu, Sun Microsystems 165454e0d7a5SMiles Xu, Sun Microsystems rx_data->priv_devi_node = Adapter->priv_devi_node; 165554e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_ring = rx_ring; 165654e0d7a5SMiles Xu, Sun Microsystems 165754e0d7a5SMiles Xu, Sun Microsystems mutex_init(&rx_data->freelist_lock, NULL, 165854e0d7a5SMiles Xu, Sun Microsystems MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 165954e0d7a5SMiles Xu, Sun Microsystems mutex_init(&rx_data->recycle_lock, NULL, 166054e0d7a5SMiles Xu, Sun Microsystems MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 166154e0d7a5SMiles Xu, Sun Microsystems 166254e0d7a5SMiles Xu, Sun Microsystems rx_ring->rx_data = rx_data; 166354e0d7a5SMiles Xu, Sun Microsystems 166454e0d7a5SMiles Xu, Sun Microsystems return (DDI_SUCCESS); 166554e0d7a5SMiles Xu, Sun Microsystems } 166654e0d7a5SMiles Xu, Sun Microsystems 166754e0d7a5SMiles Xu, Sun Microsystems void 166854e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_pending_buffers(e1000g_rx_data_t *rx_data) 166954e0d7a5SMiles Xu, Sun Microsystems { 167054e0d7a5SMiles Xu, Sun Microsystems rx_sw_packet_t *packet, *next_packet; 167154e0d7a5SMiles Xu, Sun Microsystems 167254e0d7a5SMiles Xu, Sun Microsystems if (rx_data == NULL) 167354e0d7a5SMiles Xu, Sun Microsystems return; 167454e0d7a5SMiles Xu, Sun Microsystems 167554e0d7a5SMiles Xu, Sun Microsystems packet = rx_data->packet_area; 167654e0d7a5SMiles Xu, Sun Microsystems while (packet != NULL) { 167754e0d7a5SMiles Xu, Sun Microsystems next_packet = packet->next; 167854e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_sw_packet(packet, B_TRUE); 167954e0d7a5SMiles Xu, Sun Microsystems packet = next_packet; 168054e0d7a5SMiles Xu, Sun Microsystems } 168154e0d7a5SMiles Xu, Sun Microsystems rx_data->packet_area = NULL; 168254e0d7a5SMiles Xu, Sun Microsystems } 168354e0d7a5SMiles Xu, Sun Microsystems 168454e0d7a5SMiles Xu, Sun Microsystems void 168554e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_data(e1000g_rx_data_t *rx_data) 168654e0d7a5SMiles Xu, Sun Microsystems { 168754e0d7a5SMiles Xu, Sun Microsystems if (rx_data == NULL) 168854e0d7a5SMiles Xu, Sun Microsystems return; 168954e0d7a5SMiles Xu, Sun Microsystems 169054e0d7a5SMiles Xu, Sun Microsystems mutex_destroy(&rx_data->freelist_lock); 169154e0d7a5SMiles Xu, Sun Microsystems mutex_destroy(&rx_data->recycle_lock); 169254e0d7a5SMiles Xu, Sun Microsystems 169354e0d7a5SMiles Xu, Sun Microsystems kmem_free(rx_data, sizeof (e1000g_rx_data_t)); 169454e0d7a5SMiles Xu, Sun Microsystems } 169554e0d7a5SMiles Xu, Sun Microsystems 169608057504Sxy150489 /* 169708057504Sxy150489 * Check if the link is up 169808057504Sxy150489 */ 169908057504Sxy150489 static boolean_t 170008057504Sxy150489 e1000g_link_up(struct e1000g *Adapter) 170108057504Sxy150489 { 1702caf05df5SMiles Xu, Sun Microsystems struct e1000_hw *hw = &Adapter->shared; 1703caf05df5SMiles Xu, Sun Microsystems boolean_t link_up = B_FALSE; 170408057504Sxy150489 1705caf05df5SMiles Xu, Sun Microsystems /* 1706caf05df5SMiles Xu, Sun Microsystems * get_link_status is set in the interrupt handler on link-status-change 1707caf05df5SMiles Xu, Sun Microsystems * or rx sequence error interrupt. get_link_status will stay 1708caf05df5SMiles Xu, Sun Microsystems * false until the e1000_check_for_link establishes link only 1709caf05df5SMiles Xu, Sun Microsystems * for copper adapters. 1710caf05df5SMiles Xu, Sun Microsystems */ 1711caf05df5SMiles Xu, Sun Microsystems switch (hw->phy.media_type) { 1712caf05df5SMiles Xu, Sun Microsystems case e1000_media_type_copper: 1713caf05df5SMiles Xu, Sun Microsystems if (hw->mac.get_link_status) { 171442cc51e0SRobert Mustacchi /* 171542cc51e0SRobert Mustacchi * SPT devices need a bit of extra time before we ask 171642cc51e0SRobert Mustacchi * them. 171742cc51e0SRobert Mustacchi */ 171842cc51e0SRobert Mustacchi if (hw->mac.type == e1000_pch_spt) 171942cc51e0SRobert Mustacchi msec_delay(50); 1720fe62dec3SChen-Liang Xu (void) e1000_check_for_link(hw); 17213fb4efefSchangqing li - Sun Microsystems - Beijing China if ((E1000_READ_REG(hw, E1000_STATUS) & 17223fb4efefSchangqing li - Sun Microsystems - Beijing China E1000_STATUS_LU)) { 17233fb4efefSchangqing li - Sun Microsystems - Beijing China link_up = B_TRUE; 17243fb4efefSchangqing li - Sun Microsystems - Beijing China } else { 1725caf05df5SMiles Xu, Sun Microsystems link_up = !hw->mac.get_link_status; 17263fb4efefSchangqing li - Sun Microsystems - Beijing China } 172708057504Sxy150489 } else { 1728caf05df5SMiles Xu, Sun Microsystems link_up = B_TRUE; 1729caf05df5SMiles Xu, Sun Microsystems } 1730caf05df5SMiles Xu, Sun Microsystems break; 1731caf05df5SMiles Xu, Sun Microsystems case e1000_media_type_fiber: 1732caf05df5SMiles Xu, Sun Microsystems (void) e1000_check_for_link(hw); 1733caf05df5SMiles Xu, Sun Microsystems link_up = (E1000_READ_REG(hw, E1000_STATUS) & 1734caf05df5SMiles Xu, Sun Microsystems E1000_STATUS_LU); 1735caf05df5SMiles Xu, Sun Microsystems break; 1736caf05df5SMiles Xu, Sun Microsystems case e1000_media_type_internal_serdes: 1737caf05df5SMiles Xu, Sun Microsystems (void) e1000_check_for_link(hw); 1738caf05df5SMiles Xu, Sun Microsystems link_up = hw->mac.serdes_has_link; 1739caf05df5SMiles Xu, Sun Microsystems break; 174008057504Sxy150489 } 174108057504Sxy150489 174208057504Sxy150489 return (link_up); 174308057504Sxy150489 } 174408057504Sxy150489 174508057504Sxy150489 static void 174608057504Sxy150489 e1000g_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 174708057504Sxy150489 { 174808057504Sxy150489 struct iocblk *iocp; 174908057504Sxy150489 struct e1000g *e1000gp; 175008057504Sxy150489 enum ioc_reply status; 175108057504Sxy150489 1752fe62dec3SChen-Liang Xu iocp = (struct iocblk *)(uintptr_t)mp->b_rptr; 175308057504Sxy150489 iocp->ioc_error = 0; 175408057504Sxy150489 e1000gp = (struct e1000g *)arg; 175508057504Sxy150489 175608057504Sxy150489 ASSERT(e1000gp); 175708057504Sxy150489 if (e1000gp == NULL) { 175808057504Sxy150489 miocnak(q, mp, 0, EINVAL); 175908057504Sxy150489 return; 176008057504Sxy150489 } 176108057504Sxy150489 1762d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&e1000gp->chip_lock, RW_READER); 1763d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (e1000gp->e1000g_state & E1000G_SUSPENDED) { 1764d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&e1000gp->chip_lock); 1765d5c3073dSchenlu chen - Sun Microsystems - Beijing China miocnak(q, mp, 0, EINVAL); 1766d5c3073dSchenlu chen - Sun Microsystems - Beijing China return; 1767d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 1768d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&e1000gp->chip_lock); 1769d5c3073dSchenlu chen - Sun Microsystems - Beijing China 177008057504Sxy150489 switch (iocp->ioc_cmd) { 177108057504Sxy150489 177208057504Sxy150489 case LB_GET_INFO_SIZE: 177308057504Sxy150489 case LB_GET_INFO: 177408057504Sxy150489 case LB_GET_MODE: 177508057504Sxy150489 case LB_SET_MODE: 177608057504Sxy150489 status = e1000g_loopback_ioctl(e1000gp, iocp, mp); 177708057504Sxy150489 break; 177808057504Sxy150489 177908057504Sxy150489 178025f2d433Sxy150489 #ifdef E1000G_DEBUG 178108057504Sxy150489 case E1000G_IOC_REG_PEEK: 178208057504Sxy150489 case E1000G_IOC_REG_POKE: 178308057504Sxy150489 status = e1000g_pp_ioctl(e1000gp, iocp, mp); 178408057504Sxy150489 break; 178508057504Sxy150489 case E1000G_IOC_CHIP_RESET: 178608057504Sxy150489 e1000gp->reset_count++; 178719397407SSherry Moore if (e1000g_reset_adapter(e1000gp)) 178808057504Sxy150489 status = IOC_ACK; 178908057504Sxy150489 else 179008057504Sxy150489 status = IOC_INVAL; 179108057504Sxy150489 break; 179225f2d433Sxy150489 #endif 179308057504Sxy150489 default: 179408057504Sxy150489 status = IOC_INVAL; 179508057504Sxy150489 break; 179608057504Sxy150489 } 179708057504Sxy150489 179808057504Sxy150489 /* 179908057504Sxy150489 * Decide how to reply 180008057504Sxy150489 */ 180108057504Sxy150489 switch (status) { 180208057504Sxy150489 default: 180308057504Sxy150489 case IOC_INVAL: 180408057504Sxy150489 /* 180508057504Sxy150489 * Error, reply with a NAK and EINVAL or the specified error 180608057504Sxy150489 */ 180708057504Sxy150489 miocnak(q, mp, 0, iocp->ioc_error == 0 ? 180808057504Sxy150489 EINVAL : iocp->ioc_error); 180908057504Sxy150489 break; 181008057504Sxy150489 181108057504Sxy150489 case IOC_DONE: 181208057504Sxy150489 /* 181308057504Sxy150489 * OK, reply already sent 181408057504Sxy150489 */ 181508057504Sxy150489 break; 181608057504Sxy150489 181708057504Sxy150489 case IOC_ACK: 181808057504Sxy150489 /* 181908057504Sxy150489 * OK, reply with an ACK 182008057504Sxy150489 */ 182108057504Sxy150489 miocack(q, mp, 0, 0); 182208057504Sxy150489 break; 182308057504Sxy150489 182408057504Sxy150489 case IOC_REPLY: 182508057504Sxy150489 /* 182608057504Sxy150489 * OK, send prepared reply as ACK or NAK 182708057504Sxy150489 */ 182808057504Sxy150489 mp->b_datap->db_type = iocp->ioc_error == 0 ? 182908057504Sxy150489 M_IOCACK : M_IOCNAK; 183008057504Sxy150489 qreply(q, mp); 183108057504Sxy150489 break; 183208057504Sxy150489 } 183308057504Sxy150489 } 183408057504Sxy150489 1835da14cebeSEric Cheng /* 1836da14cebeSEric Cheng * The default value of e1000g_poll_mode == 0 assumes that the NIC is 1837da14cebeSEric Cheng * capable of supporting only one interrupt and we shouldn't disable 1838da14cebeSEric Cheng * the physical interrupt. In this case we let the interrupt come and 1839da14cebeSEric Cheng * we queue the packets in the rx ring itself in case we are in polling 1840da14cebeSEric Cheng * mode (better latency but slightly lower performance and a very 1841da14cebeSEric Cheng * high intrrupt count in mpstat which is harmless). 1842da14cebeSEric Cheng * 1843da14cebeSEric Cheng * e1000g_poll_mode == 1 assumes that we have per Rx ring interrupt 1844da14cebeSEric Cheng * which can be disabled in poll mode. This gives better overall 1845da14cebeSEric Cheng * throughput (compared to the mode above), shows very low interrupt 1846da14cebeSEric Cheng * count but has slightly higher latency since we pick the packets when 1847da14cebeSEric Cheng * the poll thread does polling. 1848da14cebeSEric Cheng * 1849da14cebeSEric Cheng * Currently, this flag should be enabled only while doing performance 1850da14cebeSEric Cheng * measurement or when it can be guaranteed that entire NIC going 1851da14cebeSEric Cheng * in poll mode will not harm any traffic like cluster heartbeat etc. 1852da14cebeSEric Cheng */ 1853da14cebeSEric Cheng int e1000g_poll_mode = 0; 1854da14cebeSEric Cheng 1855da14cebeSEric Cheng /* 1856da14cebeSEric Cheng * Called from the upper layers when driver is in polling mode to 1857da14cebeSEric Cheng * pick up any queued packets. Care should be taken to not block 1858da14cebeSEric Cheng * this thread. 1859da14cebeSEric Cheng */ 1860da14cebeSEric Cheng static mblk_t *e1000g_poll_ring(void *arg, int bytes_to_pickup) 1861da14cebeSEric Cheng { 1862da14cebeSEric Cheng e1000g_rx_ring_t *rx_ring = (e1000g_rx_ring_t *)arg; 1863da14cebeSEric Cheng mblk_t *mp = NULL; 1864da14cebeSEric Cheng mblk_t *tail; 1865da14cebeSEric Cheng struct e1000g *adapter; 1866da14cebeSEric Cheng 1867da14cebeSEric Cheng adapter = rx_ring->adapter; 1868da14cebeSEric Cheng 1869d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&adapter->chip_lock, RW_READER); 1870d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1871d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (adapter->e1000g_state & E1000G_SUSPENDED) { 1872d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&adapter->chip_lock); 1873d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (NULL); 1874d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 1875d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1876da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock); 1877ae6aa22aSVenugopal Iyer mp = e1000g_receive(rx_ring, &tail, bytes_to_pickup); 1878da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock); 1879d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&adapter->chip_lock); 1880da14cebeSEric Cheng return (mp); 1881da14cebeSEric Cheng } 1882da14cebeSEric Cheng 188308057504Sxy150489 static int 188408057504Sxy150489 e1000g_m_start(void *arg) 188508057504Sxy150489 { 188608057504Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 188708057504Sxy150489 1888d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 1889d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1890d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_SUSPENDED) { 1891d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 1892d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (ECANCELED); 1893d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 1894d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1895d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (e1000g_start(Adapter, B_TRUE) != DDI_SUCCESS) { 1896d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 1897d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (ENOTACTIVE); 1898d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 1899d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1900d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state |= E1000G_STARTED; 1901d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1902d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 1903d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1904d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Enable and start the watchdog timer */ 1905d5c3073dSchenlu chen - Sun Microsystems - Beijing China enable_watchdog_timer(Adapter); 1906d5c3073dSchenlu chen - Sun Microsystems - Beijing China 1907d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (0); 190808057504Sxy150489 } 190908057504Sxy150489 191008057504Sxy150489 static int 191125f2d433Sxy150489 e1000g_start(struct e1000g *Adapter, boolean_t global) 191208057504Sxy150489 { 191354e0d7a5SMiles Xu, Sun Microsystems e1000g_rx_data_t *rx_data; 191454e0d7a5SMiles Xu, Sun Microsystems 191525f2d433Sxy150489 if (global) { 191654e0d7a5SMiles Xu, Sun Microsystems if (e1000g_alloc_rx_data(Adapter) != DDI_SUCCESS) { 191754e0d7a5SMiles Xu, Sun Microsystems e1000g_log(Adapter, CE_WARN, "Allocate rx data failed"); 191854e0d7a5SMiles Xu, Sun Microsystems goto start_fail; 191954e0d7a5SMiles Xu, Sun Microsystems } 192054e0d7a5SMiles Xu, Sun Microsystems 192125f2d433Sxy150489 /* Allocate dma resources for descriptors and buffers */ 192225f2d433Sxy150489 if (e1000g_alloc_dma_resources(Adapter) != DDI_SUCCESS) { 192325f2d433Sxy150489 e1000g_log(Adapter, CE_WARN, 192425f2d433Sxy150489 "Alloc DMA resources failed"); 192554e0d7a5SMiles Xu, Sun Microsystems goto start_fail; 192625f2d433Sxy150489 } 192725f2d433Sxy150489 Adapter->rx_buffer_setup = B_FALSE; 192825f2d433Sxy150489 } 192925f2d433Sxy150489 193008057504Sxy150489 if (!(Adapter->attach_progress & ATTACH_PROGRESS_INIT)) { 193108057504Sxy150489 if (e1000g_init(Adapter) != DDI_SUCCESS) { 193208057504Sxy150489 e1000g_log(Adapter, CE_WARN, 193308057504Sxy150489 "Adapter initialization failed"); 193454e0d7a5SMiles Xu, Sun Microsystems goto start_fail; 193508057504Sxy150489 } 193608057504Sxy150489 } 193708057504Sxy150489 193825f2d433Sxy150489 /* Setup and initialize the transmit structures */ 193925f2d433Sxy150489 e1000g_tx_setup(Adapter); 194025f2d433Sxy150489 msec_delay(5); 194125f2d433Sxy150489 194225f2d433Sxy150489 /* Setup and initialize the receive structures */ 194325f2d433Sxy150489 e1000g_rx_setup(Adapter); 194425f2d433Sxy150489 msec_delay(5); 194525f2d433Sxy150489 1946bb184967SShu-Guo Yang /* Restore the e1000g promiscuous mode */ 1947bb184967SShu-Guo Yang e1000g_restore_promisc(Adapter); 1948bb184967SShu-Guo Yang 194925f2d433Sxy150489 e1000g_mask_interrupt(Adapter); 195008057504Sxy150489 195108057504Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_INIT; 195208057504Sxy150489 1953d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 1954d5c3073dSchenlu chen - Sun Microsystems - Beijing China ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 195554e0d7a5SMiles Xu, Sun Microsystems goto start_fail; 1956d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 195708057504Sxy150489 1958d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (DDI_SUCCESS); 195954e0d7a5SMiles Xu, Sun Microsystems 196054e0d7a5SMiles Xu, Sun Microsystems start_fail: 196154e0d7a5SMiles Xu, Sun Microsystems rx_data = Adapter->rx_ring->rx_data; 196254e0d7a5SMiles Xu, Sun Microsystems 196354e0d7a5SMiles Xu, Sun Microsystems if (global) { 196454e0d7a5SMiles Xu, Sun Microsystems e1000g_release_dma_resources(Adapter); 196554e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_pending_buffers(rx_data); 196654e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_data(rx_data); 196754e0d7a5SMiles Xu, Sun Microsystems } 196854e0d7a5SMiles Xu, Sun Microsystems 196954e0d7a5SMiles Xu, Sun Microsystems mutex_enter(&e1000g_nvm_lock); 197054e0d7a5SMiles Xu, Sun Microsystems (void) e1000_reset_hw(&Adapter->shared); 197154e0d7a5SMiles Xu, Sun Microsystems mutex_exit(&e1000g_nvm_lock); 197254e0d7a5SMiles Xu, Sun Microsystems 197354e0d7a5SMiles Xu, Sun Microsystems return (DDI_FAILURE); 197408057504Sxy150489 } 197508057504Sxy150489 197642cc51e0SRobert Mustacchi /* 197742cc51e0SRobert Mustacchi * The I219 has the curious property that if the descriptor rings are not 197842cc51e0SRobert Mustacchi * emptied before resetting the hardware or before changing the device state 197942cc51e0SRobert Mustacchi * based on runtime power management, it'll cause the card to hang. This can 198042cc51e0SRobert Mustacchi * then only be fixed by a PCI reset. As such, for the I219 and it alone, we 198142cc51e0SRobert Mustacchi * have to flush the rings if we're in this state. 198242cc51e0SRobert Mustacchi */ 198342cc51e0SRobert Mustacchi static void 198442cc51e0SRobert Mustacchi e1000g_flush_desc_rings(struct e1000g *Adapter) 198542cc51e0SRobert Mustacchi { 198642cc51e0SRobert Mustacchi struct e1000_hw *hw = &Adapter->shared; 198742cc51e0SRobert Mustacchi u16 hang_state; 198842cc51e0SRobert Mustacchi u32 fext_nvm11, tdlen; 198942cc51e0SRobert Mustacchi 199042cc51e0SRobert Mustacchi /* First, disable MULR fix in FEXTNVM11 */ 199142cc51e0SRobert Mustacchi fext_nvm11 = E1000_READ_REG(hw, E1000_FEXTNVM11); 199242cc51e0SRobert Mustacchi fext_nvm11 |= E1000_FEXTNVM11_DISABLE_MULR_FIX; 199342cc51e0SRobert Mustacchi E1000_WRITE_REG(hw, E1000_FEXTNVM11, fext_nvm11); 199442cc51e0SRobert Mustacchi 199542cc51e0SRobert Mustacchi /* do nothing if we're not in faulty state, or if the queue is empty */ 199642cc51e0SRobert Mustacchi tdlen = E1000_READ_REG(hw, E1000_TDLEN(0)); 199742cc51e0SRobert Mustacchi hang_state = pci_config_get16(Adapter->osdep.cfg_handle, 199842cc51e0SRobert Mustacchi PCICFG_DESC_RING_STATUS); 199942cc51e0SRobert Mustacchi if (!(hang_state & FLUSH_DESC_REQUIRED) || !tdlen) 200042cc51e0SRobert Mustacchi return; 200142cc51e0SRobert Mustacchi e1000g_flush_tx_ring(Adapter); 200242cc51e0SRobert Mustacchi 200342cc51e0SRobert Mustacchi /* recheck, maybe the fault is caused by the rx ring */ 200442cc51e0SRobert Mustacchi hang_state = pci_config_get16(Adapter->osdep.cfg_handle, 200542cc51e0SRobert Mustacchi PCICFG_DESC_RING_STATUS); 200642cc51e0SRobert Mustacchi if (hang_state & FLUSH_DESC_REQUIRED) 200742cc51e0SRobert Mustacchi e1000g_flush_rx_ring(Adapter); 200842cc51e0SRobert Mustacchi 200942cc51e0SRobert Mustacchi } 201042cc51e0SRobert Mustacchi 201108057504Sxy150489 static void 201208057504Sxy150489 e1000g_m_stop(void *arg) 201308057504Sxy150489 { 201408057504Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 201508057504Sxy150489 2016d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Drain tx sessions */ 2017d5c3073dSchenlu chen - Sun Microsystems - Beijing China (void) e1000g_tx_drain(Adapter); 2018d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2019d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 2020d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2021d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_SUSPENDED) { 2022d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 2023d5c3073dSchenlu chen - Sun Microsystems - Beijing China return; 2024d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 2025d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state &= ~E1000G_STARTED; 202625f2d433Sxy150489 e1000g_stop(Adapter, B_TRUE); 2027d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2028d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 2029d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2030d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Disable and stop all the timers */ 2031d5c3073dSchenlu chen - Sun Microsystems - Beijing China disable_watchdog_timer(Adapter); 2032d5c3073dSchenlu chen - Sun Microsystems - Beijing China stop_link_timer(Adapter); 2033d5c3073dSchenlu chen - Sun Microsystems - Beijing China stop_82547_timer(Adapter->tx_ring); 203408057504Sxy150489 } 203508057504Sxy150489 203608057504Sxy150489 static void 203725f2d433Sxy150489 e1000g_stop(struct e1000g *Adapter, boolean_t global) 203808057504Sxy150489 { 203954e0d7a5SMiles Xu, Sun Microsystems private_devi_list_t *devi_node; 204054e0d7a5SMiles Xu, Sun Microsystems e1000g_rx_data_t *rx_data; 2041a2e9a830Scc210113 int result; 2042a2e9a830Scc210113 204308057504Sxy150489 Adapter->attach_progress &= ~ATTACH_PROGRESS_INIT; 204408057504Sxy150489 204508057504Sxy150489 /* Stop the chip and release pending resources */ 204608057504Sxy150489 20474d737963Sxiangtao you - Sun Microsystems - Beijing China /* Tell firmware driver is no longer in control */ 20484d737963Sxiangtao you - Sun Microsystems - Beijing China e1000g_release_driver_control(&Adapter->shared); 20494d737963Sxiangtao you - Sun Microsystems - Beijing China 205025f2d433Sxy150489 e1000g_clear_all_interrupts(Adapter); 2051a2e9a830Scc210113 2052a2e9a830Scc210113 mutex_enter(&e1000g_nvm_lock); 2053a2e9a830Scc210113 result = e1000_reset_hw(&Adapter->shared); 2054a2e9a830Scc210113 mutex_exit(&e1000g_nvm_lock); 2055a2e9a830Scc210113 2056a2e9a830Scc210113 if (result != E1000_SUCCESS) { 20579b6541b3Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 20589b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 20599b6541b3Sgl147354 } 206008057504Sxy150489 20610dc2366fSVenugopal Iyer mutex_enter(&Adapter->link_lock); 20620dc2366fSVenugopal Iyer Adapter->link_complete = B_FALSE; 20630dc2366fSVenugopal Iyer mutex_exit(&Adapter->link_lock); 20640dc2366fSVenugopal Iyer 206508057504Sxy150489 /* Release resources still held by the TX descriptors */ 206625f2d433Sxy150489 e1000g_tx_clean(Adapter); 20677941757cSxy150489 20689b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 20699b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 20709b6541b3Sgl147354 20717941757cSxy150489 /* Clean the pending rx jumbo packet fragment */ 207225f2d433Sxy150489 e1000g_rx_clean(Adapter); 20737941757cSxy150489 207442cc51e0SRobert Mustacchi /* 207542cc51e0SRobert Mustacchi * The I219, eg. the pch_spt, has bugs such that we must ensure that 207642cc51e0SRobert Mustacchi * rings are flushed before we do anything else. This must be done 207742cc51e0SRobert Mustacchi * before we release DMA resources. 207842cc51e0SRobert Mustacchi */ 207942cc51e0SRobert Mustacchi if (Adapter->shared.mac.type == e1000_pch_spt) 208042cc51e0SRobert Mustacchi e1000g_flush_desc_rings(Adapter); 208142cc51e0SRobert Mustacchi 208254e0d7a5SMiles Xu, Sun Microsystems if (global) { 208325f2d433Sxy150489 e1000g_release_dma_resources(Adapter); 208454e0d7a5SMiles Xu, Sun Microsystems 208554e0d7a5SMiles Xu, Sun Microsystems mutex_enter(&e1000g_rx_detach_lock); 208654e0d7a5SMiles Xu, Sun Microsystems rx_data = Adapter->rx_ring->rx_data; 208754e0d7a5SMiles Xu, Sun Microsystems rx_data->flag |= E1000G_RX_STOPPED; 208854e0d7a5SMiles Xu, Sun Microsystems 208954e0d7a5SMiles Xu, Sun Microsystems if (rx_data->pending_count == 0) { 209054e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_pending_buffers(rx_data); 209154e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_data(rx_data); 209254e0d7a5SMiles Xu, Sun Microsystems } else { 209354e0d7a5SMiles Xu, Sun Microsystems devi_node = rx_data->priv_devi_node; 209454e0d7a5SMiles Xu, Sun Microsystems if (devi_node != NULL) 209554e0d7a5SMiles Xu, Sun Microsystems atomic_inc_32(&devi_node->pending_rx_count); 209654e0d7a5SMiles Xu, Sun Microsystems else 209754e0d7a5SMiles Xu, Sun Microsystems atomic_inc_32(&Adapter->pending_rx_count); 209854e0d7a5SMiles Xu, Sun Microsystems } 209954e0d7a5SMiles Xu, Sun Microsystems mutex_exit(&e1000g_rx_detach_lock); 210054e0d7a5SMiles Xu, Sun Microsystems } 2101cb5cd232SMiles Xu, Sun Microsystems 21023fb4efefSchangqing li - Sun Microsystems - Beijing China if (Adapter->link_state != LINK_STATE_UNKNOWN) { 2103cb5cd232SMiles Xu, Sun Microsystems Adapter->link_state = LINK_STATE_UNKNOWN; 21040c35404fSchangqing li - Sun Microsystems - Beijing China if (!Adapter->reset_flag) 2105cb5cd232SMiles Xu, Sun Microsystems mac_link_update(Adapter->mh, Adapter->link_state); 2106cb5cd232SMiles Xu, Sun Microsystems } 21077941757cSxy150489 } 21087941757cSxy150489 21097941757cSxy150489 static void 211025f2d433Sxy150489 e1000g_rx_clean(struct e1000g *Adapter) 211125f2d433Sxy150489 { 211254e0d7a5SMiles Xu, Sun Microsystems e1000g_rx_data_t *rx_data = Adapter->rx_ring->rx_data; 211325f2d433Sxy150489 211454e0d7a5SMiles Xu, Sun Microsystems if (rx_data == NULL) 211554e0d7a5SMiles Xu, Sun Microsystems return; 211654e0d7a5SMiles Xu, Sun Microsystems 211754e0d7a5SMiles Xu, Sun Microsystems if (rx_data->rx_mblk != NULL) { 211854e0d7a5SMiles Xu, Sun Microsystems freemsg(rx_data->rx_mblk); 211954e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk = NULL; 212054e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_tail = NULL; 212154e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_len = 0; 212225f2d433Sxy150489 } 212325f2d433Sxy150489 } 212425f2d433Sxy150489 212525f2d433Sxy150489 static void 212625f2d433Sxy150489 e1000g_tx_clean(struct e1000g *Adapter) 21277941757cSxy150489 { 21287941757cSxy150489 e1000g_tx_ring_t *tx_ring; 212925f2d433Sxy150489 p_tx_sw_packet_t packet; 21307941757cSxy150489 mblk_t *mp; 21317941757cSxy150489 mblk_t *nmp; 21327941757cSxy150489 uint32_t packet_count; 21337941757cSxy150489 21347941757cSxy150489 tx_ring = Adapter->tx_ring; 21357941757cSxy150489 213608057504Sxy150489 /* 213708057504Sxy150489 * Here we don't need to protect the lists using 213808057504Sxy150489 * the usedlist_lock and freelist_lock, for they 213908057504Sxy150489 * have been protected by the chip_lock. 214008057504Sxy150489 */ 214108057504Sxy150489 mp = NULL; 214208057504Sxy150489 nmp = NULL; 21437941757cSxy150489 packet_count = 0; 214425f2d433Sxy150489 packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(&tx_ring->used_list); 214508057504Sxy150489 while (packet != NULL) { 214608057504Sxy150489 if (packet->mp != NULL) { 214708057504Sxy150489 /* Assemble the message chain */ 214808057504Sxy150489 if (mp == NULL) { 214908057504Sxy150489 mp = packet->mp; 215008057504Sxy150489 nmp = packet->mp; 215108057504Sxy150489 } else { 215208057504Sxy150489 nmp->b_next = packet->mp; 215308057504Sxy150489 nmp = packet->mp; 215408057504Sxy150489 } 215508057504Sxy150489 /* Disconnect the message from the sw packet */ 215608057504Sxy150489 packet->mp = NULL; 215708057504Sxy150489 } 215808057504Sxy150489 215925f2d433Sxy150489 e1000g_free_tx_swpkt(packet); 21607941757cSxy150489 packet_count++; 216108057504Sxy150489 216225f2d433Sxy150489 packet = (p_tx_sw_packet_t) 216308057504Sxy150489 QUEUE_GET_NEXT(&tx_ring->used_list, &packet->Link); 216408057504Sxy150489 } 216508057504Sxy150489 216647b7744cSyy150190 if (mp != NULL) 216747b7744cSyy150190 freemsgchain(mp); 21687941757cSxy150489 21697941757cSxy150489 if (packet_count > 0) { 217008057504Sxy150489 QUEUE_APPEND(&tx_ring->free_list, &tx_ring->used_list); 217108057504Sxy150489 QUEUE_INIT_LIST(&tx_ring->used_list); 217208057504Sxy150489 21737941757cSxy150489 /* Setup TX descriptor pointers */ 21747941757cSxy150489 tx_ring->tbd_next = tx_ring->tbd_first; 21757941757cSxy150489 tx_ring->tbd_oldest = tx_ring->tbd_first; 21767941757cSxy150489 21777941757cSxy150489 /* Setup our HW Tx Head & Tail descriptor pointers */ 2178592a4d85Scc210113 E1000_WRITE_REG(&Adapter->shared, E1000_TDH(0), 0); 2179592a4d85Scc210113 E1000_WRITE_REG(&Adapter->shared, E1000_TDT(0), 0); 218008057504Sxy150489 } 218108057504Sxy150489 } 218208057504Sxy150489 218308057504Sxy150489 static boolean_t 218408057504Sxy150489 e1000g_tx_drain(struct e1000g *Adapter) 218508057504Sxy150489 { 218608057504Sxy150489 int i; 218708057504Sxy150489 boolean_t done; 218808057504Sxy150489 e1000g_tx_ring_t *tx_ring; 218908057504Sxy150489 219008057504Sxy150489 tx_ring = Adapter->tx_ring; 219108057504Sxy150489 219208057504Sxy150489 /* Allow up to 'wsdraintime' for pending xmit's to complete. */ 219325f2d433Sxy150489 for (i = 0; i < TX_DRAIN_TIME; i++) { 219408057504Sxy150489 mutex_enter(&tx_ring->usedlist_lock); 219508057504Sxy150489 done = IS_QUEUE_EMPTY(&tx_ring->used_list); 219608057504Sxy150489 mutex_exit(&tx_ring->usedlist_lock); 219708057504Sxy150489 219808057504Sxy150489 if (done) 219908057504Sxy150489 break; 220008057504Sxy150489 220108057504Sxy150489 msec_delay(1); 220208057504Sxy150489 } 220308057504Sxy150489 220408057504Sxy150489 return (done); 220508057504Sxy150489 } 220608057504Sxy150489 220708057504Sxy150489 static boolean_t 220808057504Sxy150489 e1000g_rx_drain(struct e1000g *Adapter) 220908057504Sxy150489 { 221054e0d7a5SMiles Xu, Sun Microsystems int i; 221108057504Sxy150489 boolean_t done; 221208057504Sxy150489 221354e0d7a5SMiles Xu, Sun Microsystems /* 221454e0d7a5SMiles Xu, Sun Microsystems * Allow up to RX_DRAIN_TIME for pending received packets to complete. 221554e0d7a5SMiles Xu, Sun Microsystems */ 221654e0d7a5SMiles Xu, Sun Microsystems for (i = 0; i < RX_DRAIN_TIME; i++) { 221754e0d7a5SMiles Xu, Sun Microsystems done = (Adapter->pending_rx_count == 0); 221825f2d433Sxy150489 221954e0d7a5SMiles Xu, Sun Microsystems if (done) 222054e0d7a5SMiles Xu, Sun Microsystems break; 222125f2d433Sxy150489 222254e0d7a5SMiles Xu, Sun Microsystems msec_delay(1); 222325f2d433Sxy150489 } 222408057504Sxy150489 222508057504Sxy150489 return (done); 222608057504Sxy150489 } 222708057504Sxy150489 222819397407SSherry Moore static boolean_t 222919397407SSherry Moore e1000g_reset_adapter(struct e1000g *Adapter) 223008057504Sxy150489 { 2231d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Disable and stop all the timers */ 2232d5c3073dSchenlu chen - Sun Microsystems - Beijing China disable_watchdog_timer(Adapter); 2233d5c3073dSchenlu chen - Sun Microsystems - Beijing China stop_link_timer(Adapter); 2234d5c3073dSchenlu chen - Sun Microsystems - Beijing China stop_82547_timer(Adapter->tx_ring); 2235d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2236d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 2237d5c3073dSchenlu chen - Sun Microsystems - Beijing China 22380c35404fSchangqing li - Sun Microsystems - Beijing China if (Adapter->stall_flag) { 22390c35404fSchangqing li - Sun Microsystems - Beijing China Adapter->stall_flag = B_FALSE; 22400c35404fSchangqing li - Sun Microsystems - Beijing China Adapter->reset_flag = B_TRUE; 22410c35404fSchangqing li - Sun Microsystems - Beijing China } 22420c35404fSchangqing li - Sun Microsystems - Beijing China 22435f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China if (!(Adapter->e1000g_state & E1000G_STARTED)) { 22445f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 22455f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China return (B_TRUE); 22465f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China } 22475f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China 224825f2d433Sxy150489 e1000g_stop(Adapter, B_FALSE); 224908057504Sxy150489 2250d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (e1000g_start(Adapter, B_FALSE) != DDI_SUCCESS) { 2251d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 225208057504Sxy150489 e1000g_log(Adapter, CE_WARN, "Reset failed"); 225308057504Sxy150489 return (B_FALSE); 225408057504Sxy150489 } 225508057504Sxy150489 2256d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 2257d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2258d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Enable and start the watchdog timer */ 2259d5c3073dSchenlu chen - Sun Microsystems - Beijing China enable_watchdog_timer(Adapter); 2260d5c3073dSchenlu chen - Sun Microsystems - Beijing China 226108057504Sxy150489 return (B_TRUE); 226208057504Sxy150489 } 226308057504Sxy150489 22649b6541b3Sgl147354 boolean_t 22659b6541b3Sgl147354 e1000g_global_reset(struct e1000g *Adapter) 22669b6541b3Sgl147354 { 2267d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Disable and stop all the timers */ 2268d5c3073dSchenlu chen - Sun Microsystems - Beijing China disable_watchdog_timer(Adapter); 2269d5c3073dSchenlu chen - Sun Microsystems - Beijing China stop_link_timer(Adapter); 2270d5c3073dSchenlu chen - Sun Microsystems - Beijing China stop_82547_timer(Adapter->tx_ring); 2271d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2272d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 2273d5c3073dSchenlu chen - Sun Microsystems - Beijing China 22749b6541b3Sgl147354 e1000g_stop(Adapter, B_TRUE); 22759b6541b3Sgl147354 22769b6541b3Sgl147354 Adapter->init_count = 0; 22779b6541b3Sgl147354 2278d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (e1000g_start(Adapter, B_TRUE) != DDI_SUCCESS) { 2279d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 22809b6541b3Sgl147354 e1000g_log(Adapter, CE_WARN, "Reset failed"); 22819b6541b3Sgl147354 return (B_FALSE); 22829b6541b3Sgl147354 } 22839b6541b3Sgl147354 2284d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 2285d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2286d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Enable and start the watchdog timer */ 2287d5c3073dSchenlu chen - Sun Microsystems - Beijing China enable_watchdog_timer(Adapter); 2288d5c3073dSchenlu chen - Sun Microsystems - Beijing China 22899b6541b3Sgl147354 return (B_TRUE); 22909b6541b3Sgl147354 } 22919b6541b3Sgl147354 229208057504Sxy150489 /* 229325f2d433Sxy150489 * e1000g_intr_pciexpress - ISR for PCI Express chipsets 229425f2d433Sxy150489 * 229525f2d433Sxy150489 * This interrupt service routine is for PCI-Express adapters. 229625f2d433Sxy150489 * The ICR contents is valid only when the E1000_ICR_INT_ASSERTED 229725f2d433Sxy150489 * bit is set. 229808057504Sxy150489 */ 229908057504Sxy150489 static uint_t 230008057504Sxy150489 e1000g_intr_pciexpress(caddr_t arg) 230108057504Sxy150489 { 230208057504Sxy150489 struct e1000g *Adapter; 230325f2d433Sxy150489 uint32_t icr; 230408057504Sxy150489 2305fe62dec3SChen-Liang Xu Adapter = (struct e1000g *)(uintptr_t)arg; 230625f2d433Sxy150489 icr = E1000_READ_REG(&Adapter->shared, E1000_ICR); 230708057504Sxy150489 2308ec39b9cfSchangqing li - Sun Microsystems - Beijing China if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 23099b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 2310ec39b9cfSchangqing li - Sun Microsystems - Beijing China return (DDI_INTR_CLAIMED); 2311ec39b9cfSchangqing li - Sun Microsystems - Beijing China } 23129b6541b3Sgl147354 231325f2d433Sxy150489 if (icr & E1000_ICR_INT_ASSERTED) { 231408057504Sxy150489 /* 231508057504Sxy150489 * E1000_ICR_INT_ASSERTED bit was set: 231608057504Sxy150489 * Read(Clear) the ICR, claim this interrupt, 231708057504Sxy150489 * look for work to do. 231808057504Sxy150489 */ 231925f2d433Sxy150489 e1000g_intr_work(Adapter, icr); 232008057504Sxy150489 return (DDI_INTR_CLAIMED); 232108057504Sxy150489 } else { 232208057504Sxy150489 /* 232308057504Sxy150489 * E1000_ICR_INT_ASSERTED bit was not set: 232408057504Sxy150489 * Don't claim this interrupt, return immediately. 232508057504Sxy150489 */ 232608057504Sxy150489 return (DDI_INTR_UNCLAIMED); 232708057504Sxy150489 } 232808057504Sxy150489 } 232908057504Sxy150489 233008057504Sxy150489 /* 233125f2d433Sxy150489 * e1000g_intr - ISR for PCI/PCI-X chipsets 233225f2d433Sxy150489 * 233325f2d433Sxy150489 * This interrupt service routine is for PCI/PCI-X adapters. 233425f2d433Sxy150489 * We check the ICR contents no matter the E1000_ICR_INT_ASSERTED 233525f2d433Sxy150489 * bit is set or not. 233608057504Sxy150489 */ 233708057504Sxy150489 static uint_t 233808057504Sxy150489 e1000g_intr(caddr_t arg) 233908057504Sxy150489 { 234008057504Sxy150489 struct e1000g *Adapter; 234125f2d433Sxy150489 uint32_t icr; 234208057504Sxy150489 2343fe62dec3SChen-Liang Xu Adapter = (struct e1000g *)(uintptr_t)arg; 234425f2d433Sxy150489 icr = E1000_READ_REG(&Adapter->shared, E1000_ICR); 234508057504Sxy150489 2346ec39b9cfSchangqing li - Sun Microsystems - Beijing China if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 23479b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 2348ec39b9cfSchangqing li - Sun Microsystems - Beijing China return (DDI_INTR_CLAIMED); 2349ec39b9cfSchangqing li - Sun Microsystems - Beijing China } 23509b6541b3Sgl147354 235125f2d433Sxy150489 if (icr) { 235208057504Sxy150489 /* 235308057504Sxy150489 * Any bit was set in ICR: 235408057504Sxy150489 * Read(Clear) the ICR, claim this interrupt, 235508057504Sxy150489 * look for work to do. 235608057504Sxy150489 */ 235725f2d433Sxy150489 e1000g_intr_work(Adapter, icr); 235808057504Sxy150489 return (DDI_INTR_CLAIMED); 235908057504Sxy150489 } else { 236008057504Sxy150489 /* 236108057504Sxy150489 * No bit was set in ICR: 236208057504Sxy150489 * Don't claim this interrupt, return immediately. 236308057504Sxy150489 */ 236408057504Sxy150489 return (DDI_INTR_UNCLAIMED); 236508057504Sxy150489 } 236608057504Sxy150489 } 236708057504Sxy150489 236808057504Sxy150489 /* 236925f2d433Sxy150489 * e1000g_intr_work - actual processing of ISR 237025f2d433Sxy150489 * 237125f2d433Sxy150489 * Read(clear) the ICR contents and call appropriate interrupt 237225f2d433Sxy150489 * processing routines. 237308057504Sxy150489 */ 237408057504Sxy150489 static void 237525f2d433Sxy150489 e1000g_intr_work(struct e1000g *Adapter, uint32_t icr) 237608057504Sxy150489 { 237747b7744cSyy150190 struct e1000_hw *hw; 237847b7744cSyy150190 hw = &Adapter->shared; 237947b7744cSyy150190 e1000g_tx_ring_t *tx_ring = Adapter->tx_ring; 238047b7744cSyy150190 238147b7744cSyy150190 Adapter->rx_pkt_cnt = 0; 238247b7744cSyy150190 Adapter->tx_pkt_cnt = 0; 238347b7744cSyy150190 238408057504Sxy150489 rw_enter(&Adapter->chip_lock, RW_READER); 2385d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2386d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_SUSPENDED) { 2387d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 2388d5c3073dSchenlu chen - Sun Microsystems - Beijing China return; 2389d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 239008057504Sxy150489 /* 2391d5c3073dSchenlu chen - Sun Microsystems - Beijing China * Here we need to check the "e1000g_state" flag within the chip_lock to 239225f2d433Sxy150489 * ensure the receive routine will not execute when the adapter is 239325f2d433Sxy150489 * being reset. 239408057504Sxy150489 */ 2395d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (!(Adapter->e1000g_state & E1000G_STARTED)) { 239625f2d433Sxy150489 rw_exit(&Adapter->chip_lock); 239725f2d433Sxy150489 return; 239825f2d433Sxy150489 } 239925f2d433Sxy150489 240025f2d433Sxy150489 if (icr & E1000_ICR_RXT0) { 2401ae6aa22aSVenugopal Iyer mblk_t *mp = NULL; 2402ae6aa22aSVenugopal Iyer mblk_t *tail = NULL; 2403da14cebeSEric Cheng e1000g_rx_ring_t *rx_ring; 240425f2d433Sxy150489 2405da14cebeSEric Cheng rx_ring = Adapter->rx_ring; 2406da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock); 2407da14cebeSEric Cheng /* 2408ae6aa22aSVenugopal Iyer * Sometimes with legacy interrupts, it possible that 2409ae6aa22aSVenugopal Iyer * there is a single interrupt for Rx/Tx. In which 2410ae6aa22aSVenugopal Iyer * case, if poll flag is set, we shouldn't really 2411ae6aa22aSVenugopal Iyer * be doing Rx processing. 2412da14cebeSEric Cheng */ 2413ae6aa22aSVenugopal Iyer if (!rx_ring->poll_flag) 2414ae6aa22aSVenugopal Iyer mp = e1000g_receive(rx_ring, &tail, 2415ae6aa22aSVenugopal Iyer E1000G_CHAIN_NO_LIMIT); 2416da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock); 2417ae6aa22aSVenugopal Iyer rw_exit(&Adapter->chip_lock); 2418ae6aa22aSVenugopal Iyer if (mp != NULL) 2419da14cebeSEric Cheng mac_rx_ring(Adapter->mh, rx_ring->mrh, 2420da14cebeSEric Cheng mp, rx_ring->ring_gen_num); 242125f2d433Sxy150489 } else 242208057504Sxy150489 rw_exit(&Adapter->chip_lock); 242308057504Sxy150489 242447b7744cSyy150190 if (icr & E1000_ICR_TXDW) { 242547b7744cSyy150190 if (!Adapter->tx_intr_enable) 242647b7744cSyy150190 e1000g_clear_tx_interrupt(Adapter); 242747b7744cSyy150190 242847b7744cSyy150190 /* Recycle the tx descriptors */ 242947b7744cSyy150190 rw_enter(&Adapter->chip_lock, RW_READER); 2430fe62dec3SChen-Liang Xu (void) e1000g_recycle(tx_ring); 243147b7744cSyy150190 E1000G_DEBUG_STAT(tx_ring->stat_recycle_intr); 243247b7744cSyy150190 rw_exit(&Adapter->chip_lock); 243347b7744cSyy150190 243447b7744cSyy150190 if (tx_ring->resched_needed && 243547b7744cSyy150190 (tx_ring->tbd_avail > DEFAULT_TX_UPDATE_THRESHOLD)) { 243647b7744cSyy150190 tx_ring->resched_needed = B_FALSE; 243747b7744cSyy150190 mac_tx_update(Adapter->mh); 243847b7744cSyy150190 E1000G_STAT(tx_ring->stat_reschedule); 243947b7744cSyy150190 } 244047b7744cSyy150190 } 244147b7744cSyy150190 244208057504Sxy150489 /* 244308057504Sxy150489 * The Receive Sequence errors RXSEQ and the link status change LSC 244408057504Sxy150489 * are checked to detect that the cable has been pulled out. For 244508057504Sxy150489 * the Wiseman 2.0 silicon, the receive sequence errors interrupt 244608057504Sxy150489 * are an indication that cable is not connected. 244708057504Sxy150489 */ 244825f2d433Sxy150489 if ((icr & E1000_ICR_RXSEQ) || 244925f2d433Sxy150489 (icr & E1000_ICR_LSC) || 245025f2d433Sxy150489 (icr & E1000_ICR_GPI_EN1)) { 24517941757cSxy150489 boolean_t link_changed; 24527941757cSxy150489 timeout_id_t tid = 0; 245308057504Sxy150489 245425f2d433Sxy150489 stop_watchdog_timer(Adapter); 245508057504Sxy150489 24564914a7d0Syy150190 rw_enter(&Adapter->chip_lock, RW_WRITER); 24574914a7d0Syy150190 24584914a7d0Syy150190 /* 24594914a7d0Syy150190 * Because we got a link-status-change interrupt, force 24604914a7d0Syy150190 * e1000_check_for_link() to look at phy 24614914a7d0Syy150190 */ 24624914a7d0Syy150190 Adapter->shared.mac.get_link_status = B_TRUE; 24634914a7d0Syy150190 24647941757cSxy150489 /* e1000g_link_check takes care of link status change */ 24657941757cSxy150489 link_changed = e1000g_link_check(Adapter); 24664914a7d0Syy150190 24674914a7d0Syy150190 /* Get new phy state */ 24684914a7d0Syy150190 e1000g_get_phy_state(Adapter); 24694914a7d0Syy150190 24707941757cSxy150489 /* 24717941757cSxy150489 * If the link timer has not timed out, we'll not notify 247225f2d433Sxy150489 * the upper layer with any link state until the link is up. 24737941757cSxy150489 */ 24747941757cSxy150489 if (link_changed && !Adapter->link_complete) { 24757941757cSxy150489 if (Adapter->link_state == LINK_STATE_UP) { 24764914a7d0Syy150190 mutex_enter(&Adapter->link_lock); 24777941757cSxy150489 Adapter->link_complete = B_TRUE; 24787941757cSxy150489 tid = Adapter->link_tid; 24797941757cSxy150489 Adapter->link_tid = 0; 24804914a7d0Syy150190 mutex_exit(&Adapter->link_lock); 24817941757cSxy150489 } else { 24827941757cSxy150489 link_changed = B_FALSE; 24837941757cSxy150489 } 24847941757cSxy150489 } 24854914a7d0Syy150190 rw_exit(&Adapter->chip_lock); 248608057504Sxy150489 24877941757cSxy150489 if (link_changed) { 24887941757cSxy150489 if (tid != 0) 24897941757cSxy150489 (void) untimeout(tid); 24907941757cSxy150489 249130a54d15Sxy150489 /* 249230a54d15Sxy150489 * Workaround for esb2. Data stuck in fifo on a link 2493a2e9a830Scc210113 * down event. Stop receiver here and reset in watchdog. 249430a54d15Sxy150489 */ 249530a54d15Sxy150489 if ((Adapter->link_state == LINK_STATE_DOWN) && 2496a2e9a830Scc210113 (Adapter->shared.mac.type == e1000_80003es2lan)) { 2497a2e9a830Scc210113 uint32_t rctl = E1000_READ_REG(hw, E1000_RCTL); 2498a2e9a830Scc210113 E1000_WRITE_REG(hw, E1000_RCTL, 2499a2e9a830Scc210113 rctl & ~E1000_RCTL_EN); 2500a2e9a830Scc210113 e1000g_log(Adapter, CE_WARN, 2501a2e9a830Scc210113 "ESB2 receiver disabled"); 2502a2e9a830Scc210113 Adapter->esb2_workaround = B_TRUE; 2503a2e9a830Scc210113 } 250454e0d7a5SMiles Xu, Sun Microsystems if (!Adapter->reset_flag) 250554e0d7a5SMiles Xu, Sun Microsystems mac_link_update(Adapter->mh, 250654e0d7a5SMiles Xu, Sun Microsystems Adapter->link_state); 250754e0d7a5SMiles Xu, Sun Microsystems if (Adapter->link_state == LINK_STATE_UP) 250854e0d7a5SMiles Xu, Sun Microsystems Adapter->reset_flag = B_FALSE; 250908057504Sxy150489 } 251008057504Sxy150489 251125f2d433Sxy150489 start_watchdog_timer(Adapter); 251208057504Sxy150489 } 251347b7744cSyy150190 } 251408057504Sxy150489 251508057504Sxy150489 static void 251608057504Sxy150489 e1000g_init_unicst(struct e1000g *Adapter) 251708057504Sxy150489 { 251808057504Sxy150489 struct e1000_hw *hw; 251908057504Sxy150489 int slot; 252008057504Sxy150489 252125f2d433Sxy150489 hw = &Adapter->shared; 252208057504Sxy150489 2523da14cebeSEric Cheng if (Adapter->init_count == 0) { 252408057504Sxy150489 /* Initialize the multiple unicast addresses */ 2525b7c47e8cSHans Rosenfeld Adapter->unicst_total = min(hw->mac.rar_entry_count, 2526b7c47e8cSHans Rosenfeld MAX_NUM_UNICAST_ADDRESSES); 252708057504Sxy150489 25286055fc7aSRobert Mustacchi /* 25296055fc7aSRobert Mustacchi * The common code does not correctly calculate the number of 253042cc51e0SRobert Mustacchi * rar's that could be reserved by firmware for the pch_lpt and 253142cc51e0SRobert Mustacchi * pch_spt macs. The interface has one primary rar, and 11 253242cc51e0SRobert Mustacchi * additional ones. Those 11 additional ones are not always 253342cc51e0SRobert Mustacchi * available. According to the datasheet, we need to check a 253442cc51e0SRobert Mustacchi * few of the bits set in the FWSM register. If the value is 253542cc51e0SRobert Mustacchi * zero, everything is available. If the value is 1, none of the 25366055fc7aSRobert Mustacchi * additional registers are available. If the value is 2-7, only 25376055fc7aSRobert Mustacchi * that number are available. 25386055fc7aSRobert Mustacchi */ 253942cc51e0SRobert Mustacchi if (hw->mac.type == e1000_pch_lpt || 254042cc51e0SRobert Mustacchi hw->mac.type == e1000_pch_spt) { 25416055fc7aSRobert Mustacchi uint32_t locked, rar; 25426055fc7aSRobert Mustacchi 25436055fc7aSRobert Mustacchi locked = E1000_READ_REG(hw, E1000_FWSM) & 25446055fc7aSRobert Mustacchi E1000_FWSM_WLOCK_MAC_MASK; 25456055fc7aSRobert Mustacchi locked >>= E1000_FWSM_WLOCK_MAC_SHIFT; 25466055fc7aSRobert Mustacchi rar = 1; 25476055fc7aSRobert Mustacchi if (locked == 0) 25486055fc7aSRobert Mustacchi rar += 11; 25496055fc7aSRobert Mustacchi else if (locked == 1) 25506055fc7aSRobert Mustacchi rar += 0; 25516055fc7aSRobert Mustacchi else 25526055fc7aSRobert Mustacchi rar += locked; 25536055fc7aSRobert Mustacchi Adapter->unicst_total = min(rar, 25546055fc7aSRobert Mustacchi MAX_NUM_UNICAST_ADDRESSES); 25556055fc7aSRobert Mustacchi } 25566055fc7aSRobert Mustacchi 2557da14cebeSEric Cheng /* Workaround for an erratum of 82571 chipst */ 255825f2d433Sxy150489 if ((hw->mac.type == e1000_82571) && 255925f2d433Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) 256008057504Sxy150489 Adapter->unicst_total--; 256108057504Sxy150489 256259e72b15SGarrett D'Amore /* VMware doesn't support multiple mac addresses properly */ 256359e72b15SGarrett D'Amore if (hw->subsystem_vendor_id == 0x15ad) 256459e72b15SGarrett D'Amore Adapter->unicst_total = 1; 256559e72b15SGarrett D'Amore 2566da14cebeSEric Cheng Adapter->unicst_avail = Adapter->unicst_total; 256708057504Sxy150489 2568da14cebeSEric Cheng for (slot = 0; slot < Adapter->unicst_total; slot++) { 2569da14cebeSEric Cheng /* Clear both the flag and MAC address */ 2570da14cebeSEric Cheng Adapter->unicst_addr[slot].reg.high = 0; 2571da14cebeSEric Cheng Adapter->unicst_addr[slot].reg.low = 0; 2572da14cebeSEric Cheng } 257308057504Sxy150489 } else { 2574da14cebeSEric Cheng /* Workaround for an erratum of 82571 chipst */ 257525f2d433Sxy150489 if ((hw->mac.type == e1000_82571) && 257625f2d433Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) 2577c124a83eSRobert Mustacchi (void) e1000_rar_set(hw, hw->mac.addr, LAST_RAR_ENTRY); 257808057504Sxy150489 257908057504Sxy150489 /* Re-configure the RAR registers */ 2580da14cebeSEric Cheng for (slot = 0; slot < Adapter->unicst_total; slot++) 2581da14cebeSEric Cheng if (Adapter->unicst_addr[slot].mac.set == 1) 2582c124a83eSRobert Mustacchi (void) e1000_rar_set(hw, 258308057504Sxy150489 Adapter->unicst_addr[slot].mac.addr, slot); 258408057504Sxy150489 } 25859b6541b3Sgl147354 25869b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 25879b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 258808057504Sxy150489 } 258908057504Sxy150489 259008057504Sxy150489 static int 259108057504Sxy150489 e1000g_unicst_set(struct e1000g *Adapter, const uint8_t *mac_addr, 2592da14cebeSEric Cheng int slot) 259308057504Sxy150489 { 259408057504Sxy150489 struct e1000_hw *hw; 259508057504Sxy150489 259625f2d433Sxy150489 hw = &Adapter->shared; 259708057504Sxy150489 259808057504Sxy150489 /* 259908057504Sxy150489 * The first revision of Wiseman silicon (rev 2.0) has an errata 260008057504Sxy150489 * that requires the receiver to be in reset when any of the 260108057504Sxy150489 * receive address registers (RAR regs) are accessed. The first 260208057504Sxy150489 * rev of Wiseman silicon also requires MWI to be disabled when 260308057504Sxy150489 * a global reset or a receive reset is issued. So before we 260408057504Sxy150489 * initialize the RARs, we check the rev of the Wiseman controller 260508057504Sxy150489 * and work around any necessary HW errata. 260608057504Sxy150489 */ 260725f2d433Sxy150489 if ((hw->mac.type == e1000_82542) && 260825f2d433Sxy150489 (hw->revision_id == E1000_REVISION_2)) { 260908057504Sxy150489 e1000_pci_clear_mwi(hw); 261025f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST); 261125f2d433Sxy150489 msec_delay(5); 261208057504Sxy150489 } 2613da14cebeSEric Cheng if (mac_addr == NULL) { 2614da14cebeSEric Cheng E1000_WRITE_REG_ARRAY(hw, E1000_RA, slot << 1, 0); 2615da14cebeSEric Cheng E1000_WRITE_FLUSH(hw); 2616da14cebeSEric Cheng E1000_WRITE_REG_ARRAY(hw, E1000_RA, (slot << 1) + 1, 0); 2617da14cebeSEric Cheng E1000_WRITE_FLUSH(hw); 2618da14cebeSEric Cheng /* Clear both the flag and MAC address */ 2619da14cebeSEric Cheng Adapter->unicst_addr[slot].reg.high = 0; 2620da14cebeSEric Cheng Adapter->unicst_addr[slot].reg.low = 0; 2621da14cebeSEric Cheng } else { 2622da14cebeSEric Cheng bcopy(mac_addr, Adapter->unicst_addr[slot].mac.addr, 2623da14cebeSEric Cheng ETHERADDRL); 2624c124a83eSRobert Mustacchi (void) e1000_rar_set(hw, (uint8_t *)mac_addr, slot); 2625da14cebeSEric Cheng Adapter->unicst_addr[slot].mac.set = 1; 2626da14cebeSEric Cheng } 262708057504Sxy150489 2628da14cebeSEric Cheng /* Workaround for an erratum of 82571 chipst */ 262908057504Sxy150489 if (slot == 0) { 263025f2d433Sxy150489 if ((hw->mac.type == e1000_82571) && 263125f2d433Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) 2632da14cebeSEric Cheng if (mac_addr == NULL) { 2633da14cebeSEric Cheng E1000_WRITE_REG_ARRAY(hw, E1000_RA, 2634da14cebeSEric Cheng slot << 1, 0); 2635da14cebeSEric Cheng E1000_WRITE_FLUSH(hw); 2636da14cebeSEric Cheng E1000_WRITE_REG_ARRAY(hw, E1000_RA, 2637da14cebeSEric Cheng (slot << 1) + 1, 0); 2638da14cebeSEric Cheng E1000_WRITE_FLUSH(hw); 2639da14cebeSEric Cheng } else { 2640c124a83eSRobert Mustacchi (void) e1000_rar_set(hw, (uint8_t *)mac_addr, 2641da14cebeSEric Cheng LAST_RAR_ENTRY); 2642da14cebeSEric Cheng } 264308057504Sxy150489 } 264408057504Sxy150489 264508057504Sxy150489 /* 264608057504Sxy150489 * If we are using Wiseman rev 2.0 silicon, we will have previously 264708057504Sxy150489 * put the receive in reset, and disabled MWI, to work around some 264808057504Sxy150489 * HW errata. Now we should take the receiver out of reset, and 264908057504Sxy150489 * re-enabled if MWI if it was previously enabled by the PCI BIOS. 265008057504Sxy150489 */ 265125f2d433Sxy150489 if ((hw->mac.type == e1000_82542) && 265225f2d433Sxy150489 (hw->revision_id == E1000_REVISION_2)) { 265325f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, 0); 265425f2d433Sxy150489 msec_delay(1); 265525f2d433Sxy150489 if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) 265608057504Sxy150489 e1000_pci_set_mwi(hw); 265725f2d433Sxy150489 e1000g_rx_setup(Adapter); 265808057504Sxy150489 } 265908057504Sxy150489 26609b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 26619b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 26629b6541b3Sgl147354 return (EIO); 26639b6541b3Sgl147354 } 26649b6541b3Sgl147354 266508057504Sxy150489 return (0); 266608057504Sxy150489 } 266708057504Sxy150489 266808057504Sxy150489 static int 266908057504Sxy150489 multicst_add(struct e1000g *Adapter, const uint8_t *multiaddr) 267008057504Sxy150489 { 267125f2d433Sxy150489 struct e1000_hw *hw = &Adapter->shared; 26720c56b8d9Schangqing li - Sun Microsystems - Beijing China struct ether_addr *newtable; 26730c56b8d9Schangqing li - Sun Microsystems - Beijing China size_t new_len; 26740c56b8d9Schangqing li - Sun Microsystems - Beijing China size_t old_len; 267508057504Sxy150489 int res = 0; 267608057504Sxy150489 267708057504Sxy150489 if ((multiaddr[0] & 01) == 0) { 267808057504Sxy150489 res = EINVAL; 26790c56b8d9Schangqing li - Sun Microsystems - Beijing China e1000g_log(Adapter, CE_WARN, "Illegal multicast address"); 268008057504Sxy150489 goto done; 268108057504Sxy150489 } 268208057504Sxy150489 26830c56b8d9Schangqing li - Sun Microsystems - Beijing China if (Adapter->mcast_count >= Adapter->mcast_max_num) { 268408057504Sxy150489 res = ENOENT; 26850c56b8d9Schangqing li - Sun Microsystems - Beijing China e1000g_log(Adapter, CE_WARN, 26860c56b8d9Schangqing li - Sun Microsystems - Beijing China "Adapter requested more than %d mcast addresses", 26870c56b8d9Schangqing li - Sun Microsystems - Beijing China Adapter->mcast_max_num); 268808057504Sxy150489 goto done; 268908057504Sxy150489 } 269008057504Sxy150489 26910c56b8d9Schangqing li - Sun Microsystems - Beijing China 26920c56b8d9Schangqing li - Sun Microsystems - Beijing China if (Adapter->mcast_count == Adapter->mcast_alloc_count) { 26930c56b8d9Schangqing li - Sun Microsystems - Beijing China old_len = Adapter->mcast_alloc_count * 26940c56b8d9Schangqing li - Sun Microsystems - Beijing China sizeof (struct ether_addr); 26950c56b8d9Schangqing li - Sun Microsystems - Beijing China new_len = (Adapter->mcast_alloc_count + MCAST_ALLOC_SIZE) * 26960c56b8d9Schangqing li - Sun Microsystems - Beijing China sizeof (struct ether_addr); 26970c56b8d9Schangqing li - Sun Microsystems - Beijing China 26980c56b8d9Schangqing li - Sun Microsystems - Beijing China newtable = kmem_alloc(new_len, KM_NOSLEEP); 26990c56b8d9Schangqing li - Sun Microsystems - Beijing China if (newtable == NULL) { 27000c56b8d9Schangqing li - Sun Microsystems - Beijing China res = ENOMEM; 27010c56b8d9Schangqing li - Sun Microsystems - Beijing China e1000g_log(Adapter, CE_WARN, 27020c56b8d9Schangqing li - Sun Microsystems - Beijing China "Not enough memory to alloc mcast table"); 27030c56b8d9Schangqing li - Sun Microsystems - Beijing China goto done; 27040c56b8d9Schangqing li - Sun Microsystems - Beijing China } 27050c56b8d9Schangqing li - Sun Microsystems - Beijing China 27060c56b8d9Schangqing li - Sun Microsystems - Beijing China if (Adapter->mcast_table != NULL) { 27070c56b8d9Schangqing li - Sun Microsystems - Beijing China bcopy(Adapter->mcast_table, newtable, old_len); 27080c56b8d9Schangqing li - Sun Microsystems - Beijing China kmem_free(Adapter->mcast_table, old_len); 27090c56b8d9Schangqing li - Sun Microsystems - Beijing China } 27100c56b8d9Schangqing li - Sun Microsystems - Beijing China Adapter->mcast_alloc_count += MCAST_ALLOC_SIZE; 27110c56b8d9Schangqing li - Sun Microsystems - Beijing China Adapter->mcast_table = newtable; 27120c56b8d9Schangqing li - Sun Microsystems - Beijing China } 27130c56b8d9Schangqing li - Sun Microsystems - Beijing China 271408057504Sxy150489 bcopy(multiaddr, 271508057504Sxy150489 &Adapter->mcast_table[Adapter->mcast_count], ETHERADDRL); 271608057504Sxy150489 Adapter->mcast_count++; 271708057504Sxy150489 271808057504Sxy150489 /* 271908057504Sxy150489 * Update the MC table in the hardware 272008057504Sxy150489 */ 272125f2d433Sxy150489 e1000g_clear_interrupt(Adapter); 272208057504Sxy150489 2723caf05df5SMiles Xu, Sun Microsystems e1000_update_mc_addr_list(hw, 2724caf05df5SMiles Xu, Sun Microsystems (uint8_t *)Adapter->mcast_table, Adapter->mcast_count); 272508057504Sxy150489 272625f2d433Sxy150489 e1000g_mask_interrupt(Adapter); 272708057504Sxy150489 27289b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 27299b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 27309b6541b3Sgl147354 res = EIO; 27319b6541b3Sgl147354 } 27329b6541b3Sgl147354 2733d5c3073dSchenlu chen - Sun Microsystems - Beijing China done: 273408057504Sxy150489 return (res); 273508057504Sxy150489 } 273608057504Sxy150489 273708057504Sxy150489 static int 273808057504Sxy150489 multicst_remove(struct e1000g *Adapter, const uint8_t *multiaddr) 273908057504Sxy150489 { 274025f2d433Sxy150489 struct e1000_hw *hw = &Adapter->shared; 27410c56b8d9Schangqing li - Sun Microsystems - Beijing China struct ether_addr *newtable; 27420c56b8d9Schangqing li - Sun Microsystems - Beijing China size_t new_len; 27430c56b8d9Schangqing li - Sun Microsystems - Beijing China size_t old_len; 274408057504Sxy150489 unsigned i; 274508057504Sxy150489 274608057504Sxy150489 for (i = 0; i < Adapter->mcast_count; i++) { 274708057504Sxy150489 if (bcmp(multiaddr, &Adapter->mcast_table[i], 274808057504Sxy150489 ETHERADDRL) == 0) { 274908057504Sxy150489 for (i++; i < Adapter->mcast_count; i++) { 275008057504Sxy150489 Adapter->mcast_table[i - 1] = 275108057504Sxy150489 Adapter->mcast_table[i]; 275208057504Sxy150489 } 275308057504Sxy150489 Adapter->mcast_count--; 275408057504Sxy150489 break; 275508057504Sxy150489 } 275608057504Sxy150489 } 275708057504Sxy150489 27580c56b8d9Schangqing li - Sun Microsystems - Beijing China if ((Adapter->mcast_alloc_count - Adapter->mcast_count) > 27590c56b8d9Schangqing li - Sun Microsystems - Beijing China MCAST_ALLOC_SIZE) { 27600c56b8d9Schangqing li - Sun Microsystems - Beijing China old_len = Adapter->mcast_alloc_count * 27610c56b8d9Schangqing li - Sun Microsystems - Beijing China sizeof (struct ether_addr); 27620c56b8d9Schangqing li - Sun Microsystems - Beijing China new_len = (Adapter->mcast_alloc_count - MCAST_ALLOC_SIZE) * 27630c56b8d9Schangqing li - Sun Microsystems - Beijing China sizeof (struct ether_addr); 27640c56b8d9Schangqing li - Sun Microsystems - Beijing China 27650c56b8d9Schangqing li - Sun Microsystems - Beijing China newtable = kmem_alloc(new_len, KM_NOSLEEP); 27660c56b8d9Schangqing li - Sun Microsystems - Beijing China if (newtable != NULL) { 27670c56b8d9Schangqing li - Sun Microsystems - Beijing China bcopy(Adapter->mcast_table, newtable, new_len); 27680c56b8d9Schangqing li - Sun Microsystems - Beijing China kmem_free(Adapter->mcast_table, old_len); 27690c56b8d9Schangqing li - Sun Microsystems - Beijing China 27700c56b8d9Schangqing li - Sun Microsystems - Beijing China Adapter->mcast_alloc_count -= MCAST_ALLOC_SIZE; 27710c56b8d9Schangqing li - Sun Microsystems - Beijing China Adapter->mcast_table = newtable; 27720c56b8d9Schangqing li - Sun Microsystems - Beijing China } 27730c56b8d9Schangqing li - Sun Microsystems - Beijing China } 27740c56b8d9Schangqing li - Sun Microsystems - Beijing China 277508057504Sxy150489 /* 277608057504Sxy150489 * Update the MC table in the hardware 277708057504Sxy150489 */ 277825f2d433Sxy150489 e1000g_clear_interrupt(Adapter); 277908057504Sxy150489 2780caf05df5SMiles Xu, Sun Microsystems e1000_update_mc_addr_list(hw, 2781caf05df5SMiles Xu, Sun Microsystems (uint8_t *)Adapter->mcast_table, Adapter->mcast_count); 278208057504Sxy150489 278325f2d433Sxy150489 e1000g_mask_interrupt(Adapter); 278408057504Sxy150489 27859b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 27869b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 27879b6541b3Sgl147354 return (EIO); 27889b6541b3Sgl147354 } 27899b6541b3Sgl147354 279008057504Sxy150489 return (0); 279108057504Sxy150489 } 279208057504Sxy150489 27930c56b8d9Schangqing li - Sun Microsystems - Beijing China static void 27940c56b8d9Schangqing li - Sun Microsystems - Beijing China e1000g_release_multicast(struct e1000g *Adapter) 27950c56b8d9Schangqing li - Sun Microsystems - Beijing China { 27960c56b8d9Schangqing li - Sun Microsystems - Beijing China if (Adapter->mcast_table != NULL) { 27970c56b8d9Schangqing li - Sun Microsystems - Beijing China kmem_free(Adapter->mcast_table, 27980c56b8d9Schangqing li - Sun Microsystems - Beijing China Adapter->mcast_alloc_count * sizeof (struct ether_addr)); 27990c56b8d9Schangqing li - Sun Microsystems - Beijing China Adapter->mcast_table = NULL; 28000c56b8d9Schangqing li - Sun Microsystems - Beijing China } 28010c56b8d9Schangqing li - Sun Microsystems - Beijing China } 28020c56b8d9Schangqing li - Sun Microsystems - Beijing China 280308057504Sxy150489 int 280408057504Sxy150489 e1000g_m_multicst(void *arg, boolean_t add, const uint8_t *addr) 280508057504Sxy150489 { 280608057504Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 2807d5c3073dSchenlu chen - Sun Microsystems - Beijing China int result; 280808057504Sxy150489 2809d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 2810d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2811d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_SUSPENDED) { 2812d5c3073dSchenlu chen - Sun Microsystems - Beijing China result = ECANCELED; 2813d5c3073dSchenlu chen - Sun Microsystems - Beijing China goto done; 2814d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 2815d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2816d5c3073dSchenlu chen - Sun Microsystems - Beijing China result = (add) ? multicst_add(Adapter, addr) 2817d5c3073dSchenlu chen - Sun Microsystems - Beijing China : multicst_remove(Adapter, addr); 2818d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2819d5c3073dSchenlu chen - Sun Microsystems - Beijing China done: 2820d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 2821d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (result); 2822d5c3073dSchenlu chen - Sun Microsystems - Beijing China 282308057504Sxy150489 } 282408057504Sxy150489 282508057504Sxy150489 int 282608057504Sxy150489 e1000g_m_promisc(void *arg, boolean_t on) 282708057504Sxy150489 { 282808057504Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 282925f2d433Sxy150489 uint32_t rctl; 283008057504Sxy150489 283108057504Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 283208057504Sxy150489 2833d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_SUSPENDED) { 2834d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 2835d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (ECANCELED); 2836d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 2837d5c3073dSchenlu chen - Sun Microsystems - Beijing China 283825f2d433Sxy150489 rctl = E1000_READ_REG(&Adapter->shared, E1000_RCTL); 283908057504Sxy150489 284008057504Sxy150489 if (on) 284125f2d433Sxy150489 rctl |= 284208057504Sxy150489 (E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_BAM); 284308057504Sxy150489 else 284425f2d433Sxy150489 rctl &= (~(E1000_RCTL_UPE | E1000_RCTL_MPE)); 284508057504Sxy150489 284625f2d433Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_RCTL, rctl); 284708057504Sxy150489 284808057504Sxy150489 Adapter->e1000g_promisc = on; 284908057504Sxy150489 285008057504Sxy150489 rw_exit(&Adapter->chip_lock); 285108057504Sxy150489 28529b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 28539b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 28549b6541b3Sgl147354 return (EIO); 28559b6541b3Sgl147354 } 28569b6541b3Sgl147354 285708057504Sxy150489 return (0); 285808057504Sxy150489 } 285908057504Sxy150489 2860da14cebeSEric Cheng /* 2861da14cebeSEric Cheng * Entry points to enable and disable interrupts at the granularity of 2862da14cebeSEric Cheng * a group. 2863da14cebeSEric Cheng * Turns the poll_mode for the whole adapter on and off to enable or 2864da14cebeSEric Cheng * override the ring level polling control over the hardware interrupts. 2865da14cebeSEric Cheng */ 2866da14cebeSEric Cheng static int 2867da14cebeSEric Cheng e1000g_rx_group_intr_enable(mac_intr_handle_t arg) 2868da14cebeSEric Cheng { 2869da14cebeSEric Cheng struct e1000g *adapter = (struct e1000g *)arg; 2870da14cebeSEric Cheng e1000g_rx_ring_t *rx_ring = adapter->rx_ring; 2871da14cebeSEric Cheng 2872da14cebeSEric Cheng /* 2873da14cebeSEric Cheng * Later interrupts at the granularity of the this ring will 2874da14cebeSEric Cheng * invoke mac_rx() with NULL, indicating the need for another 2875da14cebeSEric Cheng * software classification. 2876da14cebeSEric Cheng * We have a single ring usable per adapter now, so we only need to 2877da14cebeSEric Cheng * reset the rx handle for that one. 2878da14cebeSEric Cheng * When more RX rings can be used, we should update each one of them. 2879da14cebeSEric Cheng */ 2880da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock); 2881da14cebeSEric Cheng rx_ring->mrh = NULL; 2882da14cebeSEric Cheng adapter->poll_mode = B_FALSE; 2883da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock); 2884da14cebeSEric Cheng return (0); 2885da14cebeSEric Cheng } 2886da14cebeSEric Cheng 2887da14cebeSEric Cheng static int 2888da14cebeSEric Cheng e1000g_rx_group_intr_disable(mac_intr_handle_t arg) 2889da14cebeSEric Cheng { 2890da14cebeSEric Cheng struct e1000g *adapter = (struct e1000g *)arg; 2891da14cebeSEric Cheng e1000g_rx_ring_t *rx_ring = adapter->rx_ring; 2892da14cebeSEric Cheng 2893da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock); 2894da14cebeSEric Cheng 2895da14cebeSEric Cheng /* 2896da14cebeSEric Cheng * Later interrupts at the granularity of the this ring will 2897da14cebeSEric Cheng * invoke mac_rx() with the handle for this ring; 2898da14cebeSEric Cheng */ 2899da14cebeSEric Cheng adapter->poll_mode = B_TRUE; 2900da14cebeSEric Cheng rx_ring->mrh = rx_ring->mrh_init; 2901da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock); 2902da14cebeSEric Cheng return (0); 2903da14cebeSEric Cheng } 2904da14cebeSEric Cheng 2905da14cebeSEric Cheng /* 2906da14cebeSEric Cheng * Entry points to enable and disable interrupts at the granularity of 2907da14cebeSEric Cheng * a ring. 2908da14cebeSEric Cheng * adapter poll_mode controls whether we actually proceed with hardware 2909da14cebeSEric Cheng * interrupt toggling. 2910da14cebeSEric Cheng */ 2911da14cebeSEric Cheng static int 2912da14cebeSEric Cheng e1000g_rx_ring_intr_enable(mac_intr_handle_t intrh) 2913da14cebeSEric Cheng { 2914da14cebeSEric Cheng e1000g_rx_ring_t *rx_ring = (e1000g_rx_ring_t *)intrh; 2915da14cebeSEric Cheng struct e1000g *adapter = rx_ring->adapter; 2916da14cebeSEric Cheng struct e1000_hw *hw = &adapter->shared; 2917da14cebeSEric Cheng uint32_t intr_mask; 2918da14cebeSEric Cheng 2919d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&adapter->chip_lock, RW_READER); 2920d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2921d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (adapter->e1000g_state & E1000G_SUSPENDED) { 2922d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&adapter->chip_lock); 2923d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (0); 2924d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 2925d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2926da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock); 2927da14cebeSEric Cheng rx_ring->poll_flag = 0; 2928da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock); 2929da14cebeSEric Cheng 2930da14cebeSEric Cheng /* Rx interrupt enabling for MSI and legacy */ 2931da14cebeSEric Cheng intr_mask = E1000_READ_REG(hw, E1000_IMS); 2932da14cebeSEric Cheng intr_mask |= E1000_IMS_RXT0; 2933da14cebeSEric Cheng E1000_WRITE_REG(hw, E1000_IMS, intr_mask); 2934da14cebeSEric Cheng E1000_WRITE_FLUSH(hw); 2935da14cebeSEric Cheng 2936da14cebeSEric Cheng /* Trigger a Rx interrupt to check Rx ring */ 2937da14cebeSEric Cheng E1000_WRITE_REG(hw, E1000_ICS, E1000_IMS_RXT0); 2938da14cebeSEric Cheng E1000_WRITE_FLUSH(hw); 2939d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2940d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&adapter->chip_lock); 2941da14cebeSEric Cheng return (0); 2942da14cebeSEric Cheng } 2943da14cebeSEric Cheng 2944da14cebeSEric Cheng static int 2945da14cebeSEric Cheng e1000g_rx_ring_intr_disable(mac_intr_handle_t intrh) 2946da14cebeSEric Cheng { 2947da14cebeSEric Cheng e1000g_rx_ring_t *rx_ring = (e1000g_rx_ring_t *)intrh; 2948da14cebeSEric Cheng struct e1000g *adapter = rx_ring->adapter; 2949da14cebeSEric Cheng struct e1000_hw *hw = &adapter->shared; 2950da14cebeSEric Cheng 2951d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&adapter->chip_lock, RW_READER); 2952d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2953d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (adapter->e1000g_state & E1000G_SUSPENDED) { 2954d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&adapter->chip_lock); 2955d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (0); 2956d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 2957da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock); 2958da14cebeSEric Cheng rx_ring->poll_flag = 1; 2959da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock); 2960da14cebeSEric Cheng 2961da14cebeSEric Cheng /* Rx interrupt disabling for MSI and legacy */ 2962da14cebeSEric Cheng E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_RXT0); 2963da14cebeSEric Cheng E1000_WRITE_FLUSH(hw); 2964d5c3073dSchenlu chen - Sun Microsystems - Beijing China 2965d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&adapter->chip_lock); 2966da14cebeSEric Cheng return (0); 2967da14cebeSEric Cheng } 2968da14cebeSEric Cheng 2969da14cebeSEric Cheng /* 2970da14cebeSEric Cheng * e1000g_unicst_find - Find the slot for the specified unicast address 2971da14cebeSEric Cheng */ 2972da14cebeSEric Cheng static int 2973da14cebeSEric Cheng e1000g_unicst_find(struct e1000g *Adapter, const uint8_t *mac_addr) 2974da14cebeSEric Cheng { 2975da14cebeSEric Cheng int slot; 2976da14cebeSEric Cheng 2977da14cebeSEric Cheng for (slot = 0; slot < Adapter->unicst_total; slot++) { 2978d5c3073dSchenlu chen - Sun Microsystems - Beijing China if ((Adapter->unicst_addr[slot].mac.set == 1) && 2979d5c3073dSchenlu chen - Sun Microsystems - Beijing China (bcmp(Adapter->unicst_addr[slot].mac.addr, 2980d5c3073dSchenlu chen - Sun Microsystems - Beijing China mac_addr, ETHERADDRL) == 0)) 2981da14cebeSEric Cheng return (slot); 2982da14cebeSEric Cheng } 2983da14cebeSEric Cheng 2984da14cebeSEric Cheng return (-1); 2985da14cebeSEric Cheng } 2986da14cebeSEric Cheng 2987da14cebeSEric Cheng /* 2988da14cebeSEric Cheng * Entry points to add and remove a MAC address to a ring group. 2989da14cebeSEric Cheng * The caller takes care of adding and removing the MAC addresses 2990da14cebeSEric Cheng * to the filter via these two routines. 2991da14cebeSEric Cheng */ 2992da14cebeSEric Cheng 2993da14cebeSEric Cheng static int 2994da14cebeSEric Cheng e1000g_addmac(void *arg, const uint8_t *mac_addr) 2995da14cebeSEric Cheng { 2996da14cebeSEric Cheng struct e1000g *Adapter = (struct e1000g *)arg; 299708ac1c49SNicolas Droux int slot, err; 2998da14cebeSEric Cheng 2999d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 3000d5c3073dSchenlu chen - Sun Microsystems - Beijing China 3001d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_SUSPENDED) { 3002d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 3003d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (ECANCELED); 3004d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 3005da14cebeSEric Cheng 3006da14cebeSEric Cheng if (e1000g_unicst_find(Adapter, mac_addr) != -1) { 3007da14cebeSEric Cheng /* The same address is already in slot */ 3008d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 3009da14cebeSEric Cheng return (0); 3010da14cebeSEric Cheng } 3011da14cebeSEric Cheng 3012da14cebeSEric Cheng if (Adapter->unicst_avail == 0) { 3013da14cebeSEric Cheng /* no slots available */ 3014d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 3015da14cebeSEric Cheng return (ENOSPC); 3016da14cebeSEric Cheng } 3017da14cebeSEric Cheng 3018da14cebeSEric Cheng /* Search for a free slot */ 3019da14cebeSEric Cheng for (slot = 0; slot < Adapter->unicst_total; slot++) { 3020da14cebeSEric Cheng if (Adapter->unicst_addr[slot].mac.set == 0) 3021da14cebeSEric Cheng break; 3022da14cebeSEric Cheng } 3023da14cebeSEric Cheng ASSERT(slot < Adapter->unicst_total); 3024da14cebeSEric Cheng 302508ac1c49SNicolas Droux err = e1000g_unicst_set(Adapter, mac_addr, slot); 302608ac1c49SNicolas Droux if (err == 0) 3027da14cebeSEric Cheng Adapter->unicst_avail--; 3028da14cebeSEric Cheng 3029d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 3030da14cebeSEric Cheng 303108ac1c49SNicolas Droux return (err); 3032da14cebeSEric Cheng } 3033da14cebeSEric Cheng 3034da14cebeSEric Cheng static int 3035da14cebeSEric Cheng e1000g_remmac(void *arg, const uint8_t *mac_addr) 3036da14cebeSEric Cheng { 3037da14cebeSEric Cheng struct e1000g *Adapter = (struct e1000g *)arg; 303808ac1c49SNicolas Droux int slot, err; 3039da14cebeSEric Cheng 3040d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 3041d5c3073dSchenlu chen - Sun Microsystems - Beijing China 3042d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_SUSPENDED) { 3043d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 3044d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (ECANCELED); 3045d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 3046da14cebeSEric Cheng 3047da14cebeSEric Cheng slot = e1000g_unicst_find(Adapter, mac_addr); 3048da14cebeSEric Cheng if (slot == -1) { 3049d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 3050da14cebeSEric Cheng return (EINVAL); 3051da14cebeSEric Cheng } 3052da14cebeSEric Cheng 3053da14cebeSEric Cheng ASSERT(Adapter->unicst_addr[slot].mac.set); 3054da14cebeSEric Cheng 3055da14cebeSEric Cheng /* Clear this slot */ 305608ac1c49SNicolas Droux err = e1000g_unicst_set(Adapter, NULL, slot); 305708ac1c49SNicolas Droux if (err == 0) 3058da14cebeSEric Cheng Adapter->unicst_avail++; 3059da14cebeSEric Cheng 3060d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 3061da14cebeSEric Cheng 306208ac1c49SNicolas Droux return (err); 3063da14cebeSEric Cheng } 3064da14cebeSEric Cheng 3065da14cebeSEric Cheng static int 3066da14cebeSEric Cheng e1000g_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 3067da14cebeSEric Cheng { 3068da14cebeSEric Cheng e1000g_rx_ring_t *rx_ring = (e1000g_rx_ring_t *)rh; 3069da14cebeSEric Cheng 3070da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock); 3071da14cebeSEric Cheng rx_ring->ring_gen_num = mr_gen_num; 3072da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock); 3073da14cebeSEric Cheng return (0); 3074da14cebeSEric Cheng } 3075da14cebeSEric Cheng 3076da14cebeSEric Cheng /* 3077da14cebeSEric Cheng * Callback funtion for MAC layer to register all rings. 3078da14cebeSEric Cheng * 3079da14cebeSEric Cheng * The hardware supports a single group with currently only one ring 3080da14cebeSEric Cheng * available. 3081da14cebeSEric Cheng * Though not offering virtualization ability per se, exposing the 3082da14cebeSEric Cheng * group/ring still enables the polling and interrupt toggling. 3083da14cebeSEric Cheng */ 308457ef6f69Sguoqing zhu - Sun Microsystems - Beijing China /* ARGSUSED */ 3085da14cebeSEric Cheng void 3086da14cebeSEric Cheng e1000g_fill_ring(void *arg, mac_ring_type_t rtype, const int grp_index, 3087da14cebeSEric Cheng const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 3088da14cebeSEric Cheng { 3089da14cebeSEric Cheng struct e1000g *Adapter = (struct e1000g *)arg; 3090da14cebeSEric Cheng e1000g_rx_ring_t *rx_ring = Adapter->rx_ring; 3091da14cebeSEric Cheng mac_intr_t *mintr; 3092da14cebeSEric Cheng 3093da14cebeSEric Cheng /* 3094da14cebeSEric Cheng * We advertised only RX group/rings, so the MAC framework shouldn't 3095da14cebeSEric Cheng * ask for any thing else. 3096da14cebeSEric Cheng */ 3097da14cebeSEric Cheng ASSERT(rtype == MAC_RING_TYPE_RX && grp_index == 0 && ring_index == 0); 3098da14cebeSEric Cheng 3099da14cebeSEric Cheng rx_ring->mrh = rx_ring->mrh_init = rh; 3100da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 3101da14cebeSEric Cheng infop->mri_start = e1000g_ring_start; 3102da14cebeSEric Cheng infop->mri_stop = NULL; 3103da14cebeSEric Cheng infop->mri_poll = e1000g_poll_ring; 31040dc2366fSVenugopal Iyer infop->mri_stat = e1000g_rx_ring_stat; 3105da14cebeSEric Cheng 3106da14cebeSEric Cheng /* Ring level interrupts */ 3107da14cebeSEric Cheng mintr = &infop->mri_intr; 3108da14cebeSEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring; 3109da14cebeSEric Cheng mintr->mi_enable = e1000g_rx_ring_intr_enable; 3110da14cebeSEric Cheng mintr->mi_disable = e1000g_rx_ring_intr_disable; 31110dc2366fSVenugopal Iyer if (Adapter->msi_enable) 31120dc2366fSVenugopal Iyer mintr->mi_ddi_handle = Adapter->htable[0]; 3113da14cebeSEric Cheng } 3114da14cebeSEric Cheng 311557ef6f69Sguoqing zhu - Sun Microsystems - Beijing China /* ARGSUSED */ 3116da14cebeSEric Cheng static void 3117da14cebeSEric Cheng e1000g_fill_group(void *arg, mac_ring_type_t rtype, const int grp_index, 3118da14cebeSEric Cheng mac_group_info_t *infop, mac_group_handle_t gh) 3119da14cebeSEric Cheng { 3120da14cebeSEric Cheng struct e1000g *Adapter = (struct e1000g *)arg; 3121da14cebeSEric Cheng mac_intr_t *mintr; 3122da14cebeSEric Cheng 3123da14cebeSEric Cheng /* 3124da14cebeSEric Cheng * We advertised a single RX ring. Getting a request for anything else 3125da14cebeSEric Cheng * signifies a bug in the MAC framework. 3126da14cebeSEric Cheng */ 3127da14cebeSEric Cheng ASSERT(rtype == MAC_RING_TYPE_RX && grp_index == 0); 3128da14cebeSEric Cheng 3129da14cebeSEric Cheng Adapter->rx_group = gh; 3130da14cebeSEric Cheng 3131da14cebeSEric Cheng infop->mgi_driver = (mac_group_driver_t)Adapter; 3132da14cebeSEric Cheng infop->mgi_start = NULL; 3133da14cebeSEric Cheng infop->mgi_stop = NULL; 3134da14cebeSEric Cheng infop->mgi_addmac = e1000g_addmac; 3135da14cebeSEric Cheng infop->mgi_remmac = e1000g_remmac; 3136da14cebeSEric Cheng infop->mgi_count = 1; 3137da14cebeSEric Cheng 3138da14cebeSEric Cheng /* Group level interrupts */ 3139da14cebeSEric Cheng mintr = &infop->mgi_intr; 3140da14cebeSEric Cheng mintr->mi_handle = (mac_intr_handle_t)Adapter; 3141da14cebeSEric Cheng mintr->mi_enable = e1000g_rx_group_intr_enable; 3142da14cebeSEric Cheng mintr->mi_disable = e1000g_rx_group_intr_disable; 3143da14cebeSEric Cheng } 3144da14cebeSEric Cheng 3145*b142f83dSRobert Mustacchi static void 3146*b142f83dSRobert Mustacchi e1000g_led_blink(void *arg) 3147*b142f83dSRobert Mustacchi { 3148*b142f83dSRobert Mustacchi e1000g_t *e1000g = arg; 3149*b142f83dSRobert Mustacchi 3150*b142f83dSRobert Mustacchi mutex_enter(&e1000g->e1000g_led_lock); 3151*b142f83dSRobert Mustacchi VERIFY(e1000g->e1000g_emul_blink); 3152*b142f83dSRobert Mustacchi if (e1000g->e1000g_emul_state) { 3153*b142f83dSRobert Mustacchi (void) e1000_led_on(&e1000g->shared); 3154*b142f83dSRobert Mustacchi } else { 3155*b142f83dSRobert Mustacchi (void) e1000_led_off(&e1000g->shared); 3156*b142f83dSRobert Mustacchi } 3157*b142f83dSRobert Mustacchi e1000g->e1000g_emul_state = !e1000g->e1000g_emul_state; 3158*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3159*b142f83dSRobert Mustacchi } 3160*b142f83dSRobert Mustacchi 3161*b142f83dSRobert Mustacchi static int 3162*b142f83dSRobert Mustacchi e1000g_led_set(void *arg, mac_led_mode_t mode, uint_t flags) 3163*b142f83dSRobert Mustacchi { 3164*b142f83dSRobert Mustacchi e1000g_t *e1000g = arg; 3165*b142f83dSRobert Mustacchi 3166*b142f83dSRobert Mustacchi if (flags != 0) 3167*b142f83dSRobert Mustacchi return (EINVAL); 3168*b142f83dSRobert Mustacchi 3169*b142f83dSRobert Mustacchi if (mode != MAC_LED_DEFAULT && 3170*b142f83dSRobert Mustacchi mode != MAC_LED_IDENT && 3171*b142f83dSRobert Mustacchi mode != MAC_LED_OFF && 3172*b142f83dSRobert Mustacchi mode != MAC_LED_ON) 3173*b142f83dSRobert Mustacchi return (ENOTSUP); 3174*b142f83dSRobert Mustacchi 3175*b142f83dSRobert Mustacchi mutex_enter(&e1000g->e1000g_led_lock); 3176*b142f83dSRobert Mustacchi 3177*b142f83dSRobert Mustacchi if ((mode == MAC_LED_IDENT || mode == MAC_LED_OFF || 3178*b142f83dSRobert Mustacchi mode == MAC_LED_ON) && 3179*b142f83dSRobert Mustacchi !e1000g->e1000g_led_setup) { 3180*b142f83dSRobert Mustacchi if (e1000_setup_led(&e1000g->shared) != E1000_SUCCESS) { 3181*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3182*b142f83dSRobert Mustacchi return (EIO); 3183*b142f83dSRobert Mustacchi } 3184*b142f83dSRobert Mustacchi 3185*b142f83dSRobert Mustacchi e1000g->e1000g_led_setup = B_TRUE; 3186*b142f83dSRobert Mustacchi } 3187*b142f83dSRobert Mustacchi 3188*b142f83dSRobert Mustacchi if (mode != MAC_LED_IDENT && e1000g->e1000g_blink != NULL) { 3189*b142f83dSRobert Mustacchi ddi_periodic_t id = e1000g->e1000g_blink; 3190*b142f83dSRobert Mustacchi e1000g->e1000g_blink = NULL; 3191*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3192*b142f83dSRobert Mustacchi ddi_periodic_delete(id); 3193*b142f83dSRobert Mustacchi mutex_enter(&e1000g->e1000g_led_lock); 3194*b142f83dSRobert Mustacchi } 3195*b142f83dSRobert Mustacchi 3196*b142f83dSRobert Mustacchi switch (mode) { 3197*b142f83dSRobert Mustacchi case MAC_LED_DEFAULT: 3198*b142f83dSRobert Mustacchi if (e1000g->e1000g_led_setup) { 3199*b142f83dSRobert Mustacchi if (e1000_cleanup_led(&e1000g->shared) != 3200*b142f83dSRobert Mustacchi E1000_SUCCESS) { 3201*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3202*b142f83dSRobert Mustacchi return (EIO); 3203*b142f83dSRobert Mustacchi } 3204*b142f83dSRobert Mustacchi e1000g->e1000g_led_setup = B_FALSE; 3205*b142f83dSRobert Mustacchi } 3206*b142f83dSRobert Mustacchi break; 3207*b142f83dSRobert Mustacchi case MAC_LED_IDENT: 3208*b142f83dSRobert Mustacchi if (e1000g->e1000g_emul_blink) { 3209*b142f83dSRobert Mustacchi if (e1000g->e1000g_blink != NULL) 3210*b142f83dSRobert Mustacchi break; 3211*b142f83dSRobert Mustacchi 3212*b142f83dSRobert Mustacchi /* 3213*b142f83dSRobert Mustacchi * Note, we use a 200 ms period here as that's what 3214*b142f83dSRobert Mustacchi * section 10.1.3 8254x Intel Manual (PCI/PCI-X Family 3215*b142f83dSRobert Mustacchi * of Gigabit Ethernet Controllers Software Developer's 3216*b142f83dSRobert Mustacchi * Manual) indicates that the optional blink hardware 3217*b142f83dSRobert Mustacchi * operates at. 3218*b142f83dSRobert Mustacchi */ 3219*b142f83dSRobert Mustacchi e1000g->e1000g_blink = 3220*b142f83dSRobert Mustacchi ddi_periodic_add(e1000g_led_blink, e1000g, 3221*b142f83dSRobert Mustacchi 200ULL * (NANOSEC / MILLISEC), DDI_IPL_0); 3222*b142f83dSRobert Mustacchi } else if (e1000_blink_led(&e1000g->shared) != E1000_SUCCESS) { 3223*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3224*b142f83dSRobert Mustacchi return (EIO); 3225*b142f83dSRobert Mustacchi } 3226*b142f83dSRobert Mustacchi break; 3227*b142f83dSRobert Mustacchi case MAC_LED_OFF: 3228*b142f83dSRobert Mustacchi if (e1000_led_off(&e1000g->shared) != E1000_SUCCESS) { 3229*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3230*b142f83dSRobert Mustacchi return (EIO); 3231*b142f83dSRobert Mustacchi } 3232*b142f83dSRobert Mustacchi break; 3233*b142f83dSRobert Mustacchi case MAC_LED_ON: 3234*b142f83dSRobert Mustacchi if (e1000_led_on(&e1000g->shared) != E1000_SUCCESS) { 3235*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3236*b142f83dSRobert Mustacchi return (EIO); 3237*b142f83dSRobert Mustacchi } 3238*b142f83dSRobert Mustacchi break; 3239*b142f83dSRobert Mustacchi default: 3240*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3241*b142f83dSRobert Mustacchi return (ENOTSUP); 3242*b142f83dSRobert Mustacchi } 3243*b142f83dSRobert Mustacchi 3244*b142f83dSRobert Mustacchi mutex_exit(&e1000g->e1000g_led_lock); 3245*b142f83dSRobert Mustacchi return (0); 3246*b142f83dSRobert Mustacchi 3247*b142f83dSRobert Mustacchi } 3248*b142f83dSRobert Mustacchi 324908057504Sxy150489 static boolean_t 325008057504Sxy150489 e1000g_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 325108057504Sxy150489 { 325208057504Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 325308057504Sxy150489 325408057504Sxy150489 switch (cap) { 325508057504Sxy150489 case MAC_CAPAB_HCKSUM: { 325608057504Sxy150489 uint32_t *txflags = cap_data; 3257c7770590Smx205022 3258c7770590Smx205022 if (Adapter->tx_hcksum_enable) 32596ad5fc39Ssv141092 *txflags = HCKSUM_IPHDRCKSUM | 32606ad5fc39Ssv141092 HCKSUM_INET_PARTIAL; 32616ad5fc39Ssv141092 else 32626ad5fc39Ssv141092 return (B_FALSE); 326308057504Sxy150489 break; 326408057504Sxy150489 } 3265c7770590Smx205022 3266c7770590Smx205022 case MAC_CAPAB_LSO: { 3267c7770590Smx205022 mac_capab_lso_t *cap_lso = cap_data; 3268c7770590Smx205022 3269c7770590Smx205022 if (Adapter->lso_enable) { 3270c7770590Smx205022 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; 3271c7770590Smx205022 cap_lso->lso_basic_tcp_ipv4.lso_max = 3272c7770590Smx205022 E1000_LSO_MAXLEN; 3273c7770590Smx205022 } else 3274c7770590Smx205022 return (B_FALSE); 3275c7770590Smx205022 break; 3276c7770590Smx205022 } 3277da14cebeSEric Cheng case MAC_CAPAB_RINGS: { 3278da14cebeSEric Cheng mac_capab_rings_t *cap_rings = cap_data; 3279c7770590Smx205022 3280da14cebeSEric Cheng /* No TX rings exposed yet */ 3281da14cebeSEric Cheng if (cap_rings->mr_type != MAC_RING_TYPE_RX) 3282da14cebeSEric Cheng return (B_FALSE); 3283da14cebeSEric Cheng 3284da14cebeSEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 3285da14cebeSEric Cheng cap_rings->mr_rnum = 1; 3286da14cebeSEric Cheng cap_rings->mr_gnum = 1; 3287da14cebeSEric Cheng cap_rings->mr_rget = e1000g_fill_ring; 3288da14cebeSEric Cheng cap_rings->mr_gget = e1000g_fill_group; 3289da14cebeSEric Cheng break; 3290da14cebeSEric Cheng } 3291*b142f83dSRobert Mustacchi case MAC_CAPAB_LED: { 3292*b142f83dSRobert Mustacchi mac_capab_led_t *cap_led = cap_data; 3293*b142f83dSRobert Mustacchi 3294*b142f83dSRobert Mustacchi cap_led->mcl_flags = 0; 3295*b142f83dSRobert Mustacchi cap_led->mcl_modes = MAC_LED_DEFAULT; 3296*b142f83dSRobert Mustacchi if (Adapter->shared.mac.ops.blink_led != NULL && 3297*b142f83dSRobert Mustacchi Adapter->shared.mac.ops.blink_led != 3298*b142f83dSRobert Mustacchi e1000_null_ops_generic) { 3299*b142f83dSRobert Mustacchi cap_led->mcl_modes |= MAC_LED_IDENT; 3300*b142f83dSRobert Mustacchi } 3301*b142f83dSRobert Mustacchi 3302*b142f83dSRobert Mustacchi if (Adapter->shared.mac.ops.led_off != NULL && 3303*b142f83dSRobert Mustacchi Adapter->shared.mac.ops.led_off != 3304*b142f83dSRobert Mustacchi e1000_null_ops_generic) { 3305*b142f83dSRobert Mustacchi cap_led->mcl_modes |= MAC_LED_OFF; 3306*b142f83dSRobert Mustacchi } 3307*b142f83dSRobert Mustacchi 3308*b142f83dSRobert Mustacchi if (Adapter->shared.mac.ops.led_on != NULL && 3309*b142f83dSRobert Mustacchi Adapter->shared.mac.ops.led_on != 3310*b142f83dSRobert Mustacchi e1000_null_ops_generic) { 3311*b142f83dSRobert Mustacchi cap_led->mcl_modes |= MAC_LED_ON; 3312*b142f83dSRobert Mustacchi } 3313*b142f83dSRobert Mustacchi 3314*b142f83dSRobert Mustacchi /* 3315*b142f83dSRobert Mustacchi * Some hardware doesn't support blinking natively as they're 3316*b142f83dSRobert Mustacchi * missing the optional blink circuit. If they have both off and 3317*b142f83dSRobert Mustacchi * on then we'll emulate it ourselves. 3318*b142f83dSRobert Mustacchi */ 3319*b142f83dSRobert Mustacchi if (((cap_led->mcl_modes & MAC_LED_IDENT) == 0) && 3320*b142f83dSRobert Mustacchi ((cap_led->mcl_modes & MAC_LED_OFF) != 0) && 3321*b142f83dSRobert Mustacchi ((cap_led->mcl_modes & MAC_LED_ON) != 0)) { 3322*b142f83dSRobert Mustacchi cap_led->mcl_modes |= MAC_LED_IDENT; 3323*b142f83dSRobert Mustacchi Adapter->e1000g_emul_blink = B_TRUE; 3324*b142f83dSRobert Mustacchi } 3325*b142f83dSRobert Mustacchi 3326*b142f83dSRobert Mustacchi cap_led->mcl_set = e1000g_led_set; 3327*b142f83dSRobert Mustacchi break; 3328*b142f83dSRobert Mustacchi } 332908057504Sxy150489 default: 333008057504Sxy150489 return (B_FALSE); 333108057504Sxy150489 } 333208057504Sxy150489 return (B_TRUE); 333308057504Sxy150489 } 333408057504Sxy150489 33359ce7e93cScc210113 static boolean_t 33369ce7e93cScc210113 e1000g_param_locked(mac_prop_id_t pr_num) 33379ce7e93cScc210113 { 33389ce7e93cScc210113 /* 33399ce7e93cScc210113 * All en_* parameters are locked (read-only) while 33409ce7e93cScc210113 * the device is in any sort of loopback mode ... 33419ce7e93cScc210113 */ 33429ce7e93cScc210113 switch (pr_num) { 33433fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 33443fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP: 33453fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 33463fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 33473fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 33483fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 33493fd94f8cSam223141 case MAC_PROP_AUTONEG: 33503fd94f8cSam223141 case MAC_PROP_FLOWCTRL: 33519ce7e93cScc210113 return (B_TRUE); 33529ce7e93cScc210113 } 33539ce7e93cScc210113 return (B_FALSE); 33549ce7e93cScc210113 } 33559ce7e93cScc210113 33569ce7e93cScc210113 /* 33579ce7e93cScc210113 * callback function for set/get of properties 33589ce7e93cScc210113 */ 33599ce7e93cScc210113 static int 33609ce7e93cScc210113 e1000g_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 33619ce7e93cScc210113 uint_t pr_valsize, const void *pr_val) 33629ce7e93cScc210113 { 33639ce7e93cScc210113 struct e1000g *Adapter = arg; 3364111c450cSMiles Xu, Sun Microsystems struct e1000_hw *hw = &Adapter->shared; 3365592a4d85Scc210113 struct e1000_fc_info *fc = &Adapter->shared.fc; 33669ce7e93cScc210113 int err = 0; 3367592a4d85Scc210113 link_flowctrl_t flowctrl; 33684045d941Ssowmini uint32_t cur_mtu, new_mtu; 33699ce7e93cScc210113 33709ce7e93cScc210113 rw_enter(&Adapter->chip_lock, RW_WRITER); 3371d5c3073dSchenlu chen - Sun Microsystems - Beijing China 3372d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_SUSPENDED) { 3373d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 3374d5c3073dSchenlu chen - Sun Microsystems - Beijing China return (ECANCELED); 3375d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 3376d5c3073dSchenlu chen - Sun Microsystems - Beijing China 33779ce7e93cScc210113 if (Adapter->loopback_mode != E1000G_LB_NONE && 33789ce7e93cScc210113 e1000g_param_locked(pr_num)) { 33799ce7e93cScc210113 /* 33809ce7e93cScc210113 * All en_* parameters are locked (read-only) 33819ce7e93cScc210113 * while the device is in any sort of loopback mode. 33829ce7e93cScc210113 */ 33839ce7e93cScc210113 rw_exit(&Adapter->chip_lock); 33849ce7e93cScc210113 return (EBUSY); 33859ce7e93cScc210113 } 33869ce7e93cScc210113 33879ce7e93cScc210113 switch (pr_num) { 33883fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 3389111c450cSMiles Xu, Sun Microsystems if (hw->phy.media_type != e1000_media_type_copper) { 3390111c450cSMiles Xu, Sun Microsystems err = ENOTSUP; 3391111c450cSMiles Xu, Sun Microsystems break; 3392111c450cSMiles Xu, Sun Microsystems } 33939ce7e93cScc210113 Adapter->param_en_1000fdx = *(uint8_t *)pr_val; 33949ce7e93cScc210113 Adapter->param_adv_1000fdx = *(uint8_t *)pr_val; 33959ce7e93cScc210113 goto reset; 33963fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 3397111c450cSMiles Xu, Sun Microsystems if (hw->phy.media_type != e1000_media_type_copper) { 3398111c450cSMiles Xu, Sun Microsystems err = ENOTSUP; 3399111c450cSMiles Xu, Sun Microsystems break; 3400111c450cSMiles Xu, Sun Microsystems } 34019ce7e93cScc210113 Adapter->param_en_100fdx = *(uint8_t *)pr_val; 34029ce7e93cScc210113 Adapter->param_adv_100fdx = *(uint8_t *)pr_val; 34039ce7e93cScc210113 goto reset; 34043fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 3405111c450cSMiles Xu, Sun Microsystems if (hw->phy.media_type != e1000_media_type_copper) { 3406111c450cSMiles Xu, Sun Microsystems err = ENOTSUP; 3407111c450cSMiles Xu, Sun Microsystems break; 3408111c450cSMiles Xu, Sun Microsystems } 34099ce7e93cScc210113 Adapter->param_en_100hdx = *(uint8_t *)pr_val; 34109ce7e93cScc210113 Adapter->param_adv_100hdx = *(uint8_t *)pr_val; 34119ce7e93cScc210113 goto reset; 34123fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 3413111c450cSMiles Xu, Sun Microsystems if (hw->phy.media_type != e1000_media_type_copper) { 3414111c450cSMiles Xu, Sun Microsystems err = ENOTSUP; 3415111c450cSMiles Xu, Sun Microsystems break; 3416111c450cSMiles Xu, Sun Microsystems } 34179ce7e93cScc210113 Adapter->param_en_10fdx = *(uint8_t *)pr_val; 34189ce7e93cScc210113 Adapter->param_adv_10fdx = *(uint8_t *)pr_val; 34199ce7e93cScc210113 goto reset; 34203fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 3421111c450cSMiles Xu, Sun Microsystems if (hw->phy.media_type != e1000_media_type_copper) { 3422111c450cSMiles Xu, Sun Microsystems err = ENOTSUP; 3423111c450cSMiles Xu, Sun Microsystems break; 3424111c450cSMiles Xu, Sun Microsystems } 34259ce7e93cScc210113 Adapter->param_en_10hdx = *(uint8_t *)pr_val; 34269ce7e93cScc210113 Adapter->param_adv_10hdx = *(uint8_t *)pr_val; 34279ce7e93cScc210113 goto reset; 34283fd94f8cSam223141 case MAC_PROP_AUTONEG: 3429111c450cSMiles Xu, Sun Microsystems if (hw->phy.media_type != e1000_media_type_copper) { 3430111c450cSMiles Xu, Sun Microsystems err = ENOTSUP; 3431111c450cSMiles Xu, Sun Microsystems break; 3432111c450cSMiles Xu, Sun Microsystems } 34339ce7e93cScc210113 Adapter->param_adv_autoneg = *(uint8_t *)pr_val; 34349ce7e93cScc210113 goto reset; 34353fd94f8cSam223141 case MAC_PROP_FLOWCTRL: 3436592a4d85Scc210113 fc->send_xon = B_TRUE; 3437592a4d85Scc210113 bcopy(pr_val, &flowctrl, sizeof (flowctrl)); 34389ce7e93cScc210113 3439592a4d85Scc210113 switch (flowctrl) { 34409ce7e93cScc210113 default: 34419ce7e93cScc210113 err = EINVAL; 34429ce7e93cScc210113 break; 34439ce7e93cScc210113 case LINK_FLOWCTRL_NONE: 3444623ff785Schenlu chen - Sun Microsystems - Beijing China fc->requested_mode = e1000_fc_none; 34459ce7e93cScc210113 break; 34469ce7e93cScc210113 case LINK_FLOWCTRL_RX: 3447623ff785Schenlu chen - Sun Microsystems - Beijing China fc->requested_mode = e1000_fc_rx_pause; 34489ce7e93cScc210113 break; 34499ce7e93cScc210113 case LINK_FLOWCTRL_TX: 3450623ff785Schenlu chen - Sun Microsystems - Beijing China fc->requested_mode = e1000_fc_tx_pause; 34519ce7e93cScc210113 break; 34529ce7e93cScc210113 case LINK_FLOWCTRL_BI: 3453623ff785Schenlu chen - Sun Microsystems - Beijing China fc->requested_mode = e1000_fc_full; 34549ce7e93cScc210113 break; 34559ce7e93cScc210113 } 34569ce7e93cScc210113 reset: 34579ce7e93cScc210113 if (err == 0) { 3458caf05df5SMiles Xu, Sun Microsystems /* check PCH limits & reset the link */ 3459caf05df5SMiles Xu, Sun Microsystems e1000g_pch_limits(Adapter); 34609ce7e93cScc210113 if (e1000g_reset_link(Adapter) != DDI_SUCCESS) 34619ce7e93cScc210113 err = EINVAL; 34629ce7e93cScc210113 } 34639ce7e93cScc210113 break; 34643fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP: 34653fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP: 34663fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 34673fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 34683fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 34693fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 3470afdda45fSVasumathi Sundaram - Sun Microsystems case MAC_PROP_EN_1000HDX_CAP: 34713fd94f8cSam223141 case MAC_PROP_STATUS: 34723fd94f8cSam223141 case MAC_PROP_SPEED: 34733fd94f8cSam223141 case MAC_PROP_DUPLEX: 34749ce7e93cScc210113 err = ENOTSUP; /* read-only prop. Can't set this. */ 34759ce7e93cScc210113 break; 34763fd94f8cSam223141 case MAC_PROP_MTU: 3477caf05df5SMiles Xu, Sun Microsystems /* adapter must be stopped for an MTU change */ 3478caf05df5SMiles Xu, Sun Microsystems if (Adapter->e1000g_state & E1000G_STARTED) { 3479caf05df5SMiles Xu, Sun Microsystems err = EBUSY; 3480caf05df5SMiles Xu, Sun Microsystems break; 3481caf05df5SMiles Xu, Sun Microsystems } 3482caf05df5SMiles Xu, Sun Microsystems 34839ce7e93cScc210113 cur_mtu = Adapter->default_mtu; 3484caf05df5SMiles Xu, Sun Microsystems 3485caf05df5SMiles Xu, Sun Microsystems /* get new requested MTU */ 34869ce7e93cScc210113 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 34879ce7e93cScc210113 if (new_mtu == cur_mtu) { 34889ce7e93cScc210113 err = 0; 34899ce7e93cScc210113 break; 34909ce7e93cScc210113 } 34919ce7e93cScc210113 3492caf05df5SMiles Xu, Sun Microsystems if ((new_mtu < DEFAULT_MTU) || 3493caf05df5SMiles Xu, Sun Microsystems (new_mtu > Adapter->max_mtu)) { 34949ce7e93cScc210113 err = EINVAL; 34959ce7e93cScc210113 break; 34969ce7e93cScc210113 } 34979ce7e93cScc210113 3498caf05df5SMiles Xu, Sun Microsystems /* inform MAC framework of new MTU */ 34999ce7e93cScc210113 err = mac_maxsdu_update(Adapter->mh, new_mtu); 3500caf05df5SMiles Xu, Sun Microsystems 35019ce7e93cScc210113 if (err == 0) { 35029ce7e93cScc210113 Adapter->default_mtu = new_mtu; 3503caf05df5SMiles Xu, Sun Microsystems Adapter->max_frame_size = 3504caf05df5SMiles Xu, Sun Microsystems e1000g_mtu2maxframe(new_mtu); 3505caf05df5SMiles Xu, Sun Microsystems 3506caf05df5SMiles Xu, Sun Microsystems /* 3507caf05df5SMiles Xu, Sun Microsystems * check PCH limits & set buffer sizes to 3508caf05df5SMiles Xu, Sun Microsystems * match new MTU 3509caf05df5SMiles Xu, Sun Microsystems */ 3510caf05df5SMiles Xu, Sun Microsystems e1000g_pch_limits(Adapter); 35119ce7e93cScc210113 e1000g_set_bufsize(Adapter); 35121bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 35131bc1c721Sguoqing zhu - Sun Microsystems - Beijing China /* 35141bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * decrease the number of descriptors and free 35151bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * packets for jumbo frames to reduce tx/rx 35161bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * resource consumption 35171bc1c721Sguoqing zhu - Sun Microsystems - Beijing China */ 35181bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->max_frame_size >= 35193fb4efefSchangqing li - Sun Microsystems - Beijing China (FRAME_SIZE_UPTO_4K)) { 35201bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->tx_desc_num_flag == 0) 35211bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_desc_num = 35221bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_JUMBO_NUM_TX_DESC; 35231bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 35241bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->rx_desc_num_flag == 0) 35251bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->rx_desc_num = 35261bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_JUMBO_NUM_RX_DESC; 35271bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 35281bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->tx_buf_num_flag == 0) 35291bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_freelist_num = 35301bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_JUMBO_NUM_TX_BUF; 35311bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 35321bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->rx_buf_num_flag == 0) 35333fb4efefSchangqing li - Sun Microsystems - Beijing China Adapter->rx_freelist_limit = 35341bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_JUMBO_NUM_RX_BUF; 35351bc1c721Sguoqing zhu - Sun Microsystems - Beijing China } else { 35361bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->tx_desc_num_flag == 0) 35371bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_desc_num = 35381bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_NUM_TX_DESCRIPTOR; 35391bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 35401bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->rx_desc_num_flag == 0) 35411bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->rx_desc_num = 35421bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_NUM_RX_DESCRIPTOR; 35431bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 35441bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->tx_buf_num_flag == 0) 35451bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_freelist_num = 35461bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_NUM_TX_FREELIST; 35471bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 35481bc1c721Sguoqing zhu - Sun Microsystems - Beijing China if (Adapter->rx_buf_num_flag == 0) 35493fb4efefSchangqing li - Sun Microsystems - Beijing China Adapter->rx_freelist_limit = 35501bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_NUM_RX_FREELIST; 35511bc1c721Sguoqing zhu - Sun Microsystems - Beijing China } 35529ce7e93cScc210113 } 35539ce7e93cScc210113 break; 35543fd94f8cSam223141 case MAC_PROP_PRIVATE: 35559ce7e93cScc210113 err = e1000g_set_priv_prop(Adapter, pr_name, 35569ce7e93cScc210113 pr_valsize, pr_val); 35579ce7e93cScc210113 break; 35589ce7e93cScc210113 default: 35599ce7e93cScc210113 err = ENOTSUP; 35609ce7e93cScc210113 break; 35619ce7e93cScc210113 } 35629ce7e93cScc210113 rw_exit(&Adapter->chip_lock); 35639ce7e93cScc210113 return (err); 35649ce7e93cScc210113 } 35659ce7e93cScc210113 35669ce7e93cScc210113 static int 35679ce7e93cScc210113 e1000g_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 35680dc2366fSVenugopal Iyer uint_t pr_valsize, void *pr_val) 35699ce7e93cScc210113 { 35709ce7e93cScc210113 struct e1000g *Adapter = arg; 3571592a4d85Scc210113 struct e1000_fc_info *fc = &Adapter->shared.fc; 35724045d941Ssowmini int err = 0; 3573592a4d85Scc210113 link_flowctrl_t flowctrl; 35749ce7e93cScc210113 uint64_t tmp = 0; 35759ce7e93cScc210113 35769ce7e93cScc210113 switch (pr_num) { 35773fd94f8cSam223141 case MAC_PROP_DUPLEX: 35780dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (link_duplex_t)); 35794045d941Ssowmini bcopy(&Adapter->link_duplex, pr_val, 35804045d941Ssowmini sizeof (link_duplex_t)); 35819ce7e93cScc210113 break; 35823fd94f8cSam223141 case MAC_PROP_SPEED: 35830dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (uint64_t)); 35849ce7e93cScc210113 tmp = Adapter->link_speed * 1000000ull; 35859ce7e93cScc210113 bcopy(&tmp, pr_val, sizeof (tmp)); 35869ce7e93cScc210113 break; 35873fd94f8cSam223141 case MAC_PROP_AUTONEG: 35889ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_adv_autoneg; 35899ce7e93cScc210113 break; 35903fd94f8cSam223141 case MAC_PROP_FLOWCTRL: 35910dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (link_flowctrl_t)); 3592d5c3073dSchenlu chen - Sun Microsystems - Beijing China switch (fc->current_mode) { 35939ce7e93cScc210113 case e1000_fc_none: 3594592a4d85Scc210113 flowctrl = LINK_FLOWCTRL_NONE; 35959ce7e93cScc210113 break; 35969ce7e93cScc210113 case e1000_fc_rx_pause: 3597592a4d85Scc210113 flowctrl = LINK_FLOWCTRL_RX; 35989ce7e93cScc210113 break; 35999ce7e93cScc210113 case e1000_fc_tx_pause: 3600592a4d85Scc210113 flowctrl = LINK_FLOWCTRL_TX; 36019ce7e93cScc210113 break; 36029ce7e93cScc210113 case e1000_fc_full: 3603592a4d85Scc210113 flowctrl = LINK_FLOWCTRL_BI; 36049ce7e93cScc210113 break; 36059ce7e93cScc210113 } 3606592a4d85Scc210113 bcopy(&flowctrl, pr_val, sizeof (flowctrl)); 36079ce7e93cScc210113 break; 36083fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP: 36099ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_adv_1000fdx; 36109ce7e93cScc210113 break; 36113fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP: 36129ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_en_1000fdx; 36139ce7e93cScc210113 break; 36143fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP: 36159ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_adv_1000hdx; 36169ce7e93cScc210113 break; 36173fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP: 36189ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_en_1000hdx; 36199ce7e93cScc210113 break; 36203fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP: 36219ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_adv_100fdx; 36229ce7e93cScc210113 break; 36233fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP: 36249ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_en_100fdx; 36259ce7e93cScc210113 break; 36263fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP: 36279ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_adv_100hdx; 36289ce7e93cScc210113 break; 36293fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP: 36309ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_en_100hdx; 36319ce7e93cScc210113 break; 36323fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP: 36339ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_adv_10fdx; 36349ce7e93cScc210113 break; 36353fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP: 36369ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_en_10fdx; 36379ce7e93cScc210113 break; 36383fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP: 36399ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_adv_10hdx; 36409ce7e93cScc210113 break; 36413fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP: 36429ce7e93cScc210113 *(uint8_t *)pr_val = Adapter->param_en_10hdx; 36434045d941Ssowmini break; 36443fd94f8cSam223141 case MAC_PROP_ADV_100T4_CAP: 36453fd94f8cSam223141 case MAC_PROP_EN_100T4_CAP: 36464045d941Ssowmini *(uint8_t *)pr_val = Adapter->param_adv_100t4; 36479ce7e93cScc210113 break; 36483fd94f8cSam223141 case MAC_PROP_PRIVATE: 36499ce7e93cScc210113 err = e1000g_get_priv_prop(Adapter, pr_name, 36500dc2366fSVenugopal Iyer pr_valsize, pr_val); 36519ce7e93cScc210113 break; 36529ce7e93cScc210113 default: 36539ce7e93cScc210113 err = ENOTSUP; 36549ce7e93cScc210113 break; 36559ce7e93cScc210113 } 36560dc2366fSVenugopal Iyer 36579ce7e93cScc210113 return (err); 36589ce7e93cScc210113 } 36599ce7e93cScc210113 36600dc2366fSVenugopal Iyer static void 36610dc2366fSVenugopal Iyer e1000g_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 36620dc2366fSVenugopal Iyer mac_prop_info_handle_t prh) 36630dc2366fSVenugopal Iyer { 36640dc2366fSVenugopal Iyer struct e1000g *Adapter = arg; 36650dc2366fSVenugopal Iyer struct e1000_hw *hw = &Adapter->shared; 36660dc2366fSVenugopal Iyer 36670dc2366fSVenugopal Iyer switch (pr_num) { 36680dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX: 36690dc2366fSVenugopal Iyer case MAC_PROP_SPEED: 36700dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000FDX_CAP: 36710dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000HDX_CAP: 36720dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP: 36730dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP: 36740dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP: 36750dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP: 36760dc2366fSVenugopal Iyer case MAC_PROP_ADV_100T4_CAP: 36770dc2366fSVenugopal Iyer case MAC_PROP_EN_100T4_CAP: 36780dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 36790dc2366fSVenugopal Iyer break; 36800dc2366fSVenugopal Iyer 36810dc2366fSVenugopal Iyer case MAC_PROP_EN_1000FDX_CAP: 36820dc2366fSVenugopal Iyer if (hw->phy.media_type != e1000_media_type_copper) { 36830dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 36840dc2366fSVenugopal Iyer } else { 36850dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 36860dc2366fSVenugopal Iyer ((Adapter->phy_ext_status & 36870dc2366fSVenugopal Iyer IEEE_ESR_1000T_FD_CAPS) || 36880dc2366fSVenugopal Iyer (Adapter->phy_ext_status & 36890dc2366fSVenugopal Iyer IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0); 36900dc2366fSVenugopal Iyer } 36910dc2366fSVenugopal Iyer break; 36920dc2366fSVenugopal Iyer 36930dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP: 36940dc2366fSVenugopal Iyer if (hw->phy.media_type != e1000_media_type_copper) { 36950dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 36960dc2366fSVenugopal Iyer } else { 36970dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 36980dc2366fSVenugopal Iyer ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 36990dc2366fSVenugopal Iyer (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) 37000dc2366fSVenugopal Iyer ? 1 : 0); 37010dc2366fSVenugopal Iyer } 37020dc2366fSVenugopal Iyer break; 37030dc2366fSVenugopal Iyer 37040dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP: 37050dc2366fSVenugopal Iyer if (hw->phy.media_type != e1000_media_type_copper) { 37060dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 37070dc2366fSVenugopal Iyer } else { 37080dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 37090dc2366fSVenugopal Iyer ((Adapter->phy_status & MII_SR_100X_HD_CAPS) || 37100dc2366fSVenugopal Iyer (Adapter->phy_status & MII_SR_100T2_HD_CAPS)) 37110dc2366fSVenugopal Iyer ? 1 : 0); 37120dc2366fSVenugopal Iyer } 37130dc2366fSVenugopal Iyer break; 37140dc2366fSVenugopal Iyer 37150dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP: 37160dc2366fSVenugopal Iyer if (hw->phy.media_type != e1000_media_type_copper) { 37170dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 37180dc2366fSVenugopal Iyer } else { 37190dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 37200dc2366fSVenugopal Iyer (Adapter->phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0); 37210dc2366fSVenugopal Iyer } 37220dc2366fSVenugopal Iyer break; 37230dc2366fSVenugopal Iyer 37240dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP: 37250dc2366fSVenugopal Iyer if (hw->phy.media_type != e1000_media_type_copper) { 37260dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 37270dc2366fSVenugopal Iyer } else { 37280dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 37290dc2366fSVenugopal Iyer (Adapter->phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0); 37300dc2366fSVenugopal Iyer } 37310dc2366fSVenugopal Iyer break; 37320dc2366fSVenugopal Iyer 37330dc2366fSVenugopal Iyer case MAC_PROP_EN_1000HDX_CAP: 37340dc2366fSVenugopal Iyer if (hw->phy.media_type != e1000_media_type_copper) 37350dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 37360dc2366fSVenugopal Iyer break; 37370dc2366fSVenugopal Iyer 37380dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG: 37390dc2366fSVenugopal Iyer if (hw->phy.media_type != e1000_media_type_copper) { 37400dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 37410dc2366fSVenugopal Iyer } else { 37420dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 37430dc2366fSVenugopal Iyer (Adapter->phy_status & MII_SR_AUTONEG_CAPS) 37440dc2366fSVenugopal Iyer ? 1 : 0); 37450dc2366fSVenugopal Iyer } 37460dc2366fSVenugopal Iyer break; 37470dc2366fSVenugopal Iyer 37480dc2366fSVenugopal Iyer case MAC_PROP_FLOWCTRL: 37490dc2366fSVenugopal Iyer mac_prop_info_set_default_link_flowctrl(prh, LINK_FLOWCTRL_BI); 37500dc2366fSVenugopal Iyer break; 37510dc2366fSVenugopal Iyer 37520dc2366fSVenugopal Iyer case MAC_PROP_MTU: { 37530dc2366fSVenugopal Iyer struct e1000_mac_info *mac = &Adapter->shared.mac; 37540dc2366fSVenugopal Iyer struct e1000_phy_info *phy = &Adapter->shared.phy; 37550dc2366fSVenugopal Iyer uint32_t max; 37560dc2366fSVenugopal Iyer 37570dc2366fSVenugopal Iyer /* some MAC types do not support jumbo frames */ 37580dc2366fSVenugopal Iyer if ((mac->type == e1000_ich8lan) || 37590dc2366fSVenugopal Iyer ((mac->type == e1000_ich9lan) && (phy->type == 37600dc2366fSVenugopal Iyer e1000_phy_ife))) { 37610dc2366fSVenugopal Iyer max = DEFAULT_MTU; 37620dc2366fSVenugopal Iyer } else { 37630dc2366fSVenugopal Iyer max = Adapter->max_mtu; 37640dc2366fSVenugopal Iyer } 37650dc2366fSVenugopal Iyer 37660dc2366fSVenugopal Iyer mac_prop_info_set_range_uint32(prh, DEFAULT_MTU, max); 37670dc2366fSVenugopal Iyer break; 37680dc2366fSVenugopal Iyer } 37690dc2366fSVenugopal Iyer case MAC_PROP_PRIVATE: { 37700dc2366fSVenugopal Iyer char valstr[64]; 37710dc2366fSVenugopal Iyer int value; 37720dc2366fSVenugopal Iyer 37730dc2366fSVenugopal Iyer if (strcmp(pr_name, "_adv_pause_cap") == 0 || 37740dc2366fSVenugopal Iyer strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 37750dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 37760dc2366fSVenugopal Iyer return; 37770dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 37780dc2366fSVenugopal Iyer value = DEFAULT_TX_BCOPY_THRESHOLD; 37790dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_tx_interrupt_enable") == 0) { 37800dc2366fSVenugopal Iyer value = DEFAULT_TX_INTR_ENABLE; 37810dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_tx_intr_delay") == 0) { 37820dc2366fSVenugopal Iyer value = DEFAULT_TX_INTR_DELAY; 37830dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_tx_intr_abs_delay") == 0) { 37840dc2366fSVenugopal Iyer value = DEFAULT_TX_INTR_ABS_DELAY; 37850dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 37860dc2366fSVenugopal Iyer value = DEFAULT_RX_BCOPY_THRESHOLD; 37870dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_max_num_rcv_packets") == 0) { 37880dc2366fSVenugopal Iyer value = DEFAULT_RX_LIMIT_ON_INTR; 37890dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_rx_intr_delay") == 0) { 37900dc2366fSVenugopal Iyer value = DEFAULT_RX_INTR_DELAY; 37910dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_rx_intr_abs_delay") == 0) { 37920dc2366fSVenugopal Iyer value = DEFAULT_RX_INTR_ABS_DELAY; 37930dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_intr_throttling_rate") == 0) { 37940dc2366fSVenugopal Iyer value = DEFAULT_INTR_THROTTLING; 37950dc2366fSVenugopal Iyer } else if (strcmp(pr_name, "_intr_adaptive") == 0) { 37960dc2366fSVenugopal Iyer value = 1; 37970dc2366fSVenugopal Iyer } else { 37980dc2366fSVenugopal Iyer return; 37990dc2366fSVenugopal Iyer } 38000dc2366fSVenugopal Iyer 38010dc2366fSVenugopal Iyer (void) snprintf(valstr, sizeof (valstr), "%d", value); 38020dc2366fSVenugopal Iyer mac_prop_info_set_default_str(prh, valstr); 38030dc2366fSVenugopal Iyer break; 38040dc2366fSVenugopal Iyer } 38050dc2366fSVenugopal Iyer } 38060dc2366fSVenugopal Iyer } 38070dc2366fSVenugopal Iyer 3808fe62dec3SChen-Liang Xu /* ARGSUSED2 */ 38099ce7e93cScc210113 static int 38109ce7e93cScc210113 e1000g_set_priv_prop(struct e1000g *Adapter, const char *pr_name, 38119ce7e93cScc210113 uint_t pr_valsize, const void *pr_val) 38129ce7e93cScc210113 { 38139ce7e93cScc210113 int err = 0; 38149ce7e93cScc210113 long result; 38159ce7e93cScc210113 struct e1000_hw *hw = &Adapter->shared; 38169ce7e93cScc210113 38179ce7e93cScc210113 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 38189ce7e93cScc210113 if (pr_val == NULL) { 38199ce7e93cScc210113 err = EINVAL; 38209ce7e93cScc210113 return (err); 38219ce7e93cScc210113 } 38229ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 38239ce7e93cScc210113 if (result < MIN_TX_BCOPY_THRESHOLD || 38249ce7e93cScc210113 result > MAX_TX_BCOPY_THRESHOLD) 38259ce7e93cScc210113 err = EINVAL; 38269ce7e93cScc210113 else { 38279ce7e93cScc210113 Adapter->tx_bcopy_thresh = (uint32_t)result; 38289ce7e93cScc210113 } 38299ce7e93cScc210113 return (err); 38309ce7e93cScc210113 } 38319ce7e93cScc210113 if (strcmp(pr_name, "_tx_interrupt_enable") == 0) { 38329ce7e93cScc210113 if (pr_val == NULL) { 38339ce7e93cScc210113 err = EINVAL; 38349ce7e93cScc210113 return (err); 38359ce7e93cScc210113 } 38369ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 38379ce7e93cScc210113 if (result < 0 || result > 1) 38389ce7e93cScc210113 err = EINVAL; 38399ce7e93cScc210113 else { 38409ce7e93cScc210113 Adapter->tx_intr_enable = (result == 1) ? 38419ce7e93cScc210113 B_TRUE: B_FALSE; 38429ce7e93cScc210113 if (Adapter->tx_intr_enable) 38439ce7e93cScc210113 e1000g_mask_tx_interrupt(Adapter); 38449ce7e93cScc210113 else 38459ce7e93cScc210113 e1000g_clear_tx_interrupt(Adapter); 38469ce7e93cScc210113 if (e1000g_check_acc_handle( 3847ec39b9cfSchangqing li - Sun Microsystems - Beijing China Adapter->osdep.reg_handle) != DDI_FM_OK) { 38489ce7e93cScc210113 ddi_fm_service_impact(Adapter->dip, 38499ce7e93cScc210113 DDI_SERVICE_DEGRADED); 3850ec39b9cfSchangqing li - Sun Microsystems - Beijing China err = EIO; 3851ec39b9cfSchangqing li - Sun Microsystems - Beijing China } 38529ce7e93cScc210113 } 38539ce7e93cScc210113 return (err); 38549ce7e93cScc210113 } 38559ce7e93cScc210113 if (strcmp(pr_name, "_tx_intr_delay") == 0) { 38569ce7e93cScc210113 if (pr_val == NULL) { 38579ce7e93cScc210113 err = EINVAL; 38589ce7e93cScc210113 return (err); 38599ce7e93cScc210113 } 38609ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 38619ce7e93cScc210113 if (result < MIN_TX_INTR_DELAY || 38629ce7e93cScc210113 result > MAX_TX_INTR_DELAY) 38639ce7e93cScc210113 err = EINVAL; 38649ce7e93cScc210113 else { 38659ce7e93cScc210113 Adapter->tx_intr_delay = (uint32_t)result; 38669ce7e93cScc210113 E1000_WRITE_REG(hw, E1000_TIDV, Adapter->tx_intr_delay); 38679ce7e93cScc210113 if (e1000g_check_acc_handle( 3868ec39b9cfSchangqing li - Sun Microsystems - Beijing China Adapter->osdep.reg_handle) != DDI_FM_OK) { 38699ce7e93cScc210113 ddi_fm_service_impact(Adapter->dip, 38709ce7e93cScc210113 DDI_SERVICE_DEGRADED); 3871ec39b9cfSchangqing li - Sun Microsystems - Beijing China err = EIO; 3872ec39b9cfSchangqing li - Sun Microsystems - Beijing China } 38739ce7e93cScc210113 } 38749ce7e93cScc210113 return (err); 38759ce7e93cScc210113 } 38769ce7e93cScc210113 if (strcmp(pr_name, "_tx_intr_abs_delay") == 0) { 38779ce7e93cScc210113 if (pr_val == NULL) { 38789ce7e93cScc210113 err = EINVAL; 38799ce7e93cScc210113 return (err); 38809ce7e93cScc210113 } 38819ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 38829ce7e93cScc210113 if (result < MIN_TX_INTR_ABS_DELAY || 38839ce7e93cScc210113 result > MAX_TX_INTR_ABS_DELAY) 38849ce7e93cScc210113 err = EINVAL; 38859ce7e93cScc210113 else { 38869ce7e93cScc210113 Adapter->tx_intr_abs_delay = (uint32_t)result; 38879ce7e93cScc210113 E1000_WRITE_REG(hw, E1000_TADV, 38889ce7e93cScc210113 Adapter->tx_intr_abs_delay); 38899ce7e93cScc210113 if (e1000g_check_acc_handle( 3890ec39b9cfSchangqing li - Sun Microsystems - Beijing China Adapter->osdep.reg_handle) != DDI_FM_OK) { 38919ce7e93cScc210113 ddi_fm_service_impact(Adapter->dip, 38929ce7e93cScc210113 DDI_SERVICE_DEGRADED); 3893ec39b9cfSchangqing li - Sun Microsystems - Beijing China err = EIO; 3894ec39b9cfSchangqing li - Sun Microsystems - Beijing China } 38959ce7e93cScc210113 } 38969ce7e93cScc210113 return (err); 38979ce7e93cScc210113 } 38989ce7e93cScc210113 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 38999ce7e93cScc210113 if (pr_val == NULL) { 39009ce7e93cScc210113 err = EINVAL; 39019ce7e93cScc210113 return (err); 39029ce7e93cScc210113 } 39039ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 39049ce7e93cScc210113 if (result < MIN_RX_BCOPY_THRESHOLD || 39059ce7e93cScc210113 result > MAX_RX_BCOPY_THRESHOLD) 39069ce7e93cScc210113 err = EINVAL; 39079ce7e93cScc210113 else 39089ce7e93cScc210113 Adapter->rx_bcopy_thresh = (uint32_t)result; 39099ce7e93cScc210113 return (err); 39109ce7e93cScc210113 } 39119ce7e93cScc210113 if (strcmp(pr_name, "_max_num_rcv_packets") == 0) { 39129ce7e93cScc210113 if (pr_val == NULL) { 39139ce7e93cScc210113 err = EINVAL; 39149ce7e93cScc210113 return (err); 39159ce7e93cScc210113 } 39169ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 39179ce7e93cScc210113 if (result < MIN_RX_LIMIT_ON_INTR || 39189ce7e93cScc210113 result > MAX_RX_LIMIT_ON_INTR) 39199ce7e93cScc210113 err = EINVAL; 39209ce7e93cScc210113 else 39219ce7e93cScc210113 Adapter->rx_limit_onintr = (uint32_t)result; 39229ce7e93cScc210113 return (err); 39239ce7e93cScc210113 } 39249ce7e93cScc210113 if (strcmp(pr_name, "_rx_intr_delay") == 0) { 39259ce7e93cScc210113 if (pr_val == NULL) { 39269ce7e93cScc210113 err = EINVAL; 39279ce7e93cScc210113 return (err); 39289ce7e93cScc210113 } 39299ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 39309ce7e93cScc210113 if (result < MIN_RX_INTR_DELAY || 39319ce7e93cScc210113 result > MAX_RX_INTR_DELAY) 39329ce7e93cScc210113 err = EINVAL; 39339ce7e93cScc210113 else { 39349ce7e93cScc210113 Adapter->rx_intr_delay = (uint32_t)result; 39359ce7e93cScc210113 E1000_WRITE_REG(hw, E1000_RDTR, Adapter->rx_intr_delay); 39369ce7e93cScc210113 if (e1000g_check_acc_handle( 3937ec39b9cfSchangqing li - Sun Microsystems - Beijing China Adapter->osdep.reg_handle) != DDI_FM_OK) { 39389ce7e93cScc210113 ddi_fm_service_impact(Adapter->dip, 39399ce7e93cScc210113 DDI_SERVICE_DEGRADED); 3940ec39b9cfSchangqing li - Sun Microsystems - Beijing China err = EIO; 3941ec39b9cfSchangqing li - Sun Microsystems - Beijing China } 39429ce7e93cScc210113 } 39439ce7e93cScc210113 return (err); 39449ce7e93cScc210113 } 39459ce7e93cScc210113 if (strcmp(pr_name, "_rx_intr_abs_delay") == 0) { 39469ce7e93cScc210113 if (pr_val == NULL) { 39479ce7e93cScc210113 err = EINVAL; 39489ce7e93cScc210113 return (err); 39499ce7e93cScc210113 } 39509ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 39519ce7e93cScc210113 if (result < MIN_RX_INTR_ABS_DELAY || 39529ce7e93cScc210113 result > MAX_RX_INTR_ABS_DELAY) 39539ce7e93cScc210113 err = EINVAL; 39549ce7e93cScc210113 else { 39559ce7e93cScc210113 Adapter->rx_intr_abs_delay = (uint32_t)result; 39569ce7e93cScc210113 E1000_WRITE_REG(hw, E1000_RADV, 39579ce7e93cScc210113 Adapter->rx_intr_abs_delay); 39589ce7e93cScc210113 if (e1000g_check_acc_handle( 3959ec39b9cfSchangqing li - Sun Microsystems - Beijing China Adapter->osdep.reg_handle) != DDI_FM_OK) { 39609ce7e93cScc210113 ddi_fm_service_impact(Adapter->dip, 39619ce7e93cScc210113 DDI_SERVICE_DEGRADED); 3962ec39b9cfSchangqing li - Sun Microsystems - Beijing China err = EIO; 3963ec39b9cfSchangqing li - Sun Microsystems - Beijing China } 39649ce7e93cScc210113 } 39659ce7e93cScc210113 return (err); 39669ce7e93cScc210113 } 39679ce7e93cScc210113 if (strcmp(pr_name, "_intr_throttling_rate") == 0) { 39689ce7e93cScc210113 if (pr_val == NULL) { 39699ce7e93cScc210113 err = EINVAL; 39709ce7e93cScc210113 return (err); 39719ce7e93cScc210113 } 39729ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 39739ce7e93cScc210113 if (result < MIN_INTR_THROTTLING || 39749ce7e93cScc210113 result > MAX_INTR_THROTTLING) 39759ce7e93cScc210113 err = EINVAL; 39769ce7e93cScc210113 else { 39779ce7e93cScc210113 if (hw->mac.type >= e1000_82540) { 39789ce7e93cScc210113 Adapter->intr_throttling_rate = 39799ce7e93cScc210113 (uint32_t)result; 39809ce7e93cScc210113 E1000_WRITE_REG(hw, E1000_ITR, 39819ce7e93cScc210113 Adapter->intr_throttling_rate); 39829ce7e93cScc210113 if (e1000g_check_acc_handle( 3983ec39b9cfSchangqing li - Sun Microsystems - Beijing China Adapter->osdep.reg_handle) != DDI_FM_OK) { 39849ce7e93cScc210113 ddi_fm_service_impact(Adapter->dip, 39859ce7e93cScc210113 DDI_SERVICE_DEGRADED); 3986ec39b9cfSchangqing li - Sun Microsystems - Beijing China err = EIO; 3987ec39b9cfSchangqing li - Sun Microsystems - Beijing China } 39889ce7e93cScc210113 } else 39899ce7e93cScc210113 err = EINVAL; 39909ce7e93cScc210113 } 39919ce7e93cScc210113 return (err); 39929ce7e93cScc210113 } 39939ce7e93cScc210113 if (strcmp(pr_name, "_intr_adaptive") == 0) { 39949ce7e93cScc210113 if (pr_val == NULL) { 39959ce7e93cScc210113 err = EINVAL; 39969ce7e93cScc210113 return (err); 39979ce7e93cScc210113 } 39989ce7e93cScc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 39999ce7e93cScc210113 if (result < 0 || result > 1) 40009ce7e93cScc210113 err = EINVAL; 40019ce7e93cScc210113 else { 40029ce7e93cScc210113 if (hw->mac.type >= e1000_82540) { 40039ce7e93cScc210113 Adapter->intr_adaptive = (result == 1) ? 40049ce7e93cScc210113 B_TRUE : B_FALSE; 40059ce7e93cScc210113 } else { 40069ce7e93cScc210113 err = EINVAL; 40079ce7e93cScc210113 } 40089ce7e93cScc210113 } 40099ce7e93cScc210113 return (err); 40109ce7e93cScc210113 } 40119ce7e93cScc210113 return (ENOTSUP); 40129ce7e93cScc210113 } 40139ce7e93cScc210113 40149ce7e93cScc210113 static int 40159ce7e93cScc210113 e1000g_get_priv_prop(struct e1000g *Adapter, const char *pr_name, 40160dc2366fSVenugopal Iyer uint_t pr_valsize, void *pr_val) 40179ce7e93cScc210113 { 40189ce7e93cScc210113 int err = ENOTSUP; 40194045d941Ssowmini int value; 40209ce7e93cScc210113 40214045d941Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) { 40224045d941Ssowmini value = Adapter->param_adv_pause; 40234045d941Ssowmini err = 0; 40244045d941Ssowmini goto done; 40254045d941Ssowmini } 40264045d941Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 40274045d941Ssowmini value = Adapter->param_adv_asym_pause; 40284045d941Ssowmini err = 0; 40294045d941Ssowmini goto done; 40304045d941Ssowmini } 40319ce7e93cScc210113 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 40320dc2366fSVenugopal Iyer value = Adapter->tx_bcopy_thresh; 40339ce7e93cScc210113 err = 0; 40349ce7e93cScc210113 goto done; 40359ce7e93cScc210113 } 40369ce7e93cScc210113 if (strcmp(pr_name, "_tx_interrupt_enable") == 0) { 40370dc2366fSVenugopal Iyer value = Adapter->tx_intr_enable; 40389ce7e93cScc210113 err = 0; 40399ce7e93cScc210113 goto done; 40409ce7e93cScc210113 } 40419ce7e93cScc210113 if (strcmp(pr_name, "_tx_intr_delay") == 0) { 40420dc2366fSVenugopal Iyer value = Adapter->tx_intr_delay; 40439ce7e93cScc210113 err = 0; 40449ce7e93cScc210113 goto done; 40459ce7e93cScc210113 } 40469ce7e93cScc210113 if (strcmp(pr_name, "_tx_intr_abs_delay") == 0) { 40470dc2366fSVenugopal Iyer value = Adapter->tx_intr_abs_delay; 40489ce7e93cScc210113 err = 0; 40499ce7e93cScc210113 goto done; 40509ce7e93cScc210113 } 40519ce7e93cScc210113 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 40520dc2366fSVenugopal Iyer value = Adapter->rx_bcopy_thresh; 40539ce7e93cScc210113 err = 0; 40549ce7e93cScc210113 goto done; 40559ce7e93cScc210113 } 40569ce7e93cScc210113 if (strcmp(pr_name, "_max_num_rcv_packets") == 0) { 40570dc2366fSVenugopal Iyer value = Adapter->rx_limit_onintr; 40589ce7e93cScc210113 err = 0; 40599ce7e93cScc210113 goto done; 40609ce7e93cScc210113 } 40619ce7e93cScc210113 if (strcmp(pr_name, "_rx_intr_delay") == 0) { 40620dc2366fSVenugopal Iyer value = Adapter->rx_intr_delay; 40639ce7e93cScc210113 err = 0; 40649ce7e93cScc210113 goto done; 40659ce7e93cScc210113 } 40669ce7e93cScc210113 if (strcmp(pr_name, "_rx_intr_abs_delay") == 0) { 40670dc2366fSVenugopal Iyer value = Adapter->rx_intr_abs_delay; 40689ce7e93cScc210113 err = 0; 40699ce7e93cScc210113 goto done; 40709ce7e93cScc210113 } 40719ce7e93cScc210113 if (strcmp(pr_name, "_intr_throttling_rate") == 0) { 40720dc2366fSVenugopal Iyer value = Adapter->intr_throttling_rate; 40739ce7e93cScc210113 err = 0; 40749ce7e93cScc210113 goto done; 40759ce7e93cScc210113 } 40769ce7e93cScc210113 if (strcmp(pr_name, "_intr_adaptive") == 0) { 40770dc2366fSVenugopal Iyer value = Adapter->intr_adaptive; 40789ce7e93cScc210113 err = 0; 40799ce7e93cScc210113 goto done; 40809ce7e93cScc210113 } 40819ce7e93cScc210113 done: 40829ce7e93cScc210113 if (err == 0) { 40834045d941Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value); 40849ce7e93cScc210113 } 40859ce7e93cScc210113 return (err); 40869ce7e93cScc210113 } 40879ce7e93cScc210113 408808057504Sxy150489 /* 408925f2d433Sxy150489 * e1000g_get_conf - get configurations set in e1000g.conf 409025f2d433Sxy150489 * This routine gets user-configured values out of the configuration 409125f2d433Sxy150489 * file e1000g.conf. 409225f2d433Sxy150489 * 409325f2d433Sxy150489 * For each configurable value, there is a minimum, a maximum, and a 409425f2d433Sxy150489 * default. 409525f2d433Sxy150489 * If user does not configure a value, use the default. 409625f2d433Sxy150489 * If user configures below the minimum, use the minumum. 409725f2d433Sxy150489 * If user configures above the maximum, use the maxumum. 409808057504Sxy150489 */ 409908057504Sxy150489 static void 410025f2d433Sxy150489 e1000g_get_conf(struct e1000g *Adapter) 410108057504Sxy150489 { 410225f2d433Sxy150489 struct e1000_hw *hw = &Adapter->shared; 410325f2d433Sxy150489 boolean_t tbi_compatibility = B_FALSE; 41041bc1c721Sguoqing zhu - Sun Microsystems - Beijing China boolean_t is_jumbo = B_FALSE; 41051bc1c721Sguoqing zhu - Sun Microsystems - Beijing China int propval; 41061bc1c721Sguoqing zhu - Sun Microsystems - Beijing China /* 41071bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * decrease the number of descriptors and free packets 41081bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * for jumbo frames to reduce tx/rx resource consumption 41091bc1c721Sguoqing zhu - Sun Microsystems - Beijing China */ 41103fb4efefSchangqing li - Sun Microsystems - Beijing China if (Adapter->max_frame_size >= FRAME_SIZE_UPTO_4K) { 41111bc1c721Sguoqing zhu - Sun Microsystems - Beijing China is_jumbo = B_TRUE; 41121bc1c721Sguoqing zhu - Sun Microsystems - Beijing China } 411325f2d433Sxy150489 411408057504Sxy150489 /* 411508057504Sxy150489 * get each configurable property from e1000g.conf 411608057504Sxy150489 */ 411708057504Sxy150489 411808057504Sxy150489 /* 411908057504Sxy150489 * NumTxDescriptors 412008057504Sxy150489 */ 41211bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_desc_num_flag = 412225f2d433Sxy150489 e1000g_get_prop(Adapter, "NumTxDescriptors", 412325f2d433Sxy150489 MIN_NUM_TX_DESCRIPTOR, MAX_NUM_TX_DESCRIPTOR, 41241bc1c721Sguoqing zhu - Sun Microsystems - Beijing China is_jumbo ? DEFAULT_JUMBO_NUM_TX_DESC 41251bc1c721Sguoqing zhu - Sun Microsystems - Beijing China : DEFAULT_NUM_TX_DESCRIPTOR, &propval); 41261bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_desc_num = propval; 412708057504Sxy150489 412808057504Sxy150489 /* 412908057504Sxy150489 * NumRxDescriptors 413008057504Sxy150489 */ 41311bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->rx_desc_num_flag = 413225f2d433Sxy150489 e1000g_get_prop(Adapter, "NumRxDescriptors", 413325f2d433Sxy150489 MIN_NUM_RX_DESCRIPTOR, MAX_NUM_RX_DESCRIPTOR, 41341bc1c721Sguoqing zhu - Sun Microsystems - Beijing China is_jumbo ? DEFAULT_JUMBO_NUM_RX_DESC 41351bc1c721Sguoqing zhu - Sun Microsystems - Beijing China : DEFAULT_NUM_RX_DESCRIPTOR, &propval); 41361bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->rx_desc_num = propval; 413708057504Sxy150489 413808057504Sxy150489 /* 413908057504Sxy150489 * NumRxFreeList 414008057504Sxy150489 */ 41411bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->rx_buf_num_flag = 414225f2d433Sxy150489 e1000g_get_prop(Adapter, "NumRxFreeList", 414325f2d433Sxy150489 MIN_NUM_RX_FREELIST, MAX_NUM_RX_FREELIST, 41441bc1c721Sguoqing zhu - Sun Microsystems - Beijing China is_jumbo ? DEFAULT_JUMBO_NUM_RX_BUF 41451bc1c721Sguoqing zhu - Sun Microsystems - Beijing China : DEFAULT_NUM_RX_FREELIST, &propval); 41463fb4efefSchangqing li - Sun Microsystems - Beijing China Adapter->rx_freelist_limit = propval; 414708057504Sxy150489 414808057504Sxy150489 /* 414908057504Sxy150489 * NumTxPacketList 415008057504Sxy150489 */ 41511bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_buf_num_flag = 415225f2d433Sxy150489 e1000g_get_prop(Adapter, "NumTxPacketList", 415325f2d433Sxy150489 MIN_NUM_TX_FREELIST, MAX_NUM_TX_FREELIST, 41541bc1c721Sguoqing zhu - Sun Microsystems - Beijing China is_jumbo ? DEFAULT_JUMBO_NUM_TX_BUF 41551bc1c721Sguoqing zhu - Sun Microsystems - Beijing China : DEFAULT_NUM_TX_FREELIST, &propval); 41561bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_freelist_num = propval; 415708057504Sxy150489 415808057504Sxy150489 /* 415908057504Sxy150489 * FlowControl 416008057504Sxy150489 */ 4161592a4d85Scc210113 hw->fc.send_xon = B_TRUE; 41621bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "FlowControl", 41631bc1c721Sguoqing zhu - Sun Microsystems - Beijing China e1000_fc_none, 4, DEFAULT_FLOW_CONTROL, &propval); 41641bc1c721Sguoqing zhu - Sun Microsystems - Beijing China hw->fc.requested_mode = propval; 416508057504Sxy150489 /* 4 is the setting that says "let the eeprom decide" */ 4166623ff785Schenlu chen - Sun Microsystems - Beijing China if (hw->fc.requested_mode == 4) 4167623ff785Schenlu chen - Sun Microsystems - Beijing China hw->fc.requested_mode = e1000_fc_default; 416808057504Sxy150489 416908057504Sxy150489 /* 417025f2d433Sxy150489 * Max Num Receive Packets on Interrupt 417108057504Sxy150489 */ 41721bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "MaxNumReceivePackets", 417325f2d433Sxy150489 MIN_RX_LIMIT_ON_INTR, MAX_RX_LIMIT_ON_INTR, 41741bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_RX_LIMIT_ON_INTR, &propval); 41751bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->rx_limit_onintr = propval; 417608057504Sxy150489 417708057504Sxy150489 /* 417808057504Sxy150489 * PHY master slave setting 417908057504Sxy150489 */ 41801bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "SetMasterSlave", 418108057504Sxy150489 e1000_ms_hw_default, e1000_ms_auto, 41821bc1c721Sguoqing zhu - Sun Microsystems - Beijing China e1000_ms_hw_default, &propval); 41831bc1c721Sguoqing zhu - Sun Microsystems - Beijing China hw->phy.ms_type = propval; 418408057504Sxy150489 418508057504Sxy150489 /* 418608057504Sxy150489 * Parameter which controls TBI mode workaround, which is only 418708057504Sxy150489 * needed on certain switches such as Cisco 6500/Foundry 418808057504Sxy150489 */ 41891bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "TbiCompatibilityEnable", 41901bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 0, 1, DEFAULT_TBI_COMPAT_ENABLE, &propval); 41911bc1c721Sguoqing zhu - Sun Microsystems - Beijing China tbi_compatibility = (propval == 1); 419225f2d433Sxy150489 e1000_set_tbi_compatibility_82543(hw, tbi_compatibility); 419308057504Sxy150489 419408057504Sxy150489 /* 419508057504Sxy150489 * MSI Enable 419608057504Sxy150489 */ 41971bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "MSIEnable", 41981bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 0, 1, DEFAULT_MSI_ENABLE, &propval); 41991bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->msi_enable = (propval == 1); 420008057504Sxy150489 420108057504Sxy150489 /* 420208057504Sxy150489 * Interrupt Throttling Rate 420308057504Sxy150489 */ 42041bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "intr_throttling_rate", 420525f2d433Sxy150489 MIN_INTR_THROTTLING, MAX_INTR_THROTTLING, 42061bc1c721Sguoqing zhu - Sun Microsystems - Beijing China DEFAULT_INTR_THROTTLING, &propval); 42071bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->intr_throttling_rate = propval; 420808057504Sxy150489 420908057504Sxy150489 /* 421008057504Sxy150489 * Adaptive Interrupt Blanking Enable/Disable 421108057504Sxy150489 * It is enabled by default 421208057504Sxy150489 */ 42131bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "intr_adaptive", 0, 1, 1, 42141bc1c721Sguoqing zhu - Sun Microsystems - Beijing China &propval); 42151bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->intr_adaptive = (propval == 1); 421647b7744cSyy150190 421747b7744cSyy150190 /* 42186ad5fc39Ssv141092 * Hardware checksum enable/disable parameter 42196ad5fc39Ssv141092 */ 42201bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "tx_hcksum_enable", 42211bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 0, 1, DEFAULT_TX_HCKSUM_ENABLE, &propval); 42221bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->tx_hcksum_enable = (propval == 1); 4223c7770590Smx205022 /* 4224c7770590Smx205022 * Checksum on/off selection via global parameters. 4225c7770590Smx205022 * 4226c7770590Smx205022 * If the chip is flagged as not capable of (correctly) 4227c7770590Smx205022 * handling checksumming, we don't enable it on either 4228c7770590Smx205022 * Rx or Tx side. Otherwise, we take this chip's settings 4229c7770590Smx205022 * from the patchable global defaults. 4230c7770590Smx205022 * 4231c7770590Smx205022 * We advertise our capabilities only if TX offload is 4232c7770590Smx205022 * enabled. On receive, the stack will accept checksummed 4233c7770590Smx205022 * packets anyway, even if we haven't said we can deliver 4234c7770590Smx205022 * them. 4235c7770590Smx205022 */ 4236c7770590Smx205022 switch (hw->mac.type) { 4237c7770590Smx205022 case e1000_82540: 4238c7770590Smx205022 case e1000_82544: 4239c7770590Smx205022 case e1000_82545: 4240c7770590Smx205022 case e1000_82545_rev_3: 4241c7770590Smx205022 case e1000_82546: 4242c7770590Smx205022 case e1000_82546_rev_3: 4243c7770590Smx205022 case e1000_82571: 4244c7770590Smx205022 case e1000_82572: 4245c7770590Smx205022 case e1000_82573: 4246c7770590Smx205022 case e1000_80003es2lan: 4247c7770590Smx205022 break; 4248c7770590Smx205022 /* 4249c7770590Smx205022 * For the following Intel PRO/1000 chipsets, we have not 4250c7770590Smx205022 * tested the hardware checksum offload capability, so we 4251c7770590Smx205022 * disable the capability for them. 4252c7770590Smx205022 * e1000_82542, 4253c7770590Smx205022 * e1000_82543, 4254c7770590Smx205022 * e1000_82541, 4255c7770590Smx205022 * e1000_82541_rev_2, 4256c7770590Smx205022 * e1000_82547, 4257c7770590Smx205022 * e1000_82547_rev_2, 4258c7770590Smx205022 */ 4259c7770590Smx205022 default: 4260c7770590Smx205022 Adapter->tx_hcksum_enable = B_FALSE; 4261c7770590Smx205022 } 42626ad5fc39Ssv141092 4263c7770590Smx205022 /* 4264c7770590Smx205022 * Large Send Offloading(LSO) Enable/Disable 4265c7770590Smx205022 * If the tx hardware checksum is not enabled, LSO should be 4266c7770590Smx205022 * disabled. 4267c7770590Smx205022 */ 42681bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "lso_enable", 42691bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 0, 1, DEFAULT_LSO_ENABLE, &propval); 42701bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->lso_enable = (propval == 1); 4271c7770590Smx205022 4272c7770590Smx205022 switch (hw->mac.type) { 4273c7770590Smx205022 case e1000_82546: 4274c7770590Smx205022 case e1000_82546_rev_3: 4275c7770590Smx205022 if (Adapter->lso_enable) 4276c7770590Smx205022 Adapter->lso_premature_issue = B_TRUE; 4277fe62dec3SChen-Liang Xu /* FALLTHRU */ 4278c7770590Smx205022 case e1000_82571: 4279c7770590Smx205022 case e1000_82572: 4280c7770590Smx205022 case e1000_82573: 428143a17687SMiles Xu, Sun Microsystems case e1000_80003es2lan: 4282c7770590Smx205022 break; 4283c7770590Smx205022 default: 4284c7770590Smx205022 Adapter->lso_enable = B_FALSE; 4285c7770590Smx205022 } 4286c7770590Smx205022 4287c7770590Smx205022 if (!Adapter->tx_hcksum_enable) { 4288c7770590Smx205022 Adapter->lso_premature_issue = B_FALSE; 4289c7770590Smx205022 Adapter->lso_enable = B_FALSE; 4290c7770590Smx205022 } 42913d15c084Schenlu chen - Sun Microsystems - Beijing China 42923d15c084Schenlu chen - Sun Microsystems - Beijing China /* 42933d15c084Schenlu chen - Sun Microsystems - Beijing China * If mem_workaround_82546 is enabled, the rx buffer allocated by 42943d15c084Schenlu chen - Sun Microsystems - Beijing China * e1000_82545, e1000_82546 and e1000_82546_rev_3 42953d15c084Schenlu chen - Sun Microsystems - Beijing China * will not cross 64k boundary. 42963d15c084Schenlu chen - Sun Microsystems - Beijing China */ 42971bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "mem_workaround_82546", 42981bc1c721Sguoqing zhu - Sun Microsystems - Beijing China 0, 1, DEFAULT_MEM_WORKAROUND_82546, &propval); 42991bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->mem_workaround_82546 = (propval == 1); 43000c56b8d9Schangqing li - Sun Microsystems - Beijing China 43010c56b8d9Schangqing li - Sun Microsystems - Beijing China /* 43020c56b8d9Schangqing li - Sun Microsystems - Beijing China * Max number of multicast addresses 43030c56b8d9Schangqing li - Sun Microsystems - Beijing China */ 43041bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "mcast_max_num", 43051bc1c721Sguoqing zhu - Sun Microsystems - Beijing China MIN_MCAST_NUM, MAX_MCAST_NUM, hw->mac.mta_reg_count * 32, 43061bc1c721Sguoqing zhu - Sun Microsystems - Beijing China &propval); 43071bc1c721Sguoqing zhu - Sun Microsystems - Beijing China Adapter->mcast_max_num = propval; 430808057504Sxy150489 } 430908057504Sxy150489 431008057504Sxy150489 /* 431125f2d433Sxy150489 * e1000g_get_prop - routine to read properties 431225f2d433Sxy150489 * 431325f2d433Sxy150489 * Get a user-configure property value out of the configuration 431425f2d433Sxy150489 * file e1000g.conf. 431525f2d433Sxy150489 * 431625f2d433Sxy150489 * Caller provides name of the property, a default value, a minimum 43171bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * value, a maximum value and a pointer to the returned property 43181bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * value. 431925f2d433Sxy150489 * 43201bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * Return B_TRUE if the configured value of the property is not a default 43211bc1c721Sguoqing zhu - Sun Microsystems - Beijing China * value, otherwise return B_FALSE. 432208057504Sxy150489 */ 43231bc1c721Sguoqing zhu - Sun Microsystems - Beijing China static boolean_t 432425f2d433Sxy150489 e1000g_get_prop(struct e1000g *Adapter, /* point to per-adapter structure */ 432508057504Sxy150489 char *propname, /* name of the property */ 432608057504Sxy150489 int minval, /* minimum acceptable value */ 432708057504Sxy150489 int maxval, /* maximim acceptable value */ 43281bc1c721Sguoqing zhu - Sun Microsystems - Beijing China int defval, /* default value */ 43291bc1c721Sguoqing zhu - Sun Microsystems - Beijing China int *propvalue) /* property value return to caller */ 433008057504Sxy150489 { 433108057504Sxy150489 int propval; /* value returned for requested property */ 433208057504Sxy150489 int *props; /* point to array of properties returned */ 433308057504Sxy150489 uint_t nprops; /* number of property value returned */ 43341bc1c721Sguoqing zhu - Sun Microsystems - Beijing China boolean_t ret = B_TRUE; 433508057504Sxy150489 433608057504Sxy150489 /* 433708057504Sxy150489 * get the array of properties from the config file 433808057504Sxy150489 */ 433908057504Sxy150489 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, Adapter->dip, 434008057504Sxy150489 DDI_PROP_DONTPASS, propname, &props, &nprops) == DDI_PROP_SUCCESS) { 434108057504Sxy150489 /* got some properties, test if we got enough */ 434225f2d433Sxy150489 if (Adapter->instance < nprops) { 434325f2d433Sxy150489 propval = props[Adapter->instance]; 434408057504Sxy150489 } else { 434508057504Sxy150489 /* not enough properties configured */ 434608057504Sxy150489 propval = defval; 434725f2d433Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL, 434808057504Sxy150489 "Not Enough %s values found in e1000g.conf" 434908057504Sxy150489 " - set to %d\n", 435008057504Sxy150489 propname, propval); 43511bc1c721Sguoqing zhu - Sun Microsystems - Beijing China ret = B_FALSE; 435208057504Sxy150489 } 435308057504Sxy150489 435408057504Sxy150489 /* free memory allocated for properties */ 435508057504Sxy150489 ddi_prop_free(props); 435608057504Sxy150489 435708057504Sxy150489 } else { 435808057504Sxy150489 propval = defval; 43591bc1c721Sguoqing zhu - Sun Microsystems - Beijing China ret = B_FALSE; 436008057504Sxy150489 } 436108057504Sxy150489 436208057504Sxy150489 /* 436308057504Sxy150489 * enforce limits 436408057504Sxy150489 */ 436508057504Sxy150489 if (propval > maxval) { 436608057504Sxy150489 propval = maxval; 436725f2d433Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL, 436808057504Sxy150489 "Too High %s value in e1000g.conf - set to %d\n", 436908057504Sxy150489 propname, propval); 437008057504Sxy150489 } 437108057504Sxy150489 437208057504Sxy150489 if (propval < minval) { 437308057504Sxy150489 propval = minval; 437425f2d433Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL, 437508057504Sxy150489 "Too Low %s value in e1000g.conf - set to %d\n", 437608057504Sxy150489 propname, propval); 437708057504Sxy150489 } 437808057504Sxy150489 43791bc1c721Sguoqing zhu - Sun Microsystems - Beijing China *propvalue = propval; 43801bc1c721Sguoqing zhu - Sun Microsystems - Beijing China return (ret); 438108057504Sxy150489 } 438208057504Sxy150489 438308057504Sxy150489 static boolean_t 43847941757cSxy150489 e1000g_link_check(struct e1000g *Adapter) 438508057504Sxy150489 { 43867941757cSxy150489 uint16_t speed, duplex, phydata; 43877941757cSxy150489 boolean_t link_changed = B_FALSE; 438808057504Sxy150489 struct e1000_hw *hw; 438908057504Sxy150489 uint32_t reg_tarc; 439008057504Sxy150489 439125f2d433Sxy150489 hw = &Adapter->shared; 439208057504Sxy150489 439308057504Sxy150489 if (e1000g_link_up(Adapter)) { 439408057504Sxy150489 /* 439508057504Sxy150489 * The Link is up, check whether it was marked as down earlier 439608057504Sxy150489 */ 43977941757cSxy150489 if (Adapter->link_state != LINK_STATE_UP) { 4398fe62dec3SChen-Liang Xu (void) e1000_get_speed_and_duplex(hw, &speed, &duplex); 43997941757cSxy150489 Adapter->link_speed = speed; 44007941757cSxy150489 Adapter->link_duplex = duplex; 44017941757cSxy150489 Adapter->link_state = LINK_STATE_UP; 44027941757cSxy150489 link_changed = B_TRUE; 440308057504Sxy150489 440454e0d7a5SMiles Xu, Sun Microsystems if (Adapter->link_speed == SPEED_1000) 440554e0d7a5SMiles Xu, Sun Microsystems Adapter->stall_threshold = TX_STALL_TIME_2S; 440654e0d7a5SMiles Xu, Sun Microsystems else 440754e0d7a5SMiles Xu, Sun Microsystems Adapter->stall_threshold = TX_STALL_TIME_8S; 440854e0d7a5SMiles Xu, Sun Microsystems 44097941757cSxy150489 Adapter->tx_link_down_timeout = 0; 44107941757cSxy150489 441125f2d433Sxy150489 if ((hw->mac.type == e1000_82571) || 441225f2d433Sxy150489 (hw->mac.type == e1000_82572)) { 4413592a4d85Scc210113 reg_tarc = E1000_READ_REG(hw, E1000_TARC(0)); 44147941757cSxy150489 if (speed == SPEED_1000) 441508057504Sxy150489 reg_tarc |= (1 << 21); 441608057504Sxy150489 else 441708057504Sxy150489 reg_tarc &= ~(1 << 21); 4418592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_TARC(0), reg_tarc); 441908057504Sxy150489 } 442008057504Sxy150489 } 442108057504Sxy150489 Adapter->smartspeed = 0; 442208057504Sxy150489 } else { 44237941757cSxy150489 if (Adapter->link_state != LINK_STATE_DOWN) { 442408057504Sxy150489 Adapter->link_speed = 0; 442508057504Sxy150489 Adapter->link_duplex = 0; 44267941757cSxy150489 Adapter->link_state = LINK_STATE_DOWN; 44277941757cSxy150489 link_changed = B_TRUE; 442808057504Sxy150489 442908057504Sxy150489 /* 443008057504Sxy150489 * SmartSpeed workaround for Tabor/TanaX, When the 443108057504Sxy150489 * driver loses link disable auto master/slave 443208057504Sxy150489 * resolution. 443308057504Sxy150489 */ 443425f2d433Sxy150489 if (hw->phy.type == e1000_phy_igp) { 4435fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, 443608057504Sxy150489 PHY_1000T_CTRL, &phydata); 443708057504Sxy150489 phydata |= CR_1000T_MS_ENABLE; 4438fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 443908057504Sxy150489 PHY_1000T_CTRL, phydata); 444008057504Sxy150489 } 444108057504Sxy150489 } else { 444208057504Sxy150489 e1000g_smartspeed(Adapter); 444308057504Sxy150489 } 44447941757cSxy150489 4445d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_STARTED) { 44467941757cSxy150489 if (Adapter->tx_link_down_timeout < 44477941757cSxy150489 MAX_TX_LINK_DOWN_TIMEOUT) { 44487941757cSxy150489 Adapter->tx_link_down_timeout++; 44497941757cSxy150489 } else if (Adapter->tx_link_down_timeout == 44507941757cSxy150489 MAX_TX_LINK_DOWN_TIMEOUT) { 445125f2d433Sxy150489 e1000g_tx_clean(Adapter); 44527941757cSxy150489 Adapter->tx_link_down_timeout++; 445308057504Sxy150489 } 44547941757cSxy150489 } 44557941757cSxy150489 } 44567941757cSxy150489 44579b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 44589b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 44599b6541b3Sgl147354 44607941757cSxy150489 return (link_changed); 44617941757cSxy150489 } 44627941757cSxy150489 44639ce7e93cScc210113 /* 44649ce7e93cScc210113 * e1000g_reset_link - Using the link properties to setup the link 44659ce7e93cScc210113 */ 44669ce7e93cScc210113 int 44679ce7e93cScc210113 e1000g_reset_link(struct e1000g *Adapter) 44689ce7e93cScc210113 { 44699ce7e93cScc210113 struct e1000_mac_info *mac; 44709ce7e93cScc210113 struct e1000_phy_info *phy; 4471111c450cSMiles Xu, Sun Microsystems struct e1000_hw *hw; 44729ce7e93cScc210113 boolean_t invalid; 44739ce7e93cScc210113 44749ce7e93cScc210113 mac = &Adapter->shared.mac; 44759ce7e93cScc210113 phy = &Adapter->shared.phy; 4476111c450cSMiles Xu, Sun Microsystems hw = &Adapter->shared; 44779ce7e93cScc210113 invalid = B_FALSE; 44789ce7e93cScc210113 4479111c450cSMiles Xu, Sun Microsystems if (hw->phy.media_type != e1000_media_type_copper) 4480111c450cSMiles Xu, Sun Microsystems goto out; 4481111c450cSMiles Xu, Sun Microsystems 44829ce7e93cScc210113 if (Adapter->param_adv_autoneg == 1) { 44839ce7e93cScc210113 mac->autoneg = B_TRUE; 44849ce7e93cScc210113 phy->autoneg_advertised = 0; 44859ce7e93cScc210113 44869ce7e93cScc210113 /* 44879ce7e93cScc210113 * 1000hdx is not supported for autonegotiation 44889ce7e93cScc210113 */ 44899ce7e93cScc210113 if (Adapter->param_adv_1000fdx == 1) 44909ce7e93cScc210113 phy->autoneg_advertised |= ADVERTISE_1000_FULL; 44919ce7e93cScc210113 44929ce7e93cScc210113 if (Adapter->param_adv_100fdx == 1) 44939ce7e93cScc210113 phy->autoneg_advertised |= ADVERTISE_100_FULL; 44949ce7e93cScc210113 44959ce7e93cScc210113 if (Adapter->param_adv_100hdx == 1) 44969ce7e93cScc210113 phy->autoneg_advertised |= ADVERTISE_100_HALF; 44979ce7e93cScc210113 44989ce7e93cScc210113 if (Adapter->param_adv_10fdx == 1) 44999ce7e93cScc210113 phy->autoneg_advertised |= ADVERTISE_10_FULL; 45009ce7e93cScc210113 45019ce7e93cScc210113 if (Adapter->param_adv_10hdx == 1) 45029ce7e93cScc210113 phy->autoneg_advertised |= ADVERTISE_10_HALF; 45039ce7e93cScc210113 45049ce7e93cScc210113 if (phy->autoneg_advertised == 0) 45059ce7e93cScc210113 invalid = B_TRUE; 45069ce7e93cScc210113 } else { 45079ce7e93cScc210113 mac->autoneg = B_FALSE; 45089ce7e93cScc210113 45099ce7e93cScc210113 /* 4510111c450cSMiles Xu, Sun Microsystems * For Intel copper cards, 1000fdx and 1000hdx are not 4511111c450cSMiles Xu, Sun Microsystems * supported for forced link 45129ce7e93cScc210113 */ 45139ce7e93cScc210113 if (Adapter->param_adv_100fdx == 1) 45149ce7e93cScc210113 mac->forced_speed_duplex = ADVERTISE_100_FULL; 45159ce7e93cScc210113 else if (Adapter->param_adv_100hdx == 1) 45169ce7e93cScc210113 mac->forced_speed_duplex = ADVERTISE_100_HALF; 45179ce7e93cScc210113 else if (Adapter->param_adv_10fdx == 1) 45189ce7e93cScc210113 mac->forced_speed_duplex = ADVERTISE_10_FULL; 45199ce7e93cScc210113 else if (Adapter->param_adv_10hdx == 1) 45209ce7e93cScc210113 mac->forced_speed_duplex = ADVERTISE_10_HALF; 45219ce7e93cScc210113 else 45229ce7e93cScc210113 invalid = B_TRUE; 45239ce7e93cScc210113 45249ce7e93cScc210113 } 45259ce7e93cScc210113 45269ce7e93cScc210113 if (invalid) { 45279ce7e93cScc210113 e1000g_log(Adapter, CE_WARN, 4528caf05df5SMiles Xu, Sun Microsystems "Invalid link settings. Setup link to " 45299ce7e93cScc210113 "support autonegotiation with all link capabilities."); 45309ce7e93cScc210113 mac->autoneg = B_TRUE; 4531caf05df5SMiles Xu, Sun Microsystems phy->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; 45329ce7e93cScc210113 } 45339ce7e93cScc210113 4534111c450cSMiles Xu, Sun Microsystems out: 45359ce7e93cScc210113 return (e1000_setup_link(&Adapter->shared)); 45369ce7e93cScc210113 } 45379ce7e93cScc210113 45387941757cSxy150489 static void 4539da14cebeSEric Cheng e1000g_timer_tx_resched(struct e1000g *Adapter) 4540da14cebeSEric Cheng { 4541da14cebeSEric Cheng e1000g_tx_ring_t *tx_ring = Adapter->tx_ring; 4542da14cebeSEric Cheng 4543d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_READER); 4544d5c3073dSchenlu chen - Sun Microsystems - Beijing China 4545da14cebeSEric Cheng if (tx_ring->resched_needed && 4546da14cebeSEric Cheng ((ddi_get_lbolt() - tx_ring->resched_timestamp) > 4547da14cebeSEric Cheng drv_usectohz(1000000)) && 4548d5c3073dSchenlu chen - Sun Microsystems - Beijing China (Adapter->e1000g_state & E1000G_STARTED) && 4549da14cebeSEric Cheng (tx_ring->tbd_avail >= DEFAULT_TX_NO_RESOURCE)) { 4550da14cebeSEric Cheng tx_ring->resched_needed = B_FALSE; 4551da14cebeSEric Cheng mac_tx_update(Adapter->mh); 4552da14cebeSEric Cheng E1000G_STAT(tx_ring->stat_reschedule); 4553da14cebeSEric Cheng E1000G_STAT(tx_ring->stat_timer_reschedule); 4554da14cebeSEric Cheng } 4555d5c3073dSchenlu chen - Sun Microsystems - Beijing China 4556d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 4557da14cebeSEric Cheng } 4558da14cebeSEric Cheng 4559da14cebeSEric Cheng static void 456025f2d433Sxy150489 e1000g_local_timer(void *ws) 45617941757cSxy150489 { 45627941757cSxy150489 struct e1000g *Adapter = (struct e1000g *)ws; 45637941757cSxy150489 struct e1000_hw *hw; 45647941757cSxy150489 e1000g_ether_addr_t ether_addr; 45657941757cSxy150489 boolean_t link_changed; 45667941757cSxy150489 456725f2d433Sxy150489 hw = &Adapter->shared; 45687941757cSxy150489 4569d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (Adapter->e1000g_state & E1000G_ERROR) { 4570d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_enter(&Adapter->chip_lock, RW_WRITER); 4571d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state &= ~E1000G_ERROR; 4572d5c3073dSchenlu chen - Sun Microsystems - Beijing China rw_exit(&Adapter->chip_lock); 4573d5c3073dSchenlu chen - Sun Microsystems - Beijing China 45749b6541b3Sgl147354 Adapter->reset_count++; 4575da14cebeSEric Cheng if (e1000g_global_reset(Adapter)) { 45769b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, 45779b6541b3Sgl147354 DDI_SERVICE_RESTORED); 4578da14cebeSEric Cheng e1000g_timer_tx_resched(Adapter); 4579da14cebeSEric Cheng } else 45809b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, 45819b6541b3Sgl147354 DDI_SERVICE_LOST); 45829b6541b3Sgl147354 return; 45839b6541b3Sgl147354 } 45849b6541b3Sgl147354 45857941757cSxy150489 if (e1000g_stall_check(Adapter)) { 458625f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 45877941757cSxy150489 "Tx stall detected. Activate automatic recovery.\n"); 45889b6541b3Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_STALL); 4589d5c3073dSchenlu chen - Sun Microsystems - Beijing China ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 45907941757cSxy150489 Adapter->reset_count++; 4591da14cebeSEric Cheng if (e1000g_reset_adapter(Adapter)) { 45929b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, 45939b6541b3Sgl147354 DDI_SERVICE_RESTORED); 4594da14cebeSEric Cheng e1000g_timer_tx_resched(Adapter); 4595d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 45969b6541b3Sgl147354 return; 45977941757cSxy150489 } 45987941757cSxy150489 45997941757cSxy150489 link_changed = B_FALSE; 46004914a7d0Syy150190 rw_enter(&Adapter->chip_lock, RW_READER); 46017941757cSxy150489 if (Adapter->link_complete) 46027941757cSxy150489 link_changed = e1000g_link_check(Adapter); 46034914a7d0Syy150190 rw_exit(&Adapter->chip_lock); 46047941757cSxy150489 460554e0d7a5SMiles Xu, Sun Microsystems if (link_changed) { 460672d5682dSGuoqing Zhu if (!Adapter->reset_flag && 460772d5682dSGuoqing Zhu (Adapter->e1000g_state & E1000G_STARTED) && 460872d5682dSGuoqing Zhu !(Adapter->e1000g_state & E1000G_SUSPENDED)) 4609a2e9a830Scc210113 mac_link_update(Adapter->mh, Adapter->link_state); 461054e0d7a5SMiles Xu, Sun Microsystems if (Adapter->link_state == LINK_STATE_UP) 461154e0d7a5SMiles Xu, Sun Microsystems Adapter->reset_flag = B_FALSE; 461254e0d7a5SMiles Xu, Sun Microsystems } 461330a54d15Sxy150489 /* 461430a54d15Sxy150489 * Workaround for esb2. Data stuck in fifo on a link 461530a54d15Sxy150489 * down event. Reset the adapter to recover it. 461630a54d15Sxy150489 */ 4617a2e9a830Scc210113 if (Adapter->esb2_workaround) { 4618a2e9a830Scc210113 Adapter->esb2_workaround = B_FALSE; 461919397407SSherry Moore (void) e1000g_reset_adapter(Adapter); 4620d5c3073dSchenlu chen - Sun Microsystems - Beijing China return; 462130a54d15Sxy150489 } 462208057504Sxy150489 462308057504Sxy150489 /* 462408057504Sxy150489 * With 82571 controllers, any locally administered address will 462508057504Sxy150489 * be overwritten when there is a reset on the other port. 462608057504Sxy150489 * Detect this circumstance and correct it. 462708057504Sxy150489 */ 462825f2d433Sxy150489 if ((hw->mac.type == e1000_82571) && 462925f2d433Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) { 463025f2d433Sxy150489 ether_addr.reg.low = E1000_READ_REG_ARRAY(hw, E1000_RA, 0); 463125f2d433Sxy150489 ether_addr.reg.high = E1000_READ_REG_ARRAY(hw, E1000_RA, 1); 463208057504Sxy150489 463308057504Sxy150489 ether_addr.reg.low = ntohl(ether_addr.reg.low); 463408057504Sxy150489 ether_addr.reg.high = ntohl(ether_addr.reg.high); 463508057504Sxy150489 463625f2d433Sxy150489 if ((ether_addr.mac.addr[5] != hw->mac.addr[0]) || 463725f2d433Sxy150489 (ether_addr.mac.addr[4] != hw->mac.addr[1]) || 463825f2d433Sxy150489 (ether_addr.mac.addr[3] != hw->mac.addr[2]) || 463925f2d433Sxy150489 (ether_addr.mac.addr[2] != hw->mac.addr[3]) || 464025f2d433Sxy150489 (ether_addr.mac.addr[1] != hw->mac.addr[4]) || 464125f2d433Sxy150489 (ether_addr.mac.addr[0] != hw->mac.addr[5])) { 4642c124a83eSRobert Mustacchi (void) e1000_rar_set(hw, hw->mac.addr, 0); 464308057504Sxy150489 } 464408057504Sxy150489 } 464508057504Sxy150489 464608057504Sxy150489 /* 464725f2d433Sxy150489 * Long TTL workaround for 82541/82547 464808057504Sxy150489 */ 4649fe62dec3SChen-Liang Xu (void) e1000_igp_ttl_workaround_82547(hw); 465008057504Sxy150489 465108057504Sxy150489 /* 465208057504Sxy150489 * Check for Adaptive IFS settings If there are lots of collisions 465308057504Sxy150489 * change the value in steps... 465408057504Sxy150489 * These properties should only be set for 10/100 465508057504Sxy150489 */ 4656592a4d85Scc210113 if ((hw->phy.media_type == e1000_media_type_copper) && 46577941757cSxy150489 ((Adapter->link_speed == SPEED_100) || 46587941757cSxy150489 (Adapter->link_speed == SPEED_10))) { 465908057504Sxy150489 e1000_update_adaptive(hw); 466008057504Sxy150489 } 466108057504Sxy150489 /* 466208057504Sxy150489 * Set Timer Interrupts 466308057504Sxy150489 */ 466425f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_ICS, E1000_IMS_RXT0); 466508057504Sxy150489 46669b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 46679b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 4668da14cebeSEric Cheng else 4669da14cebeSEric Cheng e1000g_timer_tx_resched(Adapter); 46709b6541b3Sgl147354 467125f2d433Sxy150489 restart_watchdog_timer(Adapter); 467208057504Sxy150489 } 467308057504Sxy150489 46747941757cSxy150489 /* 46757941757cSxy150489 * The function e1000g_link_timer() is called when the timer for link setup 46767941757cSxy150489 * is expired, which indicates the completion of the link setup. The link 46777941757cSxy150489 * state will not be updated until the link setup is completed. And the 46787941757cSxy150489 * link state will not be sent to the upper layer through mac_link_update() 46797941757cSxy150489 * in this function. It will be updated in the local timer routine or the 46807941757cSxy150489 * interrupt service routine after the interface is started (plumbed). 46817941757cSxy150489 */ 468208057504Sxy150489 static void 46837941757cSxy150489 e1000g_link_timer(void *arg) 468408057504Sxy150489 { 46857941757cSxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 468608057504Sxy150489 468725f2d433Sxy150489 mutex_enter(&Adapter->link_lock); 46887941757cSxy150489 Adapter->link_complete = B_TRUE; 46897941757cSxy150489 Adapter->link_tid = 0; 469025f2d433Sxy150489 mutex_exit(&Adapter->link_lock); 469108057504Sxy150489 } 469208057504Sxy150489 469308057504Sxy150489 /* 469425f2d433Sxy150489 * e1000g_force_speed_duplex - read forced speed/duplex out of e1000g.conf 469525f2d433Sxy150489 * 469625f2d433Sxy150489 * This function read the forced speed and duplex for 10/100 Mbps speeds 469725f2d433Sxy150489 * and also for 1000 Mbps speeds from the e1000g.conf file 469808057504Sxy150489 */ 469908057504Sxy150489 static void 470008057504Sxy150489 e1000g_force_speed_duplex(struct e1000g *Adapter) 470108057504Sxy150489 { 470208057504Sxy150489 int forced; 47031bc1c721Sguoqing zhu - Sun Microsystems - Beijing China int propval; 470425f2d433Sxy150489 struct e1000_mac_info *mac = &Adapter->shared.mac; 470525f2d433Sxy150489 struct e1000_phy_info *phy = &Adapter->shared.phy; 470608057504Sxy150489 470708057504Sxy150489 /* 470808057504Sxy150489 * get value out of config file 470908057504Sxy150489 */ 47101bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "ForceSpeedDuplex", 47111bc1c721Sguoqing zhu - Sun Microsystems - Beijing China GDIAG_10_HALF, GDIAG_ANY, GDIAG_ANY, &forced); 471208057504Sxy150489 471308057504Sxy150489 switch (forced) { 471408057504Sxy150489 case GDIAG_10_HALF: 471508057504Sxy150489 /* 471608057504Sxy150489 * Disable Auto Negotiation 471708057504Sxy150489 */ 471825f2d433Sxy150489 mac->autoneg = B_FALSE; 471925f2d433Sxy150489 mac->forced_speed_duplex = ADVERTISE_10_HALF; 472008057504Sxy150489 break; 472108057504Sxy150489 case GDIAG_10_FULL: 472208057504Sxy150489 /* 472308057504Sxy150489 * Disable Auto Negotiation 472408057504Sxy150489 */ 472525f2d433Sxy150489 mac->autoneg = B_FALSE; 472625f2d433Sxy150489 mac->forced_speed_duplex = ADVERTISE_10_FULL; 472708057504Sxy150489 break; 472808057504Sxy150489 case GDIAG_100_HALF: 472908057504Sxy150489 /* 473008057504Sxy150489 * Disable Auto Negotiation 473108057504Sxy150489 */ 473225f2d433Sxy150489 mac->autoneg = B_FALSE; 473325f2d433Sxy150489 mac->forced_speed_duplex = ADVERTISE_100_HALF; 473408057504Sxy150489 break; 473508057504Sxy150489 case GDIAG_100_FULL: 473608057504Sxy150489 /* 473708057504Sxy150489 * Disable Auto Negotiation 473808057504Sxy150489 */ 473925f2d433Sxy150489 mac->autoneg = B_FALSE; 474025f2d433Sxy150489 mac->forced_speed_duplex = ADVERTISE_100_FULL; 474108057504Sxy150489 break; 474208057504Sxy150489 case GDIAG_1000_FULL: 474308057504Sxy150489 /* 474408057504Sxy150489 * The gigabit spec requires autonegotiation. Therefore, 474508057504Sxy150489 * when the user wants to force the speed to 1000Mbps, we 474608057504Sxy150489 * enable AutoNeg, but only allow the harware to advertise 474708057504Sxy150489 * 1000Mbps. This is different from 10/100 operation, where 474808057504Sxy150489 * we are allowed to link without any negotiation. 474908057504Sxy150489 */ 475025f2d433Sxy150489 mac->autoneg = B_TRUE; 475125f2d433Sxy150489 phy->autoneg_advertised = ADVERTISE_1000_FULL; 475208057504Sxy150489 break; 475308057504Sxy150489 default: /* obey the setting of AutoNegAdvertised */ 475425f2d433Sxy150489 mac->autoneg = B_TRUE; 47551bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "AutoNegAdvertised", 475608057504Sxy150489 0, AUTONEG_ADVERTISE_SPEED_DEFAULT, 47571bc1c721Sguoqing zhu - Sun Microsystems - Beijing China AUTONEG_ADVERTISE_SPEED_DEFAULT, &propval); 47581bc1c721Sguoqing zhu - Sun Microsystems - Beijing China phy->autoneg_advertised = (uint16_t)propval; 475908057504Sxy150489 break; 476008057504Sxy150489 } /* switch */ 476108057504Sxy150489 } 476208057504Sxy150489 476308057504Sxy150489 /* 476425f2d433Sxy150489 * e1000g_get_max_frame_size - get jumbo frame setting from e1000g.conf 476525f2d433Sxy150489 * 476625f2d433Sxy150489 * This function reads MaxFrameSize from e1000g.conf 476708057504Sxy150489 */ 476808057504Sxy150489 static void 476908057504Sxy150489 e1000g_get_max_frame_size(struct e1000g *Adapter) 477008057504Sxy150489 { 477108057504Sxy150489 int max_frame; 477208057504Sxy150489 477308057504Sxy150489 /* 477408057504Sxy150489 * get value out of config file 477508057504Sxy150489 */ 47761bc1c721Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000g_get_prop(Adapter, "MaxFrameSize", 0, 3, 0, 47771bc1c721Sguoqing zhu - Sun Microsystems - Beijing China &max_frame); 477808057504Sxy150489 477908057504Sxy150489 switch (max_frame) { 478008057504Sxy150489 case 0: 47819ce7e93cScc210113 Adapter->default_mtu = ETHERMTU; 478208057504Sxy150489 break; 478308057504Sxy150489 case 1: 47849ce7e93cScc210113 Adapter->default_mtu = FRAME_SIZE_UPTO_4K - 47853fb4efefSchangqing li - Sun Microsystems - Beijing China sizeof (struct ether_vlan_header) - ETHERFCSL; 478608057504Sxy150489 break; 478708057504Sxy150489 case 2: 47889ce7e93cScc210113 Adapter->default_mtu = FRAME_SIZE_UPTO_8K - 47893fb4efefSchangqing li - Sun Microsystems - Beijing China sizeof (struct ether_vlan_header) - ETHERFCSL; 479008057504Sxy150489 break; 479108057504Sxy150489 case 3: 47929ce7e93cScc210113 Adapter->default_mtu = FRAME_SIZE_UPTO_16K - 47933fb4efefSchangqing li - Sun Microsystems - Beijing China sizeof (struct ether_vlan_header) - ETHERFCSL; 479408057504Sxy150489 break; 479508057504Sxy150489 default: 47969ce7e93cScc210113 Adapter->default_mtu = ETHERMTU; 479708057504Sxy150489 break; 479808057504Sxy150489 } /* switch */ 479908057504Sxy150489 4800caf05df5SMiles Xu, Sun Microsystems /* 4801caf05df5SMiles Xu, Sun Microsystems * If the user configed MTU is larger than the deivce's maximum MTU, 4802caf05df5SMiles Xu, Sun Microsystems * the MTU is set to the deivce's maximum value. 4803caf05df5SMiles Xu, Sun Microsystems */ 4804caf05df5SMiles Xu, Sun Microsystems if (Adapter->default_mtu > Adapter->max_mtu) 4805caf05df5SMiles Xu, Sun Microsystems Adapter->default_mtu = Adapter->max_mtu; 48069ce7e93cScc210113 4807caf05df5SMiles Xu, Sun Microsystems Adapter->max_frame_size = e1000g_mtu2maxframe(Adapter->default_mtu); 480825f2d433Sxy150489 } 480925f2d433Sxy150489 4810caf05df5SMiles Xu, Sun Microsystems /* 4811caf05df5SMiles Xu, Sun Microsystems * e1000g_pch_limits - Apply limits of the PCH silicon type 4812caf05df5SMiles Xu, Sun Microsystems * 4813caf05df5SMiles Xu, Sun Microsystems * At any frame size larger than the ethernet default, 4814caf05df5SMiles Xu, Sun Microsystems * prevent linking at 10/100 speeds. 4815caf05df5SMiles Xu, Sun Microsystems */ 4816caf05df5SMiles Xu, Sun Microsystems static void 4817caf05df5SMiles Xu, Sun Microsystems e1000g_pch_limits(struct e1000g *Adapter) 4818caf05df5SMiles Xu, Sun Microsystems { 4819caf05df5SMiles Xu, Sun Microsystems struct e1000_hw *hw = &Adapter->shared; 4820caf05df5SMiles Xu, Sun Microsystems 4821caf05df5SMiles Xu, Sun Microsystems /* only applies to PCH silicon type */ 4822dab7de2dSGarrett D'Amore if (hw->mac.type != e1000_pchlan && hw->mac.type != e1000_pch2lan) 4823caf05df5SMiles Xu, Sun Microsystems return; 4824caf05df5SMiles Xu, Sun Microsystems 4825caf05df5SMiles Xu, Sun Microsystems /* only applies to frames larger than ethernet default */ 4826caf05df5SMiles Xu, Sun Microsystems if (Adapter->max_frame_size > DEFAULT_FRAME_SIZE) { 4827caf05df5SMiles Xu, Sun Microsystems hw->mac.autoneg = B_TRUE; 4828caf05df5SMiles Xu, Sun Microsystems hw->phy.autoneg_advertised = ADVERTISE_1000_FULL; 4829caf05df5SMiles Xu, Sun Microsystems 4830caf05df5SMiles Xu, Sun Microsystems Adapter->param_adv_autoneg = 1; 4831caf05df5SMiles Xu, Sun Microsystems Adapter->param_adv_1000fdx = 1; 4832caf05df5SMiles Xu, Sun Microsystems 4833caf05df5SMiles Xu, Sun Microsystems Adapter->param_adv_100fdx = 0; 4834caf05df5SMiles Xu, Sun Microsystems Adapter->param_adv_100hdx = 0; 4835caf05df5SMiles Xu, Sun Microsystems Adapter->param_adv_10fdx = 0; 4836caf05df5SMiles Xu, Sun Microsystems Adapter->param_adv_10hdx = 0; 4837caf05df5SMiles Xu, Sun Microsystems 4838caf05df5SMiles Xu, Sun Microsystems e1000g_param_sync(Adapter); 483908057504Sxy150489 } 484008057504Sxy150489 } 484108057504Sxy150489 4842caf05df5SMiles Xu, Sun Microsystems /* 4843caf05df5SMiles Xu, Sun Microsystems * e1000g_mtu2maxframe - convert given MTU to maximum frame size 4844caf05df5SMiles Xu, Sun Microsystems */ 4845caf05df5SMiles Xu, Sun Microsystems static uint32_t 4846caf05df5SMiles Xu, Sun Microsystems e1000g_mtu2maxframe(uint32_t mtu) 4847caf05df5SMiles Xu, Sun Microsystems { 4848caf05df5SMiles Xu, Sun Microsystems uint32_t maxframe; 4849caf05df5SMiles Xu, Sun Microsystems 4850caf05df5SMiles Xu, Sun Microsystems maxframe = mtu + sizeof (struct ether_vlan_header) + ETHERFCSL; 4851caf05df5SMiles Xu, Sun Microsystems 4852caf05df5SMiles Xu, Sun Microsystems return (maxframe); 4853caf05df5SMiles Xu, Sun Microsystems } 4854caf05df5SMiles Xu, Sun Microsystems 485508057504Sxy150489 static void 485625f2d433Sxy150489 arm_watchdog_timer(struct e1000g *Adapter) 485708057504Sxy150489 { 485825f2d433Sxy150489 Adapter->watchdog_tid = 485925f2d433Sxy150489 timeout(e1000g_local_timer, 486008057504Sxy150489 (void *)Adapter, 1 * drv_usectohz(1000000)); 486108057504Sxy150489 } 486225f2d433Sxy150489 #pragma inline(arm_watchdog_timer) 486308057504Sxy150489 486408057504Sxy150489 static void 486525f2d433Sxy150489 enable_watchdog_timer(struct e1000g *Adapter) 486608057504Sxy150489 { 486725f2d433Sxy150489 mutex_enter(&Adapter->watchdog_lock); 486808057504Sxy150489 486925f2d433Sxy150489 if (!Adapter->watchdog_timer_enabled) { 487025f2d433Sxy150489 Adapter->watchdog_timer_enabled = B_TRUE; 487125f2d433Sxy150489 Adapter->watchdog_timer_started = B_TRUE; 487225f2d433Sxy150489 arm_watchdog_timer(Adapter); 487308057504Sxy150489 } 487408057504Sxy150489 487525f2d433Sxy150489 mutex_exit(&Adapter->watchdog_lock); 487608057504Sxy150489 } 487708057504Sxy150489 487808057504Sxy150489 static void 487925f2d433Sxy150489 disable_watchdog_timer(struct e1000g *Adapter) 488008057504Sxy150489 { 488108057504Sxy150489 timeout_id_t tid; 488208057504Sxy150489 488325f2d433Sxy150489 mutex_enter(&Adapter->watchdog_lock); 488408057504Sxy150489 488525f2d433Sxy150489 Adapter->watchdog_timer_enabled = B_FALSE; 488625f2d433Sxy150489 Adapter->watchdog_timer_started = B_FALSE; 488725f2d433Sxy150489 tid = Adapter->watchdog_tid; 488825f2d433Sxy150489 Adapter->watchdog_tid = 0; 488908057504Sxy150489 489025f2d433Sxy150489 mutex_exit(&Adapter->watchdog_lock); 489108057504Sxy150489 489208057504Sxy150489 if (tid != 0) 489308057504Sxy150489 (void) untimeout(tid); 489408057504Sxy150489 } 489508057504Sxy150489 489608057504Sxy150489 static void 489725f2d433Sxy150489 start_watchdog_timer(struct e1000g *Adapter) 489808057504Sxy150489 { 489925f2d433Sxy150489 mutex_enter(&Adapter->watchdog_lock); 490008057504Sxy150489 490125f2d433Sxy150489 if (Adapter->watchdog_timer_enabled) { 490225f2d433Sxy150489 if (!Adapter->watchdog_timer_started) { 490325f2d433Sxy150489 Adapter->watchdog_timer_started = B_TRUE; 490425f2d433Sxy150489 arm_watchdog_timer(Adapter); 490508057504Sxy150489 } 490608057504Sxy150489 } 490708057504Sxy150489 490825f2d433Sxy150489 mutex_exit(&Adapter->watchdog_lock); 490908057504Sxy150489 } 491008057504Sxy150489 491108057504Sxy150489 static void 491225f2d433Sxy150489 restart_watchdog_timer(struct e1000g *Adapter) 491308057504Sxy150489 { 491425f2d433Sxy150489 mutex_enter(&Adapter->watchdog_lock); 491508057504Sxy150489 491625f2d433Sxy150489 if (Adapter->watchdog_timer_started) 491725f2d433Sxy150489 arm_watchdog_timer(Adapter); 491808057504Sxy150489 491925f2d433Sxy150489 mutex_exit(&Adapter->watchdog_lock); 492008057504Sxy150489 } 492108057504Sxy150489 492208057504Sxy150489 static void 492325f2d433Sxy150489 stop_watchdog_timer(struct e1000g *Adapter) 492408057504Sxy150489 { 492508057504Sxy150489 timeout_id_t tid; 492608057504Sxy150489 492725f2d433Sxy150489 mutex_enter(&Adapter->watchdog_lock); 492808057504Sxy150489 492925f2d433Sxy150489 Adapter->watchdog_timer_started = B_FALSE; 493025f2d433Sxy150489 tid = Adapter->watchdog_tid; 493125f2d433Sxy150489 Adapter->watchdog_tid = 0; 493208057504Sxy150489 493325f2d433Sxy150489 mutex_exit(&Adapter->watchdog_lock); 493408057504Sxy150489 493525f2d433Sxy150489 if (tid != 0) 493625f2d433Sxy150489 (void) untimeout(tid); 493725f2d433Sxy150489 } 493825f2d433Sxy150489 493925f2d433Sxy150489 static void 494025f2d433Sxy150489 stop_link_timer(struct e1000g *Adapter) 494125f2d433Sxy150489 { 494225f2d433Sxy150489 timeout_id_t tid; 494325f2d433Sxy150489 494425f2d433Sxy150489 /* Disable the link timer */ 494525f2d433Sxy150489 mutex_enter(&Adapter->link_lock); 494625f2d433Sxy150489 494725f2d433Sxy150489 tid = Adapter->link_tid; 494825f2d433Sxy150489 Adapter->link_tid = 0; 494925f2d433Sxy150489 495025f2d433Sxy150489 mutex_exit(&Adapter->link_lock); 495125f2d433Sxy150489 495225f2d433Sxy150489 if (tid != 0) 495325f2d433Sxy150489 (void) untimeout(tid); 495425f2d433Sxy150489 } 495525f2d433Sxy150489 495625f2d433Sxy150489 static void 495725f2d433Sxy150489 stop_82547_timer(e1000g_tx_ring_t *tx_ring) 495825f2d433Sxy150489 { 495925f2d433Sxy150489 timeout_id_t tid; 496025f2d433Sxy150489 496125f2d433Sxy150489 /* Disable the tx timer for 82547 chipset */ 496225f2d433Sxy150489 mutex_enter(&tx_ring->tx_lock); 496325f2d433Sxy150489 496425f2d433Sxy150489 tx_ring->timer_enable_82547 = B_FALSE; 496525f2d433Sxy150489 tid = tx_ring->timer_id_82547; 496625f2d433Sxy150489 tx_ring->timer_id_82547 = 0; 496725f2d433Sxy150489 496825f2d433Sxy150489 mutex_exit(&tx_ring->tx_lock); 496908057504Sxy150489 497008057504Sxy150489 if (tid != 0) 497108057504Sxy150489 (void) untimeout(tid); 497208057504Sxy150489 } 497308057504Sxy150489 497408057504Sxy150489 void 497525f2d433Sxy150489 e1000g_clear_interrupt(struct e1000g *Adapter) 497608057504Sxy150489 { 497725f2d433Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_IMC, 497825f2d433Sxy150489 0xffffffff & ~E1000_IMS_RXSEQ); 497908057504Sxy150489 } 498008057504Sxy150489 498108057504Sxy150489 void 498225f2d433Sxy150489 e1000g_mask_interrupt(struct e1000g *Adapter) 498308057504Sxy150489 { 498425f2d433Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_IMS, 498547b7744cSyy150190 IMS_ENABLE_MASK & ~E1000_IMS_TXDW); 498647b7744cSyy150190 498747b7744cSyy150190 if (Adapter->tx_intr_enable) 498847b7744cSyy150190 e1000g_mask_tx_interrupt(Adapter); 498908057504Sxy150489 } 499008057504Sxy150489 499119397407SSherry Moore /* 499219397407SSherry Moore * This routine is called by e1000g_quiesce(), therefore must not block. 499319397407SSherry Moore */ 499408057504Sxy150489 void 499525f2d433Sxy150489 e1000g_clear_all_interrupts(struct e1000g *Adapter) 499608057504Sxy150489 { 499725f2d433Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_IMC, 0xffffffff); 499808057504Sxy150489 } 499908057504Sxy150489 500008057504Sxy150489 void 500125f2d433Sxy150489 e1000g_mask_tx_interrupt(struct e1000g *Adapter) 500208057504Sxy150489 { 500347b7744cSyy150190 E1000_WRITE_REG(&Adapter->shared, E1000_IMS, E1000_IMS_TXDW); 500408057504Sxy150489 } 500508057504Sxy150489 500608057504Sxy150489 void 500725f2d433Sxy150489 e1000g_clear_tx_interrupt(struct e1000g *Adapter) 500808057504Sxy150489 { 500947b7744cSyy150190 E1000_WRITE_REG(&Adapter->shared, E1000_IMC, E1000_IMS_TXDW); 501008057504Sxy150489 } 501108057504Sxy150489 501208057504Sxy150489 static void 501325f2d433Sxy150489 e1000g_smartspeed(struct e1000g *Adapter) 501408057504Sxy150489 { 501525f2d433Sxy150489 struct e1000_hw *hw = &Adapter->shared; 501608057504Sxy150489 uint16_t phy_status; 501708057504Sxy150489 uint16_t phy_ctrl; 501808057504Sxy150489 501908057504Sxy150489 /* 502008057504Sxy150489 * If we're not T-or-T, or we're not autoneg'ing, or we're not 502108057504Sxy150489 * advertising 1000Full, we don't even use the workaround 502208057504Sxy150489 */ 502325f2d433Sxy150489 if ((hw->phy.type != e1000_phy_igp) || 502425f2d433Sxy150489 !hw->mac.autoneg || 502525f2d433Sxy150489 !(hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)) 502608057504Sxy150489 return; 502708057504Sxy150489 502808057504Sxy150489 /* 502908057504Sxy150489 * True if this is the first call of this function or after every 503008057504Sxy150489 * 30 seconds of not having link 503108057504Sxy150489 */ 503225f2d433Sxy150489 if (Adapter->smartspeed == 0) { 503308057504Sxy150489 /* 503408057504Sxy150489 * If Master/Slave config fault is asserted twice, we 503508057504Sxy150489 * assume back-to-back 503608057504Sxy150489 */ 5037fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status); 503808057504Sxy150489 if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) 503908057504Sxy150489 return; 504008057504Sxy150489 5041fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status); 504208057504Sxy150489 if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) 504308057504Sxy150489 return; 504408057504Sxy150489 /* 504508057504Sxy150489 * We're assuming back-2-back because our status register 504608057504Sxy150489 * insists! there's a fault in the master/slave 504708057504Sxy150489 * relationship that was "negotiated" 504808057504Sxy150489 */ 5049fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl); 505008057504Sxy150489 /* 505108057504Sxy150489 * Is the phy configured for manual configuration of 505208057504Sxy150489 * master/slave? 505308057504Sxy150489 */ 505408057504Sxy150489 if (phy_ctrl & CR_1000T_MS_ENABLE) { 505508057504Sxy150489 /* 505608057504Sxy150489 * Yes. Then disable manual configuration (enable 505708057504Sxy150489 * auto configuration) of master/slave 505808057504Sxy150489 */ 505908057504Sxy150489 phy_ctrl &= ~CR_1000T_MS_ENABLE; 5060fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 506108057504Sxy150489 PHY_1000T_CTRL, phy_ctrl); 506208057504Sxy150489 /* 506308057504Sxy150489 * Effectively starting the clock 506408057504Sxy150489 */ 506525f2d433Sxy150489 Adapter->smartspeed++; 506608057504Sxy150489 /* 506708057504Sxy150489 * Restart autonegotiation 506808057504Sxy150489 */ 506925f2d433Sxy150489 if (!e1000_phy_setup_autoneg(hw) && 507025f2d433Sxy150489 !e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl)) { 507108057504Sxy150489 phy_ctrl |= (MII_CR_AUTO_NEG_EN | 507208057504Sxy150489 MII_CR_RESTART_AUTO_NEG); 5073fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 507425f2d433Sxy150489 PHY_CONTROL, phy_ctrl); 507508057504Sxy150489 } 507608057504Sxy150489 } 507708057504Sxy150489 return; 507808057504Sxy150489 /* 507908057504Sxy150489 * Has 6 seconds transpired still without link? Remember, 508008057504Sxy150489 * you should reset the smartspeed counter once you obtain 508108057504Sxy150489 * link 508208057504Sxy150489 */ 508325f2d433Sxy150489 } else if (Adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) { 508408057504Sxy150489 /* 508508057504Sxy150489 * Yes. Remember, we did at the start determine that 508608057504Sxy150489 * there's a master/slave configuration fault, so we're 508708057504Sxy150489 * still assuming there's someone on the other end, but we 508808057504Sxy150489 * just haven't yet been able to talk to it. We then 508908057504Sxy150489 * re-enable auto configuration of master/slave to see if 509008057504Sxy150489 * we're running 2/3 pair cables. 509108057504Sxy150489 */ 509208057504Sxy150489 /* 509308057504Sxy150489 * If still no link, perhaps using 2/3 pair cable 509408057504Sxy150489 */ 5095fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl); 509608057504Sxy150489 phy_ctrl |= CR_1000T_MS_ENABLE; 5097fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_ctrl); 509808057504Sxy150489 /* 509908057504Sxy150489 * Restart autoneg with phy enabled for manual 510008057504Sxy150489 * configuration of master/slave 510108057504Sxy150489 */ 510225f2d433Sxy150489 if (!e1000_phy_setup_autoneg(hw) && 510325f2d433Sxy150489 !e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl)) { 510408057504Sxy150489 phy_ctrl |= 510508057504Sxy150489 (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); 5106fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl); 510708057504Sxy150489 } 510808057504Sxy150489 /* 510908057504Sxy150489 * Hopefully, there are no more faults and we've obtained 511008057504Sxy150489 * link as a result. 511108057504Sxy150489 */ 511208057504Sxy150489 } 511308057504Sxy150489 /* 511408057504Sxy150489 * Restart process after E1000_SMARTSPEED_MAX iterations (30 511508057504Sxy150489 * seconds) 511608057504Sxy150489 */ 511725f2d433Sxy150489 if (Adapter->smartspeed++ == E1000_SMARTSPEED_MAX) 511825f2d433Sxy150489 Adapter->smartspeed = 0; 511908057504Sxy150489 } 512008057504Sxy150489 512108057504Sxy150489 static boolean_t 512208057504Sxy150489 is_valid_mac_addr(uint8_t *mac_addr) 512308057504Sxy150489 { 512408057504Sxy150489 const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 }; 512508057504Sxy150489 const uint8_t addr_test2[6] = 512608057504Sxy150489 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 512708057504Sxy150489 512808057504Sxy150489 if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) || 512908057504Sxy150489 !(bcmp(addr_test2, mac_addr, ETHERADDRL))) 513008057504Sxy150489 return (B_FALSE); 513108057504Sxy150489 513208057504Sxy150489 return (B_TRUE); 513308057504Sxy150489 } 513408057504Sxy150489 513508057504Sxy150489 /* 513625f2d433Sxy150489 * e1000g_stall_check - check for tx stall 513725f2d433Sxy150489 * 513825f2d433Sxy150489 * This function checks if the adapter is stalled (in transmit). 513925f2d433Sxy150489 * 514025f2d433Sxy150489 * It is called each time the watchdog timeout is invoked. 514125f2d433Sxy150489 * If the transmit descriptor reclaim continuously fails, 514225f2d433Sxy150489 * the watchdog value will increment by 1. If the watchdog 514325f2d433Sxy150489 * value exceeds the threshold, the adapter is assumed to 514425f2d433Sxy150489 * have stalled and need to be reset. 514508057504Sxy150489 */ 514608057504Sxy150489 static boolean_t 514708057504Sxy150489 e1000g_stall_check(struct e1000g *Adapter) 514808057504Sxy150489 { 514925f2d433Sxy150489 e1000g_tx_ring_t *tx_ring; 515025f2d433Sxy150489 515125f2d433Sxy150489 tx_ring = Adapter->tx_ring; 515225f2d433Sxy150489 51537941757cSxy150489 if (Adapter->link_state != LINK_STATE_UP) 515408057504Sxy150489 return (B_FALSE); 515508057504Sxy150489 515654e0d7a5SMiles Xu, Sun Microsystems (void) e1000g_recycle(tx_ring); 515708057504Sxy150489 51580c35404fSchangqing li - Sun Microsystems - Beijing China if (Adapter->stall_flag) 515908057504Sxy150489 return (B_TRUE); 516008057504Sxy150489 516154e0d7a5SMiles Xu, Sun Microsystems return (B_FALSE); 516254e0d7a5SMiles Xu, Sun Microsystems } 516354e0d7a5SMiles Xu, Sun Microsystems 516425f2d433Sxy150489 #ifdef E1000G_DEBUG 516508057504Sxy150489 static enum ioc_reply 516608057504Sxy150489 e1000g_pp_ioctl(struct e1000g *e1000gp, struct iocblk *iocp, mblk_t *mp) 516708057504Sxy150489 { 516808057504Sxy150489 void (*ppfn)(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd); 516908057504Sxy150489 e1000g_peekpoke_t *ppd; 517008057504Sxy150489 uint64_t mem_va; 517108057504Sxy150489 uint64_t maxoff; 517208057504Sxy150489 boolean_t peek; 517308057504Sxy150489 517408057504Sxy150489 switch (iocp->ioc_cmd) { 517508057504Sxy150489 517608057504Sxy150489 case E1000G_IOC_REG_PEEK: 517708057504Sxy150489 peek = B_TRUE; 517808057504Sxy150489 break; 517908057504Sxy150489 518008057504Sxy150489 case E1000G_IOC_REG_POKE: 518108057504Sxy150489 peek = B_FALSE; 518208057504Sxy150489 break; 518308057504Sxy150489 518408057504Sxy150489 deault: 518525f2d433Sxy150489 E1000G_DEBUGLOG_1(e1000gp, E1000G_INFO_LEVEL, 518608057504Sxy150489 "e1000g_diag_ioctl: invalid ioctl command 0x%X\n", 518708057504Sxy150489 iocp->ioc_cmd); 518808057504Sxy150489 return (IOC_INVAL); 518908057504Sxy150489 } 519008057504Sxy150489 519108057504Sxy150489 /* 519208057504Sxy150489 * Validate format of ioctl 519308057504Sxy150489 */ 519408057504Sxy150489 if (iocp->ioc_count != sizeof (e1000g_peekpoke_t)) 519508057504Sxy150489 return (IOC_INVAL); 519608057504Sxy150489 if (mp->b_cont == NULL) 519708057504Sxy150489 return (IOC_INVAL); 519808057504Sxy150489 5199fe62dec3SChen-Liang Xu ppd = (e1000g_peekpoke_t *)(uintptr_t)mp->b_cont->b_rptr; 520008057504Sxy150489 520108057504Sxy150489 /* 520208057504Sxy150489 * Validate request parameters 520308057504Sxy150489 */ 520408057504Sxy150489 switch (ppd->pp_acc_space) { 520508057504Sxy150489 520608057504Sxy150489 default: 520725f2d433Sxy150489 E1000G_DEBUGLOG_1(e1000gp, E1000G_INFO_LEVEL, 520808057504Sxy150489 "e1000g_diag_ioctl: invalid access space 0x%X\n", 520908057504Sxy150489 ppd->pp_acc_space); 521008057504Sxy150489 return (IOC_INVAL); 521108057504Sxy150489 521208057504Sxy150489 case E1000G_PP_SPACE_REG: 521308057504Sxy150489 /* 521408057504Sxy150489 * Memory-mapped I/O space 521508057504Sxy150489 */ 521608057504Sxy150489 ASSERT(ppd->pp_acc_size == 4); 521708057504Sxy150489 if (ppd->pp_acc_size != 4) 521808057504Sxy150489 return (IOC_INVAL); 521908057504Sxy150489 522008057504Sxy150489 if ((ppd->pp_acc_offset % ppd->pp_acc_size) != 0) 522108057504Sxy150489 return (IOC_INVAL); 522208057504Sxy150489 522308057504Sxy150489 mem_va = 0; 522408057504Sxy150489 maxoff = 0x10000; 522508057504Sxy150489 ppfn = peek ? e1000g_ioc_peek_reg : e1000g_ioc_poke_reg; 522608057504Sxy150489 break; 522708057504Sxy150489 522808057504Sxy150489 case E1000G_PP_SPACE_E1000G: 522908057504Sxy150489 /* 523008057504Sxy150489 * E1000g data structure! 523108057504Sxy150489 */ 523208057504Sxy150489 mem_va = (uintptr_t)e1000gp; 523308057504Sxy150489 maxoff = sizeof (struct e1000g); 523408057504Sxy150489 ppfn = peek ? e1000g_ioc_peek_mem : e1000g_ioc_poke_mem; 523508057504Sxy150489 break; 523608057504Sxy150489 523708057504Sxy150489 } 523808057504Sxy150489 523908057504Sxy150489 if (ppd->pp_acc_offset >= maxoff) 524008057504Sxy150489 return (IOC_INVAL); 524108057504Sxy150489 524208057504Sxy150489 if (ppd->pp_acc_offset + ppd->pp_acc_size > maxoff) 524308057504Sxy150489 return (IOC_INVAL); 524408057504Sxy150489 524508057504Sxy150489 /* 524608057504Sxy150489 * All OK - go! 524708057504Sxy150489 */ 524808057504Sxy150489 ppd->pp_acc_offset += mem_va; 524908057504Sxy150489 (*ppfn)(e1000gp, ppd); 525008057504Sxy150489 return (peek ? IOC_REPLY : IOC_ACK); 525108057504Sxy150489 } 525208057504Sxy150489 525308057504Sxy150489 static void 525408057504Sxy150489 e1000g_ioc_peek_reg(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd) 525508057504Sxy150489 { 525608057504Sxy150489 ddi_acc_handle_t handle; 525708057504Sxy150489 uint32_t *regaddr; 525808057504Sxy150489 525925f2d433Sxy150489 handle = e1000gp->osdep.reg_handle; 5260fe62dec3SChen-Liang Xu regaddr = (uint32_t *)((uintptr_t)e1000gp->shared.hw_addr + 5261fe62dec3SChen-Liang Xu (uintptr_t)ppd->pp_acc_offset); 526208057504Sxy150489 526308057504Sxy150489 ppd->pp_acc_data = ddi_get32(handle, regaddr); 526408057504Sxy150489 } 526508057504Sxy150489 526608057504Sxy150489 static void 526708057504Sxy150489 e1000g_ioc_poke_reg(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd) 526808057504Sxy150489 { 526908057504Sxy150489 ddi_acc_handle_t handle; 527008057504Sxy150489 uint32_t *regaddr; 527108057504Sxy150489 uint32_t value; 527208057504Sxy150489 527325f2d433Sxy150489 handle = e1000gp->osdep.reg_handle; 5274fe62dec3SChen-Liang Xu regaddr = (uint32_t *)((uintptr_t)e1000gp->shared.hw_addr + 5275fe62dec3SChen-Liang Xu (uintptr_t)ppd->pp_acc_offset); 527608057504Sxy150489 value = (uint32_t)ppd->pp_acc_data; 527708057504Sxy150489 527808057504Sxy150489 ddi_put32(handle, regaddr, value); 527908057504Sxy150489 } 528008057504Sxy150489 528108057504Sxy150489 static void 528208057504Sxy150489 e1000g_ioc_peek_mem(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd) 528308057504Sxy150489 { 528408057504Sxy150489 uint64_t value; 528508057504Sxy150489 void *vaddr; 528608057504Sxy150489 528708057504Sxy150489 vaddr = (void *)(uintptr_t)ppd->pp_acc_offset; 528808057504Sxy150489 528908057504Sxy150489 switch (ppd->pp_acc_size) { 529008057504Sxy150489 case 1: 529108057504Sxy150489 value = *(uint8_t *)vaddr; 529208057504Sxy150489 break; 529308057504Sxy150489 529408057504Sxy150489 case 2: 529508057504Sxy150489 value = *(uint16_t *)vaddr; 529608057504Sxy150489 break; 529708057504Sxy150489 529808057504Sxy150489 case 4: 529908057504Sxy150489 value = *(uint32_t *)vaddr; 530008057504Sxy150489 break; 530108057504Sxy150489 530208057504Sxy150489 case 8: 530308057504Sxy150489 value = *(uint64_t *)vaddr; 530408057504Sxy150489 break; 530508057504Sxy150489 } 530608057504Sxy150489 530725f2d433Sxy150489 E1000G_DEBUGLOG_4(e1000gp, E1000G_INFO_LEVEL, 530808057504Sxy150489 "e1000g_ioc_peek_mem($%p, $%p) peeked 0x%llx from $%p\n", 530908057504Sxy150489 (void *)e1000gp, (void *)ppd, value, vaddr); 531008057504Sxy150489 531108057504Sxy150489 ppd->pp_acc_data = value; 531208057504Sxy150489 } 531308057504Sxy150489 531408057504Sxy150489 static void 531508057504Sxy150489 e1000g_ioc_poke_mem(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd) 531608057504Sxy150489 { 531708057504Sxy150489 uint64_t value; 531808057504Sxy150489 void *vaddr; 531908057504Sxy150489 532008057504Sxy150489 vaddr = (void *)(uintptr_t)ppd->pp_acc_offset; 532108057504Sxy150489 value = ppd->pp_acc_data; 532208057504Sxy150489 532325f2d433Sxy150489 E1000G_DEBUGLOG_4(e1000gp, E1000G_INFO_LEVEL, 532408057504Sxy150489 "e1000g_ioc_poke_mem($%p, $%p) poking 0x%llx at $%p\n", 532508057504Sxy150489 (void *)e1000gp, (void *)ppd, value, vaddr); 532608057504Sxy150489 532708057504Sxy150489 switch (ppd->pp_acc_size) { 532808057504Sxy150489 case 1: 532908057504Sxy150489 *(uint8_t *)vaddr = (uint8_t)value; 533008057504Sxy150489 break; 533108057504Sxy150489 533208057504Sxy150489 case 2: 533308057504Sxy150489 *(uint16_t *)vaddr = (uint16_t)value; 533408057504Sxy150489 break; 533508057504Sxy150489 533608057504Sxy150489 case 4: 533708057504Sxy150489 *(uint32_t *)vaddr = (uint32_t)value; 533808057504Sxy150489 break; 533908057504Sxy150489 534008057504Sxy150489 case 8: 534108057504Sxy150489 *(uint64_t *)vaddr = (uint64_t)value; 534208057504Sxy150489 break; 534308057504Sxy150489 } 534408057504Sxy150489 } 534525f2d433Sxy150489 #endif 534608057504Sxy150489 534708057504Sxy150489 /* 534808057504Sxy150489 * Loopback Support 534908057504Sxy150489 */ 535008057504Sxy150489 static lb_property_t lb_normal = 535108057504Sxy150489 { normal, "normal", E1000G_LB_NONE }; 535208057504Sxy150489 static lb_property_t lb_external1000 = 535308057504Sxy150489 { external, "1000Mbps", E1000G_LB_EXTERNAL_1000 }; 535408057504Sxy150489 static lb_property_t lb_external100 = 535508057504Sxy150489 { external, "100Mbps", E1000G_LB_EXTERNAL_100 }; 535608057504Sxy150489 static lb_property_t lb_external10 = 535708057504Sxy150489 { external, "10Mbps", E1000G_LB_EXTERNAL_10 }; 535808057504Sxy150489 static lb_property_t lb_phy = 535908057504Sxy150489 { internal, "PHY", E1000G_LB_INTERNAL_PHY }; 536008057504Sxy150489 536108057504Sxy150489 static enum ioc_reply 536208057504Sxy150489 e1000g_loopback_ioctl(struct e1000g *Adapter, struct iocblk *iocp, mblk_t *mp) 536308057504Sxy150489 { 536408057504Sxy150489 lb_info_sz_t *lbsp; 536508057504Sxy150489 lb_property_t *lbpp; 536608057504Sxy150489 struct e1000_hw *hw; 536708057504Sxy150489 uint32_t *lbmp; 536808057504Sxy150489 uint32_t size; 536908057504Sxy150489 uint32_t value; 537008057504Sxy150489 537125f2d433Sxy150489 hw = &Adapter->shared; 537208057504Sxy150489 537308057504Sxy150489 if (mp->b_cont == NULL) 537408057504Sxy150489 return (IOC_INVAL); 537508057504Sxy150489 5376a2e9a830Scc210113 if (!e1000g_check_loopback_support(hw)) { 5377a2e9a830Scc210113 e1000g_log(NULL, CE_WARN, 5378a2e9a830Scc210113 "Loopback is not supported on e1000g%d", Adapter->instance); 5379a2e9a830Scc210113 return (IOC_INVAL); 5380a2e9a830Scc210113 } 5381a2e9a830Scc210113 538208057504Sxy150489 switch (iocp->ioc_cmd) { 538308057504Sxy150489 default: 538408057504Sxy150489 return (IOC_INVAL); 538508057504Sxy150489 538608057504Sxy150489 case LB_GET_INFO_SIZE: 538708057504Sxy150489 size = sizeof (lb_info_sz_t); 538808057504Sxy150489 if (iocp->ioc_count != size) 538908057504Sxy150489 return (IOC_INVAL); 539008057504Sxy150489 53914914a7d0Syy150190 rw_enter(&Adapter->chip_lock, RW_WRITER); 53924914a7d0Syy150190 e1000g_get_phy_state(Adapter); 53934914a7d0Syy150190 53944914a7d0Syy150190 /* 53954914a7d0Syy150190 * Workaround for hardware faults. In order to get a stable 53964914a7d0Syy150190 * state of phy, we will wait for a specific interval and 53974914a7d0Syy150190 * try again. The time delay is an experiential value based 53984914a7d0Syy150190 * on our testing. 53994914a7d0Syy150190 */ 54004914a7d0Syy150190 msec_delay(100); 54014914a7d0Syy150190 e1000g_get_phy_state(Adapter); 54024914a7d0Syy150190 rw_exit(&Adapter->chip_lock); 540308057504Sxy150489 540408057504Sxy150489 value = sizeof (lb_normal); 54054914a7d0Syy150190 if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) || 54064914a7d0Syy150190 (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) || 5407592a4d85Scc210113 (hw->phy.media_type == e1000_media_type_fiber) || 5408592a4d85Scc210113 (hw->phy.media_type == e1000_media_type_internal_serdes)) { 540908057504Sxy150489 value += sizeof (lb_phy); 541025f2d433Sxy150489 switch (hw->mac.type) { 541108057504Sxy150489 case e1000_82571: 541208057504Sxy150489 case e1000_82572: 5413a2e9a830Scc210113 case e1000_80003es2lan: 541408057504Sxy150489 value += sizeof (lb_external1000); 541508057504Sxy150489 break; 541608057504Sxy150489 } 541708057504Sxy150489 } 54184914a7d0Syy150190 if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 54194914a7d0Syy150190 (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) 542008057504Sxy150489 value += sizeof (lb_external100); 54214914a7d0Syy150190 if (Adapter->phy_status & MII_SR_10T_FD_CAPS) 542208057504Sxy150489 value += sizeof (lb_external10); 542308057504Sxy150489 5424fe62dec3SChen-Liang Xu lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr; 542508057504Sxy150489 *lbsp = value; 542608057504Sxy150489 break; 542708057504Sxy150489 542808057504Sxy150489 case LB_GET_INFO: 542908057504Sxy150489 value = sizeof (lb_normal); 54304914a7d0Syy150190 if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) || 54314914a7d0Syy150190 (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) || 5432592a4d85Scc210113 (hw->phy.media_type == e1000_media_type_fiber) || 5433592a4d85Scc210113 (hw->phy.media_type == e1000_media_type_internal_serdes)) { 543408057504Sxy150489 value += sizeof (lb_phy); 543525f2d433Sxy150489 switch (hw->mac.type) { 543608057504Sxy150489 case e1000_82571: 543708057504Sxy150489 case e1000_82572: 5438a2e9a830Scc210113 case e1000_80003es2lan: 543908057504Sxy150489 value += sizeof (lb_external1000); 544008057504Sxy150489 break; 544108057504Sxy150489 } 544208057504Sxy150489 } 54434914a7d0Syy150190 if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 54444914a7d0Syy150190 (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) 544508057504Sxy150489 value += sizeof (lb_external100); 54464914a7d0Syy150190 if (Adapter->phy_status & MII_SR_10T_FD_CAPS) 544708057504Sxy150489 value += sizeof (lb_external10); 544808057504Sxy150489 544908057504Sxy150489 size = value; 545008057504Sxy150489 if (iocp->ioc_count != size) 545108057504Sxy150489 return (IOC_INVAL); 545208057504Sxy150489 545308057504Sxy150489 value = 0; 5454fe62dec3SChen-Liang Xu lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr; 545508057504Sxy150489 lbpp[value++] = lb_normal; 54564914a7d0Syy150190 if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) || 54574914a7d0Syy150190 (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) || 5458592a4d85Scc210113 (hw->phy.media_type == e1000_media_type_fiber) || 5459592a4d85Scc210113 (hw->phy.media_type == e1000_media_type_internal_serdes)) { 546008057504Sxy150489 lbpp[value++] = lb_phy; 546125f2d433Sxy150489 switch (hw->mac.type) { 546208057504Sxy150489 case e1000_82571: 546308057504Sxy150489 case e1000_82572: 5464a2e9a830Scc210113 case e1000_80003es2lan: 546508057504Sxy150489 lbpp[value++] = lb_external1000; 546608057504Sxy150489 break; 546708057504Sxy150489 } 546808057504Sxy150489 } 54694914a7d0Syy150190 if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 54704914a7d0Syy150190 (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) 547108057504Sxy150489 lbpp[value++] = lb_external100; 54724914a7d0Syy150190 if (Adapter->phy_status & MII_SR_10T_FD_CAPS) 547308057504Sxy150489 lbpp[value++] = lb_external10; 547408057504Sxy150489 break; 547508057504Sxy150489 547608057504Sxy150489 case LB_GET_MODE: 547708057504Sxy150489 size = sizeof (uint32_t); 547808057504Sxy150489 if (iocp->ioc_count != size) 547908057504Sxy150489 return (IOC_INVAL); 548008057504Sxy150489 5481fe62dec3SChen-Liang Xu lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 548208057504Sxy150489 *lbmp = Adapter->loopback_mode; 548308057504Sxy150489 break; 548408057504Sxy150489 548508057504Sxy150489 case LB_SET_MODE: 548608057504Sxy150489 size = 0; 548708057504Sxy150489 if (iocp->ioc_count != sizeof (uint32_t)) 548808057504Sxy150489 return (IOC_INVAL); 548908057504Sxy150489 5490fe62dec3SChen-Liang Xu lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 549108057504Sxy150489 if (!e1000g_set_loopback_mode(Adapter, *lbmp)) 549208057504Sxy150489 return (IOC_INVAL); 549308057504Sxy150489 break; 549408057504Sxy150489 } 549508057504Sxy150489 549608057504Sxy150489 iocp->ioc_count = size; 549708057504Sxy150489 iocp->ioc_error = 0; 549808057504Sxy150489 54999b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 55009b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 55019b6541b3Sgl147354 return (IOC_INVAL); 55029b6541b3Sgl147354 } 55039b6541b3Sgl147354 550408057504Sxy150489 return (IOC_REPLY); 550508057504Sxy150489 } 550608057504Sxy150489 550708057504Sxy150489 static boolean_t 5508a2e9a830Scc210113 e1000g_check_loopback_support(struct e1000_hw *hw) 5509a2e9a830Scc210113 { 5510a2e9a830Scc210113 switch (hw->mac.type) { 5511a2e9a830Scc210113 case e1000_82540: 5512a2e9a830Scc210113 case e1000_82545: 5513a2e9a830Scc210113 case e1000_82545_rev_3: 5514a2e9a830Scc210113 case e1000_82546: 5515a2e9a830Scc210113 case e1000_82546_rev_3: 5516a2e9a830Scc210113 case e1000_82541: 5517a2e9a830Scc210113 case e1000_82541_rev_2: 5518a2e9a830Scc210113 case e1000_82547: 5519a2e9a830Scc210113 case e1000_82547_rev_2: 5520a2e9a830Scc210113 case e1000_82571: 5521a2e9a830Scc210113 case e1000_82572: 5522a2e9a830Scc210113 case e1000_82573: 5523d5c3073dSchenlu chen - Sun Microsystems - Beijing China case e1000_82574: 5524a2e9a830Scc210113 case e1000_80003es2lan: 5525d5c3073dSchenlu chen - Sun Microsystems - Beijing China case e1000_ich9lan: 5526d5c3073dSchenlu chen - Sun Microsystems - Beijing China case e1000_ich10lan: 5527a2e9a830Scc210113 return (B_TRUE); 5528a2e9a830Scc210113 } 5529a2e9a830Scc210113 return (B_FALSE); 5530a2e9a830Scc210113 } 5531a2e9a830Scc210113 5532a2e9a830Scc210113 static boolean_t 553308057504Sxy150489 e1000g_set_loopback_mode(struct e1000g *Adapter, uint32_t mode) 553408057504Sxy150489 { 553508057504Sxy150489 struct e1000_hw *hw; 553608057504Sxy150489 int i, times; 55374914a7d0Syy150190 boolean_t link_up; 553808057504Sxy150489 553908057504Sxy150489 if (mode == Adapter->loopback_mode) 554008057504Sxy150489 return (B_TRUE); 554108057504Sxy150489 554225f2d433Sxy150489 hw = &Adapter->shared; 554308057504Sxy150489 times = 0; 554408057504Sxy150489 55454914a7d0Syy150190 Adapter->loopback_mode = mode; 554608057504Sxy150489 55474914a7d0Syy150190 if (mode == E1000G_LB_NONE) { 554808057504Sxy150489 /* Reset the chip */ 5549592a4d85Scc210113 hw->phy.autoneg_wait_to_complete = B_TRUE; 555019397407SSherry Moore (void) e1000g_reset_adapter(Adapter); 5551592a4d85Scc210113 hw->phy.autoneg_wait_to_complete = B_FALSE; 55524914a7d0Syy150190 return (B_TRUE); 55534914a7d0Syy150190 } 55544914a7d0Syy150190 55554914a7d0Syy150190 again: 55564914a7d0Syy150190 55574914a7d0Syy150190 rw_enter(&Adapter->chip_lock, RW_WRITER); 55584914a7d0Syy150190 55594914a7d0Syy150190 switch (mode) { 55604914a7d0Syy150190 default: 55614914a7d0Syy150190 rw_exit(&Adapter->chip_lock); 55624914a7d0Syy150190 return (B_FALSE); 556308057504Sxy150489 556408057504Sxy150489 case E1000G_LB_EXTERNAL_1000: 556508057504Sxy150489 e1000g_set_external_loopback_1000(Adapter); 556608057504Sxy150489 break; 556708057504Sxy150489 556808057504Sxy150489 case E1000G_LB_EXTERNAL_100: 556908057504Sxy150489 e1000g_set_external_loopback_100(Adapter); 557008057504Sxy150489 break; 557108057504Sxy150489 557208057504Sxy150489 case E1000G_LB_EXTERNAL_10: 557308057504Sxy150489 e1000g_set_external_loopback_10(Adapter); 557408057504Sxy150489 break; 557508057504Sxy150489 557608057504Sxy150489 case E1000G_LB_INTERNAL_PHY: 557708057504Sxy150489 e1000g_set_internal_loopback(Adapter); 557808057504Sxy150489 break; 557908057504Sxy150489 } 558008057504Sxy150489 558108057504Sxy150489 times++; 558208057504Sxy150489 5583262055deScc210113 rw_exit(&Adapter->chip_lock); 5584262055deScc210113 558508057504Sxy150489 /* Wait for link up */ 558625f2d433Sxy150489 for (i = (PHY_FORCE_LIMIT * 2); i > 0; i--) 558708057504Sxy150489 msec_delay(100); 558808057504Sxy150489 5589262055deScc210113 rw_enter(&Adapter->chip_lock, RW_WRITER); 5590262055deScc210113 55914914a7d0Syy150190 link_up = e1000g_link_up(Adapter); 55924914a7d0Syy150190 55934914a7d0Syy150190 rw_exit(&Adapter->chip_lock); 55944914a7d0Syy150190 55954914a7d0Syy150190 if (!link_up) { 559625f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 559708057504Sxy150489 "Failed to get the link up"); 559808057504Sxy150489 if (times < 2) { 559908057504Sxy150489 /* Reset the link */ 560025f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 560108057504Sxy150489 "Reset the link ..."); 560219397407SSherry Moore (void) e1000g_reset_adapter(Adapter); 560308057504Sxy150489 goto again; 560408057504Sxy150489 } 56050c35404fSchangqing li - Sun Microsystems - Beijing China 56060c35404fSchangqing li - Sun Microsystems - Beijing China /* 56070c35404fSchangqing li - Sun Microsystems - Beijing China * Reset driver to loopback none when set loopback failed 56080c35404fSchangqing li - Sun Microsystems - Beijing China * for the second time. 56090c35404fSchangqing li - Sun Microsystems - Beijing China */ 56100c35404fSchangqing li - Sun Microsystems - Beijing China Adapter->loopback_mode = E1000G_LB_NONE; 56110c35404fSchangqing li - Sun Microsystems - Beijing China 56120c35404fSchangqing li - Sun Microsystems - Beijing China /* Reset the chip */ 56130c35404fSchangqing li - Sun Microsystems - Beijing China hw->phy.autoneg_wait_to_complete = B_TRUE; 56140c35404fSchangqing li - Sun Microsystems - Beijing China (void) e1000g_reset_adapter(Adapter); 56150c35404fSchangqing li - Sun Microsystems - Beijing China hw->phy.autoneg_wait_to_complete = B_FALSE; 56160c35404fSchangqing li - Sun Microsystems - Beijing China 56170c35404fSchangqing li - Sun Microsystems - Beijing China E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 56180c35404fSchangqing li - Sun Microsystems - Beijing China "Set loopback mode failed, reset to loopback none"); 56190c35404fSchangqing li - Sun Microsystems - Beijing China 56200c35404fSchangqing li - Sun Microsystems - Beijing China return (B_FALSE); 562108057504Sxy150489 } 562208057504Sxy150489 562308057504Sxy150489 return (B_TRUE); 562408057504Sxy150489 } 562508057504Sxy150489 562608057504Sxy150489 /* 562708057504Sxy150489 * The following loopback settings are from Intel's technical 562808057504Sxy150489 * document - "How To Loopback". All the register settings and 562908057504Sxy150489 * time delay values are directly inherited from the document 563008057504Sxy150489 * without more explanations available. 563108057504Sxy150489 */ 563208057504Sxy150489 static void 563308057504Sxy150489 e1000g_set_internal_loopback(struct e1000g *Adapter) 563408057504Sxy150489 { 563508057504Sxy150489 struct e1000_hw *hw; 563608057504Sxy150489 uint32_t ctrl; 563708057504Sxy150489 uint32_t status; 563808057504Sxy150489 uint16_t phy_ctrl; 5639d5c3073dSchenlu chen - Sun Microsystems - Beijing China uint16_t phy_reg; 56404914a7d0Syy150190 uint32_t txcw; 564108057504Sxy150489 564225f2d433Sxy150489 hw = &Adapter->shared; 564308057504Sxy150489 564408057504Sxy150489 /* Disable Smart Power Down */ 564508057504Sxy150489 phy_spd_state(hw, B_FALSE); 564608057504Sxy150489 5647fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl); 564808057504Sxy150489 phy_ctrl &= ~(MII_CR_AUTO_NEG_EN | MII_CR_SPEED_100 | MII_CR_SPEED_10); 564908057504Sxy150489 phy_ctrl |= MII_CR_FULL_DUPLEX | MII_CR_SPEED_1000; 565008057504Sxy150489 565125f2d433Sxy150489 switch (hw->mac.type) { 565208057504Sxy150489 case e1000_82540: 565308057504Sxy150489 case e1000_82545: 565408057504Sxy150489 case e1000_82545_rev_3: 565508057504Sxy150489 case e1000_82546: 565608057504Sxy150489 case e1000_82546_rev_3: 565708057504Sxy150489 case e1000_82573: 565808057504Sxy150489 /* Auto-MDI/MDIX off */ 5659fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); 566008057504Sxy150489 /* Reset PHY to update Auto-MDI/MDIX */ 5661fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_CONTROL, 566208057504Sxy150489 phy_ctrl | MII_CR_RESET | MII_CR_AUTO_NEG_EN); 566308057504Sxy150489 /* Reset PHY to auto-neg off and force 1000 */ 5664fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_CONTROL, 566508057504Sxy150489 phy_ctrl | MII_CR_RESET); 56664914a7d0Syy150190 /* 56674914a7d0Syy150190 * Disable PHY receiver for 82540/545/546 and 82573 Family. 56684914a7d0Syy150190 * See comments above e1000g_set_internal_loopback() for the 56694914a7d0Syy150190 * background. 56704914a7d0Syy150190 */ 5671fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 29, 0x001F); 5672fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 30, 0x8FFC); 5673fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 29, 0x001A); 5674fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 30, 0x8FF0); 567508057504Sxy150489 break; 5676a2e9a830Scc210113 case e1000_80003es2lan: 5677a2e9a830Scc210113 /* Force Link Up */ 5678fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 5679fe62dec3SChen-Liang Xu 0x1CC); 5680a2e9a830Scc210113 /* Sets PCS loopback at 1Gbs */ 5681fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, 5682fe62dec3SChen-Liang Xu 0x1046); 5683a2e9a830Scc210113 break; 568408057504Sxy150489 } 568508057504Sxy150489 5686d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* 5687d5c3073dSchenlu chen - Sun Microsystems - Beijing China * The following registers should be set for e1000_phy_bm phy type. 5688d5c3073dSchenlu chen - Sun Microsystems - Beijing China * e1000_82574, e1000_ich10lan and some e1000_ich9lan use this phy. 5689d5c3073dSchenlu chen - Sun Microsystems - Beijing China * For others, we do not need to set these registers. 5690d5c3073dSchenlu chen - Sun Microsystems - Beijing China */ 5691d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (hw->phy.type == e1000_phy_bm) { 5692d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Set Default MAC Interface speed to 1GB */ 569354e0d7a5SMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_REG(2, 21), &phy_reg); 5694d5c3073dSchenlu chen - Sun Microsystems - Beijing China phy_reg &= ~0x0007; 5695d5c3073dSchenlu chen - Sun Microsystems - Beijing China phy_reg |= 0x006; 569654e0d7a5SMiles Xu, Sun Microsystems (void) e1000_write_phy_reg(hw, PHY_REG(2, 21), phy_reg); 5697d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Assert SW reset for above settings to take effect */ 569854e0d7a5SMiles Xu, Sun Microsystems (void) e1000_phy_commit(hw); 5699d5c3073dSchenlu chen - Sun Microsystems - Beijing China msec_delay(1); 5700d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Force Full Duplex */ 570154e0d7a5SMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_REG(769, 16), &phy_reg); 570254e0d7a5SMiles Xu, Sun Microsystems (void) e1000_write_phy_reg(hw, PHY_REG(769, 16), 570354e0d7a5SMiles Xu, Sun Microsystems phy_reg | 0x000C); 5704d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Set Link Up (in force link) */ 570554e0d7a5SMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_REG(776, 16), &phy_reg); 570654e0d7a5SMiles Xu, Sun Microsystems (void) e1000_write_phy_reg(hw, PHY_REG(776, 16), 570754e0d7a5SMiles Xu, Sun Microsystems phy_reg | 0x0040); 5708d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Force Link */ 570954e0d7a5SMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_REG(769, 16), &phy_reg); 571054e0d7a5SMiles Xu, Sun Microsystems (void) e1000_write_phy_reg(hw, PHY_REG(769, 16), 571154e0d7a5SMiles Xu, Sun Microsystems phy_reg | 0x0040); 5712d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Set Early Link Enable */ 571354e0d7a5SMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_REG(769, 20), &phy_reg); 571454e0d7a5SMiles Xu, Sun Microsystems (void) e1000_write_phy_reg(hw, PHY_REG(769, 20), 571554e0d7a5SMiles Xu, Sun Microsystems phy_reg | 0x0400); 5716d5c3073dSchenlu chen - Sun Microsystems - Beijing China } 5717d5c3073dSchenlu chen - Sun Microsystems - Beijing China 571808057504Sxy150489 /* Set loopback */ 5719fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl | MII_CR_LOOPBACK); 572008057504Sxy150489 572108057504Sxy150489 msec_delay(250); 572208057504Sxy150489 572308057504Sxy150489 /* Now set up the MAC to the same speed/duplex as the PHY. */ 572425f2d433Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 572508057504Sxy150489 ctrl &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ 572608057504Sxy150489 ctrl |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ 572708057504Sxy150489 E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ 572808057504Sxy150489 E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */ 572908057504Sxy150489 E1000_CTRL_FD); /* Force Duplex to FULL */ 573008057504Sxy150489 573125f2d433Sxy150489 switch (hw->mac.type) { 573208057504Sxy150489 case e1000_82540: 573308057504Sxy150489 case e1000_82545: 573408057504Sxy150489 case e1000_82545_rev_3: 573508057504Sxy150489 case e1000_82546: 573608057504Sxy150489 case e1000_82546_rev_3: 573708057504Sxy150489 /* 573808057504Sxy150489 * For some serdes we'll need to commit the writes now 573908057504Sxy150489 * so that the status is updated on link 574008057504Sxy150489 */ 5741592a4d85Scc210113 if (hw->phy.media_type == e1000_media_type_internal_serdes) { 574225f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 574308057504Sxy150489 msec_delay(100); 574425f2d433Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 574508057504Sxy150489 } 574608057504Sxy150489 5747592a4d85Scc210113 if (hw->phy.media_type == e1000_media_type_copper) { 574808057504Sxy150489 /* Invert Loss of Signal */ 574908057504Sxy150489 ctrl |= E1000_CTRL_ILOS; 575008057504Sxy150489 } else { 575108057504Sxy150489 /* Set ILOS on fiber nic if half duplex is detected */ 575225f2d433Sxy150489 status = E1000_READ_REG(hw, E1000_STATUS); 575308057504Sxy150489 if ((status & E1000_STATUS_FD) == 0) 575408057504Sxy150489 ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU; 575508057504Sxy150489 } 575608057504Sxy150489 break; 575708057504Sxy150489 575808057504Sxy150489 case e1000_82571: 575908057504Sxy150489 case e1000_82572: 57604914a7d0Syy150190 /* 57614914a7d0Syy150190 * The fiber/SerDes versions of this adapter do not contain an 57624914a7d0Syy150190 * accessible PHY. Therefore, loopback beyond MAC must be done 57634914a7d0Syy150190 * using SerDes analog loopback. 57644914a7d0Syy150190 */ 5765592a4d85Scc210113 if (hw->phy.media_type != e1000_media_type_copper) { 57664914a7d0Syy150190 /* Disable autoneg by setting bit 31 of TXCW to zero */ 57674914a7d0Syy150190 txcw = E1000_READ_REG(hw, E1000_TXCW); 57684914a7d0Syy150190 txcw &= ~((uint32_t)1 << 31); 57694914a7d0Syy150190 E1000_WRITE_REG(hw, E1000_TXCW, txcw); 57704914a7d0Syy150190 57714914a7d0Syy150190 /* 57724914a7d0Syy150190 * Write 0x410 to Serdes Control register 57734914a7d0Syy150190 * to enable Serdes analog loopback 57744914a7d0Syy150190 */ 57754914a7d0Syy150190 E1000_WRITE_REG(hw, E1000_SCTL, 0x0410); 57764914a7d0Syy150190 msec_delay(10); 577708057504Sxy150489 } 5778d5c3073dSchenlu chen - Sun Microsystems - Beijing China 5779d5c3073dSchenlu chen - Sun Microsystems - Beijing China status = E1000_READ_REG(hw, E1000_STATUS); 5780d5c3073dSchenlu chen - Sun Microsystems - Beijing China /* Set ILOS on fiber nic if half duplex is detected */ 5781d5c3073dSchenlu chen - Sun Microsystems - Beijing China if ((hw->phy.media_type == e1000_media_type_fiber) && 5782d5c3073dSchenlu chen - Sun Microsystems - Beijing China ((status & E1000_STATUS_FD) == 0 || 5783d5c3073dSchenlu chen - Sun Microsystems - Beijing China (status & E1000_STATUS_LU) == 0)) 5784d5c3073dSchenlu chen - Sun Microsystems - Beijing China ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU; 5785d5c3073dSchenlu chen - Sun Microsystems - Beijing China else if (hw->phy.media_type == e1000_media_type_internal_serdes) 5786d5c3073dSchenlu chen - Sun Microsystems - Beijing China ctrl |= E1000_CTRL_SLU; 578708057504Sxy150489 break; 578808057504Sxy150489 578908057504Sxy150489 case e1000_82573: 579008057504Sxy150489 ctrl |= E1000_CTRL_ILOS; 5791d5c3073dSchenlu chen - Sun Microsystems - Beijing China break; 5792d5c3073dSchenlu chen - Sun Microsystems - Beijing China case e1000_ich9lan: 5793d5c3073dSchenlu chen - Sun Microsystems - Beijing China case e1000_ich10lan: 5794d5c3073dSchenlu chen - Sun Microsystems - Beijing China ctrl |= E1000_CTRL_SLU; 579508057504Sxy150489 break; 579608057504Sxy150489 } 5797d5c3073dSchenlu chen - Sun Microsystems - Beijing China if (hw->phy.type == e1000_phy_bm) 5798d5c3073dSchenlu chen - Sun Microsystems - Beijing China ctrl |= E1000_CTRL_SLU | E1000_CTRL_ILOS; 5799d5c3073dSchenlu chen - Sun Microsystems - Beijing China 5800d5c3073dSchenlu chen - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 580108057504Sxy150489 } 580208057504Sxy150489 580308057504Sxy150489 static void 580408057504Sxy150489 e1000g_set_external_loopback_1000(struct e1000g *Adapter) 580508057504Sxy150489 { 580608057504Sxy150489 struct e1000_hw *hw; 580708057504Sxy150489 uint32_t rctl; 580808057504Sxy150489 uint32_t ctrl_ext; 580908057504Sxy150489 uint32_t ctrl; 581008057504Sxy150489 uint32_t status; 581108057504Sxy150489 uint32_t txcw; 5812a2e9a830Scc210113 uint16_t phydata; 581308057504Sxy150489 581425f2d433Sxy150489 hw = &Adapter->shared; 581508057504Sxy150489 581608057504Sxy150489 /* Disable Smart Power Down */ 581708057504Sxy150489 phy_spd_state(hw, B_FALSE); 581808057504Sxy150489 5819a2e9a830Scc210113 switch (hw->mac.type) { 5820a2e9a830Scc210113 case e1000_82571: 5821a2e9a830Scc210113 case e1000_82572: 5822592a4d85Scc210113 switch (hw->phy.media_type) { 582308057504Sxy150489 case e1000_media_type_copper: 582408057504Sxy150489 /* Force link up (Must be done before the PHY writes) */ 582525f2d433Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 582608057504Sxy150489 ctrl |= E1000_CTRL_SLU; /* Force Link Up */ 582725f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 582808057504Sxy150489 582925f2d433Sxy150489 rctl = E1000_READ_REG(hw, E1000_RCTL); 583008057504Sxy150489 rctl |= (E1000_RCTL_EN | 583108057504Sxy150489 E1000_RCTL_SBP | 583208057504Sxy150489 E1000_RCTL_UPE | 583308057504Sxy150489 E1000_RCTL_MPE | 583408057504Sxy150489 E1000_RCTL_LPE | 583508057504Sxy150489 E1000_RCTL_BAM); /* 0x803E */ 583625f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, rctl); 583708057504Sxy150489 583825f2d433Sxy150489 ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 583908057504Sxy150489 ctrl_ext |= (E1000_CTRL_EXT_SDP4_DATA | 584008057504Sxy150489 E1000_CTRL_EXT_SDP6_DATA | 5841caf05df5SMiles Xu, Sun Microsystems E1000_CTRL_EXT_SDP3_DATA | 584208057504Sxy150489 E1000_CTRL_EXT_SDP4_DIR | 584308057504Sxy150489 E1000_CTRL_EXT_SDP6_DIR | 5844caf05df5SMiles Xu, Sun Microsystems E1000_CTRL_EXT_SDP3_DIR); /* 0x0DD0 */ 584525f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 584608057504Sxy150489 584708057504Sxy150489 /* 584808057504Sxy150489 * This sequence tunes the PHY's SDP and no customer 584908057504Sxy150489 * settable values. For background, see comments above 585008057504Sxy150489 * e1000g_set_internal_loopback(). 585108057504Sxy150489 */ 5852fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x0, 0x140); 585308057504Sxy150489 msec_delay(10); 5854fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x9, 0x1A00); 5855fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x12, 0xC10); 5856fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x12, 0x1C10); 5857fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x1F37, 0x76); 5858fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x1F33, 0x1); 5859fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x1F33, 0x0); 586008057504Sxy150489 5861fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x1F35, 0x65); 5862fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x1837, 0x3F7C); 5863fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x1437, 0x3FDC); 5864fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x1237, 0x3F7C); 5865fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, 0x1137, 0x3FDC); 586608057504Sxy150489 586708057504Sxy150489 msec_delay(50); 586808057504Sxy150489 break; 586908057504Sxy150489 case e1000_media_type_fiber: 587008057504Sxy150489 case e1000_media_type_internal_serdes: 587125f2d433Sxy150489 status = E1000_READ_REG(hw, E1000_STATUS); 587208057504Sxy150489 if (((status & E1000_STATUS_LU) == 0) || 5873a2e9a830Scc210113 (hw->phy.media_type == 5874a2e9a830Scc210113 e1000_media_type_internal_serdes)) { 587525f2d433Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 587608057504Sxy150489 ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU; 587725f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 587808057504Sxy150489 } 587908057504Sxy150489 588008057504Sxy150489 /* Disable autoneg by setting bit 31 of TXCW to zero */ 588125f2d433Sxy150489 txcw = E1000_READ_REG(hw, E1000_TXCW); 588208057504Sxy150489 txcw &= ~((uint32_t)1 << 31); 588325f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_TXCW, txcw); 588408057504Sxy150489 588508057504Sxy150489 /* 588608057504Sxy150489 * Write 0x410 to Serdes Control register 588708057504Sxy150489 * to enable Serdes analog loopback 588808057504Sxy150489 */ 588925f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_SCTL, 0x0410); 589008057504Sxy150489 msec_delay(10); 589108057504Sxy150489 break; 589208057504Sxy150489 default: 589308057504Sxy150489 break; 589408057504Sxy150489 } 5895a2e9a830Scc210113 break; 5896d5c3073dSchenlu chen - Sun Microsystems - Beijing China case e1000_82574: 5897a2e9a830Scc210113 case e1000_80003es2lan: 5898d5c3073dSchenlu chen - Sun Microsystems - Beijing China case e1000_ich9lan: 5899d5c3073dSchenlu chen - Sun Microsystems - Beijing China case e1000_ich10lan: 5900fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, GG82563_REG(6, 16), &phydata); 5901fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, GG82563_REG(6, 16), 5902fe62dec3SChen-Liang Xu phydata | (1 << 5)); 5903a2e9a830Scc210113 Adapter->param_adv_autoneg = 1; 5904a2e9a830Scc210113 Adapter->param_adv_1000fdx = 1; 5905fe62dec3SChen-Liang Xu (void) e1000g_reset_link(Adapter); 5906a2e9a830Scc210113 break; 5907a2e9a830Scc210113 } 590808057504Sxy150489 } 590908057504Sxy150489 591008057504Sxy150489 static void 591108057504Sxy150489 e1000g_set_external_loopback_100(struct e1000g *Adapter) 591208057504Sxy150489 { 591308057504Sxy150489 struct e1000_hw *hw; 591408057504Sxy150489 uint32_t ctrl; 591508057504Sxy150489 uint16_t phy_ctrl; 591608057504Sxy150489 591725f2d433Sxy150489 hw = &Adapter->shared; 591808057504Sxy150489 591908057504Sxy150489 /* Disable Smart Power Down */ 592008057504Sxy150489 phy_spd_state(hw, B_FALSE); 592108057504Sxy150489 592208057504Sxy150489 phy_ctrl = (MII_CR_FULL_DUPLEX | 592308057504Sxy150489 MII_CR_SPEED_100); 592408057504Sxy150489 592508057504Sxy150489 /* Force 100/FD, reset PHY */ 5926fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_CONTROL, 592708057504Sxy150489 phy_ctrl | MII_CR_RESET); /* 0xA100 */ 592808057504Sxy150489 msec_delay(10); 592908057504Sxy150489 593008057504Sxy150489 /* Force 100/FD */ 5931fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_CONTROL, 593208057504Sxy150489 phy_ctrl); /* 0x2100 */ 593308057504Sxy150489 msec_delay(10); 593408057504Sxy150489 593508057504Sxy150489 /* Now setup the MAC to the same speed/duplex as the PHY. */ 593625f2d433Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 593708057504Sxy150489 ctrl &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ 593808057504Sxy150489 ctrl |= (E1000_CTRL_SLU | /* Force Link Up */ 593908057504Sxy150489 E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ 594008057504Sxy150489 E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ 594108057504Sxy150489 E1000_CTRL_SPD_100 | /* Force Speed to 100 */ 594208057504Sxy150489 E1000_CTRL_FD); /* Force Duplex to FULL */ 594308057504Sxy150489 594425f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 594508057504Sxy150489 } 594608057504Sxy150489 594708057504Sxy150489 static void 594808057504Sxy150489 e1000g_set_external_loopback_10(struct e1000g *Adapter) 594908057504Sxy150489 { 595008057504Sxy150489 struct e1000_hw *hw; 595108057504Sxy150489 uint32_t ctrl; 595208057504Sxy150489 uint16_t phy_ctrl; 595308057504Sxy150489 595425f2d433Sxy150489 hw = &Adapter->shared; 595508057504Sxy150489 595608057504Sxy150489 /* Disable Smart Power Down */ 595708057504Sxy150489 phy_spd_state(hw, B_FALSE); 595808057504Sxy150489 595908057504Sxy150489 phy_ctrl = (MII_CR_FULL_DUPLEX | 596008057504Sxy150489 MII_CR_SPEED_10); 596108057504Sxy150489 596208057504Sxy150489 /* Force 10/FD, reset PHY */ 5963fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_CONTROL, 596408057504Sxy150489 phy_ctrl | MII_CR_RESET); /* 0x8100 */ 596508057504Sxy150489 msec_delay(10); 596608057504Sxy150489 596708057504Sxy150489 /* Force 10/FD */ 5968fe62dec3SChen-Liang Xu (void) e1000_write_phy_reg(hw, PHY_CONTROL, 596908057504Sxy150489 phy_ctrl); /* 0x0100 */ 597008057504Sxy150489 msec_delay(10); 597108057504Sxy150489 597208057504Sxy150489 /* Now setup the MAC to the same speed/duplex as the PHY. */ 597325f2d433Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 597408057504Sxy150489 ctrl &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ 597508057504Sxy150489 ctrl |= (E1000_CTRL_SLU | /* Force Link Up */ 597608057504Sxy150489 E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ 597708057504Sxy150489 E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ 597808057504Sxy150489 E1000_CTRL_SPD_10 | /* Force Speed to 10 */ 597908057504Sxy150489 E1000_CTRL_FD); /* Force Duplex to FULL */ 598008057504Sxy150489 598125f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 598208057504Sxy150489 } 598308057504Sxy150489 598408057504Sxy150489 #ifdef __sparc 598508057504Sxy150489 static boolean_t 598608057504Sxy150489 e1000g_find_mac_address(struct e1000g *Adapter) 598708057504Sxy150489 { 598825f2d433Sxy150489 struct e1000_hw *hw = &Adapter->shared; 598908057504Sxy150489 uchar_t *bytes; 599008057504Sxy150489 struct ether_addr sysaddr; 599108057504Sxy150489 uint_t nelts; 599208057504Sxy150489 int err; 599308057504Sxy150489 boolean_t found = B_FALSE; 599408057504Sxy150489 599508057504Sxy150489 /* 599608057504Sxy150489 * The "vendor's factory-set address" may already have 599708057504Sxy150489 * been extracted from the chip, but if the property 599808057504Sxy150489 * "local-mac-address" is set we use that instead. 599908057504Sxy150489 * 600008057504Sxy150489 * We check whether it looks like an array of 6 600108057504Sxy150489 * bytes (which it should, if OBP set it). If we can't 600208057504Sxy150489 * make sense of it this way, we'll ignore it. 600308057504Sxy150489 */ 600408057504Sxy150489 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip, 600508057504Sxy150489 DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts); 600608057504Sxy150489 if (err == DDI_PROP_SUCCESS) { 600708057504Sxy150489 if (nelts == ETHERADDRL) { 600808057504Sxy150489 while (nelts--) 600925f2d433Sxy150489 hw->mac.addr[nelts] = bytes[nelts]; 601008057504Sxy150489 found = B_TRUE; 601108057504Sxy150489 } 601208057504Sxy150489 ddi_prop_free(bytes); 601308057504Sxy150489 } 601408057504Sxy150489 601508057504Sxy150489 /* 601608057504Sxy150489 * Look up the OBP property "local-mac-address?". If the user has set 601708057504Sxy150489 * 'local-mac-address? = false', use "the system address" instead. 601808057504Sxy150489 */ 601908057504Sxy150489 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip, 0, 602008057504Sxy150489 "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) { 602108057504Sxy150489 if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) { 602208057504Sxy150489 if (localetheraddr(NULL, &sysaddr) != 0) { 602325f2d433Sxy150489 bcopy(&sysaddr, hw->mac.addr, ETHERADDRL); 602408057504Sxy150489 found = B_TRUE; 602508057504Sxy150489 } 602608057504Sxy150489 } 602708057504Sxy150489 ddi_prop_free(bytes); 602808057504Sxy150489 } 602908057504Sxy150489 603008057504Sxy150489 /* 603108057504Sxy150489 * Finally(!), if there's a valid "mac-address" property (created 603208057504Sxy150489 * if we netbooted from this interface), we must use this instead 603308057504Sxy150489 * of any of the above to ensure that the NFS/install server doesn't 603408057504Sxy150489 * get confused by the address changing as Solaris takes over! 603508057504Sxy150489 */ 603608057504Sxy150489 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip, 603708057504Sxy150489 DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts); 603808057504Sxy150489 if (err == DDI_PROP_SUCCESS) { 603908057504Sxy150489 if (nelts == ETHERADDRL) { 604008057504Sxy150489 while (nelts--) 604125f2d433Sxy150489 hw->mac.addr[nelts] = bytes[nelts]; 604208057504Sxy150489 found = B_TRUE; 604308057504Sxy150489 } 604408057504Sxy150489 ddi_prop_free(bytes); 604508057504Sxy150489 } 604608057504Sxy150489 604708057504Sxy150489 if (found) { 604825f2d433Sxy150489 bcopy(hw->mac.addr, hw->mac.perm_addr, 604908057504Sxy150489 ETHERADDRL); 605008057504Sxy150489 } 605108057504Sxy150489 605208057504Sxy150489 return (found); 605308057504Sxy150489 } 605408057504Sxy150489 #endif 605508057504Sxy150489 605608057504Sxy150489 static int 605708057504Sxy150489 e1000g_add_intrs(struct e1000g *Adapter) 605808057504Sxy150489 { 605908057504Sxy150489 dev_info_t *devinfo; 606008057504Sxy150489 int intr_types; 606108057504Sxy150489 int rc; 606208057504Sxy150489 606308057504Sxy150489 devinfo = Adapter->dip; 606408057504Sxy150489 606508057504Sxy150489 /* Get supported interrupt types */ 606608057504Sxy150489 rc = ddi_intr_get_supported_types(devinfo, &intr_types); 606708057504Sxy150489 606808057504Sxy150489 if (rc != DDI_SUCCESS) { 606925f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 607008057504Sxy150489 "Get supported interrupt types failed: %d\n", rc); 607108057504Sxy150489 return (DDI_FAILURE); 607208057504Sxy150489 } 607308057504Sxy150489 607408057504Sxy150489 /* 607508057504Sxy150489 * Based on Intel Technical Advisory document (TA-160), there are some 607608057504Sxy150489 * cases where some older Intel PCI-X NICs may "advertise" to the OS 607708057504Sxy150489 * that it supports MSI, but in fact has problems. 607808057504Sxy150489 * So we should only enable MSI for PCI-E NICs and disable MSI for old 607908057504Sxy150489 * PCI/PCI-X NICs. 608008057504Sxy150489 */ 608125f2d433Sxy150489 if (Adapter->shared.mac.type < e1000_82571) 6082c7770590Smx205022 Adapter->msi_enable = B_FALSE; 608308057504Sxy150489 6084c7770590Smx205022 if ((intr_types & DDI_INTR_TYPE_MSI) && Adapter->msi_enable) { 608508057504Sxy150489 rc = e1000g_intr_add(Adapter, DDI_INTR_TYPE_MSI); 608608057504Sxy150489 608708057504Sxy150489 if (rc != DDI_SUCCESS) { 608857ef6f69Sguoqing zhu - Sun Microsystems - Beijing China /* EMPTY */ 608925f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL, 609008057504Sxy150489 "Add MSI failed, trying Legacy interrupts\n"); 609108057504Sxy150489 } else { 609208057504Sxy150489 Adapter->intr_type = DDI_INTR_TYPE_MSI; 609308057504Sxy150489 } 609408057504Sxy150489 } 609508057504Sxy150489 609608057504Sxy150489 if ((Adapter->intr_type == 0) && 609708057504Sxy150489 (intr_types & DDI_INTR_TYPE_FIXED)) { 609808057504Sxy150489 rc = e1000g_intr_add(Adapter, DDI_INTR_TYPE_FIXED); 609908057504Sxy150489 610008057504Sxy150489 if (rc != DDI_SUCCESS) { 610125f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL, 610208057504Sxy150489 "Add Legacy interrupts failed\n"); 610308057504Sxy150489 return (DDI_FAILURE); 610408057504Sxy150489 } 610508057504Sxy150489 610608057504Sxy150489 Adapter->intr_type = DDI_INTR_TYPE_FIXED; 610708057504Sxy150489 } 610808057504Sxy150489 610908057504Sxy150489 if (Adapter->intr_type == 0) { 611025f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL, 611108057504Sxy150489 "No interrupts registered\n"); 611208057504Sxy150489 return (DDI_FAILURE); 611308057504Sxy150489 } 611408057504Sxy150489 611508057504Sxy150489 return (DDI_SUCCESS); 611608057504Sxy150489 } 611708057504Sxy150489 611808057504Sxy150489 /* 611908057504Sxy150489 * e1000g_intr_add() handles MSI/Legacy interrupts 612008057504Sxy150489 */ 612108057504Sxy150489 static int 612208057504Sxy150489 e1000g_intr_add(struct e1000g *Adapter, int intr_type) 612308057504Sxy150489 { 612408057504Sxy150489 dev_info_t *devinfo; 612508057504Sxy150489 int count, avail, actual; 612608057504Sxy150489 int x, y, rc, inum = 0; 612708057504Sxy150489 int flag; 612808057504Sxy150489 ddi_intr_handler_t *intr_handler; 612908057504Sxy150489 613008057504Sxy150489 devinfo = Adapter->dip; 613108057504Sxy150489 613208057504Sxy150489 /* get number of interrupts */ 613308057504Sxy150489 rc = ddi_intr_get_nintrs(devinfo, intr_type, &count); 613408057504Sxy150489 if ((rc != DDI_SUCCESS) || (count == 0)) { 613525f2d433Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL, 613608057504Sxy150489 "Get interrupt number failed. Return: %d, count: %d\n", 613708057504Sxy150489 rc, count); 613808057504Sxy150489 return (DDI_FAILURE); 613908057504Sxy150489 } 614008057504Sxy150489 614108057504Sxy150489 /* get number of available interrupts */ 614208057504Sxy150489 rc = ddi_intr_get_navail(devinfo, intr_type, &avail); 614308057504Sxy150489 if ((rc != DDI_SUCCESS) || (avail == 0)) { 614425f2d433Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL, 614508057504Sxy150489 "Get interrupt available number failed. " 614608057504Sxy150489 "Return: %d, available: %d\n", rc, avail); 614708057504Sxy150489 return (DDI_FAILURE); 614808057504Sxy150489 } 614908057504Sxy150489 615008057504Sxy150489 if (avail < count) { 615157ef6f69Sguoqing zhu - Sun Microsystems - Beijing China /* EMPTY */ 615225f2d433Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL, 615308057504Sxy150489 "Interrupts count: %d, available: %d\n", 615408057504Sxy150489 count, avail); 615508057504Sxy150489 } 615608057504Sxy150489 615708057504Sxy150489 /* Allocate an array of interrupt handles */ 615808057504Sxy150489 Adapter->intr_size = count * sizeof (ddi_intr_handle_t); 615908057504Sxy150489 Adapter->htable = kmem_alloc(Adapter->intr_size, KM_SLEEP); 616008057504Sxy150489 616108057504Sxy150489 /* Set NORMAL behavior for both MSI and FIXED interrupt */ 616208057504Sxy150489 flag = DDI_INTR_ALLOC_NORMAL; 616308057504Sxy150489 616408057504Sxy150489 /* call ddi_intr_alloc() */ 616508057504Sxy150489 rc = ddi_intr_alloc(devinfo, Adapter->htable, intr_type, inum, 616608057504Sxy150489 count, &actual, flag); 616708057504Sxy150489 616808057504Sxy150489 if ((rc != DDI_SUCCESS) || (actual == 0)) { 616925f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 617008057504Sxy150489 "Allocate interrupts failed: %d\n", rc); 617108057504Sxy150489 617208057504Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 617308057504Sxy150489 return (DDI_FAILURE); 617408057504Sxy150489 } 617508057504Sxy150489 617608057504Sxy150489 if (actual < count) { 617757ef6f69Sguoqing zhu - Sun Microsystems - Beijing China /* EMPTY */ 617825f2d433Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL, 617908057504Sxy150489 "Interrupts requested: %d, received: %d\n", 618008057504Sxy150489 count, actual); 618108057504Sxy150489 } 618208057504Sxy150489 618308057504Sxy150489 Adapter->intr_cnt = actual; 618408057504Sxy150489 618508057504Sxy150489 /* Get priority for first msi, assume remaining are all the same */ 618608057504Sxy150489 rc = ddi_intr_get_pri(Adapter->htable[0], &Adapter->intr_pri); 618708057504Sxy150489 618808057504Sxy150489 if (rc != DDI_SUCCESS) { 618925f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 619008057504Sxy150489 "Get interrupt priority failed: %d\n", rc); 619108057504Sxy150489 619208057504Sxy150489 /* Free already allocated intr */ 619308057504Sxy150489 for (y = 0; y < actual; y++) 619408057504Sxy150489 (void) ddi_intr_free(Adapter->htable[y]); 619508057504Sxy150489 619608057504Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 619708057504Sxy150489 return (DDI_FAILURE); 619808057504Sxy150489 } 619908057504Sxy150489 620008057504Sxy150489 /* 620108057504Sxy150489 * In Legacy Interrupt mode, for PCI-Express adapters, we should 620208057504Sxy150489 * use the interrupt service routine e1000g_intr_pciexpress() 620308057504Sxy150489 * to avoid interrupt stealing when sharing interrupt with other 620408057504Sxy150489 * devices. 620508057504Sxy150489 */ 620625f2d433Sxy150489 if (Adapter->shared.mac.type < e1000_82571) 620708057504Sxy150489 intr_handler = (ddi_intr_handler_t *)e1000g_intr; 620808057504Sxy150489 else 620908057504Sxy150489 intr_handler = (ddi_intr_handler_t *)e1000g_intr_pciexpress; 621008057504Sxy150489 621108057504Sxy150489 /* Call ddi_intr_add_handler() */ 621208057504Sxy150489 for (x = 0; x < actual; x++) { 621308057504Sxy150489 rc = ddi_intr_add_handler(Adapter->htable[x], 621408057504Sxy150489 intr_handler, (caddr_t)Adapter, NULL); 621508057504Sxy150489 621608057504Sxy150489 if (rc != DDI_SUCCESS) { 621725f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 621808057504Sxy150489 "Add interrupt handler failed: %d\n", rc); 621908057504Sxy150489 622008057504Sxy150489 /* Remove already added handler */ 622108057504Sxy150489 for (y = 0; y < x; y++) 622208057504Sxy150489 (void) ddi_intr_remove_handler( 622308057504Sxy150489 Adapter->htable[y]); 622408057504Sxy150489 622508057504Sxy150489 /* Free already allocated intr */ 622608057504Sxy150489 for (y = 0; y < actual; y++) 622708057504Sxy150489 (void) ddi_intr_free(Adapter->htable[y]); 622808057504Sxy150489 622908057504Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 623008057504Sxy150489 return (DDI_FAILURE); 623108057504Sxy150489 } 623208057504Sxy150489 } 623308057504Sxy150489 623408057504Sxy150489 rc = ddi_intr_get_cap(Adapter->htable[0], &Adapter->intr_cap); 623508057504Sxy150489 623608057504Sxy150489 if (rc != DDI_SUCCESS) { 623725f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 623808057504Sxy150489 "Get interrupt cap failed: %d\n", rc); 623908057504Sxy150489 624008057504Sxy150489 /* Free already allocated intr */ 624108057504Sxy150489 for (y = 0; y < actual; y++) { 624208057504Sxy150489 (void) ddi_intr_remove_handler(Adapter->htable[y]); 624308057504Sxy150489 (void) ddi_intr_free(Adapter->htable[y]); 624408057504Sxy150489 } 624508057504Sxy150489 624608057504Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 624708057504Sxy150489 return (DDI_FAILURE); 624808057504Sxy150489 } 624908057504Sxy150489 625008057504Sxy150489 return (DDI_SUCCESS); 625108057504Sxy150489 } 625208057504Sxy150489 625308057504Sxy150489 static int 625408057504Sxy150489 e1000g_rem_intrs(struct e1000g *Adapter) 625508057504Sxy150489 { 625608057504Sxy150489 int x; 625708057504Sxy150489 int rc; 625808057504Sxy150489 625908057504Sxy150489 for (x = 0; x < Adapter->intr_cnt; x++) { 626008057504Sxy150489 rc = ddi_intr_remove_handler(Adapter->htable[x]); 626108057504Sxy150489 if (rc != DDI_SUCCESS) { 626225f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 626308057504Sxy150489 "Remove intr handler failed: %d\n", rc); 626408057504Sxy150489 return (DDI_FAILURE); 626508057504Sxy150489 } 626608057504Sxy150489 626708057504Sxy150489 rc = ddi_intr_free(Adapter->htable[x]); 626808057504Sxy150489 if (rc != DDI_SUCCESS) { 626925f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 627008057504Sxy150489 "Free intr failed: %d\n", rc); 627108057504Sxy150489 return (DDI_FAILURE); 627208057504Sxy150489 } 627308057504Sxy150489 } 627408057504Sxy150489 627508057504Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 627608057504Sxy150489 627708057504Sxy150489 return (DDI_SUCCESS); 627808057504Sxy150489 } 627908057504Sxy150489 628008057504Sxy150489 static int 628108057504Sxy150489 e1000g_enable_intrs(struct e1000g *Adapter) 628208057504Sxy150489 { 628308057504Sxy150489 int x; 628408057504Sxy150489 int rc; 628508057504Sxy150489 628608057504Sxy150489 /* Enable interrupts */ 628708057504Sxy150489 if (Adapter->intr_cap & DDI_INTR_FLAG_BLOCK) { 628808057504Sxy150489 /* Call ddi_intr_block_enable() for MSI */ 628908057504Sxy150489 rc = ddi_intr_block_enable(Adapter->htable, 629008057504Sxy150489 Adapter->intr_cnt); 629108057504Sxy150489 if (rc != DDI_SUCCESS) { 629225f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 629308057504Sxy150489 "Enable block intr failed: %d\n", rc); 629408057504Sxy150489 return (DDI_FAILURE); 629508057504Sxy150489 } 629608057504Sxy150489 } else { 629708057504Sxy150489 /* Call ddi_intr_enable() for Legacy/MSI non block enable */ 629808057504Sxy150489 for (x = 0; x < Adapter->intr_cnt; x++) { 629908057504Sxy150489 rc = ddi_intr_enable(Adapter->htable[x]); 630008057504Sxy150489 if (rc != DDI_SUCCESS) { 630125f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 630208057504Sxy150489 "Enable intr failed: %d\n", rc); 630308057504Sxy150489 return (DDI_FAILURE); 630408057504Sxy150489 } 630508057504Sxy150489 } 630608057504Sxy150489 } 630708057504Sxy150489 630808057504Sxy150489 return (DDI_SUCCESS); 630908057504Sxy150489 } 631008057504Sxy150489 631108057504Sxy150489 static int 631208057504Sxy150489 e1000g_disable_intrs(struct e1000g *Adapter) 631308057504Sxy150489 { 631408057504Sxy150489 int x; 631508057504Sxy150489 int rc; 631608057504Sxy150489 631708057504Sxy150489 /* Disable all interrupts */ 631808057504Sxy150489 if (Adapter->intr_cap & DDI_INTR_FLAG_BLOCK) { 631908057504Sxy150489 rc = ddi_intr_block_disable(Adapter->htable, 632008057504Sxy150489 Adapter->intr_cnt); 632108057504Sxy150489 if (rc != DDI_SUCCESS) { 632225f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 632308057504Sxy150489 "Disable block intr failed: %d\n", rc); 632408057504Sxy150489 return (DDI_FAILURE); 632508057504Sxy150489 } 632608057504Sxy150489 } else { 632708057504Sxy150489 for (x = 0; x < Adapter->intr_cnt; x++) { 632808057504Sxy150489 rc = ddi_intr_disable(Adapter->htable[x]); 632908057504Sxy150489 if (rc != DDI_SUCCESS) { 633025f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 633108057504Sxy150489 "Disable intr failed: %d\n", rc); 633208057504Sxy150489 return (DDI_FAILURE); 633308057504Sxy150489 } 633408057504Sxy150489 } 633508057504Sxy150489 } 633608057504Sxy150489 633708057504Sxy150489 return (DDI_SUCCESS); 633808057504Sxy150489 } 63394914a7d0Syy150190 63404914a7d0Syy150190 /* 63414914a7d0Syy150190 * e1000g_get_phy_state - get the state of PHY registers, save in the adapter 63424914a7d0Syy150190 */ 63434914a7d0Syy150190 static void 63444914a7d0Syy150190 e1000g_get_phy_state(struct e1000g *Adapter) 63454914a7d0Syy150190 { 63464914a7d0Syy150190 struct e1000_hw *hw = &Adapter->shared; 63474914a7d0Syy150190 6348111c450cSMiles Xu, Sun Microsystems if (hw->phy.media_type == e1000_media_type_copper) { 6349fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, PHY_CONTROL, &Adapter->phy_ctrl); 6350fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, PHY_STATUS, &Adapter->phy_status); 6351111c450cSMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, 6352111c450cSMiles Xu, Sun Microsystems &Adapter->phy_an_adv); 6353111c450cSMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, 6354111c450cSMiles Xu, Sun Microsystems &Adapter->phy_an_exp); 6355111c450cSMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_EXT_STATUS, 6356111c450cSMiles Xu, Sun Microsystems &Adapter->phy_ext_status); 6357111c450cSMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_1000T_CTRL, 6358111c450cSMiles Xu, Sun Microsystems &Adapter->phy_1000t_ctrl); 6359fe62dec3SChen-Liang Xu (void) e1000_read_phy_reg(hw, PHY_1000T_STATUS, 6360fe62dec3SChen-Liang Xu &Adapter->phy_1000t_status); 6361111c450cSMiles Xu, Sun Microsystems (void) e1000_read_phy_reg(hw, PHY_LP_ABILITY, 6362111c450cSMiles Xu, Sun Microsystems &Adapter->phy_lp_able); 63639ce7e93cScc210113 63649ce7e93cScc210113 Adapter->param_autoneg_cap = 63659ce7e93cScc210113 (Adapter->phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0; 63669ce7e93cScc210113 Adapter->param_pause_cap = 63679ce7e93cScc210113 (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0; 63689ce7e93cScc210113 Adapter->param_asym_pause_cap = 63699ce7e93cScc210113 (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0; 63709ce7e93cScc210113 Adapter->param_1000fdx_cap = 63719ce7e93cScc210113 ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) || 63729ce7e93cScc210113 (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0; 63739ce7e93cScc210113 Adapter->param_1000hdx_cap = 63749ce7e93cScc210113 ((Adapter->phy_ext_status & IEEE_ESR_1000T_HD_CAPS) || 63759ce7e93cScc210113 (Adapter->phy_ext_status & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0; 63769ce7e93cScc210113 Adapter->param_100t4_cap = 63779ce7e93cScc210113 (Adapter->phy_status & MII_SR_100T4_CAPS) ? 1 : 0; 63789ce7e93cScc210113 Adapter->param_100fdx_cap = 63799ce7e93cScc210113 ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 63809ce7e93cScc210113 (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0; 63819ce7e93cScc210113 Adapter->param_100hdx_cap = 63829ce7e93cScc210113 ((Adapter->phy_status & MII_SR_100X_HD_CAPS) || 63839ce7e93cScc210113 (Adapter->phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0; 63849ce7e93cScc210113 Adapter->param_10fdx_cap = 63859ce7e93cScc210113 (Adapter->phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0; 63869ce7e93cScc210113 Adapter->param_10hdx_cap = 63879ce7e93cScc210113 (Adapter->phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0; 63889ce7e93cScc210113 63899ce7e93cScc210113 Adapter->param_adv_autoneg = hw->mac.autoneg; 63909ce7e93cScc210113 Adapter->param_adv_pause = 63919ce7e93cScc210113 (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0; 63929ce7e93cScc210113 Adapter->param_adv_asym_pause = 63939ce7e93cScc210113 (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0; 63949ce7e93cScc210113 Adapter->param_adv_1000hdx = 63959ce7e93cScc210113 (Adapter->phy_1000t_ctrl & CR_1000T_HD_CAPS) ? 1 : 0; 63969ce7e93cScc210113 Adapter->param_adv_100t4 = 63979ce7e93cScc210113 (Adapter->phy_an_adv & NWAY_AR_100T4_CAPS) ? 1 : 0; 63989ce7e93cScc210113 if (Adapter->param_adv_autoneg == 1) { 63999ce7e93cScc210113 Adapter->param_adv_1000fdx = 6400111c450cSMiles Xu, Sun Microsystems (Adapter->phy_1000t_ctrl & CR_1000T_FD_CAPS) 6401111c450cSMiles Xu, Sun Microsystems ? 1 : 0; 64029ce7e93cScc210113 Adapter->param_adv_100fdx = 6403111c450cSMiles Xu, Sun Microsystems (Adapter->phy_an_adv & NWAY_AR_100TX_FD_CAPS) 6404111c450cSMiles Xu, Sun Microsystems ? 1 : 0; 64059ce7e93cScc210113 Adapter->param_adv_100hdx = 6406111c450cSMiles Xu, Sun Microsystems (Adapter->phy_an_adv & NWAY_AR_100TX_HD_CAPS) 6407111c450cSMiles Xu, Sun Microsystems ? 1 : 0; 64089ce7e93cScc210113 Adapter->param_adv_10fdx = 64099ce7e93cScc210113 (Adapter->phy_an_adv & NWAY_AR_10T_FD_CAPS) ? 1 : 0; 64109ce7e93cScc210113 Adapter->param_adv_10hdx = 64119ce7e93cScc210113 (Adapter->phy_an_adv & NWAY_AR_10T_HD_CAPS) ? 1 : 0; 64129ce7e93cScc210113 } 64139ce7e93cScc210113 64149ce7e93cScc210113 Adapter->param_lp_autoneg = 64159ce7e93cScc210113 (Adapter->phy_an_exp & NWAY_ER_LP_NWAY_CAPS) ? 1 : 0; 64169ce7e93cScc210113 Adapter->param_lp_pause = 64179ce7e93cScc210113 (Adapter->phy_lp_able & NWAY_LPAR_PAUSE) ? 1 : 0; 64189ce7e93cScc210113 Adapter->param_lp_asym_pause = 64199ce7e93cScc210113 (Adapter->phy_lp_able & NWAY_LPAR_ASM_DIR) ? 1 : 0; 64209ce7e93cScc210113 Adapter->param_lp_1000fdx = 64219ce7e93cScc210113 (Adapter->phy_1000t_status & SR_1000T_LP_FD_CAPS) ? 1 : 0; 64229ce7e93cScc210113 Adapter->param_lp_1000hdx = 64239ce7e93cScc210113 (Adapter->phy_1000t_status & SR_1000T_LP_HD_CAPS) ? 1 : 0; 64249ce7e93cScc210113 Adapter->param_lp_100t4 = 64259ce7e93cScc210113 (Adapter->phy_lp_able & NWAY_LPAR_100T4_CAPS) ? 1 : 0; 64269ce7e93cScc210113 Adapter->param_lp_100fdx = 64279ce7e93cScc210113 (Adapter->phy_lp_able & NWAY_LPAR_100TX_FD_CAPS) ? 1 : 0; 64289ce7e93cScc210113 Adapter->param_lp_100hdx = 64299ce7e93cScc210113 (Adapter->phy_lp_able & NWAY_LPAR_100TX_HD_CAPS) ? 1 : 0; 64309ce7e93cScc210113 Adapter->param_lp_10fdx = 64319ce7e93cScc210113 (Adapter->phy_lp_able & NWAY_LPAR_10T_FD_CAPS) ? 1 : 0; 64329ce7e93cScc210113 Adapter->param_lp_10hdx = 64339ce7e93cScc210113 (Adapter->phy_lp_able & NWAY_LPAR_10T_HD_CAPS) ? 1 : 0; 6434111c450cSMiles Xu, Sun Microsystems } else { 6435111c450cSMiles Xu, Sun Microsystems /* 6436111c450cSMiles Xu, Sun Microsystems * 1Gig Fiber adapter only offers 1Gig Full Duplex. Meaning, 6437111c450cSMiles Xu, Sun Microsystems * it can only work with 1Gig Full Duplex Link Partner. 6438111c450cSMiles Xu, Sun Microsystems */ 6439111c450cSMiles Xu, Sun Microsystems Adapter->param_autoneg_cap = 0; 6440111c450cSMiles Xu, Sun Microsystems Adapter->param_pause_cap = 1; 6441111c450cSMiles Xu, Sun Microsystems Adapter->param_asym_pause_cap = 1; 6442111c450cSMiles Xu, Sun Microsystems Adapter->param_1000fdx_cap = 1; 6443111c450cSMiles Xu, Sun Microsystems Adapter->param_1000hdx_cap = 0; 6444111c450cSMiles Xu, Sun Microsystems Adapter->param_100t4_cap = 0; 6445111c450cSMiles Xu, Sun Microsystems Adapter->param_100fdx_cap = 0; 6446111c450cSMiles Xu, Sun Microsystems Adapter->param_100hdx_cap = 0; 6447111c450cSMiles Xu, Sun Microsystems Adapter->param_10fdx_cap = 0; 6448111c450cSMiles Xu, Sun Microsystems Adapter->param_10hdx_cap = 0; 6449111c450cSMiles Xu, Sun Microsystems 6450111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_autoneg = 0; 6451111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_pause = 1; 6452111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_asym_pause = 1; 6453111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_1000fdx = 1; 6454111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_1000hdx = 0; 6455111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_100t4 = 0; 6456111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_100fdx = 0; 6457111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_100hdx = 0; 6458111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_10fdx = 0; 6459111c450cSMiles Xu, Sun Microsystems Adapter->param_adv_10hdx = 0; 6460111c450cSMiles Xu, Sun Microsystems 6461111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_autoneg = 0; 6462111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_pause = 0; 6463111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_asym_pause = 0; 6464111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_1000fdx = 0; 6465111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_1000hdx = 0; 6466111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_100t4 = 0; 6467111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_100fdx = 0; 6468111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_100hdx = 0; 6469111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_10fdx = 0; 6470111c450cSMiles Xu, Sun Microsystems Adapter->param_lp_10hdx = 0; 6471111c450cSMiles Xu, Sun Microsystems } 64724914a7d0Syy150190 } 64739b6541b3Sgl147354 64749b6541b3Sgl147354 /* 64759b6541b3Sgl147354 * FMA support 64769b6541b3Sgl147354 */ 64779b6541b3Sgl147354 64789b6541b3Sgl147354 int 64799b6541b3Sgl147354 e1000g_check_acc_handle(ddi_acc_handle_t handle) 64809b6541b3Sgl147354 { 64819b6541b3Sgl147354 ddi_fm_error_t de; 64829b6541b3Sgl147354 64839b6541b3Sgl147354 ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 64849b6541b3Sgl147354 ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 64859b6541b3Sgl147354 return (de.fme_status); 64869b6541b3Sgl147354 } 64879b6541b3Sgl147354 64889b6541b3Sgl147354 int 64899b6541b3Sgl147354 e1000g_check_dma_handle(ddi_dma_handle_t handle) 64909b6541b3Sgl147354 { 64919b6541b3Sgl147354 ddi_fm_error_t de; 64929b6541b3Sgl147354 64939b6541b3Sgl147354 ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 64949b6541b3Sgl147354 return (de.fme_status); 64959b6541b3Sgl147354 } 64969b6541b3Sgl147354 64979b6541b3Sgl147354 /* 64989b6541b3Sgl147354 * The IO fault service error handling callback function 64999b6541b3Sgl147354 */ 6500fe62dec3SChen-Liang Xu /* ARGSUSED2 */ 65019b6541b3Sgl147354 static int 65029b6541b3Sgl147354 e1000g_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 65039b6541b3Sgl147354 { 65049b6541b3Sgl147354 /* 65059b6541b3Sgl147354 * as the driver can always deal with an error in any dma or 65069b6541b3Sgl147354 * access handle, we can just return the fme_status value. 65079b6541b3Sgl147354 */ 65089b6541b3Sgl147354 pci_ereport_post(dip, err, NULL); 65099b6541b3Sgl147354 return (err->fme_status); 65109b6541b3Sgl147354 } 65119b6541b3Sgl147354 65129b6541b3Sgl147354 static void 65139b6541b3Sgl147354 e1000g_fm_init(struct e1000g *Adapter) 65149b6541b3Sgl147354 { 65159b6541b3Sgl147354 ddi_iblock_cookie_t iblk; 6516837c1ac4SStephen Hanson int fma_dma_flag; 65179b6541b3Sgl147354 65189b6541b3Sgl147354 /* Only register with IO Fault Services if we have some capability */ 65199b6541b3Sgl147354 if (Adapter->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) { 65209b6541b3Sgl147354 e1000g_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; 65219b6541b3Sgl147354 } else { 65229b6541b3Sgl147354 e1000g_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; 65239b6541b3Sgl147354 } 65249b6541b3Sgl147354 65259b6541b3Sgl147354 if (Adapter->fm_capabilities & DDI_FM_DMACHK_CAPABLE) { 65269b6541b3Sgl147354 fma_dma_flag = 1; 65279b6541b3Sgl147354 } else { 65289b6541b3Sgl147354 fma_dma_flag = 0; 65299b6541b3Sgl147354 } 65309b6541b3Sgl147354 6531837c1ac4SStephen Hanson (void) e1000g_set_fma_flags(fma_dma_flag); 65329b6541b3Sgl147354 65339b6541b3Sgl147354 if (Adapter->fm_capabilities) { 65349b6541b3Sgl147354 65359b6541b3Sgl147354 /* Register capabilities with IO Fault Services */ 65369b6541b3Sgl147354 ddi_fm_init(Adapter->dip, &Adapter->fm_capabilities, &iblk); 65379b6541b3Sgl147354 65389b6541b3Sgl147354 /* 65399b6541b3Sgl147354 * Initialize pci ereport capabilities if ereport capable 65409b6541b3Sgl147354 */ 65419b6541b3Sgl147354 if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities) || 65429b6541b3Sgl147354 DDI_FM_ERRCB_CAP(Adapter->fm_capabilities)) 65439b6541b3Sgl147354 pci_ereport_setup(Adapter->dip); 65449b6541b3Sgl147354 65459b6541b3Sgl147354 /* 65469b6541b3Sgl147354 * Register error callback if error callback capable 65479b6541b3Sgl147354 */ 65489b6541b3Sgl147354 if (DDI_FM_ERRCB_CAP(Adapter->fm_capabilities)) 65499b6541b3Sgl147354 ddi_fm_handler_register(Adapter->dip, 65509b6541b3Sgl147354 e1000g_fm_error_cb, (void*) Adapter); 65519b6541b3Sgl147354 } 65529b6541b3Sgl147354 } 65539b6541b3Sgl147354 65549b6541b3Sgl147354 static void 65559b6541b3Sgl147354 e1000g_fm_fini(struct e1000g *Adapter) 65569b6541b3Sgl147354 { 65579b6541b3Sgl147354 /* Only unregister FMA capabilities if we registered some */ 65589b6541b3Sgl147354 if (Adapter->fm_capabilities) { 65599b6541b3Sgl147354 65609b6541b3Sgl147354 /* 65619b6541b3Sgl147354 * Release any resources allocated by pci_ereport_setup() 65629b6541b3Sgl147354 */ 65639b6541b3Sgl147354 if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities) || 65649b6541b3Sgl147354 DDI_FM_ERRCB_CAP(Adapter->fm_capabilities)) 65659b6541b3Sgl147354 pci_ereport_teardown(Adapter->dip); 65669b6541b3Sgl147354 65679b6541b3Sgl147354 /* 65689b6541b3Sgl147354 * Un-register error callback if error callback capable 65699b6541b3Sgl147354 */ 65709b6541b3Sgl147354 if (DDI_FM_ERRCB_CAP(Adapter->fm_capabilities)) 65719b6541b3Sgl147354 ddi_fm_handler_unregister(Adapter->dip); 65729b6541b3Sgl147354 65739b6541b3Sgl147354 /* Unregister from IO Fault Services */ 657482df3b26Schangqing li - Sun Microsystems - Beijing China mutex_enter(&e1000g_rx_detach_lock); 65759b6541b3Sgl147354 ddi_fm_fini(Adapter->dip); 657682df3b26Schangqing li - Sun Microsystems - Beijing China if (Adapter->priv_dip != NULL) { 657782df3b26Schangqing li - Sun Microsystems - Beijing China DEVI(Adapter->priv_dip)->devi_fmhdl = NULL; 657882df3b26Schangqing li - Sun Microsystems - Beijing China } 657982df3b26Schangqing li - Sun Microsystems - Beijing China mutex_exit(&e1000g_rx_detach_lock); 65809b6541b3Sgl147354 } 65819b6541b3Sgl147354 } 65829b6541b3Sgl147354 65839b6541b3Sgl147354 void 65849b6541b3Sgl147354 e1000g_fm_ereport(struct e1000g *Adapter, char *detail) 65859b6541b3Sgl147354 { 65869b6541b3Sgl147354 uint64_t ena; 65879b6541b3Sgl147354 char buf[FM_MAX_CLASS]; 65889b6541b3Sgl147354 65899b6541b3Sgl147354 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 65909b6541b3Sgl147354 ena = fm_ena_generate(0, FM_ENA_FMT1); 65919b6541b3Sgl147354 if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities)) { 65929b6541b3Sgl147354 ddi_fm_ereport_post(Adapter->dip, buf, ena, DDI_NOSLEEP, 65939b6541b3Sgl147354 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 65949b6541b3Sgl147354 } 65959b6541b3Sgl147354 } 65964045d941Ssowmini 659719397407SSherry Moore /* 659819397407SSherry Moore * quiesce(9E) entry point. 659919397407SSherry Moore * 660019397407SSherry Moore * This function is called when the system is single-threaded at high 660119397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be 660219397407SSherry Moore * blocked. 660319397407SSherry Moore * 660419397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 660519397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen. 660619397407SSherry Moore */ 660719397407SSherry Moore static int 660819397407SSherry Moore e1000g_quiesce(dev_info_t *devinfo) 660919397407SSherry Moore { 661019397407SSherry Moore struct e1000g *Adapter; 661119397407SSherry Moore 661219397407SSherry Moore Adapter = (struct e1000g *)ddi_get_driver_private(devinfo); 661319397407SSherry Moore 661419397407SSherry Moore if (Adapter == NULL) 661519397407SSherry Moore return (DDI_FAILURE); 661619397407SSherry Moore 661719397407SSherry Moore e1000g_clear_all_interrupts(Adapter); 661819397407SSherry Moore 661919397407SSherry Moore (void) e1000_reset_hw(&Adapter->shared); 662019397407SSherry Moore 662119397407SSherry Moore /* Setup our HW Tx Head & Tail descriptor pointers */ 662219397407SSherry Moore E1000_WRITE_REG(&Adapter->shared, E1000_TDH(0), 0); 662319397407SSherry Moore E1000_WRITE_REG(&Adapter->shared, E1000_TDT(0), 0); 662419397407SSherry Moore 662519397407SSherry Moore /* Setup our HW Rx Head & Tail descriptor pointers */ 662619397407SSherry Moore E1000_WRITE_REG(&Adapter->shared, E1000_RDH(0), 0); 662719397407SSherry Moore E1000_WRITE_REG(&Adapter->shared, E1000_RDT(0), 0); 662819397407SSherry Moore 662919397407SSherry Moore return (DDI_SUCCESS); 663019397407SSherry Moore } 663119397407SSherry Moore 66324045d941Ssowmini /* 66334045d941Ssowmini * synchronize the adv* and en* parameters. 66344045d941Ssowmini * 66354045d941Ssowmini * See comments in <sys/dld.h> for details of the *_en_* 66364045d941Ssowmini * parameters. The usage of ndd for setting adv parameters will 66374045d941Ssowmini * synchronize all the en parameters with the e1000g parameters, 66384d737963Sxiangtao you - Sun Microsystems - Beijing China * implicitly disabling any settings made via dladm. 66394045d941Ssowmini */ 66404045d941Ssowmini static void 66414045d941Ssowmini e1000g_param_sync(struct e1000g *Adapter) 66424045d941Ssowmini { 66434045d941Ssowmini Adapter->param_en_1000fdx = Adapter->param_adv_1000fdx; 66444045d941Ssowmini Adapter->param_en_1000hdx = Adapter->param_adv_1000hdx; 66454045d941Ssowmini Adapter->param_en_100fdx = Adapter->param_adv_100fdx; 66464045d941Ssowmini Adapter->param_en_100hdx = Adapter->param_adv_100hdx; 66474045d941Ssowmini Adapter->param_en_10fdx = Adapter->param_adv_10fdx; 66484045d941Ssowmini Adapter->param_en_10hdx = Adapter->param_adv_10hdx; 66494045d941Ssowmini } 66504d737963Sxiangtao you - Sun Microsystems - Beijing China 66514d737963Sxiangtao you - Sun Microsystems - Beijing China /* 66524d737963Sxiangtao you - Sun Microsystems - Beijing China * e1000g_get_driver_control - tell manageability firmware that the driver 66534d737963Sxiangtao you - Sun Microsystems - Beijing China * has control. 66544d737963Sxiangtao you - Sun Microsystems - Beijing China */ 66554d737963Sxiangtao you - Sun Microsystems - Beijing China static void 66564d737963Sxiangtao you - Sun Microsystems - Beijing China e1000g_get_driver_control(struct e1000_hw *hw) 66574d737963Sxiangtao you - Sun Microsystems - Beijing China { 66584d737963Sxiangtao you - Sun Microsystems - Beijing China uint32_t ctrl_ext; 66594d737963Sxiangtao you - Sun Microsystems - Beijing China uint32_t swsm; 66604d737963Sxiangtao you - Sun Microsystems - Beijing China 66614d737963Sxiangtao you - Sun Microsystems - Beijing China /* tell manageability firmware the driver has taken over */ 66624d737963Sxiangtao you - Sun Microsystems - Beijing China switch (hw->mac.type) { 66634d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_82573: 66644d737963Sxiangtao you - Sun Microsystems - Beijing China swsm = E1000_READ_REG(hw, E1000_SWSM); 66654d737963Sxiangtao you - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_DRV_LOAD); 66664d737963Sxiangtao you - Sun Microsystems - Beijing China break; 66674d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_82571: 66684d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_82572: 66694d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_82574: 66704d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_80003es2lan: 66714d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_ich8lan: 66724d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_ich9lan: 66734d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_ich10lan: 6674caf05df5SMiles Xu, Sun Microsystems case e1000_pchlan: 6675dab7de2dSGarrett D'Amore case e1000_pch2lan: 66764d737963Sxiangtao you - Sun Microsystems - Beijing China ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 66774d737963Sxiangtao you - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_CTRL_EXT, 66784d737963Sxiangtao you - Sun Microsystems - Beijing China ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); 66794d737963Sxiangtao you - Sun Microsystems - Beijing China break; 66804d737963Sxiangtao you - Sun Microsystems - Beijing China default: 66814d737963Sxiangtao you - Sun Microsystems - Beijing China /* no manageability firmware: do nothing */ 66824d737963Sxiangtao you - Sun Microsystems - Beijing China break; 66834d737963Sxiangtao you - Sun Microsystems - Beijing China } 66844d737963Sxiangtao you - Sun Microsystems - Beijing China } 66854d737963Sxiangtao you - Sun Microsystems - Beijing China 66864d737963Sxiangtao you - Sun Microsystems - Beijing China /* 66874d737963Sxiangtao you - Sun Microsystems - Beijing China * e1000g_release_driver_control - tell manageability firmware that the driver 66884d737963Sxiangtao you - Sun Microsystems - Beijing China * has released control. 66894d737963Sxiangtao you - Sun Microsystems - Beijing China */ 66904d737963Sxiangtao you - Sun Microsystems - Beijing China static void 66914d737963Sxiangtao you - Sun Microsystems - Beijing China e1000g_release_driver_control(struct e1000_hw *hw) 66924d737963Sxiangtao you - Sun Microsystems - Beijing China { 66934d737963Sxiangtao you - Sun Microsystems - Beijing China uint32_t ctrl_ext; 66944d737963Sxiangtao you - Sun Microsystems - Beijing China uint32_t swsm; 66954d737963Sxiangtao you - Sun Microsystems - Beijing China 66964d737963Sxiangtao you - Sun Microsystems - Beijing China /* tell manageability firmware the driver has released control */ 66974d737963Sxiangtao you - Sun Microsystems - Beijing China switch (hw->mac.type) { 66984d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_82573: 66994d737963Sxiangtao you - Sun Microsystems - Beijing China swsm = E1000_READ_REG(hw, E1000_SWSM); 67004d737963Sxiangtao you - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_SWSM, swsm & ~E1000_SWSM_DRV_LOAD); 67014d737963Sxiangtao you - Sun Microsystems - Beijing China break; 67024d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_82571: 67034d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_82572: 67044d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_82574: 67054d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_80003es2lan: 67064d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_ich8lan: 67074d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_ich9lan: 67084d737963Sxiangtao you - Sun Microsystems - Beijing China case e1000_ich10lan: 6709caf05df5SMiles Xu, Sun Microsystems case e1000_pchlan: 6710dab7de2dSGarrett D'Amore case e1000_pch2lan: 67114d737963Sxiangtao you - Sun Microsystems - Beijing China ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 67124d737963Sxiangtao you - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_CTRL_EXT, 67134d737963Sxiangtao you - Sun Microsystems - Beijing China ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); 67144d737963Sxiangtao you - Sun Microsystems - Beijing China break; 67154d737963Sxiangtao you - Sun Microsystems - Beijing China default: 67164d737963Sxiangtao you - Sun Microsystems - Beijing China /* no manageability firmware: do nothing */ 67174d737963Sxiangtao you - Sun Microsystems - Beijing China break; 67184d737963Sxiangtao you - Sun Microsystems - Beijing China } 67194d737963Sxiangtao you - Sun Microsystems - Beijing China } 6720bb184967SShu-Guo Yang 6721bb184967SShu-Guo Yang /* 6722bb184967SShu-Guo Yang * Restore e1000g promiscuous mode. 6723bb184967SShu-Guo Yang */ 6724bb184967SShu-Guo Yang static void 6725bb184967SShu-Guo Yang e1000g_restore_promisc(struct e1000g *Adapter) 6726bb184967SShu-Guo Yang { 6727bb184967SShu-Guo Yang if (Adapter->e1000g_promisc) { 6728bb184967SShu-Guo Yang uint32_t rctl; 6729bb184967SShu-Guo Yang 6730bb184967SShu-Guo Yang rctl = E1000_READ_REG(&Adapter->shared, E1000_RCTL); 6731bb184967SShu-Guo Yang rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_BAM); 6732bb184967SShu-Guo Yang E1000_WRITE_REG(&Adapter->shared, E1000_RCTL, rctl); 6733bb184967SShu-Guo Yang } 6734bb184967SShu-Guo Yang } 6735