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