13526Sxy150489 /* 23526Sxy150489 * This file is provided under a CDDLv1 license. When using or 33526Sxy150489 * redistributing this file, you may do so under this license. 43526Sxy150489 * In redistributing this file this license must be included 53526Sxy150489 * and no other modification of this header file is permitted. 63526Sxy150489 * 73526Sxy150489 * CDDL LICENSE SUMMARY 83526Sxy150489 * 95882Syy150190 * Copyright(c) 1999 - 2008 Intel Corporation. All rights reserved. 103526Sxy150489 * 113526Sxy150489 * The contents of this file are subject to the terms of Version 123526Sxy150489 * 1.0 of the Common Development and Distribution License (the "License"). 133526Sxy150489 * 143526Sxy150489 * You should have received a copy of the License with this software. 153526Sxy150489 * You can obtain a copy of the License at 163526Sxy150489 * http://www.opensolaris.org/os/licensing. 173526Sxy150489 * See the License for the specific language governing permissions 183526Sxy150489 * and limitations under the License. 193526Sxy150489 */ 203526Sxy150489 213526Sxy150489 /* 225858Scc210113 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 233526Sxy150489 * Use is subject to license terms of the CDDLv1. 243526Sxy150489 */ 253526Sxy150489 263526Sxy150489 #pragma ident "%Z%%M% %I% %E% SMI" 273526Sxy150489 283526Sxy150489 /* 293526Sxy150489 * ********************************************************************** 303526Sxy150489 * * 313526Sxy150489 * Module Name: * 323526Sxy150489 * e1000g_main.c * 333526Sxy150489 * * 343526Sxy150489 * Abstract: * 354919Sxy150489 * This file contains the interface routines for the solaris OS. * 364919Sxy150489 * It has all DDI entry point routines and GLD entry point routines. * 373526Sxy150489 * * 384919Sxy150489 * This file also contains routines that take care of initialization * 394919Sxy150489 * uninit routine and interrupt routine. * 403526Sxy150489 * * 413526Sxy150489 * ********************************************************************** 423526Sxy150489 */ 433526Sxy150489 443526Sxy150489 #include <sys/dlpi.h> 453526Sxy150489 #include <sys/mac.h> 46*6394Scc210113 #include <sys/dld.h> 473526Sxy150489 #include "e1000g_sw.h" 483526Sxy150489 #include "e1000g_debug.h" 493526Sxy150489 50*6394Scc210113 static char ident[] = "Intel PRO/1000 Ethernet 5.2.7"; 513526Sxy150489 static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection"; 52*6394Scc210113 static char e1000g_version[] = "Driver Ver. 5.2.7"; 533526Sxy150489 543526Sxy150489 /* 553526Sxy150489 * Proto types for DDI entry points 563526Sxy150489 */ 574919Sxy150489 static int e1000g_attach(dev_info_t *, ddi_attach_cmd_t); 584919Sxy150489 static int e1000g_detach(dev_info_t *, ddi_detach_cmd_t); 593526Sxy150489 603526Sxy150489 /* 613526Sxy150489 * init and intr routines prototype 623526Sxy150489 */ 634919Sxy150489 static int e1000g_resume(dev_info_t *); 644919Sxy150489 static int e1000g_suspend(dev_info_t *); 653526Sxy150489 static uint_t e1000g_intr_pciexpress(caddr_t); 663526Sxy150489 static uint_t e1000g_intr(caddr_t); 673526Sxy150489 static void e1000g_intr_work(struct e1000g *, uint32_t); 683526Sxy150489 #pragma inline(e1000g_intr_work) 695882Syy150190 static uint32_t e1000g_get_itr(uint32_t, uint32_t, uint32_t); 705882Syy150190 #pragma inline(e1000g_get_itr) 713526Sxy150489 static int e1000g_init(struct e1000g *); 724919Sxy150489 static int e1000g_start(struct e1000g *, boolean_t); 734919Sxy150489 static void e1000g_stop(struct e1000g *, boolean_t); 743526Sxy150489 static int e1000g_m_start(void *); 753526Sxy150489 static void e1000g_m_stop(void *); 763526Sxy150489 static int e1000g_m_promisc(void *, boolean_t); 773526Sxy150489 static boolean_t e1000g_m_getcapab(void *, mac_capab_t, void *); 783526Sxy150489 static int e1000g_m_unicst(void *, const uint8_t *); 793526Sxy150489 static int e1000g_m_unicst_add(void *, mac_multi_addr_t *); 803526Sxy150489 static int e1000g_m_unicst_remove(void *, mac_addr_slot_t); 813526Sxy150489 static int e1000g_m_unicst_modify(void *, mac_multi_addr_t *); 823526Sxy150489 static int e1000g_m_unicst_get(void *, mac_multi_addr_t *); 833526Sxy150489 static int e1000g_m_multicst(void *, boolean_t, const uint8_t *); 843526Sxy150489 static void e1000g_m_ioctl(void *, queue_t *, mblk_t *); 85*6394Scc210113 static int e1000g_m_setprop(void *, const char *, mac_prop_id_t, 86*6394Scc210113 uint_t, const void *); 87*6394Scc210113 static int e1000g_m_getprop(void *, const char *, mac_prop_id_t, 88*6394Scc210113 uint_t, void *); 89*6394Scc210113 static int e1000g_set_priv_prop(struct e1000g *, const char *, uint_t, 90*6394Scc210113 const void *); 91*6394Scc210113 static int e1000g_get_priv_prop(struct e1000g *, const char *, uint_t, 92*6394Scc210113 void *); 934919Sxy150489 static void e1000g_init_locks(struct e1000g *); 944919Sxy150489 static void e1000g_destroy_locks(struct e1000g *); 954919Sxy150489 static int e1000g_identify_hardware(struct e1000g *); 964919Sxy150489 static int e1000g_regs_map(struct e1000g *); 974919Sxy150489 static int e1000g_set_driver_params(struct e1000g *); 98*6394Scc210113 static void e1000g_set_bufsize(struct e1000g *); 994919Sxy150489 static int e1000g_register_mac(struct e1000g *); 1004919Sxy150489 static boolean_t e1000g_rx_drain(struct e1000g *); 1014919Sxy150489 static boolean_t e1000g_tx_drain(struct e1000g *); 1024919Sxy150489 static void e1000g_init_unicst(struct e1000g *); 1033526Sxy150489 static int e1000g_unicst_set(struct e1000g *, const uint8_t *, mac_addr_slot_t); 1043526Sxy150489 1053526Sxy150489 /* 1063526Sxy150489 * Local routines 1073526Sxy150489 */ 1084919Sxy150489 static void e1000g_tx_clean(struct e1000g *); 1094919Sxy150489 static void e1000g_rx_clean(struct e1000g *); 1104061Sxy150489 static void e1000g_link_timer(void *); 1114919Sxy150489 static void e1000g_local_timer(void *); 1124061Sxy150489 static boolean_t e1000g_link_check(struct e1000g *); 1133526Sxy150489 static boolean_t e1000g_stall_check(struct e1000g *); 1143526Sxy150489 static void e1000g_smartspeed(struct e1000g *); 1154919Sxy150489 static void e1000g_get_conf(struct e1000g *); 1164919Sxy150489 static int e1000g_get_prop(struct e1000g *, char *, int, int, int); 1174919Sxy150489 static void enable_watchdog_timer(struct e1000g *); 1184919Sxy150489 static void disable_watchdog_timer(struct e1000g *); 1194919Sxy150489 static void start_watchdog_timer(struct e1000g *); 1204919Sxy150489 static void restart_watchdog_timer(struct e1000g *); 1214919Sxy150489 static void stop_watchdog_timer(struct e1000g *); 1224919Sxy150489 static void stop_link_timer(struct e1000g *); 1234919Sxy150489 static void stop_82547_timer(e1000g_tx_ring_t *); 1244919Sxy150489 static void e1000g_force_speed_duplex(struct e1000g *); 1254919Sxy150489 static void e1000g_get_max_frame_size(struct e1000g *); 1264919Sxy150489 static boolean_t is_valid_mac_addr(uint8_t *); 1273526Sxy150489 static void e1000g_unattach(dev_info_t *, struct e1000g *); 1284919Sxy150489 #ifdef E1000G_DEBUG 1294919Sxy150489 static void e1000g_ioc_peek_reg(struct e1000g *, e1000g_peekpoke_t *); 1304919Sxy150489 static void e1000g_ioc_poke_reg(struct e1000g *, e1000g_peekpoke_t *); 1314919Sxy150489 static void e1000g_ioc_peek_mem(struct e1000g *, e1000g_peekpoke_t *); 1324919Sxy150489 static void e1000g_ioc_poke_mem(struct e1000g *, e1000g_peekpoke_t *); 1334919Sxy150489 static enum ioc_reply e1000g_pp_ioctl(struct e1000g *, 1344919Sxy150489 struct iocblk *, mblk_t *); 1354919Sxy150489 #endif 1364919Sxy150489 static enum ioc_reply e1000g_loopback_ioctl(struct e1000g *, 1374919Sxy150489 struct iocblk *, mblk_t *); 1384919Sxy150489 static boolean_t e1000g_set_loopback_mode(struct e1000g *, uint32_t); 1394919Sxy150489 static void e1000g_set_internal_loopback(struct e1000g *); 1404919Sxy150489 static void e1000g_set_external_loopback_1000(struct e1000g *); 1414919Sxy150489 static void e1000g_set_external_loopback_100(struct e1000g *); 1424919Sxy150489 static void e1000g_set_external_loopback_10(struct e1000g *); 1434919Sxy150489 static int e1000g_add_intrs(struct e1000g *); 1444919Sxy150489 static int e1000g_intr_add(struct e1000g *, int); 1454919Sxy150489 static int e1000g_rem_intrs(struct e1000g *); 1464919Sxy150489 static int e1000g_enable_intrs(struct e1000g *); 1474919Sxy150489 static int e1000g_disable_intrs(struct e1000g *); 1484919Sxy150489 static boolean_t e1000g_link_up(struct e1000g *); 1493526Sxy150489 #ifdef __sparc 1504919Sxy150489 static boolean_t e1000g_find_mac_address(struct e1000g *); 1513526Sxy150489 #endif 1525082Syy150190 static void e1000g_get_phy_state(struct e1000g *); 1534982Syy150190 static void e1000g_free_priv_devi_node(struct e1000g *, boolean_t); 1545273Sgl147354 static int e1000g_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, 1555273Sgl147354 const void *impl_data); 1565273Sgl147354 static void e1000g_fm_init(struct e1000g *Adapter); 1575273Sgl147354 static void e1000g_fm_fini(struct e1000g *Adapter); 1583526Sxy150489 1593526Sxy150489 static struct cb_ops cb_ws_ops = { 1603526Sxy150489 nulldev, /* cb_open */ 1613526Sxy150489 nulldev, /* cb_close */ 1623526Sxy150489 nodev, /* cb_strategy */ 1633526Sxy150489 nodev, /* cb_print */ 1643526Sxy150489 nodev, /* cb_dump */ 1653526Sxy150489 nodev, /* cb_read */ 1663526Sxy150489 nodev, /* cb_write */ 1673526Sxy150489 nodev, /* cb_ioctl */ 1683526Sxy150489 nodev, /* cb_devmap */ 1693526Sxy150489 nodev, /* cb_mmap */ 1703526Sxy150489 nodev, /* cb_segmap */ 1713526Sxy150489 nochpoll, /* cb_chpoll */ 1723526Sxy150489 ddi_prop_op, /* cb_prop_op */ 1733526Sxy150489 NULL, /* cb_stream */ 1743526Sxy150489 D_MP | D_HOTPLUG, /* cb_flag */ 1753526Sxy150489 CB_REV, /* cb_rev */ 1763526Sxy150489 nodev, /* cb_aread */ 1773526Sxy150489 nodev /* cb_awrite */ 1783526Sxy150489 }; 1793526Sxy150489 1803526Sxy150489 static struct dev_ops ws_ops = { 1813526Sxy150489 DEVO_REV, /* devo_rev */ 1823526Sxy150489 0, /* devo_refcnt */ 1833526Sxy150489 NULL, /* devo_getinfo */ 1843526Sxy150489 nulldev, /* devo_identify */ 1853526Sxy150489 nulldev, /* devo_probe */ 1864919Sxy150489 e1000g_attach, /* devo_attach */ 1874919Sxy150489 e1000g_detach, /* devo_detach */ 1883526Sxy150489 nodev, /* devo_reset */ 1893526Sxy150489 &cb_ws_ops, /* devo_cb_ops */ 1903526Sxy150489 NULL, /* devo_bus_ops */ 1913526Sxy150489 ddi_power /* devo_power */ 1923526Sxy150489 }; 1933526Sxy150489 1943526Sxy150489 static struct modldrv modldrv = { 1953526Sxy150489 &mod_driverops, /* Type of module. This one is a driver */ 1963526Sxy150489 ident, /* Discription string */ 1973526Sxy150489 &ws_ops, /* driver ops */ 1983526Sxy150489 }; 1993526Sxy150489 2003526Sxy150489 static struct modlinkage modlinkage = { 2013526Sxy150489 MODREV_1, &modldrv, NULL 2023526Sxy150489 }; 2033526Sxy150489 2044919Sxy150489 /* Access attributes for register mapping */ 2054919Sxy150489 static ddi_device_acc_attr_t e1000g_regs_acc_attr = { 2063526Sxy150489 DDI_DEVICE_ATTR_V0, 2073526Sxy150489 DDI_STRUCTURE_LE_ACC, 2083526Sxy150489 DDI_STRICTORDER_ACC, 2095273Sgl147354 DDI_FLAGERR_ACC 2103526Sxy150489 }; 2113526Sxy150489 212*6394Scc210113 #define E1000G_M_CALLBACK_FLAGS \ 213*6394Scc210113 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 2143526Sxy150489 2153526Sxy150489 static mac_callbacks_t e1000g_m_callbacks = { 2163526Sxy150489 E1000G_M_CALLBACK_FLAGS, 2173526Sxy150489 e1000g_m_stat, 2183526Sxy150489 e1000g_m_start, 2193526Sxy150489 e1000g_m_stop, 2203526Sxy150489 e1000g_m_promisc, 2213526Sxy150489 e1000g_m_multicst, 2223526Sxy150489 e1000g_m_unicst, 2233526Sxy150489 e1000g_m_tx, 2245882Syy150190 NULL, 2253526Sxy150489 e1000g_m_ioctl, 226*6394Scc210113 e1000g_m_getcapab, 227*6394Scc210113 NULL, 228*6394Scc210113 NULL, 229*6394Scc210113 e1000g_m_setprop, 230*6394Scc210113 e1000g_m_getprop 2313526Sxy150489 }; 2323526Sxy150489 2333526Sxy150489 /* 2343526Sxy150489 * Global variables 2353526Sxy150489 */ 2363526Sxy150489 uint32_t e1000g_mblks_pending = 0; 2373526Sxy150489 /* 2384894Syy150190 * Workaround for Dynamic Reconfiguration support, for x86 platform only. 2394349Sxy150489 * Here we maintain a private dev_info list if e1000g_force_detach is 2404349Sxy150489 * enabled. If we force the driver to detach while there are still some 2414349Sxy150489 * rx buffers retained in the upper layer, we have to keep a copy of the 2424349Sxy150489 * dev_info. In some cases (Dynamic Reconfiguration), the dev_info data 2434349Sxy150489 * structure will be freed after the driver is detached. However when we 2444349Sxy150489 * finally free those rx buffers released by the upper layer, we need to 2454349Sxy150489 * refer to the dev_info to free the dma buffers. So we save a copy of 2464894Syy150190 * the dev_info for this purpose. On x86 platform, we assume this copy 2474894Syy150190 * of dev_info is always valid, but on SPARC platform, it could be invalid 2484894Syy150190 * after the system board level DR operation. For this reason, the global 2494894Syy150190 * variable e1000g_force_detach must be B_FALSE on SPARC platform. 2504349Sxy150489 */ 2514894Syy150190 #ifdef __sparc 2524894Syy150190 boolean_t e1000g_force_detach = B_FALSE; 2534894Syy150190 #else 2544894Syy150190 boolean_t e1000g_force_detach = B_TRUE; 2554894Syy150190 #endif 2564349Sxy150489 private_devi_list_t *e1000g_private_devi_list = NULL; 2574894Syy150190 2584349Sxy150489 /* 2593526Sxy150489 * The rwlock is defined to protect the whole processing of rx recycling 2603526Sxy150489 * and the rx packets release in detach processing to make them mutually 2613526Sxy150489 * exclusive. 2623526Sxy150489 * The rx recycling processes different rx packets in different threads, 2633526Sxy150489 * so it will be protected with RW_READER and it won't block any other rx 2643526Sxy150489 * recycling threads. 2653526Sxy150489 * While the detach processing will be protected with RW_WRITER to make 2663526Sxy150489 * it mutually exclusive with the rx recycling. 2673526Sxy150489 */ 2683526Sxy150489 krwlock_t e1000g_rx_detach_lock; 2693526Sxy150489 /* 2703526Sxy150489 * The rwlock e1000g_dma_type_lock is defined to protect the global flag 2713526Sxy150489 * e1000g_dma_type. For SPARC, the initial value of the flag is "USE_DVMA". 2723526Sxy150489 * If there are many e1000g instances, the system may run out of DVMA 2733526Sxy150489 * resources during the initialization of the instances, then the flag will 2743526Sxy150489 * be changed to "USE_DMA". Because different e1000g instances are initialized 2753526Sxy150489 * in parallel, we need to use this lock to protect the flag. 2763526Sxy150489 */ 2773526Sxy150489 krwlock_t e1000g_dma_type_lock; 2783526Sxy150489 2793526Sxy150489 2803526Sxy150489 /* 2813526Sxy150489 * Loadable module configuration entry points for the driver 2823526Sxy150489 */ 2833526Sxy150489 2843526Sxy150489 /* 2854919Sxy150489 * _init - module initialization 2863526Sxy150489 */ 2873526Sxy150489 int 2883526Sxy150489 _init(void) 2893526Sxy150489 { 2903526Sxy150489 int status; 2913526Sxy150489 2923526Sxy150489 mac_init_ops(&ws_ops, WSNAME); 2933526Sxy150489 status = mod_install(&modlinkage); 2943526Sxy150489 if (status != DDI_SUCCESS) 2953526Sxy150489 mac_fini_ops(&ws_ops); 2963526Sxy150489 else { 2973526Sxy150489 rw_init(&e1000g_rx_detach_lock, NULL, RW_DRIVER, NULL); 2983526Sxy150489 rw_init(&e1000g_dma_type_lock, NULL, RW_DRIVER, NULL); 2993526Sxy150489 } 3003526Sxy150489 3013526Sxy150489 return (status); 3023526Sxy150489 } 3033526Sxy150489 3043526Sxy150489 /* 3054919Sxy150489 * _fini - module finalization 3063526Sxy150489 */ 3073526Sxy150489 int 3083526Sxy150489 _fini(void) 3093526Sxy150489 { 3103526Sxy150489 int status; 3113526Sxy150489 3123526Sxy150489 rw_enter(&e1000g_rx_detach_lock, RW_READER); 3133526Sxy150489 if (e1000g_mblks_pending != 0) { 3143526Sxy150489 rw_exit(&e1000g_rx_detach_lock); 3153526Sxy150489 return (EBUSY); 3163526Sxy150489 } 3173526Sxy150489 rw_exit(&e1000g_rx_detach_lock); 3183526Sxy150489 3193526Sxy150489 status = mod_remove(&modlinkage); 3203526Sxy150489 if (status == DDI_SUCCESS) { 3213526Sxy150489 mac_fini_ops(&ws_ops); 3224349Sxy150489 3234349Sxy150489 if (e1000g_force_detach) { 3244349Sxy150489 private_devi_list_t *devi_node; 3254349Sxy150489 3264349Sxy150489 rw_enter(&e1000g_rx_detach_lock, RW_WRITER); 3274349Sxy150489 while (e1000g_private_devi_list != NULL) { 3284349Sxy150489 devi_node = e1000g_private_devi_list; 3294349Sxy150489 e1000g_private_devi_list = 3304349Sxy150489 e1000g_private_devi_list->next; 3314349Sxy150489 3324349Sxy150489 kmem_free(devi_node->priv_dip, 3334349Sxy150489 sizeof (struct dev_info)); 3344349Sxy150489 kmem_free(devi_node, 3354349Sxy150489 sizeof (private_devi_list_t)); 3364349Sxy150489 } 3374349Sxy150489 rw_exit(&e1000g_rx_detach_lock); 3384349Sxy150489 } 3394349Sxy150489 3403526Sxy150489 rw_destroy(&e1000g_rx_detach_lock); 3413526Sxy150489 rw_destroy(&e1000g_dma_type_lock); 3423526Sxy150489 } 3433526Sxy150489 3443526Sxy150489 return (status); 3453526Sxy150489 } 3463526Sxy150489 3473526Sxy150489 /* 3484919Sxy150489 * _info - module information 3493526Sxy150489 */ 3503526Sxy150489 int 3513526Sxy150489 _info(struct modinfo *modinfop) 3523526Sxy150489 { 3533526Sxy150489 return (mod_info(&modlinkage, modinfop)); 3543526Sxy150489 } 3553526Sxy150489 3563526Sxy150489 /* 3574919Sxy150489 * e1000g_attach - driver attach 3584919Sxy150489 * 3594919Sxy150489 * This function is the device-specific initialization entry 3604919Sxy150489 * point. This entry point is required and must be written. 3614919Sxy150489 * The DDI_ATTACH command must be provided in the attach entry 3624919Sxy150489 * point. When attach() is called with cmd set to DDI_ATTACH, 3634919Sxy150489 * all normal kernel services (such as kmem_alloc(9F)) are 3644919Sxy150489 * available for use by the driver. 3654919Sxy150489 * 3664919Sxy150489 * The attach() function will be called once for each instance 3674919Sxy150489 * of the device on the system with cmd set to DDI_ATTACH. 3684919Sxy150489 * Until attach() succeeds, the only driver entry points which 3694919Sxy150489 * may be called are open(9E) and getinfo(9E). 3703526Sxy150489 */ 3713526Sxy150489 static int 3724919Sxy150489 e1000g_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 3733526Sxy150489 { 3743526Sxy150489 struct e1000g *Adapter; 3753526Sxy150489 struct e1000_hw *hw; 3764919Sxy150489 struct e1000g_osdep *osdep; 3773526Sxy150489 int instance; 3783526Sxy150489 3793526Sxy150489 switch (cmd) { 3803526Sxy150489 default: 3813526Sxy150489 e1000g_log(NULL, CE_WARN, 3824919Sxy150489 "Unsupported command send to e1000g_attach... "); 3833526Sxy150489 return (DDI_FAILURE); 3843526Sxy150489 3853526Sxy150489 case DDI_RESUME: 3863526Sxy150489 return (e1000g_resume(devinfo)); 3873526Sxy150489 3883526Sxy150489 case DDI_ATTACH: 3893526Sxy150489 break; 3903526Sxy150489 } 3913526Sxy150489 3923526Sxy150489 /* 3933526Sxy150489 * get device instance number 3943526Sxy150489 */ 3953526Sxy150489 instance = ddi_get_instance(devinfo); 3963526Sxy150489 3973526Sxy150489 /* 3983526Sxy150489 * Allocate soft data structure 3993526Sxy150489 */ 4003526Sxy150489 Adapter = 4013526Sxy150489 (struct e1000g *)kmem_zalloc(sizeof (*Adapter), KM_SLEEP); 4023526Sxy150489 4033526Sxy150489 Adapter->dip = devinfo; 4044919Sxy150489 Adapter->instance = instance; 4053526Sxy150489 Adapter->tx_ring->adapter = Adapter; 4063526Sxy150489 Adapter->rx_ring->adapter = Adapter; 4073526Sxy150489 4084919Sxy150489 hw = &Adapter->shared; 4094919Sxy150489 osdep = &Adapter->osdep; 4104919Sxy150489 hw->back = osdep; 4114919Sxy150489 osdep->adapter = Adapter; 4124919Sxy150489 4133526Sxy150489 ddi_set_driver_private(devinfo, (caddr_t)Adapter); 4143526Sxy150489 4154919Sxy150489 /* 4165273Sgl147354 * Initialize for fma support 4175273Sgl147354 */ 4185273Sgl147354 Adapter->fm_capabilities = e1000g_get_prop(Adapter, "fm-capable", 4195273Sgl147354 0, 0x0f, 4205273Sgl147354 DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 4215273Sgl147354 DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 4225273Sgl147354 e1000g_fm_init(Adapter); 4235273Sgl147354 Adapter->attach_progress |= ATTACH_PROGRESS_FMINIT; 4245273Sgl147354 4255273Sgl147354 /* 4264919Sxy150489 * PCI Configure 4274919Sxy150489 */ 4284919Sxy150489 if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) { 4294919Sxy150489 e1000g_log(Adapter, CE_WARN, "PCI configuration failed"); 4304919Sxy150489 goto attach_fail; 4314919Sxy150489 } 4324919Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG; 4334919Sxy150489 4344919Sxy150489 /* 4354919Sxy150489 * Setup hardware 4364919Sxy150489 */ 4374919Sxy150489 if (e1000g_identify_hardware(Adapter) != DDI_SUCCESS) { 4384919Sxy150489 e1000g_log(Adapter, CE_WARN, "Identify hardware failed"); 4394919Sxy150489 goto attach_fail; 4404919Sxy150489 } 4413526Sxy150489 4423526Sxy150489 /* 4433526Sxy150489 * Map in the device registers. 4443526Sxy150489 */ 4454919Sxy150489 if (e1000g_regs_map(Adapter) != DDI_SUCCESS) { 4464919Sxy150489 e1000g_log(Adapter, CE_WARN, "Mapping registers failed"); 4473526Sxy150489 goto attach_fail; 4483526Sxy150489 } 4494919Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_REGS_MAP; 4503526Sxy150489 4513526Sxy150489 /* 4523526Sxy150489 * Initialize driver parameters 4533526Sxy150489 */ 4543526Sxy150489 if (e1000g_set_driver_params(Adapter) != DDI_SUCCESS) { 4553526Sxy150489 goto attach_fail; 4563526Sxy150489 } 4574919Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_SETUP; 4583526Sxy150489 4595273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.cfg_handle) != DDI_FM_OK) { 4605273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 4615273Sgl147354 goto attach_fail; 4625273Sgl147354 } 4635273Sgl147354 4643526Sxy150489 /* 4653526Sxy150489 * Initialize interrupts 4663526Sxy150489 */ 4673526Sxy150489 if (e1000g_add_intrs(Adapter) != DDI_SUCCESS) { 4683526Sxy150489 e1000g_log(Adapter, CE_WARN, "Add interrupts failed"); 4693526Sxy150489 goto attach_fail; 4703526Sxy150489 } 4714919Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 4723526Sxy150489 4733526Sxy150489 /* 4743526Sxy150489 * Initialize mutex's for this device. 4753526Sxy150489 * Do this before enabling the interrupt handler and 4763526Sxy150489 * register the softint to avoid the condition where 4773526Sxy150489 * interrupt handler can try using uninitialized mutex 4783526Sxy150489 */ 4793526Sxy150489 e1000g_init_locks(Adapter); 4803526Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_LOCKS; 4813526Sxy150489 4823526Sxy150489 /* 4833526Sxy150489 * Initialize Driver Counters 4843526Sxy150489 */ 4854919Sxy150489 if (e1000g_init_stats(Adapter) != DDI_SUCCESS) { 4863526Sxy150489 e1000g_log(Adapter, CE_WARN, "Init stats failed"); 4873526Sxy150489 goto attach_fail; 4883526Sxy150489 } 4893526Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_KSTATS; 4903526Sxy150489 4913526Sxy150489 /* 4923526Sxy150489 * Initialize chip hardware and software structures 4933526Sxy150489 */ 4943526Sxy150489 if (e1000g_init(Adapter) != DDI_SUCCESS) { 4953526Sxy150489 e1000g_log(Adapter, CE_WARN, "Adapter initialization failed"); 4963526Sxy150489 goto attach_fail; 4973526Sxy150489 } 4983526Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_INIT; 4993526Sxy150489 5003526Sxy150489 /* 5013526Sxy150489 * Initialize NDD parameters 5023526Sxy150489 */ 5033526Sxy150489 if (e1000g_nd_init(Adapter) != DDI_SUCCESS) { 5044919Sxy150489 e1000g_log(Adapter, CE_WARN, "Init ndd failed"); 5053526Sxy150489 goto attach_fail; 5063526Sxy150489 } 5073526Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_NDD; 5083526Sxy150489 5093526Sxy150489 /* 5103526Sxy150489 * Register the driver to the MAC 5113526Sxy150489 */ 5123526Sxy150489 if (e1000g_register_mac(Adapter) != DDI_SUCCESS) { 5133526Sxy150489 e1000g_log(Adapter, CE_WARN, "Register MAC failed"); 5143526Sxy150489 goto attach_fail; 5153526Sxy150489 } 5164919Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_MAC; 5173526Sxy150489 5183526Sxy150489 /* 5193526Sxy150489 * Now that mutex locks are initialized, and the chip is also 5203526Sxy150489 * initialized, enable interrupts. 5213526Sxy150489 */ 5223526Sxy150489 if (e1000g_enable_intrs(Adapter) != DDI_SUCCESS) { 5233526Sxy150489 e1000g_log(Adapter, CE_WARN, "Enable DDI interrupts failed"); 5243526Sxy150489 goto attach_fail; 5253526Sxy150489 } 5264919Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 5273526Sxy150489 5284982Syy150190 /* 5294982Syy150190 * If e1000g_force_detach is enabled, in global private dip list, 5304982Syy150190 * we will create a new entry, which maintains the priv_dip for DR 5314982Syy150190 * supports after driver detached. 5324982Syy150190 */ 5334982Syy150190 if (e1000g_force_detach) { 5344982Syy150190 private_devi_list_t *devi_node; 5354982Syy150190 5364982Syy150190 Adapter->priv_dip = 5374982Syy150190 kmem_zalloc(sizeof (struct dev_info), KM_SLEEP); 5384982Syy150190 bcopy(DEVI(devinfo), DEVI(Adapter->priv_dip), 5394982Syy150190 sizeof (struct dev_info)); 5404982Syy150190 5414982Syy150190 devi_node = 5424982Syy150190 kmem_zalloc(sizeof (private_devi_list_t), KM_SLEEP); 5434982Syy150190 5444982Syy150190 rw_enter(&e1000g_rx_detach_lock, RW_WRITER); 5454982Syy150190 devi_node->priv_dip = Adapter->priv_dip; 5464982Syy150190 devi_node->flag = E1000G_PRIV_DEVI_ATTACH; 5474982Syy150190 devi_node->next = e1000g_private_devi_list; 5484982Syy150190 e1000g_private_devi_list = devi_node; 5494982Syy150190 rw_exit(&e1000g_rx_detach_lock); 5504982Syy150190 } 5514982Syy150190 5523526Sxy150489 cmn_err(CE_CONT, "!%s, %s\n", e1000g_string, e1000g_version); 5533526Sxy150489 5543526Sxy150489 return (DDI_SUCCESS); 5553526Sxy150489 5563526Sxy150489 attach_fail: 5573526Sxy150489 e1000g_unattach(devinfo, Adapter); 5583526Sxy150489 return (DDI_FAILURE); 5593526Sxy150489 } 5603526Sxy150489 5613526Sxy150489 static int 5623526Sxy150489 e1000g_register_mac(struct e1000g *Adapter) 5633526Sxy150489 { 5644919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 5653526Sxy150489 mac_register_t *mac; 5663526Sxy150489 int err; 5673526Sxy150489 5683526Sxy150489 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 5693526Sxy150489 return (DDI_FAILURE); 5704919Sxy150489 5713526Sxy150489 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 5723526Sxy150489 mac->m_driver = Adapter; 5733526Sxy150489 mac->m_dip = Adapter->dip; 5744919Sxy150489 mac->m_src_addr = hw->mac.addr; 5753526Sxy150489 mac->m_callbacks = &e1000g_m_callbacks; 5763526Sxy150489 mac->m_min_sdu = 0; 577*6394Scc210113 mac->m_max_sdu = Adapter->default_mtu; 5785895Syz147064 mac->m_margin = VLAN_TAGSZ; 5794919Sxy150489 5803526Sxy150489 err = mac_register(mac, &Adapter->mh); 5813526Sxy150489 mac_free(mac); 5824919Sxy150489 5833526Sxy150489 return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 5843526Sxy150489 } 5853526Sxy150489 5863526Sxy150489 static int 5874919Sxy150489 e1000g_identify_hardware(struct e1000g *Adapter) 5884919Sxy150489 { 5894919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 5904919Sxy150489 struct e1000g_osdep *osdep = &Adapter->osdep; 5914919Sxy150489 5924919Sxy150489 /* Get the device id */ 5934919Sxy150489 hw->vendor_id = 5944919Sxy150489 pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID); 5954919Sxy150489 hw->device_id = 5964919Sxy150489 pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID); 5974919Sxy150489 hw->revision_id = 5984919Sxy150489 pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID); 5994919Sxy150489 hw->subsystem_device_id = 6004919Sxy150489 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID); 6014919Sxy150489 hw->subsystem_vendor_id = 6024919Sxy150489 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID); 6034919Sxy150489 6044919Sxy150489 if (e1000_set_mac_type(hw) != E1000_SUCCESS) { 6054919Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 6064919Sxy150489 "MAC type could not be set properly."); 6074919Sxy150489 return (DDI_FAILURE); 6084919Sxy150489 } 6094919Sxy150489 6104919Sxy150489 return (DDI_SUCCESS); 6114919Sxy150489 } 6124919Sxy150489 6134919Sxy150489 static int 6144919Sxy150489 e1000g_regs_map(struct e1000g *Adapter) 6154919Sxy150489 { 6164919Sxy150489 dev_info_t *devinfo = Adapter->dip; 6174919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 6184919Sxy150489 struct e1000g_osdep *osdep = &Adapter->osdep; 6194919Sxy150489 off_t mem_size; 6204919Sxy150489 6214919Sxy150489 /* 6224919Sxy150489 * first get the size of device register to be mapped. The 6234919Sxy150489 * second parameter is the register we are interested. I our 6244919Sxy150489 * wiseman 0 is for config registers and 1 is for memory mapped 6254919Sxy150489 * registers Mem size should have memory mapped region size 6264919Sxy150489 */ 6274919Sxy150489 if (ddi_dev_regsize(devinfo, 1, &mem_size) != DDI_SUCCESS) { 6284919Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 6294919Sxy150489 "ddi_dev_regsize for registers failed"); 6304919Sxy150489 return (DDI_FAILURE); 6314919Sxy150489 } 6324919Sxy150489 6334919Sxy150489 if ((ddi_regs_map_setup(devinfo, 1, /* register of interest */ 6344919Sxy150489 (caddr_t *)&hw->hw_addr, 0, mem_size, &e1000g_regs_acc_attr, 6354919Sxy150489 &osdep->reg_handle)) != DDI_SUCCESS) { 6364919Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 6374919Sxy150489 "ddi_regs_map_setup for registers failed"); 6384919Sxy150489 goto regs_map_fail; 6394919Sxy150489 } 6404919Sxy150489 6414919Sxy150489 /* ICH needs to map flash memory */ 6424919Sxy150489 if (hw->mac.type == e1000_ich8lan || hw->mac.type == e1000_ich9lan) { 6434919Sxy150489 /* get flash size */ 6444919Sxy150489 if (ddi_dev_regsize(devinfo, ICH_FLASH_REG_SET, 6454919Sxy150489 &mem_size) != DDI_SUCCESS) { 6464919Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 6474919Sxy150489 "ddi_dev_regsize for ICH flash failed"); 6484919Sxy150489 goto regs_map_fail; 6494919Sxy150489 } 6504919Sxy150489 6514919Sxy150489 /* map flash in */ 6524919Sxy150489 if (ddi_regs_map_setup(devinfo, ICH_FLASH_REG_SET, 6534919Sxy150489 (caddr_t *)&hw->flash_address, 0, 6544919Sxy150489 mem_size, &e1000g_regs_acc_attr, 6554919Sxy150489 &osdep->ich_flash_handle) != DDI_SUCCESS) { 6564919Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 6574919Sxy150489 "ddi_regs_map_setup for ICH flash failed"); 6584919Sxy150489 goto regs_map_fail; 6594919Sxy150489 } 6604919Sxy150489 } 6614919Sxy150489 6624919Sxy150489 return (DDI_SUCCESS); 6634919Sxy150489 6644919Sxy150489 regs_map_fail: 6654919Sxy150489 if (osdep->reg_handle != NULL) 6664919Sxy150489 ddi_regs_map_free(&osdep->reg_handle); 6674919Sxy150489 6684919Sxy150489 return (DDI_FAILURE); 6694919Sxy150489 } 6704919Sxy150489 6714919Sxy150489 static int 6723526Sxy150489 e1000g_set_driver_params(struct e1000g *Adapter) 6733526Sxy150489 { 6743526Sxy150489 struct e1000_hw *hw; 6754919Sxy150489 e1000g_tx_ring_t *tx_ring; 6764919Sxy150489 uint32_t mem_bar, io_bar, bar64; 6773526Sxy150489 6784919Sxy150489 hw = &Adapter->shared; 6794919Sxy150489 6804919Sxy150489 /* Set MAC type and initialize hardware functions */ 6814919Sxy150489 if (e1000_setup_init_funcs(hw, B_TRUE) != E1000_SUCCESS) { 6824919Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 6834919Sxy150489 "Could not setup hardware functions"); 6843526Sxy150489 return (DDI_FAILURE); 6853526Sxy150489 } 6863526Sxy150489 6874919Sxy150489 /* Get bus information */ 6884919Sxy150489 if (e1000_get_bus_info(hw) != E1000_SUCCESS) { 6894919Sxy150489 E1000G_DEBUGLOG_0(Adapter, CE_WARN, 6904919Sxy150489 "Could not get bus information"); 6914919Sxy150489 return (DDI_FAILURE); 6923526Sxy150489 } 6933526Sxy150489 6943526Sxy150489 /* get mem_base addr */ 6954919Sxy150489 mem_bar = pci_config_get32(Adapter->osdep.cfg_handle, PCI_CONF_BASE0); 6964919Sxy150489 bar64 = mem_bar & PCI_BASE_TYPE_ALL; 6973526Sxy150489 6983526Sxy150489 /* get io_base addr */ 6994919Sxy150489 if (hw->mac.type >= e1000_82544) { 7004919Sxy150489 if (bar64) { 7013526Sxy150489 /* IO BAR is different for 64 bit BAR mode */ 7024919Sxy150489 io_bar = pci_config_get32(Adapter->osdep.cfg_handle, 7034919Sxy150489 PCI_CONF_BASE4); 7043526Sxy150489 } else { 7053526Sxy150489 /* normal 32-bit BAR mode */ 7064919Sxy150489 io_bar = pci_config_get32(Adapter->osdep.cfg_handle, 7074919Sxy150489 PCI_CONF_BASE2); 7083526Sxy150489 } 7093526Sxy150489 hw->io_base = io_bar & PCI_BASE_IO_ADDR_M; 7103526Sxy150489 } else { 7113526Sxy150489 /* no I/O access for adapters prior to 82544 */ 7123526Sxy150489 hw->io_base = 0x0; 7133526Sxy150489 } 7143526Sxy150489 7154919Sxy150489 e1000_read_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->bus.pci_cmd_word); 7164919Sxy150489 7174919Sxy150489 hw->mac.autoneg_failed = B_TRUE; 7184919Sxy150489 7194919Sxy150489 /* Set the wait_for_link flag to B_FALSE */ 7204919Sxy150489 hw->phy.wait_for_link = B_FALSE; 7213526Sxy150489 7223526Sxy150489 /* Adaptive IFS related changes */ 7234919Sxy150489 hw->mac.adaptive_ifs = B_TRUE; 7244919Sxy150489 7254919Sxy150489 /* Enable phy init script for IGP phy of 82541/82547 */ 7264919Sxy150489 if ((hw->mac.type == e1000_82547) || 7274919Sxy150489 (hw->mac.type == e1000_82541) || 7284919Sxy150489 (hw->mac.type == e1000_82547_rev_2) || 7294919Sxy150489 (hw->mac.type == e1000_82541_rev_2)) 7304919Sxy150489 e1000_init_script_state_82541(hw, B_TRUE); 7314919Sxy150489 7324919Sxy150489 /* Enable the TTL workaround for 82541/82547 */ 7334919Sxy150489 e1000_set_ttl_workaround_state_82541(hw, B_TRUE); 7343526Sxy150489 7354608Syy150190 #ifdef __sparc 7364608Syy150190 Adapter->strip_crc = B_TRUE; 7374608Syy150190 #else 7384608Syy150190 Adapter->strip_crc = B_FALSE; 7394608Syy150190 #endif 7404608Syy150190 7413526Sxy150489 /* Get conf file properties */ 7424919Sxy150489 e1000g_get_conf(Adapter); 7434919Sxy150489 7444919Sxy150489 /* Get speed/duplex settings in conf file */ 7454919Sxy150489 hw->mac.forced_speed_duplex = ADVERTISE_100_FULL; 7464919Sxy150489 hw->phy.autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; 7473526Sxy150489 e1000g_force_speed_duplex(Adapter); 7483526Sxy150489 7494919Sxy150489 /* Get Jumbo Frames settings in conf file */ 7503526Sxy150489 e1000g_get_max_frame_size(Adapter); 7513526Sxy150489 7523526Sxy150489 /* Set Rx/Tx buffer size */ 753*6394Scc210113 e1000g_set_bufsize(Adapter); 7544919Sxy150489 7554919Sxy150489 /* Master Latency Timer */ 7564919Sxy150489 Adapter->master_latency_timer = DEFAULT_MASTER_LATENCY_TIMER; 7574919Sxy150489 7583526Sxy150489 /* copper options */ 7593526Sxy150489 if (hw->media_type == e1000_media_type_copper) { 7604919Sxy150489 hw->phy.mdix = 0; /* AUTO_ALL_MODES */ 7614919Sxy150489 hw->phy.disable_polarity_correction = B_FALSE; 7624919Sxy150489 hw->phy.ms_type = e1000_ms_hw_default; /* E1000_MASTER_SLAVE */ 7633526Sxy150489 } 7643526Sxy150489 7654919Sxy150489 /* The initial link state should be "unknown" */ 7664061Sxy150489 Adapter->link_state = LINK_STATE_UNKNOWN; 7674061Sxy150489 7685882Syy150190 /* Initialize rx parameters */ 7695882Syy150190 Adapter->rx_intr_delay = DEFAULT_RX_INTR_DELAY; 7705882Syy150190 Adapter->rx_intr_abs_delay = DEFAULT_RX_INTR_ABS_DELAY; 7715882Syy150190 7724919Sxy150489 /* Initialize tx parameters */ 7734919Sxy150489 Adapter->tx_intr_enable = DEFAULT_TX_INTR_ENABLE; 7744919Sxy150489 Adapter->tx_bcopy_thresh = DEFAULT_TX_BCOPY_THRESHOLD; 7755882Syy150190 Adapter->tx_intr_delay = DEFAULT_TX_INTR_DELAY; 7765882Syy150190 Adapter->tx_intr_abs_delay = DEFAULT_TX_INTR_ABS_DELAY; 7774919Sxy150489 7784919Sxy150489 tx_ring = Adapter->tx_ring; 7794919Sxy150489 tx_ring->frags_limit = 7804919Sxy150489 (hw->mac.max_frame_size / Adapter->tx_bcopy_thresh) + 2; 7814919Sxy150489 if (tx_ring->frags_limit > (MAX_TX_DESC_PER_PACKET >> 1)) 7824919Sxy150489 tx_ring->frags_limit = (MAX_TX_DESC_PER_PACKET >> 1); 7834919Sxy150489 7844919Sxy150489 /* Initialize rx parameters */ 7854919Sxy150489 Adapter->rx_bcopy_thresh = DEFAULT_RX_BCOPY_THRESHOLD; 7864919Sxy150489 7873526Sxy150489 return (DDI_SUCCESS); 7883526Sxy150489 } 7893526Sxy150489 790*6394Scc210113 static void 791*6394Scc210113 e1000g_set_bufsize(struct e1000g *Adapter) 792*6394Scc210113 { 793*6394Scc210113 struct e1000_mac_info *mac = &Adapter->shared.mac; 794*6394Scc210113 uint64_t rx_size; 795*6394Scc210113 uint64_t tx_size; 796*6394Scc210113 797*6394Scc210113 #ifdef __sparc 798*6394Scc210113 dev_info_t *devinfo = Adapter->dip; 799*6394Scc210113 ulong_t iommu_pagesize; 800*6394Scc210113 801*6394Scc210113 /* Get the system page size */ 802*6394Scc210113 Adapter->sys_page_sz = ddi_ptob(devinfo, (ulong_t)1); 803*6394Scc210113 iommu_pagesize = dvma_pagesize(devinfo); 804*6394Scc210113 if (iommu_pagesize != 0) { 805*6394Scc210113 if (Adapter->sys_page_sz == iommu_pagesize) { 806*6394Scc210113 if (iommu_pagesize > 0x4000) 807*6394Scc210113 Adapter->sys_page_sz = 0x4000; 808*6394Scc210113 } else { 809*6394Scc210113 if (Adapter->sys_page_sz > iommu_pagesize) 810*6394Scc210113 Adapter->sys_page_sz = iommu_pagesize; 811*6394Scc210113 } 812*6394Scc210113 } 813*6394Scc210113 Adapter->dvma_page_num = mac->max_frame_size / 814*6394Scc210113 Adapter->sys_page_sz + E1000G_DEFAULT_DVMA_PAGE_NUM; 815*6394Scc210113 ASSERT(Adapter->dvma_page_num >= E1000G_DEFAULT_DVMA_PAGE_NUM); 816*6394Scc210113 #endif 817*6394Scc210113 818*6394Scc210113 mac->min_frame_size = ETHERMIN + ETHERFCSL; 819*6394Scc210113 820*6394Scc210113 rx_size = mac->max_frame_size + E1000G_IPALIGNPRESERVEROOM; 821*6394Scc210113 if ((rx_size > FRAME_SIZE_UPTO_2K) && (rx_size <= FRAME_SIZE_UPTO_4K)) 822*6394Scc210113 Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_4K; 823*6394Scc210113 else if ((rx_size > FRAME_SIZE_UPTO_4K) && 824*6394Scc210113 (rx_size <= FRAME_SIZE_UPTO_8K)) 825*6394Scc210113 Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_8K; 826*6394Scc210113 else if ((rx_size > FRAME_SIZE_UPTO_8K) && 827*6394Scc210113 (rx_size <= FRAME_SIZE_UPTO_16K)) 828*6394Scc210113 Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_16K; 829*6394Scc210113 else 830*6394Scc210113 Adapter->rx_buffer_size = E1000_RX_BUFFER_SIZE_2K; 831*6394Scc210113 832*6394Scc210113 tx_size = mac->max_frame_size; 833*6394Scc210113 if ((tx_size > FRAME_SIZE_UPTO_2K) && (tx_size <= FRAME_SIZE_UPTO_4K)) 834*6394Scc210113 Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_4K; 835*6394Scc210113 else if ((tx_size > FRAME_SIZE_UPTO_4K) && 836*6394Scc210113 (tx_size <= FRAME_SIZE_UPTO_8K)) 837*6394Scc210113 Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_8K; 838*6394Scc210113 else if ((tx_size > FRAME_SIZE_UPTO_8K) && 839*6394Scc210113 (tx_size <= FRAME_SIZE_UPTO_16K)) 840*6394Scc210113 Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_16K; 841*6394Scc210113 else 842*6394Scc210113 Adapter->tx_buffer_size = E1000_TX_BUFFER_SIZE_2K; 843*6394Scc210113 844*6394Scc210113 #ifndef NO_82542_SUPPORT 845*6394Scc210113 /* 846*6394Scc210113 * For Wiseman adapters we have an requirement of having receive 847*6394Scc210113 * buffers aligned at 256 byte boundary. Since Livengood does not 848*6394Scc210113 * require this and forcing it for all hardwares will have 849*6394Scc210113 * performance implications, I am making it applicable only for 850*6394Scc210113 * Wiseman and for Jumbo frames enabled mode as rest of the time, 851*6394Scc210113 * it is okay to have normal frames...but it does involve a 852*6394Scc210113 * potential risk where we may loose data if buffer is not 853*6394Scc210113 * aligned...so all wiseman boards to have 256 byte aligned 854*6394Scc210113 * buffers 855*6394Scc210113 */ 856*6394Scc210113 if (mac->type < e1000_82543) 857*6394Scc210113 Adapter->rx_buf_align = RECEIVE_BUFFER_ALIGN_SIZE; 858*6394Scc210113 else 859*6394Scc210113 Adapter->rx_buf_align = 1; 860*6394Scc210113 #endif 861*6394Scc210113 } 862*6394Scc210113 8633526Sxy150489 /* 8644919Sxy150489 * e1000g_detach - driver detach 8654919Sxy150489 * 8664919Sxy150489 * The detach() function is the complement of the attach routine. 8674919Sxy150489 * If cmd is set to DDI_DETACH, detach() is used to remove the 8684919Sxy150489 * state associated with a given instance of a device node 8694919Sxy150489 * prior to the removal of that instance from the system. 8704919Sxy150489 * 8714919Sxy150489 * The detach() function will be called once for each instance 8724919Sxy150489 * of the device for which there has been a successful attach() 8734919Sxy150489 * once there are no longer any opens on the device. 8744919Sxy150489 * 8754919Sxy150489 * Interrupts routine are disabled, All memory allocated by this 8764919Sxy150489 * driver are freed. 8773526Sxy150489 */ 8783526Sxy150489 static int 8794919Sxy150489 e1000g_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 8803526Sxy150489 { 8813526Sxy150489 struct e1000g *Adapter; 8824982Syy150190 boolean_t rx_drain; 8833526Sxy150489 8843526Sxy150489 switch (cmd) { 8853526Sxy150489 default: 8863526Sxy150489 return (DDI_FAILURE); 8873526Sxy150489 8883526Sxy150489 case DDI_SUSPEND: 8893526Sxy150489 return (e1000g_suspend(devinfo)); 8903526Sxy150489 8913526Sxy150489 case DDI_DETACH: 8923526Sxy150489 break; 8933526Sxy150489 } 8943526Sxy150489 8953526Sxy150489 Adapter = (struct e1000g *)ddi_get_driver_private(devinfo); 8963526Sxy150489 if (Adapter == NULL) 8973526Sxy150489 return (DDI_FAILURE); 8983526Sxy150489 8994919Sxy150489 if (mac_unregister(Adapter->mh) != 0) { 9004919Sxy150489 e1000g_log(Adapter, CE_WARN, "Unregister MAC failed"); 9014919Sxy150489 return (DDI_FAILURE); 9024919Sxy150489 } 9034919Sxy150489 Adapter->attach_progress &= ~ATTACH_PROGRESS_MAC; 9044919Sxy150489 9055273Sgl147354 9065273Sgl147354 if (Adapter->chip_state != E1000G_STOP) 9074919Sxy150489 e1000g_stop(Adapter, B_TRUE); 9083526Sxy150489 9094982Syy150190 rx_drain = e1000g_rx_drain(Adapter); 9104982Syy150190 9114982Syy150190 /* 9124982Syy150190 * If e1000g_force_detach is enabled, driver detach is safe. 9134982Syy150190 * We will let e1000g_free_priv_devi_node routine determine 9144982Syy150190 * whether we need to free the priv_dip entry for current 9154982Syy150190 * driver instance. 9164982Syy150190 */ 9174982Syy150190 if (e1000g_force_detach) { 9184982Syy150190 e1000g_free_priv_devi_node(Adapter, rx_drain); 9194982Syy150190 } else { 9204982Syy150190 if (!rx_drain) 9213526Sxy150489 return (DDI_FAILURE); 9223526Sxy150489 } 9233526Sxy150489 9243526Sxy150489 e1000g_unattach(devinfo, Adapter); 9253526Sxy150489 9263526Sxy150489 return (DDI_SUCCESS); 9273526Sxy150489 } 9283526Sxy150489 9294982Syy150190 /* 9304982Syy150190 * e1000g_free_priv_devi_node - free a priv_dip entry for driver instance 9314982Syy150190 * 9324982Syy150190 * If free_flag is true, that indicates the upper layer is not holding 9334982Syy150190 * the rx buffers, we could free the priv_dip entry safely. 9344982Syy150190 * 9354982Syy150190 * Otherwise, we have to keep this entry even after driver detached, 9364982Syy150190 * and we also need to mark this entry with E1000G_PRIV_DEVI_DETACH flag, 9374982Syy150190 * so that driver could free it while all of rx buffers are returned 9384982Syy150190 * by upper layer later. 9394982Syy150190 */ 9404982Syy150190 static void 9414982Syy150190 e1000g_free_priv_devi_node(struct e1000g *Adapter, boolean_t free_flag) 9424982Syy150190 { 9434982Syy150190 private_devi_list_t *devi_node, *devi_del; 9444982Syy150190 9454982Syy150190 rw_enter(&e1000g_rx_detach_lock, RW_WRITER); 9464982Syy150190 ASSERT(e1000g_private_devi_list != NULL); 9474982Syy150190 ASSERT(Adapter->priv_dip != NULL); 9484982Syy150190 9494982Syy150190 devi_node = e1000g_private_devi_list; 9504982Syy150190 if (devi_node->priv_dip == Adapter->priv_dip) { 9514982Syy150190 if (free_flag) { 9524982Syy150190 e1000g_private_devi_list = 9534982Syy150190 devi_node->next; 9544982Syy150190 kmem_free(devi_node->priv_dip, 9554982Syy150190 sizeof (struct dev_info)); 9564982Syy150190 kmem_free(devi_node, 9574982Syy150190 sizeof (private_devi_list_t)); 9584982Syy150190 } else { 9594982Syy150190 ASSERT(e1000g_mblks_pending != 0); 9604982Syy150190 devi_node->flag = 9614982Syy150190 E1000G_PRIV_DEVI_DETACH; 9624982Syy150190 } 9634982Syy150190 rw_exit(&e1000g_rx_detach_lock); 9644982Syy150190 return; 9654982Syy150190 } 9664982Syy150190 9674982Syy150190 devi_node = e1000g_private_devi_list; 9684982Syy150190 while (devi_node->next != NULL) { 9694982Syy150190 if (devi_node->next->priv_dip == Adapter->priv_dip) { 9704982Syy150190 if (free_flag) { 9714982Syy150190 devi_del = devi_node->next; 9724982Syy150190 devi_node->next = devi_del->next; 9734982Syy150190 kmem_free(devi_del->priv_dip, 9744982Syy150190 sizeof (struct dev_info)); 9754982Syy150190 kmem_free(devi_del, 9764982Syy150190 sizeof (private_devi_list_t)); 9774982Syy150190 } else { 9784982Syy150190 ASSERT(e1000g_mblks_pending != 0); 9794982Syy150190 devi_node->next->flag = 9804982Syy150190 E1000G_PRIV_DEVI_DETACH; 9814982Syy150190 } 9824982Syy150190 break; 9834982Syy150190 } 9844982Syy150190 devi_node = devi_node->next; 9854982Syy150190 } 9864982Syy150190 rw_exit(&e1000g_rx_detach_lock); 9874982Syy150190 } 9884982Syy150190 9893526Sxy150489 static void 9903526Sxy150489 e1000g_unattach(dev_info_t *devinfo, struct e1000g *Adapter) 9913526Sxy150489 { 9924919Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 9933526Sxy150489 (void) e1000g_disable_intrs(Adapter); 9943526Sxy150489 } 9953526Sxy150489 9964919Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_MAC) { 9973526Sxy150489 (void) mac_unregister(Adapter->mh); 9983526Sxy150489 } 9993526Sxy150489 10003526Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_NDD) { 10013526Sxy150489 e1000g_nd_cleanup(Adapter); 10023526Sxy150489 } 10033526Sxy150489 10044919Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 10053526Sxy150489 (void) e1000g_rem_intrs(Adapter); 10063526Sxy150489 } 10073526Sxy150489 10084919Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_SETUP) { 10093526Sxy150489 (void) ddi_prop_remove_all(devinfo); 10103526Sxy150489 } 10113526Sxy150489 10123526Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_KSTATS) { 10133526Sxy150489 kstat_delete((kstat_t *)Adapter->e1000g_ksp); 10143526Sxy150489 } 10153526Sxy150489 10163526Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_INIT) { 10174919Sxy150489 stop_link_timer(Adapter); 10185273Sgl147354 if (e1000_reset_hw(&Adapter->shared) != 0) { 10195273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 10205273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 10215273Sgl147354 } 10223526Sxy150489 } 10233526Sxy150489 10244919Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_REGS_MAP) { 10254919Sxy150489 if (Adapter->osdep.reg_handle != NULL) 10264919Sxy150489 ddi_regs_map_free(&Adapter->osdep.reg_handle); 10274919Sxy150489 if (Adapter->osdep.ich_flash_handle != NULL) 10284919Sxy150489 ddi_regs_map_free(&Adapter->osdep.ich_flash_handle); 10293526Sxy150489 } 10303526Sxy150489 10314919Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) { 10324919Sxy150489 if (Adapter->osdep.cfg_handle != NULL) 10334919Sxy150489 pci_config_teardown(&Adapter->osdep.cfg_handle); 10343526Sxy150489 } 10353526Sxy150489 10363526Sxy150489 if (Adapter->attach_progress & ATTACH_PROGRESS_LOCKS) { 10373526Sxy150489 e1000g_destroy_locks(Adapter); 10383526Sxy150489 } 10393526Sxy150489 10405273Sgl147354 if (Adapter->attach_progress & ATTACH_PROGRESS_FMINIT) { 10415273Sgl147354 e1000g_fm_fini(Adapter); 10425273Sgl147354 } 10435273Sgl147354 10444919Sxy150489 e1000_remove_device(&Adapter->shared); 10454919Sxy150489 10463526Sxy150489 kmem_free((caddr_t)Adapter, sizeof (struct e1000g)); 10473526Sxy150489 10483526Sxy150489 /* 10493526Sxy150489 * Another hotplug spec requirement, 10503526Sxy150489 * run ddi_set_driver_private(devinfo, null); 10513526Sxy150489 */ 10523526Sxy150489 ddi_set_driver_private(devinfo, NULL); 10533526Sxy150489 } 10543526Sxy150489 10553526Sxy150489 static void 10563526Sxy150489 e1000g_init_locks(struct e1000g *Adapter) 10573526Sxy150489 { 10583526Sxy150489 e1000g_tx_ring_t *tx_ring; 10593526Sxy150489 e1000g_rx_ring_t *rx_ring; 10603526Sxy150489 10613526Sxy150489 rw_init(&Adapter->chip_lock, NULL, 10623526Sxy150489 RW_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 10634919Sxy150489 mutex_init(&Adapter->link_lock, NULL, 10643526Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 10654919Sxy150489 mutex_init(&Adapter->watchdog_lock, NULL, 10663526Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 10673526Sxy150489 10683526Sxy150489 tx_ring = Adapter->tx_ring; 10693526Sxy150489 10703526Sxy150489 mutex_init(&tx_ring->tx_lock, NULL, 10713526Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 10723526Sxy150489 mutex_init(&tx_ring->usedlist_lock, NULL, 10733526Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 10743526Sxy150489 mutex_init(&tx_ring->freelist_lock, NULL, 10753526Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 10763526Sxy150489 10773526Sxy150489 rx_ring = Adapter->rx_ring; 10783526Sxy150489 10793526Sxy150489 mutex_init(&rx_ring->freelist_lock, NULL, 10803526Sxy150489 MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri)); 10813526Sxy150489 } 10823526Sxy150489 10833526Sxy150489 static void 10843526Sxy150489 e1000g_destroy_locks(struct e1000g *Adapter) 10853526Sxy150489 { 10863526Sxy150489 e1000g_tx_ring_t *tx_ring; 10873526Sxy150489 e1000g_rx_ring_t *rx_ring; 10883526Sxy150489 10893526Sxy150489 tx_ring = Adapter->tx_ring; 10903526Sxy150489 mutex_destroy(&tx_ring->tx_lock); 10913526Sxy150489 mutex_destroy(&tx_ring->usedlist_lock); 10923526Sxy150489 mutex_destroy(&tx_ring->freelist_lock); 10933526Sxy150489 10943526Sxy150489 rx_ring = Adapter->rx_ring; 10953526Sxy150489 mutex_destroy(&rx_ring->freelist_lock); 10963526Sxy150489 10974919Sxy150489 mutex_destroy(&Adapter->link_lock); 10984919Sxy150489 mutex_destroy(&Adapter->watchdog_lock); 10993526Sxy150489 rw_destroy(&Adapter->chip_lock); 11003526Sxy150489 } 11013526Sxy150489 11023526Sxy150489 static int 11033526Sxy150489 e1000g_resume(dev_info_t *devinfo) 11043526Sxy150489 { 11053526Sxy150489 struct e1000g *Adapter; 11063526Sxy150489 11073526Sxy150489 Adapter = (struct e1000g *)ddi_get_driver_private(devinfo); 11083526Sxy150489 if (Adapter == NULL) 11093526Sxy150489 return (DDI_FAILURE); 11103526Sxy150489 11114919Sxy150489 if (e1000g_start(Adapter, B_TRUE)) 11123526Sxy150489 return (DDI_FAILURE); 11133526Sxy150489 11143526Sxy150489 return (DDI_SUCCESS); 11153526Sxy150489 } 11163526Sxy150489 11173526Sxy150489 static int 11183526Sxy150489 e1000g_suspend(dev_info_t *devinfo) 11193526Sxy150489 { 11203526Sxy150489 struct e1000g *Adapter; 11213526Sxy150489 11223526Sxy150489 Adapter = (struct e1000g *)ddi_get_driver_private(devinfo); 11233526Sxy150489 if (Adapter == NULL) 11243526Sxy150489 return (DDI_FAILURE); 11253526Sxy150489 11264919Sxy150489 e1000g_stop(Adapter, B_TRUE); 11273526Sxy150489 11283526Sxy150489 return (DDI_SUCCESS); 11293526Sxy150489 } 11303526Sxy150489 11313526Sxy150489 static int 11323526Sxy150489 e1000g_init(struct e1000g *Adapter) 11333526Sxy150489 { 11343526Sxy150489 uint32_t pba; 11354919Sxy150489 uint32_t high_water; 11363526Sxy150489 struct e1000_hw *hw; 11374061Sxy150489 clock_t link_timeout; 11383526Sxy150489 11394919Sxy150489 hw = &Adapter->shared; 11403526Sxy150489 11413526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 11423526Sxy150489 11433526Sxy150489 /* 11443526Sxy150489 * reset to put the hardware in a known state 11453526Sxy150489 * before we try to do anything with the eeprom 11463526Sxy150489 */ 11475273Sgl147354 if (e1000_reset_hw(hw) != 0) { 11485273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 11495273Sgl147354 goto init_fail; 11505273Sgl147354 } 11513526Sxy150489 11524919Sxy150489 if (e1000_validate_nvm_checksum(hw) < 0) { 11534061Sxy150489 /* 11544061Sxy150489 * Some PCI-E parts fail the first check due to 11554061Sxy150489 * the link being in sleep state. Call it again, 11564061Sxy150489 * if it fails a second time its a real issue. 11574061Sxy150489 */ 11584919Sxy150489 if (e1000_validate_nvm_checksum(hw) < 0) { 11594061Sxy150489 e1000g_log(Adapter, CE_WARN, 11604919Sxy150489 "Invalid NVM checksum. Please contact " 11614919Sxy150489 "the vendor to update the NVM."); 11625273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 11634061Sxy150489 goto init_fail; 11644061Sxy150489 } 11653526Sxy150489 } 11663526Sxy150489 11673526Sxy150489 #ifdef __sparc 11683526Sxy150489 /* 11693526Sxy150489 * Firstly, we try to get the local ethernet address from OBP. If 11703526Sxy150489 * fail, we get from EEPROM of NIC card. 11713526Sxy150489 */ 11723526Sxy150489 if (!e1000g_find_mac_address(Adapter)) { 11733526Sxy150489 if (e1000_read_mac_addr(hw) < 0) { 11743526Sxy150489 e1000g_log(Adapter, CE_WARN, "Read mac addr failed"); 11755273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 11763526Sxy150489 goto init_fail; 11773526Sxy150489 } 11783526Sxy150489 } 11793526Sxy150489 #else 11803526Sxy150489 /* Get the local ethernet address. */ 11813526Sxy150489 if (e1000_read_mac_addr(hw) < 0) { 11823526Sxy150489 e1000g_log(Adapter, CE_WARN, "Read mac addr failed"); 11835273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 11843526Sxy150489 goto init_fail; 11853526Sxy150489 } 11863526Sxy150489 #endif 11873526Sxy150489 11883526Sxy150489 /* check for valid mac address */ 11894919Sxy150489 if (!is_valid_mac_addr(hw->mac.addr)) { 11903526Sxy150489 e1000g_log(Adapter, CE_WARN, "Invalid mac addr"); 11915273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 11923526Sxy150489 goto init_fail; 11933526Sxy150489 } 11943526Sxy150489 11954919Sxy150489 /* Set LAA state for 82571 chipset */ 11964919Sxy150489 e1000_set_laa_state_82571(hw, B_TRUE); 11973526Sxy150489 11983526Sxy150489 /* Master Latency Timer implementation */ 11994919Sxy150489 if (Adapter->master_latency_timer) { 12004919Sxy150489 pci_config_put8(Adapter->osdep.cfg_handle, 12014919Sxy150489 PCI_CONF_LATENCY_TIMER, Adapter->master_latency_timer); 12023526Sxy150489 } 12033526Sxy150489 12044919Sxy150489 if (hw->mac.type < e1000_82547) { 12053526Sxy150489 /* 12063526Sxy150489 * Total FIFO is 64K 12073526Sxy150489 */ 12084919Sxy150489 if (hw->mac.max_frame_size > FRAME_SIZE_UPTO_8K) 12093526Sxy150489 pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */ 12103526Sxy150489 else 12113526Sxy150489 pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */ 12124919Sxy150489 } else if (hw->mac.type >= e1000_82571 && 12134919Sxy150489 hw->mac.type <= e1000_82572) { 12143526Sxy150489 /* 12153526Sxy150489 * Total FIFO is 48K 12163526Sxy150489 */ 12174919Sxy150489 if (hw->mac.max_frame_size > FRAME_SIZE_UPTO_8K) 12183526Sxy150489 pba = E1000_PBA_30K; /* 30K for Rx, 18K for Tx */ 12193526Sxy150489 else 12203526Sxy150489 pba = E1000_PBA_38K; /* 38K for Rx, 10K for Tx */ 12214919Sxy150489 } else if (hw->mac.type == e1000_ich8lan) { 12223526Sxy150489 pba = E1000_PBA_8K; /* 8K for Rx, 12K for Tx */ 12234919Sxy150489 } else if (hw->mac.type == e1000_ich9lan) { 12244919Sxy150489 pba = E1000_PBA_12K; 12253526Sxy150489 } else { 12263526Sxy150489 /* 12273526Sxy150489 * Total FIFO is 40K 12283526Sxy150489 */ 12294919Sxy150489 if (hw->mac.max_frame_size > FRAME_SIZE_UPTO_8K) 12303526Sxy150489 pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */ 12313526Sxy150489 else 12323526Sxy150489 pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */ 12333526Sxy150489 } 12344919Sxy150489 E1000_WRITE_REG(hw, E1000_PBA, pba); 12353526Sxy150489 12363526Sxy150489 /* 12373526Sxy150489 * These parameters set thresholds for the adapter's generation(Tx) 12383526Sxy150489 * and response(Rx) to Ethernet PAUSE frames. These are just threshold 12393526Sxy150489 * settings. Flow control is enabled or disabled in the configuration 12403526Sxy150489 * file. 12413526Sxy150489 * High-water mark is set down from the top of the rx fifo (not 12423526Sxy150489 * sensitive to max_frame_size) and low-water is set just below 12433526Sxy150489 * high-water mark. 12444919Sxy150489 * The high water mark must be low enough to fit one full frame above 12454919Sxy150489 * it in the rx FIFO. Should be the lower of: 12464919Sxy150489 * 90% of the Rx FIFO size and the full Rx FIFO size minus the early 12474919Sxy150489 * receive size (assuming ERT set to E1000_ERT_2048), or the full 12484919Sxy150489 * Rx FIFO size minus one full frame. 12493526Sxy150489 */ 12504919Sxy150489 high_water = min(((pba << 10) * 9 / 10), 12514919Sxy150489 ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_ich9lan) ? 12524919Sxy150489 ((pba << 10) - (E1000_ERT_2048 << 3)) : 12534919Sxy150489 ((pba << 10) - hw->mac.max_frame_size))); 12544919Sxy150489 12554919Sxy150489 hw->mac.fc_high_water = high_water & 0xFFF8; 12564919Sxy150489 hw->mac.fc_low_water = hw->mac.fc_high_water - 8; 12574919Sxy150489 12584919Sxy150489 if (hw->mac.type == e1000_80003es2lan) 12594919Sxy150489 hw->mac.fc_pause_time = 0xFFFF; 12604919Sxy150489 else 12614919Sxy150489 hw->mac.fc_pause_time = E1000_FC_PAUSE_TIME; 12624919Sxy150489 hw->mac.fc_send_xon = B_TRUE; 12634919Sxy150489 hw->mac.fc = hw->mac.original_fc; 12643526Sxy150489 12653526Sxy150489 /* 12663526Sxy150489 * Reset the adapter hardware the second time. 12673526Sxy150489 */ 12685273Sgl147354 if (e1000_reset_hw(hw) != 0) { 12695273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 12705273Sgl147354 goto init_fail; 12715273Sgl147354 } 12723526Sxy150489 12733526Sxy150489 /* disable wakeup control by default */ 12744919Sxy150489 if (hw->mac.type >= e1000_82544) 12754919Sxy150489 E1000_WRITE_REG(hw, E1000_WUC, 0); 12763526Sxy150489 12773526Sxy150489 /* MWI setup */ 12784919Sxy150489 e1000_pci_set_mwi(hw); 12793526Sxy150489 12803526Sxy150489 /* 12813526Sxy150489 * Configure/Initialize hardware 12823526Sxy150489 */ 12833526Sxy150489 if (e1000_init_hw(hw) < 0) { 12843526Sxy150489 e1000g_log(Adapter, CE_WARN, "Initialize hw failed"); 12855273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 12863526Sxy150489 goto init_fail; 12873526Sxy150489 } 12883526Sxy150489 12893526Sxy150489 /* Disable Smart Power Down */ 12903526Sxy150489 phy_spd_state(hw, B_FALSE); 12913526Sxy150489 12925082Syy150190 /* Make sure driver has control */ 12935082Syy150190 e1000g_get_driver_control(hw); 12945082Syy150190 12953526Sxy150489 /* 12963526Sxy150489 * Initialize unicast addresses. 12973526Sxy150489 */ 12983526Sxy150489 e1000g_init_unicst(Adapter); 12993526Sxy150489 13003526Sxy150489 /* 13013526Sxy150489 * Setup and initialize the mctable structures. After this routine 13023526Sxy150489 * completes Multicast table will be set 13033526Sxy150489 */ 13044919Sxy150489 e1000g_setup_multicast(Adapter); 13054919Sxy150489 msec_delay(5); 13063526Sxy150489 13073526Sxy150489 /* 13083526Sxy150489 * Implement Adaptive IFS 13093526Sxy150489 */ 13103526Sxy150489 e1000_reset_adaptive(hw); 13113526Sxy150489 13123526Sxy150489 /* Setup Interrupt Throttling Register */ 13135882Syy150190 if (hw->mac.type >= e1000_82540) { 13145882Syy150190 E1000_WRITE_REG(hw, E1000_ITR, Adapter->intr_throttling_rate); 13155882Syy150190 } else 13165882Syy150190 Adapter->intr_adaptive = B_FALSE; 13173526Sxy150489 13184061Sxy150489 /* Start the timer for link setup */ 13194919Sxy150489 if (hw->mac.autoneg) 13204919Sxy150489 link_timeout = PHY_AUTO_NEG_LIMIT * drv_usectohz(100000); 13214061Sxy150489 else 13224919Sxy150489 link_timeout = PHY_FORCE_LIMIT * drv_usectohz(100000); 13234919Sxy150489 13244919Sxy150489 mutex_enter(&Adapter->link_lock); 13254919Sxy150489 if (hw->phy.wait_for_link) { 13264061Sxy150489 Adapter->link_complete = B_TRUE; 13273526Sxy150489 } else { 13284061Sxy150489 Adapter->link_complete = B_FALSE; 13294061Sxy150489 Adapter->link_tid = timeout(e1000g_link_timer, 13304061Sxy150489 (void *)Adapter, link_timeout); 13313526Sxy150489 } 13324919Sxy150489 mutex_exit(&Adapter->link_lock); 13333526Sxy150489 13343526Sxy150489 /* Enable PCI-Ex master */ 13354919Sxy150489 if (hw->bus.type == e1000_bus_type_pci_express) { 13363526Sxy150489 e1000_enable_pciex_master(hw); 13373526Sxy150489 } 13383526Sxy150489 13395082Syy150190 /* Save the state of the phy */ 13405082Syy150190 e1000g_get_phy_state(Adapter); 13415082Syy150190 13423526Sxy150489 Adapter->init_count++; 13433526Sxy150489 13445273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.cfg_handle) != DDI_FM_OK) { 13455273Sgl147354 goto init_fail; 13465273Sgl147354 } 13475273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 13485273Sgl147354 goto init_fail; 13495273Sgl147354 } 13505273Sgl147354 13513526Sxy150489 rw_exit(&Adapter->chip_lock); 13523526Sxy150489 13533526Sxy150489 return (DDI_SUCCESS); 13543526Sxy150489 13553526Sxy150489 init_fail: 13563526Sxy150489 rw_exit(&Adapter->chip_lock); 13575273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 13583526Sxy150489 return (DDI_FAILURE); 13593526Sxy150489 } 13603526Sxy150489 13613526Sxy150489 /* 13623526Sxy150489 * Check if the link is up 13633526Sxy150489 */ 13643526Sxy150489 static boolean_t 13653526Sxy150489 e1000g_link_up(struct e1000g *Adapter) 13663526Sxy150489 { 13673526Sxy150489 struct e1000_hw *hw; 13683526Sxy150489 boolean_t link_up; 13693526Sxy150489 13704919Sxy150489 hw = &Adapter->shared; 13713526Sxy150489 13723526Sxy150489 e1000_check_for_link(hw); 13733526Sxy150489 13744919Sxy150489 if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) || 13754919Sxy150489 ((!hw->mac.get_link_status) && (hw->mac.type == e1000_82543)) || 13763526Sxy150489 ((hw->media_type == e1000_media_type_internal_serdes) && 13774919Sxy150489 (hw->mac.serdes_has_link))) { 13783526Sxy150489 link_up = B_TRUE; 13793526Sxy150489 } else { 13803526Sxy150489 link_up = B_FALSE; 13813526Sxy150489 } 13823526Sxy150489 13833526Sxy150489 return (link_up); 13843526Sxy150489 } 13853526Sxy150489 13863526Sxy150489 static void 13873526Sxy150489 e1000g_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 13883526Sxy150489 { 13893526Sxy150489 struct iocblk *iocp; 13903526Sxy150489 struct e1000g *e1000gp; 13913526Sxy150489 enum ioc_reply status; 13923526Sxy150489 int err; 13933526Sxy150489 13943526Sxy150489 iocp = (struct iocblk *)mp->b_rptr; 13953526Sxy150489 iocp->ioc_error = 0; 13963526Sxy150489 e1000gp = (struct e1000g *)arg; 13973526Sxy150489 13983526Sxy150489 ASSERT(e1000gp); 13993526Sxy150489 if (e1000gp == NULL) { 14003526Sxy150489 miocnak(q, mp, 0, EINVAL); 14013526Sxy150489 return; 14023526Sxy150489 } 14033526Sxy150489 14043526Sxy150489 switch (iocp->ioc_cmd) { 14053526Sxy150489 14063526Sxy150489 case LB_GET_INFO_SIZE: 14073526Sxy150489 case LB_GET_INFO: 14083526Sxy150489 case LB_GET_MODE: 14093526Sxy150489 case LB_SET_MODE: 14103526Sxy150489 status = e1000g_loopback_ioctl(e1000gp, iocp, mp); 14113526Sxy150489 break; 14123526Sxy150489 14133526Sxy150489 case ND_GET: 14143526Sxy150489 case ND_SET: 14153526Sxy150489 status = e1000g_nd_ioctl(e1000gp, q, mp, iocp); 14163526Sxy150489 break; 14173526Sxy150489 14184919Sxy150489 #ifdef E1000G_DEBUG 14193526Sxy150489 case E1000G_IOC_REG_PEEK: 14203526Sxy150489 case E1000G_IOC_REG_POKE: 14213526Sxy150489 status = e1000g_pp_ioctl(e1000gp, iocp, mp); 14223526Sxy150489 break; 14233526Sxy150489 case E1000G_IOC_CHIP_RESET: 14243526Sxy150489 e1000gp->reset_count++; 14253526Sxy150489 if (e1000g_reset(e1000gp)) 14263526Sxy150489 status = IOC_ACK; 14273526Sxy150489 else 14283526Sxy150489 status = IOC_INVAL; 14293526Sxy150489 break; 14304919Sxy150489 #endif 14313526Sxy150489 default: 14323526Sxy150489 status = IOC_INVAL; 14333526Sxy150489 break; 14343526Sxy150489 } 14353526Sxy150489 14363526Sxy150489 /* 14373526Sxy150489 * Decide how to reply 14383526Sxy150489 */ 14393526Sxy150489 switch (status) { 14403526Sxy150489 default: 14413526Sxy150489 case IOC_INVAL: 14423526Sxy150489 /* 14433526Sxy150489 * Error, reply with a NAK and EINVAL or the specified error 14443526Sxy150489 */ 14453526Sxy150489 miocnak(q, mp, 0, iocp->ioc_error == 0 ? 14464349Sxy150489 EINVAL : iocp->ioc_error); 14473526Sxy150489 break; 14483526Sxy150489 14493526Sxy150489 case IOC_DONE: 14503526Sxy150489 /* 14513526Sxy150489 * OK, reply already sent 14523526Sxy150489 */ 14533526Sxy150489 break; 14543526Sxy150489 14553526Sxy150489 case IOC_ACK: 14563526Sxy150489 /* 14573526Sxy150489 * OK, reply with an ACK 14583526Sxy150489 */ 14593526Sxy150489 miocack(q, mp, 0, 0); 14603526Sxy150489 break; 14613526Sxy150489 14623526Sxy150489 case IOC_REPLY: 14633526Sxy150489 /* 14643526Sxy150489 * OK, send prepared reply as ACK or NAK 14653526Sxy150489 */ 14663526Sxy150489 mp->b_datap->db_type = iocp->ioc_error == 0 ? 14674349Sxy150489 M_IOCACK : M_IOCNAK; 14683526Sxy150489 qreply(q, mp); 14693526Sxy150489 break; 14703526Sxy150489 } 14713526Sxy150489 } 14723526Sxy150489 14733526Sxy150489 static int 14743526Sxy150489 e1000g_m_start(void *arg) 14753526Sxy150489 { 14763526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 14773526Sxy150489 14784919Sxy150489 return (e1000g_start(Adapter, B_TRUE)); 14793526Sxy150489 } 14803526Sxy150489 14813526Sxy150489 static int 14824919Sxy150489 e1000g_start(struct e1000g *Adapter, boolean_t global) 14833526Sxy150489 { 14844919Sxy150489 if (global) { 14854919Sxy150489 /* Allocate dma resources for descriptors and buffers */ 14864919Sxy150489 if (e1000g_alloc_dma_resources(Adapter) != DDI_SUCCESS) { 14874919Sxy150489 e1000g_log(Adapter, CE_WARN, 14884919Sxy150489 "Alloc DMA resources failed"); 14894919Sxy150489 return (ENOTACTIVE); 14904919Sxy150489 } 14914919Sxy150489 Adapter->rx_buffer_setup = B_FALSE; 14924919Sxy150489 } 14934919Sxy150489 14943526Sxy150489 if (!(Adapter->attach_progress & ATTACH_PROGRESS_INIT)) { 14953526Sxy150489 if (e1000g_init(Adapter) != DDI_SUCCESS) { 14963526Sxy150489 e1000g_log(Adapter, CE_WARN, 14973526Sxy150489 "Adapter initialization failed"); 14984919Sxy150489 if (global) 14994919Sxy150489 e1000g_release_dma_resources(Adapter); 15003526Sxy150489 return (ENOTACTIVE); 15013526Sxy150489 } 15023526Sxy150489 } 15033526Sxy150489 15043526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 15053526Sxy150489 15064919Sxy150489 /* Setup and initialize the transmit structures */ 15074919Sxy150489 e1000g_tx_setup(Adapter); 15084919Sxy150489 msec_delay(5); 15094919Sxy150489 15104919Sxy150489 /* Setup and initialize the receive structures */ 15114919Sxy150489 e1000g_rx_setup(Adapter); 15124919Sxy150489 msec_delay(5); 15134919Sxy150489 15144919Sxy150489 e1000g_mask_interrupt(Adapter); 15153526Sxy150489 15165273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 15175273Sgl147354 rw_exit(&Adapter->chip_lock); 15185273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 15195273Sgl147354 return (ENOTACTIVE); 15205273Sgl147354 } 15215273Sgl147354 15225273Sgl147354 Adapter->chip_state = E1000G_START; 15233526Sxy150489 Adapter->attach_progress |= ATTACH_PROGRESS_INIT; 15243526Sxy150489 15253526Sxy150489 rw_exit(&Adapter->chip_lock); 15263526Sxy150489 15274919Sxy150489 /* Enable and start the watchdog timer */ 15284919Sxy150489 enable_watchdog_timer(Adapter); 15294919Sxy150489 15303526Sxy150489 return (0); 15313526Sxy150489 } 15323526Sxy150489 15333526Sxy150489 static void 15343526Sxy150489 e1000g_m_stop(void *arg) 15353526Sxy150489 { 15363526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 15373526Sxy150489 15384919Sxy150489 e1000g_stop(Adapter, B_TRUE); 15393526Sxy150489 } 15403526Sxy150489 15413526Sxy150489 static void 15424919Sxy150489 e1000g_stop(struct e1000g *Adapter, boolean_t global) 15433526Sxy150489 { 15443526Sxy150489 /* Set stop flags */ 15453526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 15463526Sxy150489 15475273Sgl147354 Adapter->chip_state = E1000G_STOP; 15483526Sxy150489 Adapter->attach_progress &= ~ATTACH_PROGRESS_INIT; 15493526Sxy150489 15503526Sxy150489 rw_exit(&Adapter->chip_lock); 15513526Sxy150489 15523526Sxy150489 /* Drain tx sessions */ 15533526Sxy150489 (void) e1000g_tx_drain(Adapter); 15543526Sxy150489 15554919Sxy150489 /* Disable and stop all the timers */ 15564919Sxy150489 disable_watchdog_timer(Adapter); 15574919Sxy150489 stop_link_timer(Adapter); 15584919Sxy150489 stop_82547_timer(Adapter->tx_ring); 15594061Sxy150489 15603526Sxy150489 /* Stop the chip and release pending resources */ 15613526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 15623526Sxy150489 15634919Sxy150489 e1000g_clear_all_interrupts(Adapter); 15645273Sgl147354 if (e1000_reset_hw(&Adapter->shared) != 0) { 15655273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_INVAL_STATE); 15665273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 15675273Sgl147354 } 15683526Sxy150489 15693526Sxy150489 /* Release resources still held by the TX descriptors */ 15704919Sxy150489 e1000g_tx_clean(Adapter); 15714061Sxy150489 15725273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 15735273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_LOST); 15745273Sgl147354 15754061Sxy150489 /* Clean the pending rx jumbo packet fragment */ 15764919Sxy150489 e1000g_rx_clean(Adapter); 15774061Sxy150489 15784061Sxy150489 rw_exit(&Adapter->chip_lock); 15794919Sxy150489 15804919Sxy150489 if (global) 15814919Sxy150489 e1000g_release_dma_resources(Adapter); 15824061Sxy150489 } 15834061Sxy150489 15844061Sxy150489 static void 15854919Sxy150489 e1000g_rx_clean(struct e1000g *Adapter) 15864919Sxy150489 { 15874919Sxy150489 e1000g_rx_ring_t *rx_ring = Adapter->rx_ring; 15884919Sxy150489 15894919Sxy150489 if (rx_ring->rx_mblk != NULL) { 15904919Sxy150489 freemsg(rx_ring->rx_mblk); 15914919Sxy150489 rx_ring->rx_mblk = NULL; 15924919Sxy150489 rx_ring->rx_mblk_tail = NULL; 15934919Sxy150489 rx_ring->rx_mblk_len = 0; 15944919Sxy150489 } 15954919Sxy150489 } 15964919Sxy150489 15974919Sxy150489 static void 15984919Sxy150489 e1000g_tx_clean(struct e1000g *Adapter) 15994061Sxy150489 { 16004061Sxy150489 e1000g_tx_ring_t *tx_ring; 16014919Sxy150489 p_tx_sw_packet_t packet; 16024061Sxy150489 mblk_t *mp; 16034061Sxy150489 mblk_t *nmp; 16044061Sxy150489 uint32_t packet_count; 16054061Sxy150489 16064061Sxy150489 tx_ring = Adapter->tx_ring; 16074061Sxy150489 16083526Sxy150489 /* 16093526Sxy150489 * Here we don't need to protect the lists using 16103526Sxy150489 * the usedlist_lock and freelist_lock, for they 16113526Sxy150489 * have been protected by the chip_lock. 16123526Sxy150489 */ 16133526Sxy150489 mp = NULL; 16143526Sxy150489 nmp = NULL; 16154061Sxy150489 packet_count = 0; 16164919Sxy150489 packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(&tx_ring->used_list); 16173526Sxy150489 while (packet != NULL) { 16183526Sxy150489 if (packet->mp != NULL) { 16193526Sxy150489 /* Assemble the message chain */ 16203526Sxy150489 if (mp == NULL) { 16213526Sxy150489 mp = packet->mp; 16223526Sxy150489 nmp = packet->mp; 16233526Sxy150489 } else { 16243526Sxy150489 nmp->b_next = packet->mp; 16253526Sxy150489 nmp = packet->mp; 16263526Sxy150489 } 16273526Sxy150489 /* Disconnect the message from the sw packet */ 16283526Sxy150489 packet->mp = NULL; 16293526Sxy150489 } 16303526Sxy150489 16314919Sxy150489 e1000g_free_tx_swpkt(packet); 16324061Sxy150489 packet_count++; 16333526Sxy150489 16344919Sxy150489 packet = (p_tx_sw_packet_t) 16353526Sxy150489 QUEUE_GET_NEXT(&tx_ring->used_list, &packet->Link); 16363526Sxy150489 } 16373526Sxy150489 16385882Syy150190 if (mp != NULL) 16395882Syy150190 freemsgchain(mp); 16404061Sxy150489 16414061Sxy150489 if (packet_count > 0) { 16424061Sxy150489 QUEUE_APPEND(&tx_ring->free_list, &tx_ring->used_list); 16434061Sxy150489 QUEUE_INIT_LIST(&tx_ring->used_list); 16444061Sxy150489 16454061Sxy150489 /* Setup TX descriptor pointers */ 16464061Sxy150489 tx_ring->tbd_next = tx_ring->tbd_first; 16474061Sxy150489 tx_ring->tbd_oldest = tx_ring->tbd_first; 16484061Sxy150489 16494061Sxy150489 /* Setup our HW Tx Head & Tail descriptor pointers */ 16504919Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_TDH, 0); 16514919Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_TDT, 0); 16523526Sxy150489 } 16533526Sxy150489 } 16543526Sxy150489 16553526Sxy150489 static boolean_t 16563526Sxy150489 e1000g_tx_drain(struct e1000g *Adapter) 16573526Sxy150489 { 16583526Sxy150489 int i; 16593526Sxy150489 boolean_t done; 16603526Sxy150489 e1000g_tx_ring_t *tx_ring; 16613526Sxy150489 16623526Sxy150489 tx_ring = Adapter->tx_ring; 16633526Sxy150489 16643526Sxy150489 /* Allow up to 'wsdraintime' for pending xmit's to complete. */ 16654919Sxy150489 for (i = 0; i < TX_DRAIN_TIME; i++) { 16663526Sxy150489 mutex_enter(&tx_ring->usedlist_lock); 16673526Sxy150489 done = IS_QUEUE_EMPTY(&tx_ring->used_list); 16683526Sxy150489 mutex_exit(&tx_ring->usedlist_lock); 16693526Sxy150489 16703526Sxy150489 if (done) 16713526Sxy150489 break; 16723526Sxy150489 16733526Sxy150489 msec_delay(1); 16743526Sxy150489 } 16753526Sxy150489 16763526Sxy150489 return (done); 16773526Sxy150489 } 16783526Sxy150489 16793526Sxy150489 static boolean_t 16803526Sxy150489 e1000g_rx_drain(struct e1000g *Adapter) 16813526Sxy150489 { 16824919Sxy150489 e1000g_rx_ring_t *rx_ring; 16834919Sxy150489 p_rx_sw_packet_t packet; 16843526Sxy150489 boolean_t done; 16853526Sxy150489 16864919Sxy150489 rx_ring = Adapter->rx_ring; 16874919Sxy150489 done = B_TRUE; 16884919Sxy150489 16894919Sxy150489 rw_enter(&e1000g_rx_detach_lock, RW_WRITER); 16904919Sxy150489 16914919Sxy150489 while (rx_ring->pending_list != NULL) { 16924919Sxy150489 packet = rx_ring->pending_list; 16934919Sxy150489 rx_ring->pending_list = 16944919Sxy150489 rx_ring->pending_list->next; 16954919Sxy150489 16964919Sxy150489 if (packet->flag == E1000G_RX_SW_STOP) { 16974919Sxy150489 packet->flag = E1000G_RX_SW_DETACH; 16984919Sxy150489 done = B_FALSE; 16994919Sxy150489 } else { 17004919Sxy150489 ASSERT(packet->flag == E1000G_RX_SW_FREE); 17014919Sxy150489 ASSERT(packet->mp == NULL); 17024919Sxy150489 e1000g_free_rx_sw_packet(packet); 17034919Sxy150489 } 17044919Sxy150489 } 17054919Sxy150489 17064919Sxy150489 rw_exit(&e1000g_rx_detach_lock); 17073526Sxy150489 17083526Sxy150489 return (done); 17093526Sxy150489 } 17103526Sxy150489 17114061Sxy150489 boolean_t 17123526Sxy150489 e1000g_reset(struct e1000g *Adapter) 17133526Sxy150489 { 17144919Sxy150489 e1000g_stop(Adapter, B_FALSE); 17154919Sxy150489 17164919Sxy150489 if (e1000g_start(Adapter, B_FALSE)) { 17173526Sxy150489 e1000g_log(Adapter, CE_WARN, "Reset failed"); 17183526Sxy150489 return (B_FALSE); 17193526Sxy150489 } 17203526Sxy150489 17213526Sxy150489 return (B_TRUE); 17223526Sxy150489 } 17233526Sxy150489 17245273Sgl147354 boolean_t 17255273Sgl147354 e1000g_global_reset(struct e1000g *Adapter) 17265273Sgl147354 { 17275273Sgl147354 e1000g_stop(Adapter, B_TRUE); 17285273Sgl147354 17295273Sgl147354 Adapter->init_count = 0; 17305273Sgl147354 17315273Sgl147354 if (e1000g_start(Adapter, B_TRUE)) { 17325273Sgl147354 e1000g_log(Adapter, CE_WARN, "Reset failed"); 17335273Sgl147354 return (B_FALSE); 17345273Sgl147354 } 17355273Sgl147354 17365273Sgl147354 return (B_TRUE); 17375273Sgl147354 } 17385273Sgl147354 17393526Sxy150489 /* 17404919Sxy150489 * e1000g_intr_pciexpress - ISR for PCI Express chipsets 17414919Sxy150489 * 17424919Sxy150489 * This interrupt service routine is for PCI-Express adapters. 17434919Sxy150489 * The ICR contents is valid only when the E1000_ICR_INT_ASSERTED 17444919Sxy150489 * bit is set. 17453526Sxy150489 */ 17463526Sxy150489 static uint_t 17473526Sxy150489 e1000g_intr_pciexpress(caddr_t arg) 17483526Sxy150489 { 17493526Sxy150489 struct e1000g *Adapter; 17504919Sxy150489 uint32_t icr; 17513526Sxy150489 17523526Sxy150489 Adapter = (struct e1000g *)arg; 17534919Sxy150489 icr = E1000_READ_REG(&Adapter->shared, E1000_ICR); 17544919Sxy150489 17555273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 17565273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 17575273Sgl147354 17584919Sxy150489 if (icr & E1000_ICR_INT_ASSERTED) { 17593526Sxy150489 /* 17603526Sxy150489 * E1000_ICR_INT_ASSERTED bit was set: 17613526Sxy150489 * Read(Clear) the ICR, claim this interrupt, 17623526Sxy150489 * look for work to do. 17633526Sxy150489 */ 17644919Sxy150489 e1000g_intr_work(Adapter, icr); 17653526Sxy150489 return (DDI_INTR_CLAIMED); 17663526Sxy150489 } else { 17673526Sxy150489 /* 17683526Sxy150489 * E1000_ICR_INT_ASSERTED bit was not set: 17693526Sxy150489 * Don't claim this interrupt, return immediately. 17703526Sxy150489 */ 17713526Sxy150489 return (DDI_INTR_UNCLAIMED); 17723526Sxy150489 } 17733526Sxy150489 } 17743526Sxy150489 17753526Sxy150489 /* 17764919Sxy150489 * e1000g_intr - ISR for PCI/PCI-X chipsets 17774919Sxy150489 * 17784919Sxy150489 * This interrupt service routine is for PCI/PCI-X adapters. 17794919Sxy150489 * We check the ICR contents no matter the E1000_ICR_INT_ASSERTED 17804919Sxy150489 * bit is set or not. 17813526Sxy150489 */ 17823526Sxy150489 static uint_t 17833526Sxy150489 e1000g_intr(caddr_t arg) 17843526Sxy150489 { 17853526Sxy150489 struct e1000g *Adapter; 17864919Sxy150489 uint32_t icr; 17873526Sxy150489 17883526Sxy150489 Adapter = (struct e1000g *)arg; 17894919Sxy150489 icr = E1000_READ_REG(&Adapter->shared, E1000_ICR); 17904919Sxy150489 17915273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 17925273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 17935273Sgl147354 17944919Sxy150489 if (icr) { 17953526Sxy150489 /* 17963526Sxy150489 * Any bit was set in ICR: 17973526Sxy150489 * Read(Clear) the ICR, claim this interrupt, 17983526Sxy150489 * look for work to do. 17993526Sxy150489 */ 18004919Sxy150489 e1000g_intr_work(Adapter, icr); 18013526Sxy150489 return (DDI_INTR_CLAIMED); 18023526Sxy150489 } else { 18033526Sxy150489 /* 18043526Sxy150489 * No bit was set in ICR: 18053526Sxy150489 * Don't claim this interrupt, return immediately. 18063526Sxy150489 */ 18073526Sxy150489 return (DDI_INTR_UNCLAIMED); 18083526Sxy150489 } 18093526Sxy150489 } 18103526Sxy150489 18113526Sxy150489 /* 18124919Sxy150489 * e1000g_intr_work - actual processing of ISR 18134919Sxy150489 * 18144919Sxy150489 * Read(clear) the ICR contents and call appropriate interrupt 18154919Sxy150489 * processing routines. 18163526Sxy150489 */ 18173526Sxy150489 static void 18184919Sxy150489 e1000g_intr_work(struct e1000g *Adapter, uint32_t icr) 18193526Sxy150489 { 18205882Syy150190 struct e1000_hw *hw; 18215882Syy150190 hw = &Adapter->shared; 18225882Syy150190 e1000g_tx_ring_t *tx_ring = Adapter->tx_ring; 18235882Syy150190 uint32_t itr; 18245882Syy150190 18255882Syy150190 Adapter->rx_pkt_cnt = 0; 18265882Syy150190 Adapter->tx_pkt_cnt = 0; 18275882Syy150190 18284919Sxy150489 rw_enter(&Adapter->chip_lock, RW_READER); 18294919Sxy150489 /* 18305273Sgl147354 * Here we need to check the "chip_state" flag within the chip_lock to 18314919Sxy150489 * ensure the receive routine will not execute when the adapter is 18324919Sxy150489 * being reset. 18334919Sxy150489 */ 18345273Sgl147354 if (Adapter->chip_state != E1000G_START) { 18354919Sxy150489 rw_exit(&Adapter->chip_lock); 18364919Sxy150489 return; 18374919Sxy150489 } 18384919Sxy150489 18394919Sxy150489 if (icr & E1000_ICR_RXT0) { 18403526Sxy150489 mblk_t *mp; 18413526Sxy150489 18424919Sxy150489 mp = e1000g_receive(Adapter); 18434919Sxy150489 18444919Sxy150489 rw_exit(&Adapter->chip_lock); 18454919Sxy150489 18464919Sxy150489 if (mp != NULL) 18474919Sxy150489 mac_rx(Adapter->mh, Adapter->mrh, mp); 18484919Sxy150489 } else 18494919Sxy150489 rw_exit(&Adapter->chip_lock); 18503526Sxy150489 18515882Syy150190 if (icr & E1000_ICR_TXDW) { 18525882Syy150190 if (!Adapter->tx_intr_enable) 18535882Syy150190 e1000g_clear_tx_interrupt(Adapter); 18545882Syy150190 18555882Syy150190 /* Recycle the tx descriptors */ 18565882Syy150190 rw_enter(&Adapter->chip_lock, RW_READER); 18575882Syy150190 e1000g_recycle(tx_ring); 18585882Syy150190 E1000G_DEBUG_STAT(tx_ring->stat_recycle_intr); 18595882Syy150190 rw_exit(&Adapter->chip_lock); 18605882Syy150190 18615882Syy150190 /* Schedule the re-transmit */ 18625882Syy150190 if (tx_ring->resched_needed && 18635882Syy150190 (tx_ring->tbd_avail > DEFAULT_TX_UPDATE_THRESHOLD)) { 18645882Syy150190 tx_ring->resched_needed = B_FALSE; 18655882Syy150190 mac_tx_update(Adapter->mh); 18665882Syy150190 E1000G_STAT(tx_ring->stat_reschedule); 18675882Syy150190 } 18685882Syy150190 } 18695882Syy150190 18705882Syy150190 if (Adapter->intr_adaptive) { 18715882Syy150190 itr = e1000g_get_itr(Adapter->rx_pkt_cnt, Adapter->tx_pkt_cnt, 18725882Syy150190 Adapter->intr_throttling_rate); 18735882Syy150190 if (itr) { 18745882Syy150190 E1000_WRITE_REG(hw, E1000_ITR, itr); 18755882Syy150190 Adapter->intr_throttling_rate = itr; 18765882Syy150190 } 18775882Syy150190 } 18785882Syy150190 18793526Sxy150489 /* 18803526Sxy150489 * The Receive Sequence errors RXSEQ and the link status change LSC 18813526Sxy150489 * are checked to detect that the cable has been pulled out. For 18823526Sxy150489 * the Wiseman 2.0 silicon, the receive sequence errors interrupt 18833526Sxy150489 * are an indication that cable is not connected. 18843526Sxy150489 */ 18854919Sxy150489 if ((icr & E1000_ICR_RXSEQ) || 18864919Sxy150489 (icr & E1000_ICR_LSC) || 18874919Sxy150489 (icr & E1000_ICR_GPI_EN1)) { 18884061Sxy150489 boolean_t link_changed; 18894061Sxy150489 timeout_id_t tid = 0; 18903526Sxy150489 18914919Sxy150489 stop_watchdog_timer(Adapter); 18924919Sxy150489 18935082Syy150190 rw_enter(&Adapter->chip_lock, RW_WRITER); 18945082Syy150190 18955082Syy150190 /* 18965082Syy150190 * Because we got a link-status-change interrupt, force 18975082Syy150190 * e1000_check_for_link() to look at phy 18985082Syy150190 */ 18995082Syy150190 Adapter->shared.mac.get_link_status = B_TRUE; 19005082Syy150190 19014061Sxy150489 /* e1000g_link_check takes care of link status change */ 19024061Sxy150489 link_changed = e1000g_link_check(Adapter); 19035082Syy150190 19045082Syy150190 /* Get new phy state */ 19055082Syy150190 e1000g_get_phy_state(Adapter); 19065082Syy150190 19074061Sxy150489 /* 19084061Sxy150489 * If the link timer has not timed out, we'll not notify 19094919Sxy150489 * the upper layer with any link state until the link is up. 19104061Sxy150489 */ 19114061Sxy150489 if (link_changed && !Adapter->link_complete) { 19124061Sxy150489 if (Adapter->link_state == LINK_STATE_UP) { 19135082Syy150190 mutex_enter(&Adapter->link_lock); 19144061Sxy150489 Adapter->link_complete = B_TRUE; 19154061Sxy150489 tid = Adapter->link_tid; 19164061Sxy150489 Adapter->link_tid = 0; 19175082Syy150190 mutex_exit(&Adapter->link_lock); 19184061Sxy150489 } else { 19194061Sxy150489 link_changed = B_FALSE; 19204061Sxy150489 } 19214061Sxy150489 } 19225082Syy150190 rw_exit(&Adapter->chip_lock); 19233526Sxy150489 19244061Sxy150489 if (link_changed) { 19254061Sxy150489 if (tid != 0) 19264061Sxy150489 (void) untimeout(tid); 19274061Sxy150489 19284139Sxy150489 /* 19294139Sxy150489 * Workaround for esb2. Data stuck in fifo on a link 19304139Sxy150489 * down event. Reset the adapter to recover it. 19314139Sxy150489 */ 19324139Sxy150489 if ((Adapter->link_state == LINK_STATE_DOWN) && 19334919Sxy150489 (Adapter->shared.mac.type == e1000_80003es2lan)) 19344139Sxy150489 (void) e1000g_reset(Adapter); 19354139Sxy150489 19364061Sxy150489 mac_link_update(Adapter->mh, Adapter->link_state); 19373526Sxy150489 } 19383526Sxy150489 19394919Sxy150489 start_watchdog_timer(Adapter); 19403526Sxy150489 } 19415882Syy150190 } 19425882Syy150190 19435882Syy150190 static uint32_t 19445882Syy150190 e1000g_get_itr(uint32_t rx_packet, uint32_t tx_packet, uint32_t cur_itr) 19455882Syy150190 { 19465882Syy150190 uint32_t new_itr; 19475882Syy150190 19485882Syy150190 /* 19495882Syy150190 * Determine a propper itr according to rx/tx packet count 19505882Syy150190 * per interrupt, the value of itr are based on document 19515882Syy150190 * and testing. 19525882Syy150190 */ 19535882Syy150190 if ((rx_packet < DEFAULT_INTR_PACKET_LOW) || 19545882Syy150190 (tx_packet < DEFAULT_INTR_PACKET_LOW)) { 19555882Syy150190 new_itr = DEFAULT_INTR_THROTTLING_LOW; 19565882Syy150190 goto itr_done; 19573526Sxy150489 } 19585882Syy150190 if ((rx_packet > DEFAULT_INTR_PACKET_HIGH) || 19595882Syy150190 (tx_packet > DEFAULT_INTR_PACKET_HIGH)) { 19605882Syy150190 new_itr = DEFAULT_INTR_THROTTLING_LOW; 19615882Syy150190 goto itr_done; 19625882Syy150190 } 19635882Syy150190 if (cur_itr < DEFAULT_INTR_THROTTLING_HIGH) { 19645882Syy150190 new_itr = cur_itr + (DEFAULT_INTR_THROTTLING_HIGH >> 2); 19655882Syy150190 if (new_itr > DEFAULT_INTR_THROTTLING_HIGH) 19665882Syy150190 new_itr = DEFAULT_INTR_THROTTLING_HIGH; 19675882Syy150190 } else 19685882Syy150190 new_itr = DEFAULT_INTR_THROTTLING_HIGH; 19695882Syy150190 19705882Syy150190 itr_done: 19715882Syy150190 if (cur_itr == new_itr) 19725882Syy150190 return (0); 19735882Syy150190 else 19745882Syy150190 return (new_itr); 19753526Sxy150489 } 19763526Sxy150489 19773526Sxy150489 static void 19783526Sxy150489 e1000g_init_unicst(struct e1000g *Adapter) 19793526Sxy150489 { 19803526Sxy150489 struct e1000_hw *hw; 19813526Sxy150489 int slot; 19823526Sxy150489 19834919Sxy150489 hw = &Adapter->shared; 19843526Sxy150489 19855273Sgl147354 if (!Adapter->unicst_init) { 19863526Sxy150489 /* Initialize the multiple unicast addresses */ 19873526Sxy150489 Adapter->unicst_total = MAX_NUM_UNICAST_ADDRESSES; 19883526Sxy150489 19894919Sxy150489 if ((hw->mac.type == e1000_82571) && 19904919Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) 19913526Sxy150489 Adapter->unicst_total--; 19923526Sxy150489 19933526Sxy150489 Adapter->unicst_avail = Adapter->unicst_total - 1; 19943526Sxy150489 19953526Sxy150489 /* Store the default mac address */ 19964919Sxy150489 e1000_rar_set(hw, hw->mac.addr, 0); 19974919Sxy150489 if ((hw->mac.type == e1000_82571) && 19984919Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) 19994919Sxy150489 e1000_rar_set(hw, hw->mac.addr, LAST_RAR_ENTRY); 20004919Sxy150489 20014919Sxy150489 bcopy(hw->mac.addr, Adapter->unicst_addr[0].mac.addr, 20023526Sxy150489 ETHERADDRL); 20033526Sxy150489 Adapter->unicst_addr[0].mac.set = 1; 20043526Sxy150489 20053526Sxy150489 for (slot = 1; slot < Adapter->unicst_total; slot++) 20063526Sxy150489 Adapter->unicst_addr[slot].mac.set = 0; 20075273Sgl147354 20085273Sgl147354 Adapter->unicst_init = B_TRUE; 20093526Sxy150489 } else { 20103526Sxy150489 /* Recover the default mac address */ 20114919Sxy150489 bcopy(Adapter->unicst_addr[0].mac.addr, hw->mac.addr, 20123526Sxy150489 ETHERADDRL); 20133526Sxy150489 20143526Sxy150489 /* Store the default mac address */ 20154919Sxy150489 e1000_rar_set(hw, hw->mac.addr, 0); 20164919Sxy150489 if ((hw->mac.type == e1000_82571) && 20174919Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) 20184919Sxy150489 e1000_rar_set(hw, hw->mac.addr, LAST_RAR_ENTRY); 20193526Sxy150489 20203526Sxy150489 /* Re-configure the RAR registers */ 20213526Sxy150489 for (slot = 1; slot < Adapter->unicst_total; slot++) 20223526Sxy150489 e1000_rar_set(hw, 20233526Sxy150489 Adapter->unicst_addr[slot].mac.addr, slot); 20243526Sxy150489 } 20255273Sgl147354 20265273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 20275273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 20283526Sxy150489 } 20293526Sxy150489 20303526Sxy150489 static int 20313526Sxy150489 e1000g_m_unicst(void *arg, const uint8_t *mac_addr) 20323526Sxy150489 { 20333526Sxy150489 struct e1000g *Adapter; 20343526Sxy150489 20353526Sxy150489 Adapter = (struct e1000g *)arg; 20363526Sxy150489 20373526Sxy150489 /* Store the default MAC address */ 20384919Sxy150489 bcopy(mac_addr, Adapter->shared.mac.addr, ETHERADDRL); 20393526Sxy150489 20403526Sxy150489 /* Set MAC address in address slot 0, which is the default address */ 20413526Sxy150489 return (e1000g_unicst_set(Adapter, mac_addr, 0)); 20423526Sxy150489 } 20433526Sxy150489 20443526Sxy150489 static int 20453526Sxy150489 e1000g_unicst_set(struct e1000g *Adapter, const uint8_t *mac_addr, 20463526Sxy150489 mac_addr_slot_t slot) 20473526Sxy150489 { 20483526Sxy150489 struct e1000_hw *hw; 20493526Sxy150489 20504919Sxy150489 hw = &Adapter->shared; 20513526Sxy150489 20523526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 20533526Sxy150489 20544919Sxy150489 #ifndef NO_82542_SUPPORT 20553526Sxy150489 /* 20563526Sxy150489 * The first revision of Wiseman silicon (rev 2.0) has an errata 20573526Sxy150489 * that requires the receiver to be in reset when any of the 20583526Sxy150489 * receive address registers (RAR regs) are accessed. The first 20593526Sxy150489 * rev of Wiseman silicon also requires MWI to be disabled when 20603526Sxy150489 * a global reset or a receive reset is issued. So before we 20613526Sxy150489 * initialize the RARs, we check the rev of the Wiseman controller 20623526Sxy150489 * and work around any necessary HW errata. 20633526Sxy150489 */ 20644919Sxy150489 if ((hw->mac.type == e1000_82542) && 20654919Sxy150489 (hw->revision_id == E1000_REVISION_2)) { 20663526Sxy150489 e1000_pci_clear_mwi(hw); 20674919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST); 20684919Sxy150489 msec_delay(5); 20693526Sxy150489 } 20704919Sxy150489 #endif 20713526Sxy150489 20723526Sxy150489 bcopy(mac_addr, Adapter->unicst_addr[slot].mac.addr, ETHERADDRL); 20733526Sxy150489 e1000_rar_set(hw, (uint8_t *)mac_addr, slot); 20743526Sxy150489 20753526Sxy150489 if (slot == 0) { 20764919Sxy150489 if ((hw->mac.type == e1000_82571) && 20774919Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) 20784919Sxy150489 e1000_rar_set(hw, (uint8_t *)mac_addr, LAST_RAR_ENTRY); 20793526Sxy150489 } 20803526Sxy150489 20814919Sxy150489 #ifndef NO_82542_SUPPORT 20823526Sxy150489 /* 20833526Sxy150489 * If we are using Wiseman rev 2.0 silicon, we will have previously 20843526Sxy150489 * put the receive in reset, and disabled MWI, to work around some 20853526Sxy150489 * HW errata. Now we should take the receiver out of reset, and 20863526Sxy150489 * re-enabled if MWI if it was previously enabled by the PCI BIOS. 20873526Sxy150489 */ 20884919Sxy150489 if ((hw->mac.type == e1000_82542) && 20894919Sxy150489 (hw->revision_id == E1000_REVISION_2)) { 20904919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, 0); 20914919Sxy150489 msec_delay(1); 20924919Sxy150489 if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) 20933526Sxy150489 e1000_pci_set_mwi(hw); 20944919Sxy150489 e1000g_rx_setup(Adapter); 20953526Sxy150489 } 20964919Sxy150489 #endif 20973526Sxy150489 20983526Sxy150489 rw_exit(&Adapter->chip_lock); 20993526Sxy150489 21005273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 21015273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 21025273Sgl147354 return (EIO); 21035273Sgl147354 } 21045273Sgl147354 21053526Sxy150489 return (0); 21063526Sxy150489 } 21073526Sxy150489 21083526Sxy150489 /* 21093526Sxy150489 * e1000g_m_unicst_add() - will find an unused address slot, set the 21103526Sxy150489 * address value to the one specified, reserve that slot and enable 21113526Sxy150489 * the NIC to start filtering on the new MAC address. 21123526Sxy150489 * Returns 0 on success. 21133526Sxy150489 */ 21143526Sxy150489 static int 21153526Sxy150489 e1000g_m_unicst_add(void *arg, mac_multi_addr_t *maddr) 21163526Sxy150489 { 21173526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 21183526Sxy150489 mac_addr_slot_t slot; 21193526Sxy150489 int err; 21203526Sxy150489 21213526Sxy150489 if (mac_unicst_verify(Adapter->mh, 21223526Sxy150489 maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) 21233526Sxy150489 return (EINVAL); 21243526Sxy150489 21253526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 21263526Sxy150489 if (Adapter->unicst_avail == 0) { 21273526Sxy150489 /* no slots available */ 21283526Sxy150489 rw_exit(&Adapter->chip_lock); 21293526Sxy150489 return (ENOSPC); 21303526Sxy150489 } 21313526Sxy150489 21323526Sxy150489 /* 21333526Sxy150489 * Primary/default address is in slot 0. The next addresses 21343526Sxy150489 * are the multiple MAC addresses. So multiple MAC address 0 21353526Sxy150489 * is in slot 1, 1 in slot 2, and so on. So the first multiple 21363526Sxy150489 * MAC address resides in slot 1. 21373526Sxy150489 */ 21383526Sxy150489 for (slot = 1; slot < Adapter->unicst_total; slot++) { 21393526Sxy150489 if (Adapter->unicst_addr[slot].mac.set == 0) { 21403526Sxy150489 Adapter->unicst_addr[slot].mac.set = 1; 21413526Sxy150489 break; 21423526Sxy150489 } 21433526Sxy150489 } 21443526Sxy150489 21453526Sxy150489 ASSERT((slot > 0) && (slot < Adapter->unicst_total)); 21463526Sxy150489 21473526Sxy150489 Adapter->unicst_avail--; 21483526Sxy150489 rw_exit(&Adapter->chip_lock); 21493526Sxy150489 21503526Sxy150489 maddr->mma_slot = slot; 21513526Sxy150489 21523526Sxy150489 if ((err = e1000g_unicst_set(Adapter, maddr->mma_addr, slot)) != 0) { 21533526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 21543526Sxy150489 Adapter->unicst_addr[slot].mac.set = 0; 21553526Sxy150489 Adapter->unicst_avail++; 21563526Sxy150489 rw_exit(&Adapter->chip_lock); 21573526Sxy150489 } 21583526Sxy150489 21593526Sxy150489 return (err); 21603526Sxy150489 } 21613526Sxy150489 21623526Sxy150489 /* 21633526Sxy150489 * e1000g_m_unicst_remove() - removes a MAC address that was added by a 21643526Sxy150489 * call to e1000g_m_unicst_add(). The slot number that was returned in 21653526Sxy150489 * e1000g_m_unicst_add() is passed in the call to remove the address. 21663526Sxy150489 * Returns 0 on success. 21673526Sxy150489 */ 21683526Sxy150489 static int 21693526Sxy150489 e1000g_m_unicst_remove(void *arg, mac_addr_slot_t slot) 21703526Sxy150489 { 21713526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 21723526Sxy150489 int err; 21733526Sxy150489 21743526Sxy150489 if ((slot <= 0) || (slot >= Adapter->unicst_total)) 21753526Sxy150489 return (EINVAL); 21763526Sxy150489 21773526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 21783526Sxy150489 if (Adapter->unicst_addr[slot].mac.set == 1) { 21793526Sxy150489 Adapter->unicst_addr[slot].mac.set = 0; 21803526Sxy150489 Adapter->unicst_avail++; 21813526Sxy150489 rw_exit(&Adapter->chip_lock); 21823526Sxy150489 21833526Sxy150489 /* Copy the default address to the passed slot */ 21843526Sxy150489 if (err = e1000g_unicst_set(Adapter, 21853526Sxy150489 Adapter->unicst_addr[0].mac.addr, slot) != 0) { 21863526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 21873526Sxy150489 Adapter->unicst_addr[slot].mac.set = 1; 21883526Sxy150489 Adapter->unicst_avail--; 21893526Sxy150489 rw_exit(&Adapter->chip_lock); 21903526Sxy150489 } 21913526Sxy150489 return (err); 21923526Sxy150489 } 21933526Sxy150489 rw_exit(&Adapter->chip_lock); 21943526Sxy150489 21953526Sxy150489 return (EINVAL); 21963526Sxy150489 } 21973526Sxy150489 21983526Sxy150489 /* 21993526Sxy150489 * e1000g_m_unicst_modify() - modifies the value of an address that 22003526Sxy150489 * has been added by e1000g_m_unicst_add(). The new address, address 22013526Sxy150489 * length and the slot number that was returned in the call to add 22023526Sxy150489 * should be passed to e1000g_m_unicst_modify(). mma_flags should be 22033526Sxy150489 * set to 0. Returns 0 on success. 22043526Sxy150489 */ 22053526Sxy150489 static int 22063526Sxy150489 e1000g_m_unicst_modify(void *arg, mac_multi_addr_t *maddr) 22073526Sxy150489 { 22083526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 22093526Sxy150489 mac_addr_slot_t slot; 22103526Sxy150489 22113526Sxy150489 if (mac_unicst_verify(Adapter->mh, 22123526Sxy150489 maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) 22133526Sxy150489 return (EINVAL); 22143526Sxy150489 22153526Sxy150489 slot = maddr->mma_slot; 22163526Sxy150489 22173526Sxy150489 if ((slot <= 0) || (slot >= Adapter->unicst_total)) 22183526Sxy150489 return (EINVAL); 22193526Sxy150489 22203526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 22213526Sxy150489 if (Adapter->unicst_addr[slot].mac.set == 1) { 22223526Sxy150489 rw_exit(&Adapter->chip_lock); 22233526Sxy150489 22243526Sxy150489 return (e1000g_unicst_set(Adapter, maddr->mma_addr, slot)); 22253526Sxy150489 } 22263526Sxy150489 rw_exit(&Adapter->chip_lock); 22273526Sxy150489 22283526Sxy150489 return (EINVAL); 22293526Sxy150489 } 22303526Sxy150489 22313526Sxy150489 /* 22323526Sxy150489 * e1000g_m_unicst_get() - will get the MAC address and all other 22333526Sxy150489 * information related to the address slot passed in mac_multi_addr_t. 22343526Sxy150489 * mma_flags should be set to 0 in the call. 22353526Sxy150489 * On return, mma_flags can take the following values: 22363526Sxy150489 * 1) MMAC_SLOT_UNUSED 22373526Sxy150489 * 2) MMAC_SLOT_USED | MMAC_VENDOR_ADDR 22383526Sxy150489 * 3) MMAC_SLOT_UNUSED | MMAC_VENDOR_ADDR 22393526Sxy150489 * 4) MMAC_SLOT_USED 22403526Sxy150489 */ 22413526Sxy150489 static int 22423526Sxy150489 e1000g_m_unicst_get(void *arg, mac_multi_addr_t *maddr) 22433526Sxy150489 { 22443526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 22453526Sxy150489 mac_addr_slot_t slot; 22463526Sxy150489 22473526Sxy150489 slot = maddr->mma_slot; 22483526Sxy150489 22493526Sxy150489 if ((slot <= 0) || (slot >= Adapter->unicst_total)) 22503526Sxy150489 return (EINVAL); 22513526Sxy150489 22523526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 22533526Sxy150489 if (Adapter->unicst_addr[slot].mac.set == 1) { 22543526Sxy150489 bcopy(Adapter->unicst_addr[slot].mac.addr, 22553526Sxy150489 maddr->mma_addr, ETHERADDRL); 22563526Sxy150489 maddr->mma_flags = MMAC_SLOT_USED; 22573526Sxy150489 } else { 22583526Sxy150489 maddr->mma_flags = MMAC_SLOT_UNUSED; 22593526Sxy150489 } 22603526Sxy150489 rw_exit(&Adapter->chip_lock); 22613526Sxy150489 22623526Sxy150489 return (0); 22633526Sxy150489 } 22643526Sxy150489 22653526Sxy150489 static int 22663526Sxy150489 multicst_add(struct e1000g *Adapter, const uint8_t *multiaddr) 22673526Sxy150489 { 22684919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 22693526Sxy150489 unsigned i; 22703526Sxy150489 int res = 0; 22713526Sxy150489 22723526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 22733526Sxy150489 22743526Sxy150489 if ((multiaddr[0] & 01) == 0) { 22753526Sxy150489 res = EINVAL; 22763526Sxy150489 goto done; 22773526Sxy150489 } 22783526Sxy150489 22793526Sxy150489 if (Adapter->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) { 22803526Sxy150489 res = ENOENT; 22813526Sxy150489 goto done; 22823526Sxy150489 } 22833526Sxy150489 22843526Sxy150489 bcopy(multiaddr, 22853526Sxy150489 &Adapter->mcast_table[Adapter->mcast_count], ETHERADDRL); 22863526Sxy150489 Adapter->mcast_count++; 22873526Sxy150489 22883526Sxy150489 /* 22893526Sxy150489 * Update the MC table in the hardware 22903526Sxy150489 */ 22914919Sxy150489 e1000g_clear_interrupt(Adapter); 22924919Sxy150489 22934919Sxy150489 e1000g_setup_multicast(Adapter); 22944919Sxy150489 22954919Sxy150489 #ifndef NO_82542_SUPPORT 22964919Sxy150489 if ((hw->mac.type == e1000_82542) && 22974919Sxy150489 (hw->revision_id == E1000_REVISION_2)) 22984919Sxy150489 e1000g_rx_setup(Adapter); 22994919Sxy150489 #endif 23004919Sxy150489 23014919Sxy150489 e1000g_mask_interrupt(Adapter); 23023526Sxy150489 23033526Sxy150489 done: 23043526Sxy150489 rw_exit(&Adapter->chip_lock); 23055273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 23065273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 23075273Sgl147354 res = EIO; 23085273Sgl147354 } 23095273Sgl147354 23103526Sxy150489 return (res); 23113526Sxy150489 } 23123526Sxy150489 23133526Sxy150489 static int 23143526Sxy150489 multicst_remove(struct e1000g *Adapter, const uint8_t *multiaddr) 23153526Sxy150489 { 23164919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 23173526Sxy150489 unsigned i; 23183526Sxy150489 23193526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 23203526Sxy150489 23213526Sxy150489 for (i = 0; i < Adapter->mcast_count; i++) { 23223526Sxy150489 if (bcmp(multiaddr, &Adapter->mcast_table[i], 23233526Sxy150489 ETHERADDRL) == 0) { 23243526Sxy150489 for (i++; i < Adapter->mcast_count; i++) { 23253526Sxy150489 Adapter->mcast_table[i - 1] = 23263526Sxy150489 Adapter->mcast_table[i]; 23273526Sxy150489 } 23283526Sxy150489 Adapter->mcast_count--; 23293526Sxy150489 break; 23303526Sxy150489 } 23313526Sxy150489 } 23323526Sxy150489 23333526Sxy150489 /* 23343526Sxy150489 * Update the MC table in the hardware 23353526Sxy150489 */ 23364919Sxy150489 e1000g_clear_interrupt(Adapter); 23374919Sxy150489 23384919Sxy150489 e1000g_setup_multicast(Adapter); 23394919Sxy150489 23404919Sxy150489 #ifndef NO_82542_SUPPORT 23414919Sxy150489 if ((hw->mac.type == e1000_82542) && 23424919Sxy150489 (hw->revision_id == E1000_REVISION_2)) 23434919Sxy150489 e1000g_rx_setup(Adapter); 23444919Sxy150489 #endif 23454919Sxy150489 23464919Sxy150489 e1000g_mask_interrupt(Adapter); 23473526Sxy150489 23483526Sxy150489 done: 23493526Sxy150489 rw_exit(&Adapter->chip_lock); 23505273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 23515273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 23525273Sgl147354 return (EIO); 23535273Sgl147354 } 23545273Sgl147354 23553526Sxy150489 return (0); 23563526Sxy150489 } 23573526Sxy150489 23584919Sxy150489 /* 23594919Sxy150489 * e1000g_setup_multicast - setup multicast data structures 23604919Sxy150489 * 23614919Sxy150489 * This routine initializes all of the multicast related structures. 23624919Sxy150489 */ 23634919Sxy150489 void 23644919Sxy150489 e1000g_setup_multicast(struct e1000g *Adapter) 23654919Sxy150489 { 23664919Sxy150489 uint8_t *mc_addr_list; 23674919Sxy150489 uint32_t mc_addr_count; 23684919Sxy150489 uint32_t rctl; 23694919Sxy150489 struct e1000_hw *hw; 23704919Sxy150489 23714919Sxy150489 hw = &Adapter->shared; 23724919Sxy150489 23734919Sxy150489 /* 23744919Sxy150489 * The e1000g has the ability to do perfect filtering of 16 23754919Sxy150489 * addresses. The driver uses one of the e1000g's 16 receive 23764919Sxy150489 * address registers for its node/network/mac/individual address. 23774919Sxy150489 * So, we have room for up to 15 multicast addresses in the CAM, 23784919Sxy150489 * additional MC addresses are handled by the MTA (Multicast Table 23794919Sxy150489 * Array) 23804919Sxy150489 */ 23814919Sxy150489 23824919Sxy150489 rctl = E1000_READ_REG(hw, E1000_RCTL); 23834919Sxy150489 23844919Sxy150489 mc_addr_list = (uint8_t *)Adapter->mcast_table; 23854919Sxy150489 23864919Sxy150489 if (Adapter->mcast_count > MAX_NUM_MULTICAST_ADDRESSES) { 23874919Sxy150489 E1000G_DEBUGLOG_1(Adapter, CE_WARN, 23884919Sxy150489 "Adapter requested more than %d MC Addresses.\n", 23894919Sxy150489 MAX_NUM_MULTICAST_ADDRESSES); 23904919Sxy150489 mc_addr_count = MAX_NUM_MULTICAST_ADDRESSES; 23914919Sxy150489 } else { 23924919Sxy150489 /* 23934919Sxy150489 * Set the number of MC addresses that we are being 23944919Sxy150489 * requested to use 23954919Sxy150489 */ 23964919Sxy150489 mc_addr_count = Adapter->mcast_count; 23974919Sxy150489 } 23984919Sxy150489 #ifndef NO_82542_SUPPORT 23994919Sxy150489 /* 24004919Sxy150489 * The Wiseman 2.0 silicon has an errata by which the receiver will 24014919Sxy150489 * hang while writing to the receive address registers if the receiver 24024919Sxy150489 * is not in reset before writing to the registers. Updating the RAR 24034919Sxy150489 * is done during the setting up of the multicast table, hence the 24044919Sxy150489 * receiver has to be put in reset before updating the multicast table 24054919Sxy150489 * and then taken out of reset at the end 24064919Sxy150489 */ 24074919Sxy150489 /* 24084919Sxy150489 * if WMI was enabled then dis able it before issueing the global 24094919Sxy150489 * reset to the hardware. 24104919Sxy150489 */ 24114919Sxy150489 /* 24124919Sxy150489 * Only required for WISEMAN_2_0 24134919Sxy150489 */ 24144919Sxy150489 if ((hw->mac.type == e1000_82542) && 24154919Sxy150489 (hw->revision_id == E1000_REVISION_2)) { 24164919Sxy150489 e1000_pci_clear_mwi(hw); 24174919Sxy150489 /* 24184919Sxy150489 * The e1000g must be in reset before changing any RA 24194919Sxy150489 * registers. Reset receive unit. The chip will remain in 24204919Sxy150489 * the reset state until software explicitly restarts it. 24214919Sxy150489 */ 24224919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST); 24234919Sxy150489 /* Allow receiver time to go in to reset */ 24244919Sxy150489 msec_delay(5); 24254919Sxy150489 } 24264919Sxy150489 #endif 24274919Sxy150489 24284919Sxy150489 e1000_mc_addr_list_update(hw, mc_addr_list, mc_addr_count, 24294919Sxy150489 Adapter->unicst_total, hw->mac.rar_entry_count); 24304919Sxy150489 24314919Sxy150489 #ifndef NO_82542_SUPPORT 24324919Sxy150489 /* 24334919Sxy150489 * Only for Wiseman_2_0 24344919Sxy150489 * If MWI was enabled then re-enable it after issueing (as we 24354919Sxy150489 * disabled it up there) the receive reset command. 24364919Sxy150489 * Wainwright does not have a receive reset command and only thing 24374919Sxy150489 * close to it is global reset which will require tx setup also 24384919Sxy150489 */ 24394919Sxy150489 if ((hw->mac.type == e1000_82542) && 24404919Sxy150489 (hw->revision_id == E1000_REVISION_2)) { 24414919Sxy150489 /* 24424919Sxy150489 * if WMI was enabled then reenable it after issueing the 24434919Sxy150489 * global or receive reset to the hardware. 24444919Sxy150489 */ 24454919Sxy150489 24464919Sxy150489 /* 24474919Sxy150489 * Take receiver out of reset 24484919Sxy150489 * clear E1000_RCTL_RST bit (and all others) 24494919Sxy150489 */ 24504919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, 0); 24514919Sxy150489 msec_delay(5); 24524919Sxy150489 if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) 24534919Sxy150489 e1000_pci_set_mwi(hw); 24544919Sxy150489 } 24554919Sxy150489 #endif 24564919Sxy150489 24574919Sxy150489 /* 24584919Sxy150489 * Restore original value 24594919Sxy150489 */ 24604919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, rctl); 24614919Sxy150489 } 24624919Sxy150489 24633526Sxy150489 int 24643526Sxy150489 e1000g_m_multicst(void *arg, boolean_t add, const uint8_t *addr) 24653526Sxy150489 { 24663526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 24673526Sxy150489 24683526Sxy150489 return ((add) ? multicst_add(Adapter, addr) 24694349Sxy150489 : multicst_remove(Adapter, addr)); 24703526Sxy150489 } 24713526Sxy150489 24723526Sxy150489 int 24733526Sxy150489 e1000g_m_promisc(void *arg, boolean_t on) 24743526Sxy150489 { 24753526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 24764919Sxy150489 uint32_t rctl; 24773526Sxy150489 24783526Sxy150489 rw_enter(&Adapter->chip_lock, RW_WRITER); 24793526Sxy150489 24804919Sxy150489 rctl = E1000_READ_REG(&Adapter->shared, E1000_RCTL); 24813526Sxy150489 24823526Sxy150489 if (on) 24834919Sxy150489 rctl |= 24843526Sxy150489 (E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_BAM); 24853526Sxy150489 else 24864919Sxy150489 rctl &= (~(E1000_RCTL_UPE | E1000_RCTL_MPE)); 24874919Sxy150489 24884919Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_RCTL, rctl); 24893526Sxy150489 24903526Sxy150489 Adapter->e1000g_promisc = on; 24913526Sxy150489 24923526Sxy150489 rw_exit(&Adapter->chip_lock); 24933526Sxy150489 24945273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 24955273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 24965273Sgl147354 return (EIO); 24975273Sgl147354 } 24985273Sgl147354 24993526Sxy150489 return (0); 25003526Sxy150489 } 25013526Sxy150489 25023526Sxy150489 static boolean_t 25033526Sxy150489 e1000g_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 25043526Sxy150489 { 25053526Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 25064919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 25073526Sxy150489 25083526Sxy150489 switch (cap) { 25093526Sxy150489 case MAC_CAPAB_HCKSUM: { 25103526Sxy150489 uint32_t *txflags = cap_data; 25113526Sxy150489 /* 25123526Sxy150489 * Checksum on/off selection via global parameters. 25133526Sxy150489 * 25143526Sxy150489 * If the chip is flagged as not capable of (correctly) 25154919Sxy150489 * handling checksumming, we don't enable it on either 25163526Sxy150489 * Rx or Tx side. Otherwise, we take this chip's settings 25173526Sxy150489 * from the patchable global defaults. 25183526Sxy150489 * 25193526Sxy150489 * We advertise our capabilities only if TX offload is 25203526Sxy150489 * enabled. On receive, the stack will accept checksummed 25213526Sxy150489 * packets anyway, even if we haven't said we can deliver 25223526Sxy150489 * them. 25233526Sxy150489 */ 25244919Sxy150489 switch (hw->mac.type) { 25253526Sxy150489 case e1000_82540: 25264919Sxy150489 case e1000_82544: 25273526Sxy150489 case e1000_82545: 25284919Sxy150489 case e1000_82545_rev_3: 25294919Sxy150489 case e1000_82546: 25304919Sxy150489 case e1000_82546_rev_3: 25313526Sxy150489 case e1000_82571: 25323526Sxy150489 case e1000_82572: 25333526Sxy150489 case e1000_82573: 25343526Sxy150489 case e1000_80003es2lan: 25356011Ssv141092 if (Adapter->tx_hcksum_enabled) 25366011Ssv141092 *txflags = HCKSUM_IPHDRCKSUM | 25376011Ssv141092 HCKSUM_INET_PARTIAL; 25386011Ssv141092 else 25396011Ssv141092 return (B_FALSE); 25403526Sxy150489 break; 25413526Sxy150489 25423526Sxy150489 /* 25434919Sxy150489 * For the following Intel PRO/1000 chipsets, we have not 25444919Sxy150489 * tested the hardware checksum offload capability, so we 25454919Sxy150489 * disable the capability for them. 25464919Sxy150489 * e1000_82542, 25473526Sxy150489 * e1000_82543, 25483526Sxy150489 * e1000_82541, 25493526Sxy150489 * e1000_82541_rev_2, 25503526Sxy150489 * e1000_82547, 25513526Sxy150489 * e1000_82547_rev_2, 25523526Sxy150489 */ 25533526Sxy150489 default: 25543526Sxy150489 return (B_FALSE); 25553526Sxy150489 } 25563526Sxy150489 25573526Sxy150489 break; 25583526Sxy150489 } 25593526Sxy150489 case MAC_CAPAB_POLL: 25603526Sxy150489 /* 25613526Sxy150489 * There's nothing for us to fill in, simply returning 25623526Sxy150489 * B_TRUE stating that we support polling is sufficient. 25633526Sxy150489 */ 25643526Sxy150489 break; 25653526Sxy150489 25663526Sxy150489 case MAC_CAPAB_MULTIADDRESS: { 25673526Sxy150489 multiaddress_capab_t *mmacp = cap_data; 25683526Sxy150489 25693526Sxy150489 /* 25703526Sxy150489 * The number of MAC addresses made available by 25713526Sxy150489 * this capability is one less than the total as 25723526Sxy150489 * the primary address in slot 0 is counted in 25733526Sxy150489 * the total. 25743526Sxy150489 */ 25753526Sxy150489 mmacp->maddr_naddr = Adapter->unicst_total - 1; 25763526Sxy150489 mmacp->maddr_naddrfree = Adapter->unicst_avail; 25773526Sxy150489 /* No multiple factory addresses, set mma_flag to 0 */ 25783526Sxy150489 mmacp->maddr_flag = 0; 25793526Sxy150489 mmacp->maddr_handle = Adapter; 25803526Sxy150489 mmacp->maddr_add = e1000g_m_unicst_add; 25813526Sxy150489 mmacp->maddr_remove = e1000g_m_unicst_remove; 25823526Sxy150489 mmacp->maddr_modify = e1000g_m_unicst_modify; 25833526Sxy150489 mmacp->maddr_get = e1000g_m_unicst_get; 25843526Sxy150489 mmacp->maddr_reserve = NULL; 25853526Sxy150489 break; 25863526Sxy150489 } 25873526Sxy150489 default: 25883526Sxy150489 return (B_FALSE); 25893526Sxy150489 } 25903526Sxy150489 return (B_TRUE); 25913526Sxy150489 } 25923526Sxy150489 2593*6394Scc210113 static boolean_t 2594*6394Scc210113 e1000g_param_locked(mac_prop_id_t pr_num) 2595*6394Scc210113 { 2596*6394Scc210113 /* 2597*6394Scc210113 * All en_* parameters are locked (read-only) while 2598*6394Scc210113 * the device is in any sort of loopback mode ... 2599*6394Scc210113 */ 2600*6394Scc210113 switch (pr_num) { 2601*6394Scc210113 case DLD_PROP_EN_1000FDX_CAP: 2602*6394Scc210113 case DLD_PROP_EN_1000HDX_CAP: 2603*6394Scc210113 case DLD_PROP_EN_100FDX_CAP: 2604*6394Scc210113 case DLD_PROP_EN_100HDX_CAP: 2605*6394Scc210113 case DLD_PROP_EN_10FDX_CAP: 2606*6394Scc210113 case DLD_PROP_EN_10HDX_CAP: 2607*6394Scc210113 case DLD_PROP_AUTONEG: 2608*6394Scc210113 case DLD_PROP_FLOWCTRL: 2609*6394Scc210113 return (B_TRUE); 2610*6394Scc210113 } 2611*6394Scc210113 return (B_FALSE); 2612*6394Scc210113 } 2613*6394Scc210113 2614*6394Scc210113 /* 2615*6394Scc210113 * callback function for set/get of properties 2616*6394Scc210113 */ 2617*6394Scc210113 static int 2618*6394Scc210113 e1000g_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 2619*6394Scc210113 uint_t pr_valsize, const void *pr_val) 2620*6394Scc210113 { 2621*6394Scc210113 struct e1000g *Adapter = arg; 2622*6394Scc210113 struct e1000_mac_info *mac = &Adapter->shared.mac; 2623*6394Scc210113 struct e1000_phy_info *phy = &Adapter->shared.phy; 2624*6394Scc210113 e1000g_tx_ring_t *tx_ring; 2625*6394Scc210113 int err = 0; 2626*6394Scc210113 link_flowctrl_t fc; 2627*6394Scc210113 uint64_t cur_mtu, new_mtu; 2628*6394Scc210113 uint64_t tmp = 0; 2629*6394Scc210113 2630*6394Scc210113 rw_enter(&Adapter->chip_lock, RW_WRITER); 2631*6394Scc210113 if (Adapter->loopback_mode != E1000G_LB_NONE && 2632*6394Scc210113 e1000g_param_locked(pr_num)) { 2633*6394Scc210113 /* 2634*6394Scc210113 * All en_* parameters are locked (read-only) 2635*6394Scc210113 * while the device is in any sort of loopback mode. 2636*6394Scc210113 */ 2637*6394Scc210113 rw_exit(&Adapter->chip_lock); 2638*6394Scc210113 return (EBUSY); 2639*6394Scc210113 } 2640*6394Scc210113 2641*6394Scc210113 switch (pr_num) { 2642*6394Scc210113 case DLD_PROP_EN_1000FDX_CAP: 2643*6394Scc210113 Adapter->param_en_1000fdx = *(uint8_t *)pr_val; 2644*6394Scc210113 Adapter->param_adv_1000fdx = *(uint8_t *)pr_val; 2645*6394Scc210113 goto reset; 2646*6394Scc210113 case DLD_PROP_EN_1000HDX_CAP: 2647*6394Scc210113 Adapter->param_en_1000hdx = *(uint8_t *)pr_val; 2648*6394Scc210113 Adapter->param_adv_1000hdx = *(uint8_t *)pr_val; 2649*6394Scc210113 goto reset; 2650*6394Scc210113 case DLD_PROP_EN_100FDX_CAP: 2651*6394Scc210113 Adapter->param_en_100fdx = *(uint8_t *)pr_val; 2652*6394Scc210113 Adapter->param_adv_100fdx = *(uint8_t *)pr_val; 2653*6394Scc210113 goto reset; 2654*6394Scc210113 case DLD_PROP_EN_100HDX_CAP: 2655*6394Scc210113 Adapter->param_en_100hdx = *(uint8_t *)pr_val; 2656*6394Scc210113 Adapter->param_adv_100hdx = *(uint8_t *)pr_val; 2657*6394Scc210113 goto reset; 2658*6394Scc210113 case DLD_PROP_EN_10FDX_CAP: 2659*6394Scc210113 Adapter->param_en_10fdx = *(uint8_t *)pr_val; 2660*6394Scc210113 Adapter->param_adv_10fdx = *(uint8_t *)pr_val; 2661*6394Scc210113 goto reset; 2662*6394Scc210113 case DLD_PROP_EN_10HDX_CAP: 2663*6394Scc210113 Adapter->param_en_10hdx = *(uint8_t *)pr_val; 2664*6394Scc210113 Adapter->param_adv_10hdx = *(uint8_t *)pr_val; 2665*6394Scc210113 goto reset; 2666*6394Scc210113 case DLD_PROP_AUTONEG: 2667*6394Scc210113 Adapter->param_adv_autoneg = *(uint8_t *)pr_val; 2668*6394Scc210113 goto reset; 2669*6394Scc210113 case DLD_PROP_FLOWCTRL: 2670*6394Scc210113 mac->fc_send_xon = B_TRUE; 2671*6394Scc210113 bcopy(pr_val, &fc, sizeof (fc)); 2672*6394Scc210113 2673*6394Scc210113 switch (fc) { 2674*6394Scc210113 default: 2675*6394Scc210113 err = EINVAL; 2676*6394Scc210113 break; 2677*6394Scc210113 case LINK_FLOWCTRL_NONE: 2678*6394Scc210113 mac->fc = e1000_fc_none; 2679*6394Scc210113 break; 2680*6394Scc210113 case LINK_FLOWCTRL_RX: 2681*6394Scc210113 mac->fc = e1000_fc_rx_pause; 2682*6394Scc210113 break; 2683*6394Scc210113 case LINK_FLOWCTRL_TX: 2684*6394Scc210113 mac->fc = e1000_fc_tx_pause; 2685*6394Scc210113 break; 2686*6394Scc210113 case LINK_FLOWCTRL_BI: 2687*6394Scc210113 mac->fc = e1000_fc_full; 2688*6394Scc210113 break; 2689*6394Scc210113 } 2690*6394Scc210113 reset: 2691*6394Scc210113 if (err == 0) { 2692*6394Scc210113 if (e1000g_reset_link(Adapter) != DDI_SUCCESS) 2693*6394Scc210113 err = EINVAL; 2694*6394Scc210113 } 2695*6394Scc210113 break; 2696*6394Scc210113 case DLD_PROP_ADV_1000FDX_CAP: 2697*6394Scc210113 case DLD_PROP_ADV_1000HDX_CAP: 2698*6394Scc210113 case DLD_PROP_ADV_100FDX_CAP: 2699*6394Scc210113 case DLD_PROP_ADV_100HDX_CAP: 2700*6394Scc210113 case DLD_PROP_ADV_10FDX_CAP: 2701*6394Scc210113 case DLD_PROP_ADV_10HDX_CAP: 2702*6394Scc210113 case DLD_PROP_STATUS: 2703*6394Scc210113 case DLD_PROP_SPEED: 2704*6394Scc210113 case DLD_PROP_DUPLEX: 2705*6394Scc210113 err = ENOTSUP; /* read-only prop. Can't set this. */ 2706*6394Scc210113 break; 2707*6394Scc210113 case DLD_PROP_DEFMTU: 2708*6394Scc210113 cur_mtu = Adapter->default_mtu; 2709*6394Scc210113 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 2710*6394Scc210113 if (new_mtu == cur_mtu) { 2711*6394Scc210113 err = 0; 2712*6394Scc210113 break; 2713*6394Scc210113 } 2714*6394Scc210113 2715*6394Scc210113 tmp = new_mtu + sizeof (struct ether_vlan_header) + 2716*6394Scc210113 ETHERFCSL; 2717*6394Scc210113 if ((tmp < DEFAULT_FRAME_SIZE) || 2718*6394Scc210113 (tmp > MAXIMUM_FRAME_SIZE)) { 2719*6394Scc210113 err = EINVAL; 2720*6394Scc210113 break; 2721*6394Scc210113 } 2722*6394Scc210113 2723*6394Scc210113 /* ich8 doed not support jumbo frames */ 2724*6394Scc210113 if ((mac->type == e1000_ich8lan) && 2725*6394Scc210113 (tmp > DEFAULT_FRAME_SIZE)) { 2726*6394Scc210113 err = EINVAL; 2727*6394Scc210113 break; 2728*6394Scc210113 } 2729*6394Scc210113 /* ich9 does not do jumbo frames on one phy type */ 2730*6394Scc210113 if ((mac->type == e1000_ich9lan) && 2731*6394Scc210113 (phy->type == e1000_phy_ife) && 2732*6394Scc210113 (tmp > DEFAULT_FRAME_SIZE)) { 2733*6394Scc210113 err = EINVAL; 2734*6394Scc210113 break; 2735*6394Scc210113 } 2736*6394Scc210113 if (Adapter->chip_state != E1000G_STOP) { 2737*6394Scc210113 err = EBUSY; 2738*6394Scc210113 break; 2739*6394Scc210113 } 2740*6394Scc210113 2741*6394Scc210113 err = mac_maxsdu_update(Adapter->mh, new_mtu); 2742*6394Scc210113 if (err == 0) { 2743*6394Scc210113 mac->max_frame_size = tmp; 2744*6394Scc210113 Adapter->default_mtu = new_mtu; 2745*6394Scc210113 e1000g_set_bufsize(Adapter); 2746*6394Scc210113 tx_ring = Adapter->tx_ring; 2747*6394Scc210113 tx_ring->frags_limit = (mac->max_frame_size / 2748*6394Scc210113 Adapter->tx_bcopy_thresh) + 2; 2749*6394Scc210113 if (tx_ring->frags_limit > 2750*6394Scc210113 (MAX_TX_DESC_PER_PACKET >> 1)) 2751*6394Scc210113 tx_ring->frags_limit = 2752*6394Scc210113 (MAX_TX_DESC_PER_PACKET >> 1); 2753*6394Scc210113 } 2754*6394Scc210113 break; 2755*6394Scc210113 case DLD_PROP_PRIVATE: 2756*6394Scc210113 err = e1000g_set_priv_prop(Adapter, pr_name, 2757*6394Scc210113 pr_valsize, pr_val); 2758*6394Scc210113 break; 2759*6394Scc210113 default: 2760*6394Scc210113 err = ENOTSUP; 2761*6394Scc210113 break; 2762*6394Scc210113 } 2763*6394Scc210113 rw_exit(&Adapter->chip_lock); 2764*6394Scc210113 return (err); 2765*6394Scc210113 } 2766*6394Scc210113 2767*6394Scc210113 static int 2768*6394Scc210113 e1000g_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 2769*6394Scc210113 uint_t pr_valsize, void *pr_val) 2770*6394Scc210113 { 2771*6394Scc210113 struct e1000g *Adapter = arg; 2772*6394Scc210113 struct e1000_mac_info *mac = &Adapter->shared.mac; 2773*6394Scc210113 int err = EINVAL; 2774*6394Scc210113 link_flowctrl_t fc; 2775*6394Scc210113 uint64_t tmp = 0; 2776*6394Scc210113 2777*6394Scc210113 bzero(pr_val, pr_valsize); 2778*6394Scc210113 switch (pr_num) { 2779*6394Scc210113 case DLD_PROP_DUPLEX: 2780*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2781*6394Scc210113 *(uint8_t *)pr_val = Adapter->link_duplex; 2782*6394Scc210113 err = 0; 2783*6394Scc210113 } 2784*6394Scc210113 break; 2785*6394Scc210113 case DLD_PROP_SPEED: 2786*6394Scc210113 if (pr_valsize >= sizeof (uint64_t)) { 2787*6394Scc210113 tmp = Adapter->link_speed * 1000000ull; 2788*6394Scc210113 bcopy(&tmp, pr_val, sizeof (tmp)); 2789*6394Scc210113 err = 0; 2790*6394Scc210113 } 2791*6394Scc210113 break; 2792*6394Scc210113 case DLD_PROP_STATUS: 2793*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2794*6394Scc210113 *(uint8_t *)pr_val = Adapter->link_state; 2795*6394Scc210113 err = 0; 2796*6394Scc210113 } 2797*6394Scc210113 break; 2798*6394Scc210113 case DLD_PROP_AUTONEG: 2799*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2800*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_adv_autoneg; 2801*6394Scc210113 err = 0; 2802*6394Scc210113 } 2803*6394Scc210113 break; 2804*6394Scc210113 case DLD_PROP_DEFMTU: 2805*6394Scc210113 if (pr_valsize >= sizeof (uint64_t)) { 2806*6394Scc210113 tmp = Adapter->default_mtu; 2807*6394Scc210113 bcopy(&tmp, pr_val, sizeof (tmp)); 2808*6394Scc210113 err = 0; 2809*6394Scc210113 } 2810*6394Scc210113 break; 2811*6394Scc210113 case DLD_PROP_FLOWCTRL: 2812*6394Scc210113 if (pr_valsize >= sizeof (link_flowctrl_t)) { 2813*6394Scc210113 switch (mac->fc) { 2814*6394Scc210113 case e1000_fc_none: 2815*6394Scc210113 fc = LINK_FLOWCTRL_NONE; 2816*6394Scc210113 break; 2817*6394Scc210113 case e1000_fc_rx_pause: 2818*6394Scc210113 fc = LINK_FLOWCTRL_RX; 2819*6394Scc210113 break; 2820*6394Scc210113 case e1000_fc_tx_pause: 2821*6394Scc210113 fc = LINK_FLOWCTRL_TX; 2822*6394Scc210113 break; 2823*6394Scc210113 case e1000_fc_full: 2824*6394Scc210113 fc = LINK_FLOWCTRL_BI; 2825*6394Scc210113 break; 2826*6394Scc210113 } 2827*6394Scc210113 bcopy(&fc, pr_val, sizeof (fc)); 2828*6394Scc210113 err = 0; 2829*6394Scc210113 } 2830*6394Scc210113 break; 2831*6394Scc210113 case DLD_PROP_ADV_1000FDX_CAP: 2832*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2833*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_adv_1000fdx; 2834*6394Scc210113 err = 0; 2835*6394Scc210113 } 2836*6394Scc210113 break; 2837*6394Scc210113 case DLD_PROP_EN_1000FDX_CAP: 2838*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2839*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_en_1000fdx; 2840*6394Scc210113 err = 0; 2841*6394Scc210113 } 2842*6394Scc210113 break; 2843*6394Scc210113 case DLD_PROP_ADV_1000HDX_CAP: 2844*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2845*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_adv_1000hdx; 2846*6394Scc210113 err = 0; 2847*6394Scc210113 } 2848*6394Scc210113 break; 2849*6394Scc210113 case DLD_PROP_EN_1000HDX_CAP: 2850*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2851*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_en_1000hdx; 2852*6394Scc210113 err = 0; 2853*6394Scc210113 } 2854*6394Scc210113 break; 2855*6394Scc210113 case DLD_PROP_ADV_100FDX_CAP: 2856*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2857*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_adv_100fdx; 2858*6394Scc210113 err = 0; 2859*6394Scc210113 } 2860*6394Scc210113 break; 2861*6394Scc210113 case DLD_PROP_EN_100FDX_CAP: 2862*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2863*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_en_100fdx; 2864*6394Scc210113 err = 0; 2865*6394Scc210113 } 2866*6394Scc210113 break; 2867*6394Scc210113 case DLD_PROP_ADV_100HDX_CAP: 2868*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2869*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_adv_100hdx; 2870*6394Scc210113 err = 0; 2871*6394Scc210113 } 2872*6394Scc210113 break; 2873*6394Scc210113 case DLD_PROP_EN_100HDX_CAP: 2874*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2875*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_en_100hdx; 2876*6394Scc210113 err = 0; 2877*6394Scc210113 } 2878*6394Scc210113 break; 2879*6394Scc210113 case DLD_PROP_ADV_10FDX_CAP: 2880*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2881*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_adv_10fdx; 2882*6394Scc210113 err = 0; 2883*6394Scc210113 } 2884*6394Scc210113 break; 2885*6394Scc210113 case DLD_PROP_EN_10FDX_CAP: 2886*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2887*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_en_10fdx; 2888*6394Scc210113 err = 0; 2889*6394Scc210113 } 2890*6394Scc210113 break; 2891*6394Scc210113 case DLD_PROP_ADV_10HDX_CAP: 2892*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2893*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_adv_10hdx; 2894*6394Scc210113 err = 0; 2895*6394Scc210113 } 2896*6394Scc210113 break; 2897*6394Scc210113 case DLD_PROP_EN_10HDX_CAP: 2898*6394Scc210113 if (pr_valsize >= sizeof (uint8_t)) { 2899*6394Scc210113 *(uint8_t *)pr_val = Adapter->param_en_10hdx; 2900*6394Scc210113 err = 0; 2901*6394Scc210113 } 2902*6394Scc210113 break; 2903*6394Scc210113 case DLD_PROP_PRIVATE: 2904*6394Scc210113 err = e1000g_get_priv_prop(Adapter, pr_name, 2905*6394Scc210113 pr_valsize, pr_val); 2906*6394Scc210113 break; 2907*6394Scc210113 default: 2908*6394Scc210113 err = ENOTSUP; 2909*6394Scc210113 break; 2910*6394Scc210113 } 2911*6394Scc210113 return (err); 2912*6394Scc210113 } 2913*6394Scc210113 2914*6394Scc210113 /* ARGUSED */ 2915*6394Scc210113 static int 2916*6394Scc210113 e1000g_set_priv_prop(struct e1000g *Adapter, const char *pr_name, 2917*6394Scc210113 uint_t pr_valsize, const void *pr_val) 2918*6394Scc210113 { 2919*6394Scc210113 int err = 0; 2920*6394Scc210113 long result; 2921*6394Scc210113 e1000g_tx_ring_t *tx_ring = Adapter->tx_ring; 2922*6394Scc210113 struct e1000_hw *hw = &Adapter->shared; 2923*6394Scc210113 2924*6394Scc210113 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 2925*6394Scc210113 if (pr_val == NULL) { 2926*6394Scc210113 err = EINVAL; 2927*6394Scc210113 return (err); 2928*6394Scc210113 } 2929*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 2930*6394Scc210113 if (result < MIN_TX_BCOPY_THRESHOLD || 2931*6394Scc210113 result > MAX_TX_BCOPY_THRESHOLD) 2932*6394Scc210113 err = EINVAL; 2933*6394Scc210113 else { 2934*6394Scc210113 Adapter->tx_bcopy_thresh = (uint32_t)result; 2935*6394Scc210113 tx_ring->frags_limit = (hw->mac.max_frame_size / 2936*6394Scc210113 Adapter->tx_bcopy_thresh) + 2; 2937*6394Scc210113 if (tx_ring->frags_limit > 2938*6394Scc210113 (MAX_TX_DESC_PER_PACKET >> 1)) 2939*6394Scc210113 tx_ring->frags_limit = 2940*6394Scc210113 (MAX_TX_DESC_PER_PACKET >> 1); 2941*6394Scc210113 } 2942*6394Scc210113 return (err); 2943*6394Scc210113 } 2944*6394Scc210113 if (strcmp(pr_name, "_tx_interrupt_enable") == 0) { 2945*6394Scc210113 if (pr_val == NULL) { 2946*6394Scc210113 err = EINVAL; 2947*6394Scc210113 return (err); 2948*6394Scc210113 } 2949*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 2950*6394Scc210113 if (result < 0 || result > 1) 2951*6394Scc210113 err = EINVAL; 2952*6394Scc210113 else { 2953*6394Scc210113 Adapter->tx_intr_enable = (result == 1) ? 2954*6394Scc210113 B_TRUE: B_FALSE; 2955*6394Scc210113 if (Adapter->tx_intr_enable) 2956*6394Scc210113 e1000g_mask_tx_interrupt(Adapter); 2957*6394Scc210113 else 2958*6394Scc210113 e1000g_clear_tx_interrupt(Adapter); 2959*6394Scc210113 if (e1000g_check_acc_handle( 2960*6394Scc210113 Adapter->osdep.reg_handle) != DDI_FM_OK) 2961*6394Scc210113 ddi_fm_service_impact(Adapter->dip, 2962*6394Scc210113 DDI_SERVICE_DEGRADED); 2963*6394Scc210113 } 2964*6394Scc210113 return (err); 2965*6394Scc210113 } 2966*6394Scc210113 if (strcmp(pr_name, "_tx_intr_delay") == 0) { 2967*6394Scc210113 if (pr_val == NULL) { 2968*6394Scc210113 err = EINVAL; 2969*6394Scc210113 return (err); 2970*6394Scc210113 } 2971*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 2972*6394Scc210113 if (result < MIN_TX_INTR_DELAY || 2973*6394Scc210113 result > MAX_TX_INTR_DELAY) 2974*6394Scc210113 err = EINVAL; 2975*6394Scc210113 else { 2976*6394Scc210113 Adapter->tx_intr_delay = (uint32_t)result; 2977*6394Scc210113 E1000_WRITE_REG(hw, E1000_TIDV, Adapter->tx_intr_delay); 2978*6394Scc210113 if (e1000g_check_acc_handle( 2979*6394Scc210113 Adapter->osdep.reg_handle) != DDI_FM_OK) 2980*6394Scc210113 ddi_fm_service_impact(Adapter->dip, 2981*6394Scc210113 DDI_SERVICE_DEGRADED); 2982*6394Scc210113 } 2983*6394Scc210113 return (err); 2984*6394Scc210113 } 2985*6394Scc210113 if (strcmp(pr_name, "_tx_intr_abs_delay") == 0) { 2986*6394Scc210113 if (pr_val == NULL) { 2987*6394Scc210113 err = EINVAL; 2988*6394Scc210113 return (err); 2989*6394Scc210113 } 2990*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 2991*6394Scc210113 if (result < MIN_TX_INTR_ABS_DELAY || 2992*6394Scc210113 result > MAX_TX_INTR_ABS_DELAY) 2993*6394Scc210113 err = EINVAL; 2994*6394Scc210113 else { 2995*6394Scc210113 Adapter->tx_intr_abs_delay = (uint32_t)result; 2996*6394Scc210113 E1000_WRITE_REG(hw, E1000_TADV, 2997*6394Scc210113 Adapter->tx_intr_abs_delay); 2998*6394Scc210113 if (e1000g_check_acc_handle( 2999*6394Scc210113 Adapter->osdep.reg_handle) != DDI_FM_OK) 3000*6394Scc210113 ddi_fm_service_impact(Adapter->dip, 3001*6394Scc210113 DDI_SERVICE_DEGRADED); 3002*6394Scc210113 } 3003*6394Scc210113 return (err); 3004*6394Scc210113 } 3005*6394Scc210113 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 3006*6394Scc210113 if (pr_val == NULL) { 3007*6394Scc210113 err = EINVAL; 3008*6394Scc210113 return (err); 3009*6394Scc210113 } 3010*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 3011*6394Scc210113 if (result < MIN_RX_BCOPY_THRESHOLD || 3012*6394Scc210113 result > MAX_RX_BCOPY_THRESHOLD) 3013*6394Scc210113 err = EINVAL; 3014*6394Scc210113 else 3015*6394Scc210113 Adapter->rx_bcopy_thresh = (uint32_t)result; 3016*6394Scc210113 return (err); 3017*6394Scc210113 } 3018*6394Scc210113 if (strcmp(pr_name, "_max_num_rcv_packets") == 0) { 3019*6394Scc210113 if (pr_val == NULL) { 3020*6394Scc210113 err = EINVAL; 3021*6394Scc210113 return (err); 3022*6394Scc210113 } 3023*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 3024*6394Scc210113 if (result < MIN_RX_LIMIT_ON_INTR || 3025*6394Scc210113 result > MAX_RX_LIMIT_ON_INTR) 3026*6394Scc210113 err = EINVAL; 3027*6394Scc210113 else 3028*6394Scc210113 Adapter->rx_limit_onintr = (uint32_t)result; 3029*6394Scc210113 return (err); 3030*6394Scc210113 } 3031*6394Scc210113 if (strcmp(pr_name, "_rx_intr_delay") == 0) { 3032*6394Scc210113 if (pr_val == NULL) { 3033*6394Scc210113 err = EINVAL; 3034*6394Scc210113 return (err); 3035*6394Scc210113 } 3036*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 3037*6394Scc210113 if (result < MIN_RX_INTR_DELAY || 3038*6394Scc210113 result > MAX_RX_INTR_DELAY) 3039*6394Scc210113 err = EINVAL; 3040*6394Scc210113 else { 3041*6394Scc210113 Adapter->rx_intr_delay = (uint32_t)result; 3042*6394Scc210113 E1000_WRITE_REG(hw, E1000_RDTR, Adapter->rx_intr_delay); 3043*6394Scc210113 if (e1000g_check_acc_handle( 3044*6394Scc210113 Adapter->osdep.reg_handle) != DDI_FM_OK) 3045*6394Scc210113 ddi_fm_service_impact(Adapter->dip, 3046*6394Scc210113 DDI_SERVICE_DEGRADED); 3047*6394Scc210113 } 3048*6394Scc210113 return (err); 3049*6394Scc210113 } 3050*6394Scc210113 if (strcmp(pr_name, "_rx_intr_abs_delay") == 0) { 3051*6394Scc210113 if (pr_val == NULL) { 3052*6394Scc210113 err = EINVAL; 3053*6394Scc210113 return (err); 3054*6394Scc210113 } 3055*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 3056*6394Scc210113 if (result < MIN_RX_INTR_ABS_DELAY || 3057*6394Scc210113 result > MAX_RX_INTR_ABS_DELAY) 3058*6394Scc210113 err = EINVAL; 3059*6394Scc210113 else { 3060*6394Scc210113 Adapter->rx_intr_abs_delay = (uint32_t)result; 3061*6394Scc210113 E1000_WRITE_REG(hw, E1000_RADV, 3062*6394Scc210113 Adapter->rx_intr_abs_delay); 3063*6394Scc210113 if (e1000g_check_acc_handle( 3064*6394Scc210113 Adapter->osdep.reg_handle) != DDI_FM_OK) 3065*6394Scc210113 ddi_fm_service_impact(Adapter->dip, 3066*6394Scc210113 DDI_SERVICE_DEGRADED); 3067*6394Scc210113 } 3068*6394Scc210113 return (err); 3069*6394Scc210113 } 3070*6394Scc210113 if (strcmp(pr_name, "_intr_throttling_rate") == 0) { 3071*6394Scc210113 if (pr_val == NULL) { 3072*6394Scc210113 err = EINVAL; 3073*6394Scc210113 return (err); 3074*6394Scc210113 } 3075*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 3076*6394Scc210113 if (result < MIN_INTR_THROTTLING || 3077*6394Scc210113 result > MAX_INTR_THROTTLING) 3078*6394Scc210113 err = EINVAL; 3079*6394Scc210113 else { 3080*6394Scc210113 if (hw->mac.type >= e1000_82540) { 3081*6394Scc210113 Adapter->intr_throttling_rate = 3082*6394Scc210113 (uint32_t)result; 3083*6394Scc210113 E1000_WRITE_REG(hw, E1000_ITR, 3084*6394Scc210113 Adapter->intr_throttling_rate); 3085*6394Scc210113 if (e1000g_check_acc_handle( 3086*6394Scc210113 Adapter->osdep.reg_handle) != DDI_FM_OK) 3087*6394Scc210113 ddi_fm_service_impact(Adapter->dip, 3088*6394Scc210113 DDI_SERVICE_DEGRADED); 3089*6394Scc210113 } else 3090*6394Scc210113 err = EINVAL; 3091*6394Scc210113 } 3092*6394Scc210113 return (err); 3093*6394Scc210113 } 3094*6394Scc210113 if (strcmp(pr_name, "_intr_adaptive") == 0) { 3095*6394Scc210113 if (pr_val == NULL) { 3096*6394Scc210113 err = EINVAL; 3097*6394Scc210113 return (err); 3098*6394Scc210113 } 3099*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 3100*6394Scc210113 if (result < 0 || result > 1) 3101*6394Scc210113 err = EINVAL; 3102*6394Scc210113 else { 3103*6394Scc210113 if (hw->mac.type >= e1000_82540) { 3104*6394Scc210113 Adapter->intr_adaptive = (result == 1) ? 3105*6394Scc210113 B_TRUE : B_FALSE; 3106*6394Scc210113 } else { 3107*6394Scc210113 err = EINVAL; 3108*6394Scc210113 } 3109*6394Scc210113 } 3110*6394Scc210113 return (err); 3111*6394Scc210113 } 3112*6394Scc210113 if (strcmp(pr_name, "_tx_recycle_thresh") == 0) { 3113*6394Scc210113 if (pr_val == NULL) { 3114*6394Scc210113 err = EINVAL; 3115*6394Scc210113 return (err); 3116*6394Scc210113 } 3117*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 3118*6394Scc210113 if (result < MIN_TX_RECYCLE_THRESHOLD || 3119*6394Scc210113 result > MAX_TX_RECYCLE_THRESHOLD) 3120*6394Scc210113 err = EINVAL; 3121*6394Scc210113 else 3122*6394Scc210113 Adapter->tx_recycle_thresh = (uint32_t)result; 3123*6394Scc210113 return (err); 3124*6394Scc210113 } 3125*6394Scc210113 if (strcmp(pr_name, "_tx_recycle_num") == 0) { 3126*6394Scc210113 if (pr_val == NULL) { 3127*6394Scc210113 err = EINVAL; 3128*6394Scc210113 return (err); 3129*6394Scc210113 } 3130*6394Scc210113 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 3131*6394Scc210113 if (result < MIN_TX_RECYCLE_NUM || 3132*6394Scc210113 result > MAX_TX_RECYCLE_NUM) 3133*6394Scc210113 err = EINVAL; 3134*6394Scc210113 else 3135*6394Scc210113 Adapter->tx_recycle_num = (uint32_t)result; 3136*6394Scc210113 return (err); 3137*6394Scc210113 } 3138*6394Scc210113 return (ENOTSUP); 3139*6394Scc210113 } 3140*6394Scc210113 3141*6394Scc210113 static int 3142*6394Scc210113 e1000g_get_priv_prop(struct e1000g *Adapter, const char *pr_name, 3143*6394Scc210113 uint_t pr_valsize, void *pr_val) 3144*6394Scc210113 { 3145*6394Scc210113 char valstr[MAXNAMELEN]; 3146*6394Scc210113 int err = ENOTSUP; 3147*6394Scc210113 uint_t strsize; 3148*6394Scc210113 3149*6394Scc210113 if (strcmp(pr_name, "_tx_bcopy_threshold") == 0) { 3150*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->tx_bcopy_thresh); 3151*6394Scc210113 err = 0; 3152*6394Scc210113 goto done; 3153*6394Scc210113 } 3154*6394Scc210113 if (strcmp(pr_name, "_tx_interrupt_enable") == 0) { 3155*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->tx_intr_enable); 3156*6394Scc210113 err = 0; 3157*6394Scc210113 goto done; 3158*6394Scc210113 } 3159*6394Scc210113 if (strcmp(pr_name, "_tx_intr_delay") == 0) { 3160*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->tx_intr_delay); 3161*6394Scc210113 err = 0; 3162*6394Scc210113 goto done; 3163*6394Scc210113 } 3164*6394Scc210113 if (strcmp(pr_name, "_tx_intr_abs_delay") == 0) { 3165*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->tx_intr_abs_delay); 3166*6394Scc210113 err = 0; 3167*6394Scc210113 goto done; 3168*6394Scc210113 } 3169*6394Scc210113 if (strcmp(pr_name, "_rx_bcopy_threshold") == 0) { 3170*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->rx_bcopy_thresh); 3171*6394Scc210113 err = 0; 3172*6394Scc210113 goto done; 3173*6394Scc210113 } 3174*6394Scc210113 if (strcmp(pr_name, "_max_num_rcv_packets") == 0) { 3175*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->rx_limit_onintr); 3176*6394Scc210113 err = 0; 3177*6394Scc210113 goto done; 3178*6394Scc210113 } 3179*6394Scc210113 if (strcmp(pr_name, "_rx_intr_delay") == 0) { 3180*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->rx_intr_delay); 3181*6394Scc210113 err = 0; 3182*6394Scc210113 goto done; 3183*6394Scc210113 } 3184*6394Scc210113 if (strcmp(pr_name, "_rx_intr_abs_delay") == 0) { 3185*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->rx_intr_abs_delay); 3186*6394Scc210113 err = 0; 3187*6394Scc210113 goto done; 3188*6394Scc210113 } 3189*6394Scc210113 if (strcmp(pr_name, "_intr_throttling_rate") == 0) { 3190*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->intr_throttling_rate); 3191*6394Scc210113 err = 0; 3192*6394Scc210113 goto done; 3193*6394Scc210113 } 3194*6394Scc210113 if (strcmp(pr_name, "_intr_adaptive") == 0) { 3195*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->intr_adaptive); 3196*6394Scc210113 err = 0; 3197*6394Scc210113 goto done; 3198*6394Scc210113 } 3199*6394Scc210113 if (strcmp(pr_name, "_tx_recycle_thresh") == 0) { 3200*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->tx_recycle_thresh); 3201*6394Scc210113 err = 0; 3202*6394Scc210113 goto done; 3203*6394Scc210113 } 3204*6394Scc210113 if (strcmp(pr_name, "_tx_recycle_num") == 0) { 3205*6394Scc210113 (void) sprintf(valstr, "%d", Adapter->tx_recycle_num); 3206*6394Scc210113 err = 0; 3207*6394Scc210113 goto done; 3208*6394Scc210113 } 3209*6394Scc210113 done: 3210*6394Scc210113 if (err == 0) { 3211*6394Scc210113 strsize = (uint_t)strlen(valstr); 3212*6394Scc210113 if (pr_valsize < strsize) 3213*6394Scc210113 err = ENOBUFS; 3214*6394Scc210113 else 3215*6394Scc210113 (void) strlcpy(pr_val, valstr, pr_valsize); 3216*6394Scc210113 } 3217*6394Scc210113 return (err); 3218*6394Scc210113 } 3219*6394Scc210113 32203526Sxy150489 /* 32214919Sxy150489 * e1000g_get_conf - get configurations set in e1000g.conf 32224919Sxy150489 * This routine gets user-configured values out of the configuration 32234919Sxy150489 * file e1000g.conf. 32244919Sxy150489 * 32254919Sxy150489 * For each configurable value, there is a minimum, a maximum, and a 32264919Sxy150489 * default. 32274919Sxy150489 * If user does not configure a value, use the default. 32284919Sxy150489 * If user configures below the minimum, use the minumum. 32294919Sxy150489 * If user configures above the maximum, use the maxumum. 32303526Sxy150489 */ 32313526Sxy150489 static void 32324919Sxy150489 e1000g_get_conf(struct e1000g *Adapter) 32333526Sxy150489 { 32344919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 32354919Sxy150489 boolean_t tbi_compatibility = B_FALSE; 32364919Sxy150489 32373526Sxy150489 /* 32383526Sxy150489 * get each configurable property from e1000g.conf 32393526Sxy150489 */ 32403526Sxy150489 32413526Sxy150489 /* 32423526Sxy150489 * NumTxDescriptors 32433526Sxy150489 */ 32444919Sxy150489 Adapter->tx_desc_num = 32454919Sxy150489 e1000g_get_prop(Adapter, "NumTxDescriptors", 32464919Sxy150489 MIN_NUM_TX_DESCRIPTOR, MAX_NUM_TX_DESCRIPTOR, 32474919Sxy150489 DEFAULT_NUM_TX_DESCRIPTOR); 32483526Sxy150489 32493526Sxy150489 /* 32503526Sxy150489 * NumRxDescriptors 32513526Sxy150489 */ 32524919Sxy150489 Adapter->rx_desc_num = 32534919Sxy150489 e1000g_get_prop(Adapter, "NumRxDescriptors", 32544919Sxy150489 MIN_NUM_RX_DESCRIPTOR, MAX_NUM_RX_DESCRIPTOR, 32554919Sxy150489 DEFAULT_NUM_RX_DESCRIPTOR); 32563526Sxy150489 32573526Sxy150489 /* 32583526Sxy150489 * NumRxFreeList 32593526Sxy150489 */ 32604919Sxy150489 Adapter->rx_freelist_num = 32614919Sxy150489 e1000g_get_prop(Adapter, "NumRxFreeList", 32624919Sxy150489 MIN_NUM_RX_FREELIST, MAX_NUM_RX_FREELIST, 32634919Sxy150489 DEFAULT_NUM_RX_FREELIST); 32643526Sxy150489 32653526Sxy150489 /* 32663526Sxy150489 * NumTxPacketList 32673526Sxy150489 */ 32684919Sxy150489 Adapter->tx_freelist_num = 32694919Sxy150489 e1000g_get_prop(Adapter, "NumTxPacketList", 32704919Sxy150489 MIN_NUM_TX_FREELIST, MAX_NUM_TX_FREELIST, 32714919Sxy150489 DEFAULT_NUM_TX_FREELIST); 32723526Sxy150489 32733526Sxy150489 /* 32743526Sxy150489 * FlowControl 32753526Sxy150489 */ 32764919Sxy150489 hw->mac.fc_send_xon = B_TRUE; 32774919Sxy150489 hw->mac.fc = 32784919Sxy150489 e1000g_get_prop(Adapter, "FlowControl", 32794919Sxy150489 e1000_fc_none, 4, DEFAULT_FLOW_CONTROL); 32803526Sxy150489 /* 4 is the setting that says "let the eeprom decide" */ 32814919Sxy150489 if (hw->mac.fc == 4) 32824919Sxy150489 hw->mac.fc = e1000_fc_default; 32833526Sxy150489 32843526Sxy150489 /* 32854919Sxy150489 * Max Num Receive Packets on Interrupt 32863526Sxy150489 */ 32874919Sxy150489 Adapter->rx_limit_onintr = 32884919Sxy150489 e1000g_get_prop(Adapter, "MaxNumReceivePackets", 32894919Sxy150489 MIN_RX_LIMIT_ON_INTR, MAX_RX_LIMIT_ON_INTR, 32904919Sxy150489 DEFAULT_RX_LIMIT_ON_INTR); 32913526Sxy150489 32923526Sxy150489 /* 32933526Sxy150489 * PHY master slave setting 32943526Sxy150489 */ 32954919Sxy150489 hw->phy.ms_type = 32964919Sxy150489 e1000g_get_prop(Adapter, "SetMasterSlave", 32973526Sxy150489 e1000_ms_hw_default, e1000_ms_auto, 32983526Sxy150489 e1000_ms_hw_default); 32993526Sxy150489 33003526Sxy150489 /* 33013526Sxy150489 * Parameter which controls TBI mode workaround, which is only 33023526Sxy150489 * needed on certain switches such as Cisco 6500/Foundry 33033526Sxy150489 */ 33044919Sxy150489 tbi_compatibility = 33054919Sxy150489 e1000g_get_prop(Adapter, "TbiCompatibilityEnable", 33064919Sxy150489 0, 1, DEFAULT_TBI_COMPAT_ENABLE); 33074919Sxy150489 e1000_set_tbi_compatibility_82543(hw, tbi_compatibility); 33083526Sxy150489 33093526Sxy150489 /* 33103526Sxy150489 * MSI Enable 33113526Sxy150489 */ 33123526Sxy150489 Adapter->msi_enabled = 33134919Sxy150489 e1000g_get_prop(Adapter, "MSIEnable", 33144919Sxy150489 0, 1, DEFAULT_MSI_ENABLE); 33153526Sxy150489 33163526Sxy150489 /* 33173526Sxy150489 * Interrupt Throttling Rate 33183526Sxy150489 */ 33193526Sxy150489 Adapter->intr_throttling_rate = 33204919Sxy150489 e1000g_get_prop(Adapter, "intr_throttling_rate", 33214919Sxy150489 MIN_INTR_THROTTLING, MAX_INTR_THROTTLING, 33224919Sxy150489 DEFAULT_INTR_THROTTLING); 33233526Sxy150489 33243526Sxy150489 /* 33253526Sxy150489 * Adaptive Interrupt Blanking Enable/Disable 33263526Sxy150489 * It is enabled by default 33273526Sxy150489 */ 33283526Sxy150489 Adapter->intr_adaptive = 33294919Sxy150489 (e1000g_get_prop(Adapter, "intr_adaptive", 0, 1, 1) == 1) ? 33303526Sxy150489 B_TRUE : B_FALSE; 33315882Syy150190 33325882Syy150190 /* 33335882Syy150190 * Tx recycle threshold 33345882Syy150190 */ 33355882Syy150190 Adapter->tx_recycle_thresh = 33365882Syy150190 e1000g_get_prop(Adapter, "tx_recycle_thresh", 33375882Syy150190 MIN_TX_RECYCLE_THRESHOLD, MAX_TX_RECYCLE_THRESHOLD, 33385882Syy150190 DEFAULT_TX_RECYCLE_THRESHOLD); 33395882Syy150190 33405882Syy150190 /* 33415882Syy150190 * Tx recycle descriptor number 33425882Syy150190 */ 33435882Syy150190 Adapter->tx_recycle_num = 33445882Syy150190 e1000g_get_prop(Adapter, "tx_recycle_num", 33455882Syy150190 MIN_TX_RECYCLE_NUM, MAX_TX_RECYCLE_NUM, 33465882Syy150190 DEFAULT_TX_RECYCLE_NUM); 33476011Ssv141092 33486011Ssv141092 /* 33496011Ssv141092 * Hardware checksum enable/disable parameter 33506011Ssv141092 */ 33516011Ssv141092 Adapter->tx_hcksum_enabled = 33526011Ssv141092 e1000g_get_prop(Adapter, "tx_hcksum_enabled", 33536011Ssv141092 0, 1, DEFAULT_TX_HCKSUM_ENABLE); 33546011Ssv141092 33553526Sxy150489 } 33563526Sxy150489 33573526Sxy150489 /* 33584919Sxy150489 * e1000g_get_prop - routine to read properties 33594919Sxy150489 * 33604919Sxy150489 * Get a user-configure property value out of the configuration 33614919Sxy150489 * file e1000g.conf. 33624919Sxy150489 * 33634919Sxy150489 * Caller provides name of the property, a default value, a minimum 33644919Sxy150489 * value, and a maximum value. 33654919Sxy150489 * 33664919Sxy150489 * Return configured value of the property, with default, minimum and 33674919Sxy150489 * maximum properly applied. 33683526Sxy150489 */ 33693526Sxy150489 static int 33704919Sxy150489 e1000g_get_prop(struct e1000g *Adapter, /* point to per-adapter structure */ 33713526Sxy150489 char *propname, /* name of the property */ 33723526Sxy150489 int minval, /* minimum acceptable value */ 33733526Sxy150489 int maxval, /* maximim acceptable value */ 33743526Sxy150489 int defval) /* default value */ 33753526Sxy150489 { 33763526Sxy150489 int propval; /* value returned for requested property */ 33773526Sxy150489 int *props; /* point to array of properties returned */ 33783526Sxy150489 uint_t nprops; /* number of property value returned */ 33793526Sxy150489 33803526Sxy150489 /* 33813526Sxy150489 * get the array of properties from the config file 33823526Sxy150489 */ 33833526Sxy150489 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, Adapter->dip, 33843526Sxy150489 DDI_PROP_DONTPASS, propname, &props, &nprops) == DDI_PROP_SUCCESS) { 33853526Sxy150489 /* got some properties, test if we got enough */ 33864919Sxy150489 if (Adapter->instance < nprops) { 33874919Sxy150489 propval = props[Adapter->instance]; 33883526Sxy150489 } else { 33893526Sxy150489 /* not enough properties configured */ 33903526Sxy150489 propval = defval; 33914919Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL, 33923526Sxy150489 "Not Enough %s values found in e1000g.conf" 33933526Sxy150489 " - set to %d\n", 33943526Sxy150489 propname, propval); 33953526Sxy150489 } 33963526Sxy150489 33973526Sxy150489 /* free memory allocated for properties */ 33983526Sxy150489 ddi_prop_free(props); 33993526Sxy150489 34003526Sxy150489 } else { 34013526Sxy150489 propval = defval; 34023526Sxy150489 } 34033526Sxy150489 34043526Sxy150489 /* 34053526Sxy150489 * enforce limits 34063526Sxy150489 */ 34073526Sxy150489 if (propval > maxval) { 34083526Sxy150489 propval = maxval; 34094919Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL, 34103526Sxy150489 "Too High %s value in e1000g.conf - set to %d\n", 34113526Sxy150489 propname, propval); 34123526Sxy150489 } 34133526Sxy150489 34143526Sxy150489 if (propval < minval) { 34153526Sxy150489 propval = minval; 34164919Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_INFO_LEVEL, 34173526Sxy150489 "Too Low %s value in e1000g.conf - set to %d\n", 34183526Sxy150489 propname, propval); 34193526Sxy150489 } 34203526Sxy150489 34213526Sxy150489 return (propval); 34223526Sxy150489 } 34233526Sxy150489 34243526Sxy150489 static boolean_t 34254061Sxy150489 e1000g_link_check(struct e1000g *Adapter) 34263526Sxy150489 { 34274061Sxy150489 uint16_t speed, duplex, phydata; 34284061Sxy150489 boolean_t link_changed = B_FALSE; 34293526Sxy150489 struct e1000_hw *hw; 34303526Sxy150489 uint32_t reg_tarc; 34313526Sxy150489 34324919Sxy150489 hw = &Adapter->shared; 34333526Sxy150489 34343526Sxy150489 if (e1000g_link_up(Adapter)) { 34353526Sxy150489 /* 34363526Sxy150489 * The Link is up, check whether it was marked as down earlier 34373526Sxy150489 */ 34384061Sxy150489 if (Adapter->link_state != LINK_STATE_UP) { 34394061Sxy150489 e1000_get_speed_and_duplex(hw, &speed, &duplex); 34404061Sxy150489 Adapter->link_speed = speed; 34414061Sxy150489 Adapter->link_duplex = duplex; 34424061Sxy150489 Adapter->link_state = LINK_STATE_UP; 34434061Sxy150489 link_changed = B_TRUE; 34444061Sxy150489 34454061Sxy150489 Adapter->tx_link_down_timeout = 0; 34464061Sxy150489 34474919Sxy150489 if ((hw->mac.type == e1000_82571) || 34484919Sxy150489 (hw->mac.type == e1000_82572)) { 34494919Sxy150489 reg_tarc = E1000_READ_REG(hw, E1000_TARC0); 34504061Sxy150489 if (speed == SPEED_1000) 34514061Sxy150489 reg_tarc |= (1 << 21); 34524061Sxy150489 else 34534061Sxy150489 reg_tarc &= ~(1 << 21); 34544919Sxy150489 E1000_WRITE_REG(hw, E1000_TARC0, reg_tarc); 34553526Sxy150489 } 34563526Sxy150489 } 34573526Sxy150489 Adapter->smartspeed = 0; 34583526Sxy150489 } else { 34594061Sxy150489 if (Adapter->link_state != LINK_STATE_DOWN) { 34603526Sxy150489 Adapter->link_speed = 0; 34613526Sxy150489 Adapter->link_duplex = 0; 34624061Sxy150489 Adapter->link_state = LINK_STATE_DOWN; 34634061Sxy150489 link_changed = B_TRUE; 34644061Sxy150489 34653526Sxy150489 /* 34663526Sxy150489 * SmartSpeed workaround for Tabor/TanaX, When the 34673526Sxy150489 * driver loses link disable auto master/slave 34683526Sxy150489 * resolution. 34693526Sxy150489 */ 34704919Sxy150489 if (hw->phy.type == e1000_phy_igp) { 34713526Sxy150489 e1000_read_phy_reg(hw, 34723526Sxy150489 PHY_1000T_CTRL, &phydata); 34733526Sxy150489 phydata |= CR_1000T_MS_ENABLE; 34743526Sxy150489 e1000_write_phy_reg(hw, 34753526Sxy150489 PHY_1000T_CTRL, phydata); 34763526Sxy150489 } 34773526Sxy150489 } else { 34783526Sxy150489 e1000g_smartspeed(Adapter); 34793526Sxy150489 } 34804061Sxy150489 34815273Sgl147354 if (Adapter->chip_state == E1000G_START) { 34824061Sxy150489 if (Adapter->tx_link_down_timeout < 34834061Sxy150489 MAX_TX_LINK_DOWN_TIMEOUT) { 34844061Sxy150489 Adapter->tx_link_down_timeout++; 34854061Sxy150489 } else if (Adapter->tx_link_down_timeout == 34864061Sxy150489 MAX_TX_LINK_DOWN_TIMEOUT) { 34874919Sxy150489 e1000g_tx_clean(Adapter); 34884061Sxy150489 Adapter->tx_link_down_timeout++; 34894061Sxy150489 } 34904061Sxy150489 } 34913526Sxy150489 } 34923526Sxy150489 34935273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 34945273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 34955273Sgl147354 34964061Sxy150489 return (link_changed); 34974061Sxy150489 } 34984061Sxy150489 3499*6394Scc210113 /* 3500*6394Scc210113 * e1000g_reset_link - Using the link properties to setup the link 3501*6394Scc210113 */ 3502*6394Scc210113 int 3503*6394Scc210113 e1000g_reset_link(struct e1000g *Adapter) 3504*6394Scc210113 { 3505*6394Scc210113 struct e1000_mac_info *mac; 3506*6394Scc210113 struct e1000_phy_info *phy; 3507*6394Scc210113 boolean_t invalid; 3508*6394Scc210113 3509*6394Scc210113 mac = &Adapter->shared.mac; 3510*6394Scc210113 phy = &Adapter->shared.phy; 3511*6394Scc210113 invalid = B_FALSE; 3512*6394Scc210113 3513*6394Scc210113 if (Adapter->param_adv_autoneg == 1) { 3514*6394Scc210113 mac->autoneg = B_TRUE; 3515*6394Scc210113 phy->autoneg_advertised = 0; 3516*6394Scc210113 3517*6394Scc210113 /* 3518*6394Scc210113 * 1000hdx is not supported for autonegotiation 3519*6394Scc210113 */ 3520*6394Scc210113 if (Adapter->param_adv_1000fdx == 1) 3521*6394Scc210113 phy->autoneg_advertised |= ADVERTISE_1000_FULL; 3522*6394Scc210113 3523*6394Scc210113 if (Adapter->param_adv_100fdx == 1) 3524*6394Scc210113 phy->autoneg_advertised |= ADVERTISE_100_FULL; 3525*6394Scc210113 3526*6394Scc210113 if (Adapter->param_adv_100hdx == 1) 3527*6394Scc210113 phy->autoneg_advertised |= ADVERTISE_100_HALF; 3528*6394Scc210113 3529*6394Scc210113 if (Adapter->param_adv_10fdx == 1) 3530*6394Scc210113 phy->autoneg_advertised |= ADVERTISE_10_FULL; 3531*6394Scc210113 3532*6394Scc210113 if (Adapter->param_adv_10hdx == 1) 3533*6394Scc210113 phy->autoneg_advertised |= ADVERTISE_10_HALF; 3534*6394Scc210113 3535*6394Scc210113 if (phy->autoneg_advertised == 0) 3536*6394Scc210113 invalid = B_TRUE; 3537*6394Scc210113 } else { 3538*6394Scc210113 mac->autoneg = B_FALSE; 3539*6394Scc210113 3540*6394Scc210113 /* 3541*6394Scc210113 * 1000fdx and 1000hdx are not supported for forced link 3542*6394Scc210113 */ 3543*6394Scc210113 if (Adapter->param_adv_100fdx == 1) 3544*6394Scc210113 mac->forced_speed_duplex = ADVERTISE_100_FULL; 3545*6394Scc210113 else if (Adapter->param_adv_100hdx == 1) 3546*6394Scc210113 mac->forced_speed_duplex = ADVERTISE_100_HALF; 3547*6394Scc210113 else if (Adapter->param_adv_10fdx == 1) 3548*6394Scc210113 mac->forced_speed_duplex = ADVERTISE_10_FULL; 3549*6394Scc210113 else if (Adapter->param_adv_10hdx == 1) 3550*6394Scc210113 mac->forced_speed_duplex = ADVERTISE_10_HALF; 3551*6394Scc210113 else 3552*6394Scc210113 invalid = B_TRUE; 3553*6394Scc210113 3554*6394Scc210113 } 3555*6394Scc210113 3556*6394Scc210113 if (invalid) { 3557*6394Scc210113 e1000g_log(Adapter, CE_WARN, 3558*6394Scc210113 "Invalid link sets. Setup link to" 3559*6394Scc210113 "support autonegotiation with all link capabilities."); 3560*6394Scc210113 mac->autoneg = B_TRUE; 3561*6394Scc210113 phy->autoneg_advertised = ADVERTISE_1000_FULL | 3562*6394Scc210113 ADVERTISE_100_FULL | ADVERTISE_100_HALF | 3563*6394Scc210113 ADVERTISE_10_FULL | ADVERTISE_10_HALF; 3564*6394Scc210113 } 3565*6394Scc210113 3566*6394Scc210113 return (e1000_setup_link(&Adapter->shared)); 3567*6394Scc210113 } 3568*6394Scc210113 35694061Sxy150489 static void 35704919Sxy150489 e1000g_local_timer(void *ws) 35714061Sxy150489 { 35724061Sxy150489 struct e1000g *Adapter = (struct e1000g *)ws; 35734061Sxy150489 struct e1000_hw *hw; 35744061Sxy150489 e1000g_ether_addr_t ether_addr; 35754061Sxy150489 boolean_t link_changed; 35764061Sxy150489 35774919Sxy150489 hw = &Adapter->shared; 35784919Sxy150489 35795273Sgl147354 if (Adapter->chip_state == E1000G_ERROR) { 35805273Sgl147354 Adapter->reset_count++; 35815273Sgl147354 if (e1000g_global_reset(Adapter)) 35825273Sgl147354 ddi_fm_service_impact(Adapter->dip, 35835273Sgl147354 DDI_SERVICE_RESTORED); 35845273Sgl147354 else 35855273Sgl147354 ddi_fm_service_impact(Adapter->dip, 35865273Sgl147354 DDI_SERVICE_LOST); 35875273Sgl147354 return; 35885273Sgl147354 } 35895273Sgl147354 35904061Sxy150489 if (e1000g_stall_check(Adapter)) { 35914919Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 35924061Sxy150489 "Tx stall detected. Activate automatic recovery.\n"); 35935273Sgl147354 e1000g_fm_ereport(Adapter, DDI_FM_DEVICE_STALL); 35944061Sxy150489 Adapter->reset_count++; 35955273Sgl147354 if (e1000g_reset(Adapter)) 35965273Sgl147354 ddi_fm_service_impact(Adapter->dip, 35975273Sgl147354 DDI_SERVICE_RESTORED); 35985273Sgl147354 else 35995273Sgl147354 ddi_fm_service_impact(Adapter->dip, 36005273Sgl147354 DDI_SERVICE_LOST); 36015273Sgl147354 return; 36024061Sxy150489 } 36034061Sxy150489 36044061Sxy150489 link_changed = B_FALSE; 36055082Syy150190 rw_enter(&Adapter->chip_lock, RW_READER); 36064061Sxy150489 if (Adapter->link_complete) 36074061Sxy150489 link_changed = e1000g_link_check(Adapter); 36085082Syy150190 rw_exit(&Adapter->chip_lock); 36094061Sxy150489 36104139Sxy150489 if (link_changed) { 36114139Sxy150489 /* 36124139Sxy150489 * Workaround for esb2. Data stuck in fifo on a link 36134139Sxy150489 * down event. Reset the adapter to recover it. 36144139Sxy150489 */ 36154139Sxy150489 if ((Adapter->link_state == LINK_STATE_DOWN) && 36164919Sxy150489 (hw->mac.type == e1000_80003es2lan)) 36174139Sxy150489 (void) e1000g_reset(Adapter); 36184139Sxy150489 36194061Sxy150489 mac_link_update(Adapter->mh, Adapter->link_state); 36204139Sxy150489 } 36214061Sxy150489 36223526Sxy150489 /* 36233526Sxy150489 * With 82571 controllers, any locally administered address will 36243526Sxy150489 * be overwritten when there is a reset on the other port. 36253526Sxy150489 * Detect this circumstance and correct it. 36263526Sxy150489 */ 36274919Sxy150489 if ((hw->mac.type == e1000_82571) && 36284919Sxy150489 (e1000_get_laa_state_82571(hw) == B_TRUE)) { 36294919Sxy150489 ether_addr.reg.low = E1000_READ_REG_ARRAY(hw, E1000_RA, 0); 36304919Sxy150489 ether_addr.reg.high = E1000_READ_REG_ARRAY(hw, E1000_RA, 1); 36313526Sxy150489 36323526Sxy150489 ether_addr.reg.low = ntohl(ether_addr.reg.low); 36333526Sxy150489 ether_addr.reg.high = ntohl(ether_addr.reg.high); 36343526Sxy150489 36354919Sxy150489 if ((ether_addr.mac.addr[5] != hw->mac.addr[0]) || 36364919Sxy150489 (ether_addr.mac.addr[4] != hw->mac.addr[1]) || 36374919Sxy150489 (ether_addr.mac.addr[3] != hw->mac.addr[2]) || 36384919Sxy150489 (ether_addr.mac.addr[2] != hw->mac.addr[3]) || 36394919Sxy150489 (ether_addr.mac.addr[1] != hw->mac.addr[4]) || 36404919Sxy150489 (ether_addr.mac.addr[0] != hw->mac.addr[5])) { 36414919Sxy150489 e1000_rar_set(hw, hw->mac.addr, 0); 36423526Sxy150489 } 36433526Sxy150489 } 36443526Sxy150489 36453526Sxy150489 /* 36464919Sxy150489 * Long TTL workaround for 82541/82547 36473526Sxy150489 */ 36484919Sxy150489 e1000_igp_ttl_workaround_82547(hw); 36493526Sxy150489 36503526Sxy150489 /* 36513526Sxy150489 * Check for Adaptive IFS settings If there are lots of collisions 36523526Sxy150489 * change the value in steps... 36533526Sxy150489 * These properties should only be set for 10/100 36543526Sxy150489 */ 36553526Sxy150489 if ((hw->media_type == e1000_media_type_copper) && 36564061Sxy150489 ((Adapter->link_speed == SPEED_100) || 36574061Sxy150489 (Adapter->link_speed == SPEED_10))) { 36583526Sxy150489 e1000_update_adaptive(hw); 36593526Sxy150489 } 36603526Sxy150489 /* 36613526Sxy150489 * Set Timer Interrupts 36623526Sxy150489 */ 36634919Sxy150489 E1000_WRITE_REG(hw, E1000_ICS, E1000_IMS_RXT0); 36644919Sxy150489 36655273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) 36665273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 36675273Sgl147354 36684919Sxy150489 restart_watchdog_timer(Adapter); 36693526Sxy150489 } 36703526Sxy150489 36714061Sxy150489 /* 36724061Sxy150489 * The function e1000g_link_timer() is called when the timer for link setup 36734061Sxy150489 * is expired, which indicates the completion of the link setup. The link 36744061Sxy150489 * state will not be updated until the link setup is completed. And the 36754061Sxy150489 * link state will not be sent to the upper layer through mac_link_update() 36764061Sxy150489 * in this function. It will be updated in the local timer routine or the 36774061Sxy150489 * interrupt service routine after the interface is started (plumbed). 36784061Sxy150489 */ 36793526Sxy150489 static void 36804061Sxy150489 e1000g_link_timer(void *arg) 36813526Sxy150489 { 36824061Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg; 36833526Sxy150489 36844919Sxy150489 mutex_enter(&Adapter->link_lock); 36854061Sxy150489 Adapter->link_complete = B_TRUE; 36864061Sxy150489 Adapter->link_tid = 0; 36874919Sxy150489 mutex_exit(&Adapter->link_lock); 36883526Sxy150489 } 36893526Sxy150489 36903526Sxy150489 /* 36914919Sxy150489 * e1000g_force_speed_duplex - read forced speed/duplex out of e1000g.conf 36924919Sxy150489 * 36934919Sxy150489 * This function read the forced speed and duplex for 10/100 Mbps speeds 36944919Sxy150489 * and also for 1000 Mbps speeds from the e1000g.conf file 36953526Sxy150489 */ 36963526Sxy150489 static void 36973526Sxy150489 e1000g_force_speed_duplex(struct e1000g *Adapter) 36983526Sxy150489 { 36993526Sxy150489 int forced; 37004919Sxy150489 struct e1000_mac_info *mac = &Adapter->shared.mac; 37014919Sxy150489 struct e1000_phy_info *phy = &Adapter->shared.phy; 37023526Sxy150489 37033526Sxy150489 /* 37043526Sxy150489 * get value out of config file 37053526Sxy150489 */ 37064919Sxy150489 forced = e1000g_get_prop(Adapter, "ForceSpeedDuplex", 37073526Sxy150489 GDIAG_10_HALF, GDIAG_ANY, GDIAG_ANY); 37083526Sxy150489 37093526Sxy150489 switch (forced) { 37103526Sxy150489 case GDIAG_10_HALF: 37113526Sxy150489 /* 37123526Sxy150489 * Disable Auto Negotiation 37133526Sxy150489 */ 37144919Sxy150489 mac->autoneg = B_FALSE; 37154919Sxy150489 mac->forced_speed_duplex = ADVERTISE_10_HALF; 37163526Sxy150489 break; 37173526Sxy150489 case GDIAG_10_FULL: 37183526Sxy150489 /* 37193526Sxy150489 * Disable Auto Negotiation 37203526Sxy150489 */ 37214919Sxy150489 mac->autoneg = B_FALSE; 37224919Sxy150489 mac->forced_speed_duplex = ADVERTISE_10_FULL; 37233526Sxy150489 break; 37243526Sxy150489 case GDIAG_100_HALF: 37253526Sxy150489 /* 37263526Sxy150489 * Disable Auto Negotiation 37273526Sxy150489 */ 37284919Sxy150489 mac->autoneg = B_FALSE; 37294919Sxy150489 mac->forced_speed_duplex = ADVERTISE_100_HALF; 37303526Sxy150489 break; 37313526Sxy150489 case GDIAG_100_FULL: 37323526Sxy150489 /* 37333526Sxy150489 * Disable Auto Negotiation 37343526Sxy150489 */ 37354919Sxy150489 mac->autoneg = B_FALSE; 37364919Sxy150489 mac->forced_speed_duplex = ADVERTISE_100_FULL; 37373526Sxy150489 break; 37383526Sxy150489 case GDIAG_1000_FULL: 37393526Sxy150489 /* 37403526Sxy150489 * The gigabit spec requires autonegotiation. Therefore, 37413526Sxy150489 * when the user wants to force the speed to 1000Mbps, we 37423526Sxy150489 * enable AutoNeg, but only allow the harware to advertise 37433526Sxy150489 * 1000Mbps. This is different from 10/100 operation, where 37443526Sxy150489 * we are allowed to link without any negotiation. 37453526Sxy150489 */ 37464919Sxy150489 mac->autoneg = B_TRUE; 37474919Sxy150489 phy->autoneg_advertised = ADVERTISE_1000_FULL; 37483526Sxy150489 break; 37493526Sxy150489 default: /* obey the setting of AutoNegAdvertised */ 37504919Sxy150489 mac->autoneg = B_TRUE; 37514919Sxy150489 phy->autoneg_advertised = 37524919Sxy150489 (uint16_t)e1000g_get_prop(Adapter, "AutoNegAdvertised", 37534349Sxy150489 0, AUTONEG_ADVERTISE_SPEED_DEFAULT, 37544349Sxy150489 AUTONEG_ADVERTISE_SPEED_DEFAULT); 37553526Sxy150489 break; 37563526Sxy150489 } /* switch */ 37573526Sxy150489 } 37583526Sxy150489 37593526Sxy150489 /* 37604919Sxy150489 * e1000g_get_max_frame_size - get jumbo frame setting from e1000g.conf 37614919Sxy150489 * 37624919Sxy150489 * This function reads MaxFrameSize from e1000g.conf 37633526Sxy150489 */ 37643526Sxy150489 static void 37653526Sxy150489 e1000g_get_max_frame_size(struct e1000g *Adapter) 37663526Sxy150489 { 37673526Sxy150489 int max_frame; 37684919Sxy150489 struct e1000_mac_info *mac = &Adapter->shared.mac; 37694919Sxy150489 struct e1000_phy_info *phy = &Adapter->shared.phy; 37703526Sxy150489 37713526Sxy150489 /* 37723526Sxy150489 * get value out of config file 37733526Sxy150489 */ 37744919Sxy150489 max_frame = e1000g_get_prop(Adapter, "MaxFrameSize", 0, 3, 0); 37753526Sxy150489 37763526Sxy150489 switch (max_frame) { 37773526Sxy150489 case 0: 3778*6394Scc210113 Adapter->default_mtu = ETHERMTU; 37793526Sxy150489 break; 3780*6394Scc210113 /* 3781*6394Scc210113 * To avoid excessive memory allocation for rx buffers, 3782*6394Scc210113 * the bytes of E1000G_IPALIGNPRESERVEROOM are reserved. 3783*6394Scc210113 */ 37843526Sxy150489 case 1: 3785*6394Scc210113 Adapter->default_mtu = FRAME_SIZE_UPTO_4K - 3786*6394Scc210113 sizeof (struct ether_vlan_header) - ETHERFCSL - 3787*6394Scc210113 E1000G_IPALIGNPRESERVEROOM; 37883526Sxy150489 break; 37893526Sxy150489 case 2: 3790*6394Scc210113 Adapter->default_mtu = FRAME_SIZE_UPTO_8K - 3791*6394Scc210113 sizeof (struct ether_vlan_header) - ETHERFCSL - 3792*6394Scc210113 E1000G_IPALIGNPRESERVEROOM; 37933526Sxy150489 break; 37943526Sxy150489 case 3: 3795*6394Scc210113 if (mac->type >= e1000_82571) 3796*6394Scc210113 Adapter->default_mtu = MAXIMUM_MTU; 37973526Sxy150489 else 3798*6394Scc210113 Adapter->default_mtu = FRAME_SIZE_UPTO_16K - 3799*6394Scc210113 sizeof (struct ether_vlan_header) - ETHERFCSL - 3800*6394Scc210113 E1000G_IPALIGNPRESERVEROOM; 38013526Sxy150489 break; 38023526Sxy150489 default: 3803*6394Scc210113 Adapter->default_mtu = ETHERMTU; 38043526Sxy150489 break; 38053526Sxy150489 } /* switch */ 38063526Sxy150489 3807*6394Scc210113 mac->max_frame_size = Adapter->default_mtu + 3808*6394Scc210113 sizeof (struct ether_vlan_header) + ETHERFCSL; 3809*6394Scc210113 38103526Sxy150489 /* ich8 does not do jumbo frames */ 38114919Sxy150489 if (mac->type == e1000_ich8lan) { 38124919Sxy150489 mac->max_frame_size = ETHERMAX; 38134919Sxy150489 } 38144919Sxy150489 38154919Sxy150489 /* ich9 does not do jumbo frames on one phy type */ 38164919Sxy150489 if ((mac->type == e1000_ich9lan) && 38174919Sxy150489 (phy->type == e1000_phy_ife)) { 38184919Sxy150489 mac->max_frame_size = ETHERMAX; 38193526Sxy150489 } 38203526Sxy150489 } 38213526Sxy150489 38223526Sxy150489 static void 38234919Sxy150489 arm_watchdog_timer(struct e1000g *Adapter) 38243526Sxy150489 { 38254919Sxy150489 Adapter->watchdog_tid = 38264919Sxy150489 timeout(e1000g_local_timer, 38273526Sxy150489 (void *)Adapter, 1 * drv_usectohz(1000000)); 38283526Sxy150489 } 38294919Sxy150489 #pragma inline(arm_watchdog_timer) 38304919Sxy150489 38314919Sxy150489 static void 38324919Sxy150489 enable_watchdog_timer(struct e1000g *Adapter) 38334919Sxy150489 { 38344919Sxy150489 mutex_enter(&Adapter->watchdog_lock); 38354919Sxy150489 38364919Sxy150489 if (!Adapter->watchdog_timer_enabled) { 38374919Sxy150489 Adapter->watchdog_timer_enabled = B_TRUE; 38384919Sxy150489 Adapter->watchdog_timer_started = B_TRUE; 38394919Sxy150489 arm_watchdog_timer(Adapter); 38404919Sxy150489 } 38414919Sxy150489 38424919Sxy150489 mutex_exit(&Adapter->watchdog_lock); 38434919Sxy150489 } 38443526Sxy150489 38453526Sxy150489 static void 38464919Sxy150489 disable_watchdog_timer(struct e1000g *Adapter) 38473526Sxy150489 { 38483526Sxy150489 timeout_id_t tid; 38493526Sxy150489 38504919Sxy150489 mutex_enter(&Adapter->watchdog_lock); 38514919Sxy150489 38524919Sxy150489 Adapter->watchdog_timer_enabled = B_FALSE; 38534919Sxy150489 Adapter->watchdog_timer_started = B_FALSE; 38544919Sxy150489 tid = Adapter->watchdog_tid; 38554919Sxy150489 Adapter->watchdog_tid = 0; 38564919Sxy150489 38574919Sxy150489 mutex_exit(&Adapter->watchdog_lock); 38583526Sxy150489 38593526Sxy150489 if (tid != 0) 38603526Sxy150489 (void) untimeout(tid); 38613526Sxy150489 } 38623526Sxy150489 38633526Sxy150489 static void 38644919Sxy150489 start_watchdog_timer(struct e1000g *Adapter) 38653526Sxy150489 { 38664919Sxy150489 mutex_enter(&Adapter->watchdog_lock); 38674919Sxy150489 38684919Sxy150489 if (Adapter->watchdog_timer_enabled) { 38694919Sxy150489 if (!Adapter->watchdog_timer_started) { 38704919Sxy150489 Adapter->watchdog_timer_started = B_TRUE; 38714919Sxy150489 arm_watchdog_timer(Adapter); 38723526Sxy150489 } 38733526Sxy150489 } 38743526Sxy150489 38754919Sxy150489 mutex_exit(&Adapter->watchdog_lock); 38764919Sxy150489 } 38774919Sxy150489 38784919Sxy150489 static void 38794919Sxy150489 restart_watchdog_timer(struct e1000g *Adapter) 38804919Sxy150489 { 38814919Sxy150489 mutex_enter(&Adapter->watchdog_lock); 38824919Sxy150489 38834919Sxy150489 if (Adapter->watchdog_timer_started) 38844919Sxy150489 arm_watchdog_timer(Adapter); 38854919Sxy150489 38864919Sxy150489 mutex_exit(&Adapter->watchdog_lock); 38873526Sxy150489 } 38883526Sxy150489 38893526Sxy150489 static void 38904919Sxy150489 stop_watchdog_timer(struct e1000g *Adapter) 38913526Sxy150489 { 38924919Sxy150489 timeout_id_t tid; 38934919Sxy150489 38944919Sxy150489 mutex_enter(&Adapter->watchdog_lock); 38954919Sxy150489 38964919Sxy150489 Adapter->watchdog_timer_started = B_FALSE; 38974919Sxy150489 tid = Adapter->watchdog_tid; 38984919Sxy150489 Adapter->watchdog_tid = 0; 38994919Sxy150489 39004919Sxy150489 mutex_exit(&Adapter->watchdog_lock); 39014919Sxy150489 39024919Sxy150489 if (tid != 0) 39034919Sxy150489 (void) untimeout(tid); 39043526Sxy150489 } 39053526Sxy150489 39063526Sxy150489 static void 39074919Sxy150489 stop_link_timer(struct e1000g *Adapter) 39083526Sxy150489 { 39093526Sxy150489 timeout_id_t tid; 39103526Sxy150489 39114919Sxy150489 /* Disable the link timer */ 39124919Sxy150489 mutex_enter(&Adapter->link_lock); 39134919Sxy150489 39144919Sxy150489 tid = Adapter->link_tid; 39154919Sxy150489 Adapter->link_tid = 0; 39164919Sxy150489 39174919Sxy150489 mutex_exit(&Adapter->link_lock); 39184919Sxy150489 39194919Sxy150489 if (tid != 0) 39204919Sxy150489 (void) untimeout(tid); 39214919Sxy150489 } 39224919Sxy150489 39234919Sxy150489 static void 39244919Sxy150489 stop_82547_timer(e1000g_tx_ring_t *tx_ring) 39254919Sxy150489 { 39264919Sxy150489 timeout_id_t tid; 39274919Sxy150489 39284919Sxy150489 /* Disable the tx timer for 82547 chipset */ 39294919Sxy150489 mutex_enter(&tx_ring->tx_lock); 39304919Sxy150489 39314919Sxy150489 tx_ring->timer_enable_82547 = B_FALSE; 39324919Sxy150489 tid = tx_ring->timer_id_82547; 39334919Sxy150489 tx_ring->timer_id_82547 = 0; 39344919Sxy150489 39354919Sxy150489 mutex_exit(&tx_ring->tx_lock); 39363526Sxy150489 39373526Sxy150489 if (tid != 0) 39383526Sxy150489 (void) untimeout(tid); 39393526Sxy150489 } 39403526Sxy150489 39413526Sxy150489 void 39424919Sxy150489 e1000g_clear_interrupt(struct e1000g *Adapter) 39433526Sxy150489 { 39444919Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_IMC, 39454919Sxy150489 0xffffffff & ~E1000_IMS_RXSEQ); 39463526Sxy150489 } 39473526Sxy150489 39483526Sxy150489 void 39494919Sxy150489 e1000g_mask_interrupt(struct e1000g *Adapter) 39503526Sxy150489 { 39514919Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_IMS, 39525882Syy150190 IMS_ENABLE_MASK & ~E1000_IMS_TXDW); 39535882Syy150190 39545882Syy150190 if (Adapter->tx_intr_enable) 39555882Syy150190 e1000g_mask_tx_interrupt(Adapter); 39563526Sxy150489 } 39573526Sxy150489 39583526Sxy150489 void 39594919Sxy150489 e1000g_clear_all_interrupts(struct e1000g *Adapter) 39603526Sxy150489 { 39614919Sxy150489 E1000_WRITE_REG(&Adapter->shared, E1000_IMC, 0xffffffff); 39623526Sxy150489 } 39633526Sxy150489 39643526Sxy150489 void 39654919Sxy150489 e1000g_mask_tx_interrupt(struct e1000g *Adapter) 39663526Sxy150489 { 39675882Syy150190 E1000_WRITE_REG(&Adapter->shared, E1000_IMS, E1000_IMS_TXDW); 39683526Sxy150489 } 39693526Sxy150489 39703526Sxy150489 void 39714919Sxy150489 e1000g_clear_tx_interrupt(struct e1000g *Adapter) 39723526Sxy150489 { 39735882Syy150190 E1000_WRITE_REG(&Adapter->shared, E1000_IMC, E1000_IMS_TXDW); 39743526Sxy150489 } 39753526Sxy150489 39763526Sxy150489 static void 39774919Sxy150489 e1000g_smartspeed(struct e1000g *Adapter) 39783526Sxy150489 { 39794919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 39803526Sxy150489 uint16_t phy_status; 39813526Sxy150489 uint16_t phy_ctrl; 39823526Sxy150489 39833526Sxy150489 /* 39843526Sxy150489 * If we're not T-or-T, or we're not autoneg'ing, or we're not 39853526Sxy150489 * advertising 1000Full, we don't even use the workaround 39863526Sxy150489 */ 39874919Sxy150489 if ((hw->phy.type != e1000_phy_igp) || 39884919Sxy150489 !hw->mac.autoneg || 39894919Sxy150489 !(hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)) 39903526Sxy150489 return; 39913526Sxy150489 39923526Sxy150489 /* 39933526Sxy150489 * True if this is the first call of this function or after every 39943526Sxy150489 * 30 seconds of not having link 39953526Sxy150489 */ 39964919Sxy150489 if (Adapter->smartspeed == 0) { 39973526Sxy150489 /* 39983526Sxy150489 * If Master/Slave config fault is asserted twice, we 39993526Sxy150489 * assume back-to-back 40003526Sxy150489 */ 40014919Sxy150489 e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status); 40023526Sxy150489 if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) 40033526Sxy150489 return; 40043526Sxy150489 40054919Sxy150489 e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status); 40063526Sxy150489 if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) 40073526Sxy150489 return; 40083526Sxy150489 /* 40093526Sxy150489 * We're assuming back-2-back because our status register 40103526Sxy150489 * insists! there's a fault in the master/slave 40113526Sxy150489 * relationship that was "negotiated" 40123526Sxy150489 */ 40134919Sxy150489 e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl); 40143526Sxy150489 /* 40153526Sxy150489 * Is the phy configured for manual configuration of 40163526Sxy150489 * master/slave? 40173526Sxy150489 */ 40183526Sxy150489 if (phy_ctrl & CR_1000T_MS_ENABLE) { 40193526Sxy150489 /* 40203526Sxy150489 * Yes. Then disable manual configuration (enable 40213526Sxy150489 * auto configuration) of master/slave 40223526Sxy150489 */ 40233526Sxy150489 phy_ctrl &= ~CR_1000T_MS_ENABLE; 40244919Sxy150489 e1000_write_phy_reg(hw, 40253526Sxy150489 PHY_1000T_CTRL, phy_ctrl); 40263526Sxy150489 /* 40273526Sxy150489 * Effectively starting the clock 40283526Sxy150489 */ 40294919Sxy150489 Adapter->smartspeed++; 40303526Sxy150489 /* 40313526Sxy150489 * Restart autonegotiation 40323526Sxy150489 */ 40334919Sxy150489 if (!e1000_phy_setup_autoneg(hw) && 40344919Sxy150489 !e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl)) { 40353526Sxy150489 phy_ctrl |= (MII_CR_AUTO_NEG_EN | 40363526Sxy150489 MII_CR_RESTART_AUTO_NEG); 40374919Sxy150489 e1000_write_phy_reg(hw, 40384919Sxy150489 PHY_CONTROL, phy_ctrl); 40393526Sxy150489 } 40403526Sxy150489 } 40413526Sxy150489 return; 40423526Sxy150489 /* 40433526Sxy150489 * Has 6 seconds transpired still without link? Remember, 40443526Sxy150489 * you should reset the smartspeed counter once you obtain 40453526Sxy150489 * link 40463526Sxy150489 */ 40474919Sxy150489 } else if (Adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) { 40483526Sxy150489 /* 40493526Sxy150489 * Yes. Remember, we did at the start determine that 40503526Sxy150489 * there's a master/slave configuration fault, so we're 40513526Sxy150489 * still assuming there's someone on the other end, but we 40523526Sxy150489 * just haven't yet been able to talk to it. We then 40533526Sxy150489 * re-enable auto configuration of master/slave to see if 40543526Sxy150489 * we're running 2/3 pair cables. 40553526Sxy150489 */ 40563526Sxy150489 /* 40573526Sxy150489 * If still no link, perhaps using 2/3 pair cable 40583526Sxy150489 */ 40594919Sxy150489 e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl); 40603526Sxy150489 phy_ctrl |= CR_1000T_MS_ENABLE; 40614919Sxy150489 e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_ctrl); 40623526Sxy150489 /* 40633526Sxy150489 * Restart autoneg with phy enabled for manual 40643526Sxy150489 * configuration of master/slave 40653526Sxy150489 */ 40664919Sxy150489 if (!e1000_phy_setup_autoneg(hw) && 40674919Sxy150489 !e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl)) { 40683526Sxy150489 phy_ctrl |= 40693526Sxy150489 (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); 40704919Sxy150489 e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl); 40713526Sxy150489 } 40723526Sxy150489 /* 40733526Sxy150489 * Hopefully, there are no more faults and we've obtained 40743526Sxy150489 * link as a result. 40753526Sxy150489 */ 40763526Sxy150489 } 40773526Sxy150489 /* 40783526Sxy150489 * Restart process after E1000_SMARTSPEED_MAX iterations (30 40793526Sxy150489 * seconds) 40803526Sxy150489 */ 40814919Sxy150489 if (Adapter->smartspeed++ == E1000_SMARTSPEED_MAX) 40824919Sxy150489 Adapter->smartspeed = 0; 40833526Sxy150489 } 40843526Sxy150489 40853526Sxy150489 static boolean_t 40863526Sxy150489 is_valid_mac_addr(uint8_t *mac_addr) 40873526Sxy150489 { 40883526Sxy150489 const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 }; 40893526Sxy150489 const uint8_t addr_test2[6] = 40903526Sxy150489 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 40913526Sxy150489 40923526Sxy150489 if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) || 40933526Sxy150489 !(bcmp(addr_test2, mac_addr, ETHERADDRL))) 40943526Sxy150489 return (B_FALSE); 40953526Sxy150489 40963526Sxy150489 return (B_TRUE); 40973526Sxy150489 } 40983526Sxy150489 40993526Sxy150489 /* 41004919Sxy150489 * e1000g_stall_check - check for tx stall 41014919Sxy150489 * 41024919Sxy150489 * This function checks if the adapter is stalled (in transmit). 41034919Sxy150489 * 41044919Sxy150489 * It is called each time the watchdog timeout is invoked. 41054919Sxy150489 * If the transmit descriptor reclaim continuously fails, 41064919Sxy150489 * the watchdog value will increment by 1. If the watchdog 41074919Sxy150489 * value exceeds the threshold, the adapter is assumed to 41084919Sxy150489 * have stalled and need to be reset. 41093526Sxy150489 */ 41103526Sxy150489 static boolean_t 41113526Sxy150489 e1000g_stall_check(struct e1000g *Adapter) 41123526Sxy150489 { 41134919Sxy150489 e1000g_tx_ring_t *tx_ring; 41144919Sxy150489 41154919Sxy150489 tx_ring = Adapter->tx_ring; 41164919Sxy150489 41174061Sxy150489 if (Adapter->link_state != LINK_STATE_UP) 41183526Sxy150489 return (B_FALSE); 41193526Sxy150489 41204919Sxy150489 if (tx_ring->recycle_fail > 0) 41214919Sxy150489 tx_ring->stall_watchdog++; 41223526Sxy150489 else 41234919Sxy150489 tx_ring->stall_watchdog = 0; 41244919Sxy150489 41254919Sxy150489 if (tx_ring->stall_watchdog < E1000G_STALL_WATCHDOG_COUNT) 41263526Sxy150489 return (B_FALSE); 41273526Sxy150489 41284919Sxy150489 tx_ring->stall_watchdog = 0; 41294919Sxy150489 tx_ring->recycle_fail = 0; 41304919Sxy150489 41313526Sxy150489 return (B_TRUE); 41323526Sxy150489 } 41333526Sxy150489 41344919Sxy150489 #ifdef E1000G_DEBUG 41353526Sxy150489 static enum ioc_reply 41363526Sxy150489 e1000g_pp_ioctl(struct e1000g *e1000gp, struct iocblk *iocp, mblk_t *mp) 41373526Sxy150489 { 41383526Sxy150489 void (*ppfn)(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd); 41393526Sxy150489 e1000g_peekpoke_t *ppd; 41403526Sxy150489 uint64_t mem_va; 41413526Sxy150489 uint64_t maxoff; 41423526Sxy150489 boolean_t peek; 41433526Sxy150489 41443526Sxy150489 switch (iocp->ioc_cmd) { 41453526Sxy150489 41463526Sxy150489 case E1000G_IOC_REG_PEEK: 41473526Sxy150489 peek = B_TRUE; 41483526Sxy150489 break; 41493526Sxy150489 41503526Sxy150489 case E1000G_IOC_REG_POKE: 41513526Sxy150489 peek = B_FALSE; 41523526Sxy150489 break; 41533526Sxy150489 41543526Sxy150489 deault: 41554919Sxy150489 E1000G_DEBUGLOG_1(e1000gp, E1000G_INFO_LEVEL, 41564349Sxy150489 "e1000g_diag_ioctl: invalid ioctl command 0x%X\n", 41574349Sxy150489 iocp->ioc_cmd); 41583526Sxy150489 return (IOC_INVAL); 41593526Sxy150489 } 41603526Sxy150489 41613526Sxy150489 /* 41623526Sxy150489 * Validate format of ioctl 41633526Sxy150489 */ 41643526Sxy150489 if (iocp->ioc_count != sizeof (e1000g_peekpoke_t)) 41653526Sxy150489 return (IOC_INVAL); 41663526Sxy150489 if (mp->b_cont == NULL) 41673526Sxy150489 return (IOC_INVAL); 41683526Sxy150489 41693526Sxy150489 ppd = (e1000g_peekpoke_t *)mp->b_cont->b_rptr; 41703526Sxy150489 41713526Sxy150489 /* 41723526Sxy150489 * Validate request parameters 41733526Sxy150489 */ 41743526Sxy150489 switch (ppd->pp_acc_space) { 41753526Sxy150489 41763526Sxy150489 default: 41774919Sxy150489 E1000G_DEBUGLOG_1(e1000gp, E1000G_INFO_LEVEL, 41784349Sxy150489 "e1000g_diag_ioctl: invalid access space 0x%X\n", 41794349Sxy150489 ppd->pp_acc_space); 41803526Sxy150489 return (IOC_INVAL); 41813526Sxy150489 41823526Sxy150489 case E1000G_PP_SPACE_REG: 41833526Sxy150489 /* 41843526Sxy150489 * Memory-mapped I/O space 41853526Sxy150489 */ 41863526Sxy150489 ASSERT(ppd->pp_acc_size == 4); 41873526Sxy150489 if (ppd->pp_acc_size != 4) 41883526Sxy150489 return (IOC_INVAL); 41893526Sxy150489 41903526Sxy150489 if ((ppd->pp_acc_offset % ppd->pp_acc_size) != 0) 41913526Sxy150489 return (IOC_INVAL); 41923526Sxy150489 41933526Sxy150489 mem_va = 0; 41943526Sxy150489 maxoff = 0x10000; 41953526Sxy150489 ppfn = peek ? e1000g_ioc_peek_reg : e1000g_ioc_poke_reg; 41963526Sxy150489 break; 41973526Sxy150489 41983526Sxy150489 case E1000G_PP_SPACE_E1000G: 41993526Sxy150489 /* 42003526Sxy150489 * E1000g data structure! 42013526Sxy150489 */ 42023526Sxy150489 mem_va = (uintptr_t)e1000gp; 42033526Sxy150489 maxoff = sizeof (struct e1000g); 42043526Sxy150489 ppfn = peek ? e1000g_ioc_peek_mem : e1000g_ioc_poke_mem; 42053526Sxy150489 break; 42063526Sxy150489 42073526Sxy150489 } 42083526Sxy150489 42093526Sxy150489 if (ppd->pp_acc_offset >= maxoff) 42103526Sxy150489 return (IOC_INVAL); 42113526Sxy150489 42123526Sxy150489 if (ppd->pp_acc_offset + ppd->pp_acc_size > maxoff) 42133526Sxy150489 return (IOC_INVAL); 42143526Sxy150489 42153526Sxy150489 /* 42163526Sxy150489 * All OK - go! 42173526Sxy150489 */ 42183526Sxy150489 ppd->pp_acc_offset += mem_va; 42193526Sxy150489 (*ppfn)(e1000gp, ppd); 42203526Sxy150489 return (peek ? IOC_REPLY : IOC_ACK); 42213526Sxy150489 } 42223526Sxy150489 42233526Sxy150489 static void 42243526Sxy150489 e1000g_ioc_peek_reg(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd) 42253526Sxy150489 { 42263526Sxy150489 ddi_acc_handle_t handle; 42273526Sxy150489 uint32_t *regaddr; 42283526Sxy150489 42294919Sxy150489 handle = e1000gp->osdep.reg_handle; 42303526Sxy150489 regaddr = 42314919Sxy150489 (uint32_t *)(e1000gp->shared.hw_addr + ppd->pp_acc_offset); 42323526Sxy150489 42333526Sxy150489 ppd->pp_acc_data = ddi_get32(handle, regaddr); 42343526Sxy150489 } 42353526Sxy150489 42363526Sxy150489 static void 42373526Sxy150489 e1000g_ioc_poke_reg(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd) 42383526Sxy150489 { 42393526Sxy150489 ddi_acc_handle_t handle; 42403526Sxy150489 uint32_t *regaddr; 42413526Sxy150489 uint32_t value; 42423526Sxy150489 42434919Sxy150489 handle = e1000gp->osdep.reg_handle; 42443526Sxy150489 regaddr = 42454919Sxy150489 (uint32_t *)(e1000gp->shared.hw_addr + ppd->pp_acc_offset); 42463526Sxy150489 value = (uint32_t)ppd->pp_acc_data; 42473526Sxy150489 42483526Sxy150489 ddi_put32(handle, regaddr, value); 42493526Sxy150489 } 42503526Sxy150489 42513526Sxy150489 static void 42523526Sxy150489 e1000g_ioc_peek_mem(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd) 42533526Sxy150489 { 42543526Sxy150489 uint64_t value; 42553526Sxy150489 void *vaddr; 42563526Sxy150489 42573526Sxy150489 vaddr = (void *)(uintptr_t)ppd->pp_acc_offset; 42583526Sxy150489 42593526Sxy150489 switch (ppd->pp_acc_size) { 42603526Sxy150489 case 1: 42613526Sxy150489 value = *(uint8_t *)vaddr; 42623526Sxy150489 break; 42633526Sxy150489 42643526Sxy150489 case 2: 42653526Sxy150489 value = *(uint16_t *)vaddr; 42663526Sxy150489 break; 42673526Sxy150489 42683526Sxy150489 case 4: 42693526Sxy150489 value = *(uint32_t *)vaddr; 42703526Sxy150489 break; 42713526Sxy150489 42723526Sxy150489 case 8: 42733526Sxy150489 value = *(uint64_t *)vaddr; 42743526Sxy150489 break; 42753526Sxy150489 } 42763526Sxy150489 42774919Sxy150489 E1000G_DEBUGLOG_4(e1000gp, E1000G_INFO_LEVEL, 42784349Sxy150489 "e1000g_ioc_peek_mem($%p, $%p) peeked 0x%llx from $%p\n", 42794349Sxy150489 (void *)e1000gp, (void *)ppd, value, vaddr); 42803526Sxy150489 42813526Sxy150489 ppd->pp_acc_data = value; 42823526Sxy150489 } 42833526Sxy150489 42843526Sxy150489 static void 42853526Sxy150489 e1000g_ioc_poke_mem(struct e1000g *e1000gp, e1000g_peekpoke_t *ppd) 42863526Sxy150489 { 42873526Sxy150489 uint64_t value; 42883526Sxy150489 void *vaddr; 42893526Sxy150489 42903526Sxy150489 vaddr = (void *)(uintptr_t)ppd->pp_acc_offset; 42913526Sxy150489 value = ppd->pp_acc_data; 42923526Sxy150489 42934919Sxy150489 E1000G_DEBUGLOG_4(e1000gp, E1000G_INFO_LEVEL, 42944349Sxy150489 "e1000g_ioc_poke_mem($%p, $%p) poking 0x%llx at $%p\n", 42954349Sxy150489 (void *)e1000gp, (void *)ppd, value, vaddr); 42963526Sxy150489 42973526Sxy150489 switch (ppd->pp_acc_size) { 42983526Sxy150489 case 1: 42993526Sxy150489 *(uint8_t *)vaddr = (uint8_t)value; 43003526Sxy150489 break; 43013526Sxy150489 43023526Sxy150489 case 2: 43033526Sxy150489 *(uint16_t *)vaddr = (uint16_t)value; 43043526Sxy150489 break; 43053526Sxy150489 43063526Sxy150489 case 4: 43073526Sxy150489 *(uint32_t *)vaddr = (uint32_t)value; 43083526Sxy150489 break; 43093526Sxy150489 43103526Sxy150489 case 8: 43113526Sxy150489 *(uint64_t *)vaddr = (uint64_t)value; 43123526Sxy150489 break; 43133526Sxy150489 } 43143526Sxy150489 } 43154919Sxy150489 #endif 43163526Sxy150489 43173526Sxy150489 /* 43183526Sxy150489 * Loopback Support 43193526Sxy150489 */ 43203526Sxy150489 static lb_property_t lb_normal = 43213526Sxy150489 { normal, "normal", E1000G_LB_NONE }; 43223526Sxy150489 static lb_property_t lb_external1000 = 43233526Sxy150489 { external, "1000Mbps", E1000G_LB_EXTERNAL_1000 }; 43243526Sxy150489 static lb_property_t lb_external100 = 43253526Sxy150489 { external, "100Mbps", E1000G_LB_EXTERNAL_100 }; 43263526Sxy150489 static lb_property_t lb_external10 = 43273526Sxy150489 { external, "10Mbps", E1000G_LB_EXTERNAL_10 }; 43283526Sxy150489 static lb_property_t lb_phy = 43293526Sxy150489 { internal, "PHY", E1000G_LB_INTERNAL_PHY }; 43303526Sxy150489 43313526Sxy150489 static enum ioc_reply 43323526Sxy150489 e1000g_loopback_ioctl(struct e1000g *Adapter, struct iocblk *iocp, mblk_t *mp) 43333526Sxy150489 { 43343526Sxy150489 lb_info_sz_t *lbsp; 43353526Sxy150489 lb_property_t *lbpp; 43363526Sxy150489 struct e1000_hw *hw; 43373526Sxy150489 uint32_t *lbmp; 43383526Sxy150489 uint32_t size; 43393526Sxy150489 uint32_t value; 43403526Sxy150489 43414919Sxy150489 hw = &Adapter->shared; 43423526Sxy150489 43433526Sxy150489 if (mp->b_cont == NULL) 43443526Sxy150489 return (IOC_INVAL); 43453526Sxy150489 43463526Sxy150489 switch (iocp->ioc_cmd) { 43473526Sxy150489 default: 43483526Sxy150489 return (IOC_INVAL); 43493526Sxy150489 43503526Sxy150489 case LB_GET_INFO_SIZE: 43513526Sxy150489 size = sizeof (lb_info_sz_t); 43523526Sxy150489 if (iocp->ioc_count != size) 43533526Sxy150489 return (IOC_INVAL); 43543526Sxy150489 43555082Syy150190 rw_enter(&Adapter->chip_lock, RW_WRITER); 43565082Syy150190 e1000g_get_phy_state(Adapter); 43575082Syy150190 43585082Syy150190 /* 43595082Syy150190 * Workaround for hardware faults. In order to get a stable 43605082Syy150190 * state of phy, we will wait for a specific interval and 43615082Syy150190 * try again. The time delay is an experiential value based 43625082Syy150190 * on our testing. 43635082Syy150190 */ 43645082Syy150190 msec_delay(100); 43655082Syy150190 e1000g_get_phy_state(Adapter); 43665082Syy150190 rw_exit(&Adapter->chip_lock); 43673526Sxy150489 43683526Sxy150489 value = sizeof (lb_normal); 43695082Syy150190 if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) || 43705082Syy150190 (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) || 43713526Sxy150489 (hw->media_type == e1000_media_type_fiber) || 43723526Sxy150489 (hw->media_type == e1000_media_type_internal_serdes)) { 43733526Sxy150489 value += sizeof (lb_phy); 43744919Sxy150489 switch (hw->mac.type) { 43753526Sxy150489 case e1000_82571: 43763526Sxy150489 case e1000_82572: 43773526Sxy150489 value += sizeof (lb_external1000); 43783526Sxy150489 break; 43793526Sxy150489 } 43803526Sxy150489 } 43815082Syy150190 if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 43825082Syy150190 (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) 43833526Sxy150489 value += sizeof (lb_external100); 43845082Syy150190 if (Adapter->phy_status & MII_SR_10T_FD_CAPS) 43853526Sxy150489 value += sizeof (lb_external10); 43863526Sxy150489 43873526Sxy150489 lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr; 43883526Sxy150489 *lbsp = value; 43893526Sxy150489 break; 43903526Sxy150489 43913526Sxy150489 case LB_GET_INFO: 43923526Sxy150489 value = sizeof (lb_normal); 43935082Syy150190 if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) || 43945082Syy150190 (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) || 43953526Sxy150489 (hw->media_type == e1000_media_type_fiber) || 43963526Sxy150489 (hw->media_type == e1000_media_type_internal_serdes)) { 43973526Sxy150489 value += sizeof (lb_phy); 43984919Sxy150489 switch (hw->mac.type) { 43993526Sxy150489 case e1000_82571: 44003526Sxy150489 case e1000_82572: 44013526Sxy150489 value += sizeof (lb_external1000); 44023526Sxy150489 break; 44033526Sxy150489 } 44043526Sxy150489 } 44055082Syy150190 if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 44065082Syy150190 (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) 44073526Sxy150489 value += sizeof (lb_external100); 44085082Syy150190 if (Adapter->phy_status & MII_SR_10T_FD_CAPS) 44093526Sxy150489 value += sizeof (lb_external10); 44103526Sxy150489 44113526Sxy150489 size = value; 44123526Sxy150489 if (iocp->ioc_count != size) 44133526Sxy150489 return (IOC_INVAL); 44143526Sxy150489 44153526Sxy150489 value = 0; 44163526Sxy150489 lbpp = (lb_property_t *)mp->b_cont->b_rptr; 44173526Sxy150489 lbpp[value++] = lb_normal; 44185082Syy150190 if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) || 44195082Syy150190 (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) || 44203526Sxy150489 (hw->media_type == e1000_media_type_fiber) || 44213526Sxy150489 (hw->media_type == e1000_media_type_internal_serdes)) { 44223526Sxy150489 lbpp[value++] = lb_phy; 44234919Sxy150489 switch (hw->mac.type) { 44243526Sxy150489 case e1000_82571: 44253526Sxy150489 case e1000_82572: 44263526Sxy150489 lbpp[value++] = lb_external1000; 44273526Sxy150489 break; 44283526Sxy150489 } 44293526Sxy150489 } 44305082Syy150190 if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 44315082Syy150190 (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) 44323526Sxy150489 lbpp[value++] = lb_external100; 44335082Syy150190 if (Adapter->phy_status & MII_SR_10T_FD_CAPS) 44343526Sxy150489 lbpp[value++] = lb_external10; 44353526Sxy150489 break; 44363526Sxy150489 44373526Sxy150489 case LB_GET_MODE: 44383526Sxy150489 size = sizeof (uint32_t); 44393526Sxy150489 if (iocp->ioc_count != size) 44403526Sxy150489 return (IOC_INVAL); 44413526Sxy150489 44423526Sxy150489 lbmp = (uint32_t *)mp->b_cont->b_rptr; 44433526Sxy150489 *lbmp = Adapter->loopback_mode; 44443526Sxy150489 break; 44453526Sxy150489 44463526Sxy150489 case LB_SET_MODE: 44473526Sxy150489 size = 0; 44483526Sxy150489 if (iocp->ioc_count != sizeof (uint32_t)) 44493526Sxy150489 return (IOC_INVAL); 44503526Sxy150489 44513526Sxy150489 lbmp = (uint32_t *)mp->b_cont->b_rptr; 44523526Sxy150489 if (!e1000g_set_loopback_mode(Adapter, *lbmp)) 44533526Sxy150489 return (IOC_INVAL); 44543526Sxy150489 break; 44553526Sxy150489 } 44563526Sxy150489 44573526Sxy150489 iocp->ioc_count = size; 44583526Sxy150489 iocp->ioc_error = 0; 44593526Sxy150489 44605273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 44615273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 44625273Sgl147354 return (IOC_INVAL); 44635273Sgl147354 } 44645273Sgl147354 44653526Sxy150489 return (IOC_REPLY); 44663526Sxy150489 } 44673526Sxy150489 44683526Sxy150489 static boolean_t 44693526Sxy150489 e1000g_set_loopback_mode(struct e1000g *Adapter, uint32_t mode) 44703526Sxy150489 { 44713526Sxy150489 struct e1000_hw *hw; 44723526Sxy150489 int i, times; 44735082Syy150190 boolean_t link_up; 44743526Sxy150489 44753526Sxy150489 if (mode == Adapter->loopback_mode) 44763526Sxy150489 return (B_TRUE); 44773526Sxy150489 44784919Sxy150489 hw = &Adapter->shared; 44793526Sxy150489 times = 0; 44803526Sxy150489 44815082Syy150190 Adapter->loopback_mode = mode; 44825082Syy150190 44835082Syy150190 if (mode == E1000G_LB_NONE) { 44843526Sxy150489 /* Reset the chip */ 44854919Sxy150489 hw->phy.wait_for_link = B_TRUE; 44863526Sxy150489 (void) e1000g_reset(Adapter); 44874919Sxy150489 hw->phy.wait_for_link = B_FALSE; 44885082Syy150190 return (B_TRUE); 44895082Syy150190 } 44905082Syy150190 44915082Syy150190 again: 44925082Syy150190 44935082Syy150190 rw_enter(&Adapter->chip_lock, RW_WRITER); 44945082Syy150190 44955082Syy150190 switch (mode) { 44965082Syy150190 default: 44975082Syy150190 rw_exit(&Adapter->chip_lock); 44985082Syy150190 return (B_FALSE); 44993526Sxy150489 45003526Sxy150489 case E1000G_LB_EXTERNAL_1000: 45013526Sxy150489 e1000g_set_external_loopback_1000(Adapter); 45023526Sxy150489 break; 45033526Sxy150489 45043526Sxy150489 case E1000G_LB_EXTERNAL_100: 45053526Sxy150489 e1000g_set_external_loopback_100(Adapter); 45063526Sxy150489 break; 45073526Sxy150489 45083526Sxy150489 case E1000G_LB_EXTERNAL_10: 45093526Sxy150489 e1000g_set_external_loopback_10(Adapter); 45103526Sxy150489 break; 45113526Sxy150489 45123526Sxy150489 case E1000G_LB_INTERNAL_PHY: 45133526Sxy150489 e1000g_set_internal_loopback(Adapter); 45143526Sxy150489 break; 45153526Sxy150489 } 45163526Sxy150489 45173526Sxy150489 times++; 45183526Sxy150489 45195858Scc210113 rw_exit(&Adapter->chip_lock); 45205858Scc210113 45215082Syy150190 /* Wait for link up */ 45225082Syy150190 for (i = (PHY_FORCE_LIMIT * 2); i > 0; i--) 45235082Syy150190 msec_delay(100); 45245082Syy150190 45255858Scc210113 rw_enter(&Adapter->chip_lock, RW_WRITER); 45265858Scc210113 45275082Syy150190 link_up = e1000g_link_up(Adapter); 45285082Syy150190 45295082Syy150190 rw_exit(&Adapter->chip_lock); 45305082Syy150190 45315082Syy150190 if (!link_up) { 45325082Syy150190 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 45335082Syy150190 "Failed to get the link up"); 45345082Syy150190 if (times < 2) { 45355082Syy150190 /* Reset the link */ 45364919Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 45375082Syy150190 "Reset the link ..."); 45385082Syy150190 (void) e1000g_reset(Adapter); 45395082Syy150190 goto again; 45403526Sxy150489 } 45413526Sxy150489 } 45423526Sxy150489 45433526Sxy150489 return (B_TRUE); 45443526Sxy150489 } 45453526Sxy150489 45463526Sxy150489 /* 45473526Sxy150489 * The following loopback settings are from Intel's technical 45483526Sxy150489 * document - "How To Loopback". All the register settings and 45493526Sxy150489 * time delay values are directly inherited from the document 45503526Sxy150489 * without more explanations available. 45513526Sxy150489 */ 45523526Sxy150489 static void 45533526Sxy150489 e1000g_set_internal_loopback(struct e1000g *Adapter) 45543526Sxy150489 { 45553526Sxy150489 struct e1000_hw *hw; 45563526Sxy150489 uint32_t ctrl; 45573526Sxy150489 uint32_t status; 45583526Sxy150489 uint16_t phy_ctrl; 45595082Syy150190 uint32_t txcw; 45603526Sxy150489 45614919Sxy150489 hw = &Adapter->shared; 45623526Sxy150489 45633526Sxy150489 /* Disable Smart Power Down */ 45643526Sxy150489 phy_spd_state(hw, B_FALSE); 45653526Sxy150489 45664919Sxy150489 e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl); 45673526Sxy150489 phy_ctrl &= ~(MII_CR_AUTO_NEG_EN | MII_CR_SPEED_100 | MII_CR_SPEED_10); 45683526Sxy150489 phy_ctrl |= MII_CR_FULL_DUPLEX | MII_CR_SPEED_1000; 45693526Sxy150489 45704919Sxy150489 switch (hw->mac.type) { 45713526Sxy150489 case e1000_82540: 45723526Sxy150489 case e1000_82545: 45733526Sxy150489 case e1000_82545_rev_3: 45743526Sxy150489 case e1000_82546: 45753526Sxy150489 case e1000_82546_rev_3: 45763526Sxy150489 case e1000_82573: 45773526Sxy150489 /* Auto-MDI/MDIX off */ 45783526Sxy150489 e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); 45793526Sxy150489 /* Reset PHY to update Auto-MDI/MDIX */ 45804919Sxy150489 e1000_write_phy_reg(hw, PHY_CONTROL, 45814349Sxy150489 phy_ctrl | MII_CR_RESET | MII_CR_AUTO_NEG_EN); 45823526Sxy150489 /* Reset PHY to auto-neg off and force 1000 */ 45834919Sxy150489 e1000_write_phy_reg(hw, PHY_CONTROL, 45844349Sxy150489 phy_ctrl | MII_CR_RESET); 45855082Syy150190 /* 45865082Syy150190 * Disable PHY receiver for 82540/545/546 and 82573 Family. 45875082Syy150190 * See comments above e1000g_set_internal_loopback() for the 45885082Syy150190 * background. 45895082Syy150190 */ 45905082Syy150190 e1000_write_phy_reg(hw, 29, 0x001F); 45915082Syy150190 e1000_write_phy_reg(hw, 30, 0x8FFC); 45925082Syy150190 e1000_write_phy_reg(hw, 29, 0x001A); 45935082Syy150190 e1000_write_phy_reg(hw, 30, 0x8FF0); 45943526Sxy150489 break; 45953526Sxy150489 } 45963526Sxy150489 45973526Sxy150489 /* Set loopback */ 45984919Sxy150489 e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl | MII_CR_LOOPBACK); 45993526Sxy150489 46003526Sxy150489 msec_delay(250); 46013526Sxy150489 46023526Sxy150489 /* Now set up the MAC to the same speed/duplex as the PHY. */ 46034919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 46043526Sxy150489 ctrl &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ 46053526Sxy150489 ctrl |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ 46064349Sxy150489 E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ 46074349Sxy150489 E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */ 46084349Sxy150489 E1000_CTRL_FD); /* Force Duplex to FULL */ 46093526Sxy150489 46104919Sxy150489 switch (hw->mac.type) { 46113526Sxy150489 case e1000_82540: 46123526Sxy150489 case e1000_82545: 46133526Sxy150489 case e1000_82545_rev_3: 46143526Sxy150489 case e1000_82546: 46153526Sxy150489 case e1000_82546_rev_3: 46163526Sxy150489 /* 46173526Sxy150489 * For some serdes we'll need to commit the writes now 46183526Sxy150489 * so that the status is updated on link 46193526Sxy150489 */ 46203526Sxy150489 if (hw->media_type == e1000_media_type_internal_serdes) { 46214919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 46223526Sxy150489 msec_delay(100); 46234919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 46243526Sxy150489 } 46253526Sxy150489 46263526Sxy150489 if (hw->media_type == e1000_media_type_copper) { 46273526Sxy150489 /* Invert Loss of Signal */ 46283526Sxy150489 ctrl |= E1000_CTRL_ILOS; 46293526Sxy150489 } else { 46303526Sxy150489 /* Set ILOS on fiber nic if half duplex is detected */ 46314919Sxy150489 status = E1000_READ_REG(hw, E1000_STATUS); 46323526Sxy150489 if ((status & E1000_STATUS_FD) == 0) 46333526Sxy150489 ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU; 46343526Sxy150489 } 46353526Sxy150489 break; 46363526Sxy150489 46373526Sxy150489 case e1000_82571: 46383526Sxy150489 case e1000_82572: 46395082Syy150190 /* 46405082Syy150190 * The fiber/SerDes versions of this adapter do not contain an 46415082Syy150190 * accessible PHY. Therefore, loopback beyond MAC must be done 46425082Syy150190 * using SerDes analog loopback. 46435082Syy150190 */ 46443526Sxy150489 if (hw->media_type != e1000_media_type_copper) { 46454919Sxy150489 status = E1000_READ_REG(hw, E1000_STATUS); 46465082Syy150190 /* Set ILOS on fiber nic if half duplex is detected */ 46475082Syy150190 if (((status & E1000_STATUS_LU) == 0) || 46485082Syy150190 ((status & E1000_STATUS_FD) == 0) || 46495082Syy150190 (hw->media_type == 46505082Syy150190 e1000_media_type_internal_serdes)) 46513526Sxy150489 ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU; 46525082Syy150190 46535082Syy150190 /* Disable autoneg by setting bit 31 of TXCW to zero */ 46545082Syy150190 txcw = E1000_READ_REG(hw, E1000_TXCW); 46555082Syy150190 txcw &= ~((uint32_t)1 << 31); 46565082Syy150190 E1000_WRITE_REG(hw, E1000_TXCW, txcw); 46575082Syy150190 46585082Syy150190 /* 46595082Syy150190 * Write 0x410 to Serdes Control register 46605082Syy150190 * to enable Serdes analog loopback 46615082Syy150190 */ 46625082Syy150190 E1000_WRITE_REG(hw, E1000_SCTL, 0x0410); 46635082Syy150190 msec_delay(10); 46643526Sxy150489 } 46653526Sxy150489 break; 46663526Sxy150489 46673526Sxy150489 case e1000_82573: 46683526Sxy150489 ctrl |= E1000_CTRL_ILOS; 46693526Sxy150489 break; 46703526Sxy150489 } 46713526Sxy150489 46724919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 46733526Sxy150489 46743526Sxy150489 } 46753526Sxy150489 46763526Sxy150489 static void 46773526Sxy150489 e1000g_set_external_loopback_1000(struct e1000g *Adapter) 46783526Sxy150489 { 46793526Sxy150489 struct e1000_hw *hw; 46803526Sxy150489 uint32_t rctl; 46813526Sxy150489 uint32_t ctrl_ext; 46823526Sxy150489 uint32_t ctrl; 46833526Sxy150489 uint32_t status; 46843526Sxy150489 uint32_t txcw; 46853526Sxy150489 46864919Sxy150489 hw = &Adapter->shared; 46873526Sxy150489 46883526Sxy150489 /* Disable Smart Power Down */ 46893526Sxy150489 phy_spd_state(hw, B_FALSE); 46903526Sxy150489 46913526Sxy150489 switch (hw->media_type) { 46923526Sxy150489 case e1000_media_type_copper: 46933526Sxy150489 /* Force link up (Must be done before the PHY writes) */ 46944919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 46953526Sxy150489 ctrl |= E1000_CTRL_SLU; /* Force Link Up */ 46964919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 46974919Sxy150489 46984919Sxy150489 rctl = E1000_READ_REG(hw, E1000_RCTL); 46993526Sxy150489 rctl |= (E1000_RCTL_EN | 47004349Sxy150489 E1000_RCTL_SBP | 47014349Sxy150489 E1000_RCTL_UPE | 47024349Sxy150489 E1000_RCTL_MPE | 47034349Sxy150489 E1000_RCTL_LPE | 47044349Sxy150489 E1000_RCTL_BAM); /* 0x803E */ 47054919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, rctl); 47064919Sxy150489 47074919Sxy150489 ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 47083526Sxy150489 ctrl_ext |= (E1000_CTRL_EXT_SDP4_DATA | 47094349Sxy150489 E1000_CTRL_EXT_SDP6_DATA | 47104349Sxy150489 E1000_CTRL_EXT_SDP7_DATA | 47114349Sxy150489 E1000_CTRL_EXT_SDP4_DIR | 47124349Sxy150489 E1000_CTRL_EXT_SDP6_DIR | 47134349Sxy150489 E1000_CTRL_EXT_SDP7_DIR); /* 0x0DD0 */ 47144919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 47153526Sxy150489 47163526Sxy150489 /* 47173526Sxy150489 * This sequence tunes the PHY's SDP and no customer 47183526Sxy150489 * settable values. For background, see comments above 47193526Sxy150489 * e1000g_set_internal_loopback(). 47203526Sxy150489 */ 47213526Sxy150489 e1000_write_phy_reg(hw, 0x0, 0x140); 47223526Sxy150489 msec_delay(10); 47233526Sxy150489 e1000_write_phy_reg(hw, 0x9, 0x1A00); 47243526Sxy150489 e1000_write_phy_reg(hw, 0x12, 0xC10); 47253526Sxy150489 e1000_write_phy_reg(hw, 0x12, 0x1C10); 47263526Sxy150489 e1000_write_phy_reg(hw, 0x1F37, 0x76); 47273526Sxy150489 e1000_write_phy_reg(hw, 0x1F33, 0x1); 47283526Sxy150489 e1000_write_phy_reg(hw, 0x1F33, 0x0); 47293526Sxy150489 47303526Sxy150489 e1000_write_phy_reg(hw, 0x1F35, 0x65); 47313526Sxy150489 e1000_write_phy_reg(hw, 0x1837, 0x3F7C); 47323526Sxy150489 e1000_write_phy_reg(hw, 0x1437, 0x3FDC); 47333526Sxy150489 e1000_write_phy_reg(hw, 0x1237, 0x3F7C); 47343526Sxy150489 e1000_write_phy_reg(hw, 0x1137, 0x3FDC); 47353526Sxy150489 47363526Sxy150489 msec_delay(50); 47373526Sxy150489 break; 47383526Sxy150489 case e1000_media_type_fiber: 47393526Sxy150489 case e1000_media_type_internal_serdes: 47404919Sxy150489 status = E1000_READ_REG(hw, E1000_STATUS); 47413526Sxy150489 if (((status & E1000_STATUS_LU) == 0) || 47423526Sxy150489 (hw->media_type == e1000_media_type_internal_serdes)) { 47434919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 47443526Sxy150489 ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU; 47454919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 47463526Sxy150489 } 47473526Sxy150489 47483526Sxy150489 /* Disable autoneg by setting bit 31 of TXCW to zero */ 47494919Sxy150489 txcw = E1000_READ_REG(hw, E1000_TXCW); 47503526Sxy150489 txcw &= ~((uint32_t)1 << 31); 47514919Sxy150489 E1000_WRITE_REG(hw, E1000_TXCW, txcw); 47523526Sxy150489 47533526Sxy150489 /* 47543526Sxy150489 * Write 0x410 to Serdes Control register 47553526Sxy150489 * to enable Serdes analog loopback 47563526Sxy150489 */ 47574919Sxy150489 E1000_WRITE_REG(hw, E1000_SCTL, 0x0410); 47583526Sxy150489 msec_delay(10); 47593526Sxy150489 break; 47603526Sxy150489 default: 47613526Sxy150489 break; 47623526Sxy150489 } 47633526Sxy150489 } 47643526Sxy150489 47653526Sxy150489 static void 47663526Sxy150489 e1000g_set_external_loopback_100(struct e1000g *Adapter) 47673526Sxy150489 { 47683526Sxy150489 struct e1000_hw *hw; 47693526Sxy150489 uint32_t ctrl; 47703526Sxy150489 uint16_t phy_ctrl; 47713526Sxy150489 47724919Sxy150489 hw = &Adapter->shared; 47733526Sxy150489 47743526Sxy150489 /* Disable Smart Power Down */ 47753526Sxy150489 phy_spd_state(hw, B_FALSE); 47763526Sxy150489 47773526Sxy150489 phy_ctrl = (MII_CR_FULL_DUPLEX | 47784349Sxy150489 MII_CR_SPEED_100); 47793526Sxy150489 47803526Sxy150489 /* Force 100/FD, reset PHY */ 47814919Sxy150489 e1000_write_phy_reg(hw, PHY_CONTROL, 47824349Sxy150489 phy_ctrl | MII_CR_RESET); /* 0xA100 */ 47833526Sxy150489 msec_delay(10); 47843526Sxy150489 47853526Sxy150489 /* Force 100/FD */ 47864919Sxy150489 e1000_write_phy_reg(hw, PHY_CONTROL, 47874349Sxy150489 phy_ctrl); /* 0x2100 */ 47883526Sxy150489 msec_delay(10); 47893526Sxy150489 47903526Sxy150489 /* Now setup the MAC to the same speed/duplex as the PHY. */ 47914919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 47923526Sxy150489 ctrl &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ 47933526Sxy150489 ctrl |= (E1000_CTRL_SLU | /* Force Link Up */ 47944349Sxy150489 E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ 47954349Sxy150489 E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ 47964349Sxy150489 E1000_CTRL_SPD_100 | /* Force Speed to 100 */ 47974349Sxy150489 E1000_CTRL_FD); /* Force Duplex to FULL */ 47983526Sxy150489 47994919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 48003526Sxy150489 } 48013526Sxy150489 48023526Sxy150489 static void 48033526Sxy150489 e1000g_set_external_loopback_10(struct e1000g *Adapter) 48043526Sxy150489 { 48053526Sxy150489 struct e1000_hw *hw; 48063526Sxy150489 uint32_t ctrl; 48073526Sxy150489 uint16_t phy_ctrl; 48083526Sxy150489 48094919Sxy150489 hw = &Adapter->shared; 48103526Sxy150489 48113526Sxy150489 /* Disable Smart Power Down */ 48123526Sxy150489 phy_spd_state(hw, B_FALSE); 48133526Sxy150489 48143526Sxy150489 phy_ctrl = (MII_CR_FULL_DUPLEX | 48154349Sxy150489 MII_CR_SPEED_10); 48163526Sxy150489 48173526Sxy150489 /* Force 10/FD, reset PHY */ 48184919Sxy150489 e1000_write_phy_reg(hw, PHY_CONTROL, 48194349Sxy150489 phy_ctrl | MII_CR_RESET); /* 0x8100 */ 48203526Sxy150489 msec_delay(10); 48213526Sxy150489 48223526Sxy150489 /* Force 10/FD */ 48234919Sxy150489 e1000_write_phy_reg(hw, PHY_CONTROL, 48244349Sxy150489 phy_ctrl); /* 0x0100 */ 48253526Sxy150489 msec_delay(10); 48263526Sxy150489 48273526Sxy150489 /* Now setup the MAC to the same speed/duplex as the PHY. */ 48284919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL); 48293526Sxy150489 ctrl &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ 48303526Sxy150489 ctrl |= (E1000_CTRL_SLU | /* Force Link Up */ 48314349Sxy150489 E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ 48324349Sxy150489 E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ 48334349Sxy150489 E1000_CTRL_SPD_10 | /* Force Speed to 10 */ 48344349Sxy150489 E1000_CTRL_FD); /* Force Duplex to FULL */ 48353526Sxy150489 48364919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 48373526Sxy150489 } 48383526Sxy150489 48393526Sxy150489 #ifdef __sparc 48403526Sxy150489 static boolean_t 48413526Sxy150489 e1000g_find_mac_address(struct e1000g *Adapter) 48423526Sxy150489 { 48434919Sxy150489 struct e1000_hw *hw = &Adapter->shared; 48443526Sxy150489 uchar_t *bytes; 48453526Sxy150489 struct ether_addr sysaddr; 48463526Sxy150489 uint_t nelts; 48473526Sxy150489 int err; 48483526Sxy150489 boolean_t found = B_FALSE; 48493526Sxy150489 48503526Sxy150489 /* 48513526Sxy150489 * The "vendor's factory-set address" may already have 48523526Sxy150489 * been extracted from the chip, but if the property 48533526Sxy150489 * "local-mac-address" is set we use that instead. 48543526Sxy150489 * 48553526Sxy150489 * We check whether it looks like an array of 6 48563526Sxy150489 * bytes (which it should, if OBP set it). If we can't 48573526Sxy150489 * make sense of it this way, we'll ignore it. 48583526Sxy150489 */ 48593526Sxy150489 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip, 48603526Sxy150489 DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts); 48613526Sxy150489 if (err == DDI_PROP_SUCCESS) { 48623526Sxy150489 if (nelts == ETHERADDRL) { 48633526Sxy150489 while (nelts--) 48644919Sxy150489 hw->mac.addr[nelts] = bytes[nelts]; 48653526Sxy150489 found = B_TRUE; 48663526Sxy150489 } 48673526Sxy150489 ddi_prop_free(bytes); 48683526Sxy150489 } 48693526Sxy150489 48703526Sxy150489 /* 48713526Sxy150489 * Look up the OBP property "local-mac-address?". If the user has set 48723526Sxy150489 * 'local-mac-address? = false', use "the system address" instead. 48733526Sxy150489 */ 48743526Sxy150489 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip, 0, 48753526Sxy150489 "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) { 48763526Sxy150489 if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) { 48773526Sxy150489 if (localetheraddr(NULL, &sysaddr) != 0) { 48784919Sxy150489 bcopy(&sysaddr, hw->mac.addr, ETHERADDRL); 48793526Sxy150489 found = B_TRUE; 48803526Sxy150489 } 48813526Sxy150489 } 48823526Sxy150489 ddi_prop_free(bytes); 48833526Sxy150489 } 48843526Sxy150489 48853526Sxy150489 /* 48863526Sxy150489 * Finally(!), if there's a valid "mac-address" property (created 48873526Sxy150489 * if we netbooted from this interface), we must use this instead 48883526Sxy150489 * of any of the above to ensure that the NFS/install server doesn't 48893526Sxy150489 * get confused by the address changing as Solaris takes over! 48903526Sxy150489 */ 48913526Sxy150489 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, Adapter->dip, 48923526Sxy150489 DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts); 48933526Sxy150489 if (err == DDI_PROP_SUCCESS) { 48943526Sxy150489 if (nelts == ETHERADDRL) { 48953526Sxy150489 while (nelts--) 48964919Sxy150489 hw->mac.addr[nelts] = bytes[nelts]; 48973526Sxy150489 found = B_TRUE; 48983526Sxy150489 } 48993526Sxy150489 ddi_prop_free(bytes); 49003526Sxy150489 } 49013526Sxy150489 49023526Sxy150489 if (found) { 49034919Sxy150489 bcopy(hw->mac.addr, hw->mac.perm_addr, 49043526Sxy150489 ETHERADDRL); 49053526Sxy150489 } 49063526Sxy150489 49073526Sxy150489 return (found); 49083526Sxy150489 } 49093526Sxy150489 #endif 49103526Sxy150489 49113526Sxy150489 static int 49123526Sxy150489 e1000g_add_intrs(struct e1000g *Adapter) 49133526Sxy150489 { 49143526Sxy150489 dev_info_t *devinfo; 49153526Sxy150489 int intr_types; 49163526Sxy150489 int rc; 49173526Sxy150489 49183526Sxy150489 devinfo = Adapter->dip; 49193526Sxy150489 49203526Sxy150489 /* Get supported interrupt types */ 49213526Sxy150489 rc = ddi_intr_get_supported_types(devinfo, &intr_types); 49223526Sxy150489 49233526Sxy150489 if (rc != DDI_SUCCESS) { 49244919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 49253526Sxy150489 "Get supported interrupt types failed: %d\n", rc); 49263526Sxy150489 return (DDI_FAILURE); 49273526Sxy150489 } 49283526Sxy150489 49293526Sxy150489 /* 49303526Sxy150489 * Based on Intel Technical Advisory document (TA-160), there are some 49313526Sxy150489 * cases where some older Intel PCI-X NICs may "advertise" to the OS 49323526Sxy150489 * that it supports MSI, but in fact has problems. 49333526Sxy150489 * So we should only enable MSI for PCI-E NICs and disable MSI for old 49343526Sxy150489 * PCI/PCI-X NICs. 49353526Sxy150489 */ 49364919Sxy150489 if (Adapter->shared.mac.type < e1000_82571) 49373526Sxy150489 Adapter->msi_enabled = B_FALSE; 49383526Sxy150489 49393526Sxy150489 if ((intr_types & DDI_INTR_TYPE_MSI) && Adapter->msi_enabled) { 49403526Sxy150489 rc = e1000g_intr_add(Adapter, DDI_INTR_TYPE_MSI); 49413526Sxy150489 49423526Sxy150489 if (rc != DDI_SUCCESS) { 49434919Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL, 49443526Sxy150489 "Add MSI failed, trying Legacy interrupts\n"); 49453526Sxy150489 } else { 49463526Sxy150489 Adapter->intr_type = DDI_INTR_TYPE_MSI; 49473526Sxy150489 } 49483526Sxy150489 } 49493526Sxy150489 49503526Sxy150489 if ((Adapter->intr_type == 0) && 49513526Sxy150489 (intr_types & DDI_INTR_TYPE_FIXED)) { 49523526Sxy150489 rc = e1000g_intr_add(Adapter, DDI_INTR_TYPE_FIXED); 49533526Sxy150489 49543526Sxy150489 if (rc != DDI_SUCCESS) { 49554919Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL, 49563526Sxy150489 "Add Legacy interrupts failed\n"); 49573526Sxy150489 return (DDI_FAILURE); 49583526Sxy150489 } 49593526Sxy150489 49603526Sxy150489 Adapter->intr_type = DDI_INTR_TYPE_FIXED; 49613526Sxy150489 } 49623526Sxy150489 49633526Sxy150489 if (Adapter->intr_type == 0) { 49644919Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_WARN_LEVEL, 49653526Sxy150489 "No interrupts registered\n"); 49663526Sxy150489 return (DDI_FAILURE); 49673526Sxy150489 } 49683526Sxy150489 49693526Sxy150489 return (DDI_SUCCESS); 49703526Sxy150489 } 49713526Sxy150489 49723526Sxy150489 /* 49733526Sxy150489 * e1000g_intr_add() handles MSI/Legacy interrupts 49743526Sxy150489 */ 49753526Sxy150489 static int 49763526Sxy150489 e1000g_intr_add(struct e1000g *Adapter, int intr_type) 49773526Sxy150489 { 49783526Sxy150489 dev_info_t *devinfo; 49793526Sxy150489 int count, avail, actual; 49803526Sxy150489 int x, y, rc, inum = 0; 49813526Sxy150489 int flag; 49823526Sxy150489 ddi_intr_handler_t *intr_handler; 49833526Sxy150489 49843526Sxy150489 devinfo = Adapter->dip; 49853526Sxy150489 49863526Sxy150489 /* get number of interrupts */ 49873526Sxy150489 rc = ddi_intr_get_nintrs(devinfo, intr_type, &count); 49883526Sxy150489 if ((rc != DDI_SUCCESS) || (count == 0)) { 49894919Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL, 49903526Sxy150489 "Get interrupt number failed. Return: %d, count: %d\n", 49913526Sxy150489 rc, count); 49923526Sxy150489 return (DDI_FAILURE); 49933526Sxy150489 } 49943526Sxy150489 49953526Sxy150489 /* get number of available interrupts */ 49963526Sxy150489 rc = ddi_intr_get_navail(devinfo, intr_type, &avail); 49973526Sxy150489 if ((rc != DDI_SUCCESS) || (avail == 0)) { 49984919Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL, 49993526Sxy150489 "Get interrupt available number failed. " 50003526Sxy150489 "Return: %d, available: %d\n", rc, avail); 50013526Sxy150489 return (DDI_FAILURE); 50023526Sxy150489 } 50033526Sxy150489 50043526Sxy150489 if (avail < count) { 50054919Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL, 50063526Sxy150489 "Interrupts count: %d, available: %d\n", 50073526Sxy150489 count, avail); 50083526Sxy150489 } 50093526Sxy150489 50103526Sxy150489 /* Allocate an array of interrupt handles */ 50113526Sxy150489 Adapter->intr_size = count * sizeof (ddi_intr_handle_t); 50123526Sxy150489 Adapter->htable = kmem_alloc(Adapter->intr_size, KM_SLEEP); 50133526Sxy150489 50143526Sxy150489 /* Set NORMAL behavior for both MSI and FIXED interrupt */ 50153526Sxy150489 flag = DDI_INTR_ALLOC_NORMAL; 50163526Sxy150489 50173526Sxy150489 /* call ddi_intr_alloc() */ 50183526Sxy150489 rc = ddi_intr_alloc(devinfo, Adapter->htable, intr_type, inum, 50193526Sxy150489 count, &actual, flag); 50203526Sxy150489 50213526Sxy150489 if ((rc != DDI_SUCCESS) || (actual == 0)) { 50224919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 50233526Sxy150489 "Allocate interrupts failed: %d\n", rc); 50243526Sxy150489 50253526Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 50263526Sxy150489 return (DDI_FAILURE); 50273526Sxy150489 } 50283526Sxy150489 50293526Sxy150489 if (actual < count) { 50304919Sxy150489 E1000G_DEBUGLOG_2(Adapter, E1000G_WARN_LEVEL, 50313526Sxy150489 "Interrupts requested: %d, received: %d\n", 50323526Sxy150489 count, actual); 50333526Sxy150489 } 50343526Sxy150489 50353526Sxy150489 Adapter->intr_cnt = actual; 50363526Sxy150489 50373526Sxy150489 /* Get priority for first msi, assume remaining are all the same */ 50383526Sxy150489 rc = ddi_intr_get_pri(Adapter->htable[0], &Adapter->intr_pri); 50393526Sxy150489 50403526Sxy150489 if (rc != DDI_SUCCESS) { 50414919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 50423526Sxy150489 "Get interrupt priority failed: %d\n", rc); 50433526Sxy150489 50443526Sxy150489 /* Free already allocated intr */ 50453526Sxy150489 for (y = 0; y < actual; y++) 50463526Sxy150489 (void) ddi_intr_free(Adapter->htable[y]); 50473526Sxy150489 50483526Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 50493526Sxy150489 return (DDI_FAILURE); 50503526Sxy150489 } 50513526Sxy150489 50523526Sxy150489 /* 50533526Sxy150489 * In Legacy Interrupt mode, for PCI-Express adapters, we should 50543526Sxy150489 * use the interrupt service routine e1000g_intr_pciexpress() 50553526Sxy150489 * to avoid interrupt stealing when sharing interrupt with other 50563526Sxy150489 * devices. 50573526Sxy150489 */ 50584919Sxy150489 if (Adapter->shared.mac.type < e1000_82571) 50593526Sxy150489 intr_handler = (ddi_intr_handler_t *)e1000g_intr; 50603526Sxy150489 else 50613526Sxy150489 intr_handler = (ddi_intr_handler_t *)e1000g_intr_pciexpress; 50623526Sxy150489 50633526Sxy150489 /* Call ddi_intr_add_handler() */ 50643526Sxy150489 for (x = 0; x < actual; x++) { 50653526Sxy150489 rc = ddi_intr_add_handler(Adapter->htable[x], 50663526Sxy150489 intr_handler, (caddr_t)Adapter, NULL); 50673526Sxy150489 50683526Sxy150489 if (rc != DDI_SUCCESS) { 50694919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 50703526Sxy150489 "Add interrupt handler failed: %d\n", rc); 50713526Sxy150489 50723526Sxy150489 /* Remove already added handler */ 50733526Sxy150489 for (y = 0; y < x; y++) 50743526Sxy150489 (void) ddi_intr_remove_handler( 50753526Sxy150489 Adapter->htable[y]); 50763526Sxy150489 50773526Sxy150489 /* Free already allocated intr */ 50783526Sxy150489 for (y = 0; y < actual; y++) 50793526Sxy150489 (void) ddi_intr_free(Adapter->htable[y]); 50803526Sxy150489 50813526Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 50823526Sxy150489 return (DDI_FAILURE); 50833526Sxy150489 } 50843526Sxy150489 } 50853526Sxy150489 50863526Sxy150489 rc = ddi_intr_get_cap(Adapter->htable[0], &Adapter->intr_cap); 50873526Sxy150489 50883526Sxy150489 if (rc != DDI_SUCCESS) { 50894919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 50903526Sxy150489 "Get interrupt cap failed: %d\n", rc); 50913526Sxy150489 50923526Sxy150489 /* Free already allocated intr */ 50933526Sxy150489 for (y = 0; y < actual; y++) { 50943526Sxy150489 (void) ddi_intr_remove_handler(Adapter->htable[y]); 50953526Sxy150489 (void) ddi_intr_free(Adapter->htable[y]); 50963526Sxy150489 } 50973526Sxy150489 50983526Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 50993526Sxy150489 return (DDI_FAILURE); 51003526Sxy150489 } 51013526Sxy150489 51023526Sxy150489 return (DDI_SUCCESS); 51033526Sxy150489 } 51043526Sxy150489 51053526Sxy150489 static int 51063526Sxy150489 e1000g_rem_intrs(struct e1000g *Adapter) 51073526Sxy150489 { 51083526Sxy150489 int x; 51093526Sxy150489 int rc; 51103526Sxy150489 51113526Sxy150489 for (x = 0; x < Adapter->intr_cnt; x++) { 51123526Sxy150489 rc = ddi_intr_remove_handler(Adapter->htable[x]); 51133526Sxy150489 if (rc != DDI_SUCCESS) { 51144919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 51153526Sxy150489 "Remove intr handler failed: %d\n", rc); 51163526Sxy150489 return (DDI_FAILURE); 51173526Sxy150489 } 51183526Sxy150489 51193526Sxy150489 rc = ddi_intr_free(Adapter->htable[x]); 51203526Sxy150489 if (rc != DDI_SUCCESS) { 51214919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 51223526Sxy150489 "Free intr failed: %d\n", rc); 51233526Sxy150489 return (DDI_FAILURE); 51243526Sxy150489 } 51253526Sxy150489 } 51263526Sxy150489 51273526Sxy150489 kmem_free(Adapter->htable, Adapter->intr_size); 51283526Sxy150489 51293526Sxy150489 return (DDI_SUCCESS); 51303526Sxy150489 } 51313526Sxy150489 51323526Sxy150489 static int 51333526Sxy150489 e1000g_enable_intrs(struct e1000g *Adapter) 51343526Sxy150489 { 51353526Sxy150489 int x; 51363526Sxy150489 int rc; 51373526Sxy150489 51383526Sxy150489 /* Enable interrupts */ 51393526Sxy150489 if (Adapter->intr_cap & DDI_INTR_FLAG_BLOCK) { 51403526Sxy150489 /* Call ddi_intr_block_enable() for MSI */ 51413526Sxy150489 rc = ddi_intr_block_enable(Adapter->htable, 51423526Sxy150489 Adapter->intr_cnt); 51433526Sxy150489 if (rc != DDI_SUCCESS) { 51444919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 51453526Sxy150489 "Enable block intr failed: %d\n", rc); 51463526Sxy150489 return (DDI_FAILURE); 51473526Sxy150489 } 51483526Sxy150489 } else { 51493526Sxy150489 /* Call ddi_intr_enable() for Legacy/MSI non block enable */ 51503526Sxy150489 for (x = 0; x < Adapter->intr_cnt; x++) { 51513526Sxy150489 rc = ddi_intr_enable(Adapter->htable[x]); 51523526Sxy150489 if (rc != DDI_SUCCESS) { 51534919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 51543526Sxy150489 "Enable intr failed: %d\n", rc); 51553526Sxy150489 return (DDI_FAILURE); 51563526Sxy150489 } 51573526Sxy150489 } 51583526Sxy150489 } 51593526Sxy150489 51603526Sxy150489 return (DDI_SUCCESS); 51613526Sxy150489 } 51623526Sxy150489 51633526Sxy150489 static int 51643526Sxy150489 e1000g_disable_intrs(struct e1000g *Adapter) 51653526Sxy150489 { 51663526Sxy150489 int x; 51673526Sxy150489 int rc; 51683526Sxy150489 51693526Sxy150489 /* Disable all interrupts */ 51703526Sxy150489 if (Adapter->intr_cap & DDI_INTR_FLAG_BLOCK) { 51713526Sxy150489 rc = ddi_intr_block_disable(Adapter->htable, 51723526Sxy150489 Adapter->intr_cnt); 51733526Sxy150489 if (rc != DDI_SUCCESS) { 51744919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 51753526Sxy150489 "Disable block intr failed: %d\n", rc); 51763526Sxy150489 return (DDI_FAILURE); 51773526Sxy150489 } 51783526Sxy150489 } else { 51793526Sxy150489 for (x = 0; x < Adapter->intr_cnt; x++) { 51803526Sxy150489 rc = ddi_intr_disable(Adapter->htable[x]); 51813526Sxy150489 if (rc != DDI_SUCCESS) { 51824919Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL, 51833526Sxy150489 "Disable intr failed: %d\n", rc); 51843526Sxy150489 return (DDI_FAILURE); 51853526Sxy150489 } 51863526Sxy150489 } 51873526Sxy150489 } 51883526Sxy150489 51893526Sxy150489 return (DDI_SUCCESS); 51903526Sxy150489 } 51915082Syy150190 51925082Syy150190 /* 51935082Syy150190 * e1000g_get_phy_state - get the state of PHY registers, save in the adapter 51945082Syy150190 */ 51955082Syy150190 static void 51965082Syy150190 e1000g_get_phy_state(struct e1000g *Adapter) 51975082Syy150190 { 51985082Syy150190 struct e1000_hw *hw = &Adapter->shared; 51995082Syy150190 52005082Syy150190 e1000_read_phy_reg(hw, PHY_CONTROL, &Adapter->phy_ctrl); 52015082Syy150190 e1000_read_phy_reg(hw, PHY_STATUS, &Adapter->phy_status); 52025082Syy150190 e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &Adapter->phy_an_adv); 52035082Syy150190 e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &Adapter->phy_an_exp); 52045082Syy150190 e1000_read_phy_reg(hw, PHY_EXT_STATUS, &Adapter->phy_ext_status); 52055082Syy150190 e1000_read_phy_reg(hw, PHY_1000T_CTRL, &Adapter->phy_1000t_ctrl); 52065082Syy150190 e1000_read_phy_reg(hw, PHY_1000T_STATUS, &Adapter->phy_1000t_status); 52075082Syy150190 e1000_read_phy_reg(hw, PHY_LP_ABILITY, &Adapter->phy_lp_able); 5208*6394Scc210113 5209*6394Scc210113 Adapter->param_autoneg_cap = 5210*6394Scc210113 (Adapter->phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0; 5211*6394Scc210113 Adapter->param_pause_cap = 5212*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0; 5213*6394Scc210113 Adapter->param_asym_pause_cap = 5214*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0; 5215*6394Scc210113 Adapter->param_1000fdx_cap = 5216*6394Scc210113 ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) || 5217*6394Scc210113 (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0; 5218*6394Scc210113 Adapter->param_1000hdx_cap = 5219*6394Scc210113 ((Adapter->phy_ext_status & IEEE_ESR_1000T_HD_CAPS) || 5220*6394Scc210113 (Adapter->phy_ext_status & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0; 5221*6394Scc210113 Adapter->param_100t4_cap = 5222*6394Scc210113 (Adapter->phy_status & MII_SR_100T4_CAPS) ? 1 : 0; 5223*6394Scc210113 Adapter->param_100fdx_cap = 5224*6394Scc210113 ((Adapter->phy_status & MII_SR_100X_FD_CAPS) || 5225*6394Scc210113 (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0; 5226*6394Scc210113 Adapter->param_100hdx_cap = 5227*6394Scc210113 ((Adapter->phy_status & MII_SR_100X_HD_CAPS) || 5228*6394Scc210113 (Adapter->phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0; 5229*6394Scc210113 Adapter->param_10fdx_cap = 5230*6394Scc210113 (Adapter->phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0; 5231*6394Scc210113 Adapter->param_10hdx_cap = 5232*6394Scc210113 (Adapter->phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0; 5233*6394Scc210113 5234*6394Scc210113 Adapter->param_adv_autoneg = hw->mac.autoneg; 5235*6394Scc210113 Adapter->param_adv_pause = 5236*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0; 5237*6394Scc210113 Adapter->param_adv_asym_pause = 5238*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0; 5239*6394Scc210113 Adapter->param_adv_1000hdx = 5240*6394Scc210113 (Adapter->phy_1000t_ctrl & CR_1000T_HD_CAPS) ? 1 : 0; 5241*6394Scc210113 Adapter->param_adv_100t4 = 5242*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_100T4_CAPS) ? 1 : 0; 5243*6394Scc210113 if (Adapter->param_adv_autoneg == 1) { 5244*6394Scc210113 Adapter->param_adv_1000fdx = 5245*6394Scc210113 (Adapter->phy_1000t_ctrl & CR_1000T_FD_CAPS) ? 1 : 0; 5246*6394Scc210113 Adapter->param_adv_100fdx = 5247*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_100TX_FD_CAPS) ? 1 : 0; 5248*6394Scc210113 Adapter->param_adv_100hdx = 5249*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_100TX_HD_CAPS) ? 1 : 0; 5250*6394Scc210113 Adapter->param_adv_10fdx = 5251*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_10T_FD_CAPS) ? 1 : 0; 5252*6394Scc210113 Adapter->param_adv_10hdx = 5253*6394Scc210113 (Adapter->phy_an_adv & NWAY_AR_10T_HD_CAPS) ? 1 : 0; 5254*6394Scc210113 } 5255*6394Scc210113 5256*6394Scc210113 Adapter->param_lp_autoneg = 5257*6394Scc210113 (Adapter->phy_an_exp & NWAY_ER_LP_NWAY_CAPS) ? 1 : 0; 5258*6394Scc210113 Adapter->param_lp_pause = 5259*6394Scc210113 (Adapter->phy_lp_able & NWAY_LPAR_PAUSE) ? 1 : 0; 5260*6394Scc210113 Adapter->param_lp_asym_pause = 5261*6394Scc210113 (Adapter->phy_lp_able & NWAY_LPAR_ASM_DIR) ? 1 : 0; 5262*6394Scc210113 Adapter->param_lp_1000fdx = 5263*6394Scc210113 (Adapter->phy_1000t_status & SR_1000T_LP_FD_CAPS) ? 1 : 0; 5264*6394Scc210113 Adapter->param_lp_1000hdx = 5265*6394Scc210113 (Adapter->phy_1000t_status & SR_1000T_LP_HD_CAPS) ? 1 : 0; 5266*6394Scc210113 Adapter->param_lp_100t4 = 5267*6394Scc210113 (Adapter->phy_lp_able & NWAY_LPAR_100T4_CAPS) ? 1 : 0; 5268*6394Scc210113 Adapter->param_lp_100fdx = 5269*6394Scc210113 (Adapter->phy_lp_able & NWAY_LPAR_100TX_FD_CAPS) ? 1 : 0; 5270*6394Scc210113 Adapter->param_lp_100hdx = 5271*6394Scc210113 (Adapter->phy_lp_able & NWAY_LPAR_100TX_HD_CAPS) ? 1 : 0; 5272*6394Scc210113 Adapter->param_lp_10fdx = 5273*6394Scc210113 (Adapter->phy_lp_able & NWAY_LPAR_10T_FD_CAPS) ? 1 : 0; 5274*6394Scc210113 Adapter->param_lp_10hdx = 5275*6394Scc210113 (Adapter->phy_lp_able & NWAY_LPAR_10T_HD_CAPS) ? 1 : 0; 52765082Syy150190 } 52775273Sgl147354 52785273Sgl147354 /* 52795273Sgl147354 * FMA support 52805273Sgl147354 */ 52815273Sgl147354 52825273Sgl147354 int 52835273Sgl147354 e1000g_check_acc_handle(ddi_acc_handle_t handle) 52845273Sgl147354 { 52855273Sgl147354 ddi_fm_error_t de; 52865273Sgl147354 52875273Sgl147354 ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 52885273Sgl147354 ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 52895273Sgl147354 return (de.fme_status); 52905273Sgl147354 } 52915273Sgl147354 52925273Sgl147354 int 52935273Sgl147354 e1000g_check_dma_handle(ddi_dma_handle_t handle) 52945273Sgl147354 { 52955273Sgl147354 ddi_fm_error_t de; 52965273Sgl147354 52975273Sgl147354 ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 52985273Sgl147354 return (de.fme_status); 52995273Sgl147354 } 53005273Sgl147354 53015273Sgl147354 /* 53025273Sgl147354 * The IO fault service error handling callback function 53035273Sgl147354 */ 53045273Sgl147354 static int 53055273Sgl147354 e1000g_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 53065273Sgl147354 { 53075273Sgl147354 /* 53085273Sgl147354 * as the driver can always deal with an error in any dma or 53095273Sgl147354 * access handle, we can just return the fme_status value. 53105273Sgl147354 */ 53115273Sgl147354 pci_ereport_post(dip, err, NULL); 53125273Sgl147354 return (err->fme_status); 53135273Sgl147354 } 53145273Sgl147354 53155273Sgl147354 static void 53165273Sgl147354 e1000g_fm_init(struct e1000g *Adapter) 53175273Sgl147354 { 53185273Sgl147354 ddi_iblock_cookie_t iblk; 53195273Sgl147354 int fma_acc_flag, fma_dma_flag; 53205273Sgl147354 53215273Sgl147354 /* Only register with IO Fault Services if we have some capability */ 53225273Sgl147354 if (Adapter->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) { 53235273Sgl147354 e1000g_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; 53245273Sgl147354 fma_acc_flag = 1; 53255273Sgl147354 } else { 53265273Sgl147354 e1000g_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; 53275273Sgl147354 fma_acc_flag = 0; 53285273Sgl147354 } 53295273Sgl147354 53305273Sgl147354 if (Adapter->fm_capabilities & DDI_FM_DMACHK_CAPABLE) { 53315273Sgl147354 fma_dma_flag = 1; 53325273Sgl147354 } else { 53335273Sgl147354 fma_dma_flag = 0; 53345273Sgl147354 } 53355273Sgl147354 53365273Sgl147354 (void) e1000g_set_fma_flags(Adapter, fma_acc_flag, fma_dma_flag); 53375273Sgl147354 53385273Sgl147354 if (Adapter->fm_capabilities) { 53395273Sgl147354 53405273Sgl147354 /* Register capabilities with IO Fault Services */ 53415273Sgl147354 ddi_fm_init(Adapter->dip, &Adapter->fm_capabilities, &iblk); 53425273Sgl147354 53435273Sgl147354 /* 53445273Sgl147354 * Initialize pci ereport capabilities if ereport capable 53455273Sgl147354 */ 53465273Sgl147354 if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities) || 53475273Sgl147354 DDI_FM_ERRCB_CAP(Adapter->fm_capabilities)) 53485273Sgl147354 pci_ereport_setup(Adapter->dip); 53495273Sgl147354 53505273Sgl147354 /* 53515273Sgl147354 * Register error callback if error callback capable 53525273Sgl147354 */ 53535273Sgl147354 if (DDI_FM_ERRCB_CAP(Adapter->fm_capabilities)) 53545273Sgl147354 ddi_fm_handler_register(Adapter->dip, 53555273Sgl147354 e1000g_fm_error_cb, (void*) Adapter); 53565273Sgl147354 } 53575273Sgl147354 } 53585273Sgl147354 53595273Sgl147354 static void 53605273Sgl147354 e1000g_fm_fini(struct e1000g *Adapter) 53615273Sgl147354 { 53625273Sgl147354 /* Only unregister FMA capabilities if we registered some */ 53635273Sgl147354 if (Adapter->fm_capabilities) { 53645273Sgl147354 53655273Sgl147354 /* 53665273Sgl147354 * Release any resources allocated by pci_ereport_setup() 53675273Sgl147354 */ 53685273Sgl147354 if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities) || 53695273Sgl147354 DDI_FM_ERRCB_CAP(Adapter->fm_capabilities)) 53705273Sgl147354 pci_ereport_teardown(Adapter->dip); 53715273Sgl147354 53725273Sgl147354 /* 53735273Sgl147354 * Un-register error callback if error callback capable 53745273Sgl147354 */ 53755273Sgl147354 if (DDI_FM_ERRCB_CAP(Adapter->fm_capabilities)) 53765273Sgl147354 ddi_fm_handler_unregister(Adapter->dip); 53775273Sgl147354 53785273Sgl147354 /* Unregister from IO Fault Services */ 53795273Sgl147354 ddi_fm_fini(Adapter->dip); 53805273Sgl147354 } 53815273Sgl147354 } 53825273Sgl147354 53835273Sgl147354 void 53845273Sgl147354 e1000g_fm_ereport(struct e1000g *Adapter, char *detail) 53855273Sgl147354 { 53865273Sgl147354 uint64_t ena; 53875273Sgl147354 char buf[FM_MAX_CLASS]; 53885273Sgl147354 53895273Sgl147354 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 53905273Sgl147354 ena = fm_ena_generate(0, FM_ENA_FMT1); 53915273Sgl147354 if (DDI_FM_EREPORT_CAP(Adapter->fm_capabilities)) { 53925273Sgl147354 ddi_fm_ereport_post(Adapter->dip, buf, ena, DDI_NOSLEEP, 53935273Sgl147354 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 53945273Sgl147354 } 53955273Sgl147354 } 5396