16621Sbt150084 /* 26621Sbt150084 * CDDL HEADER START 36621Sbt150084 * 49353SSamuel.Tu@Sun.COM * Copyright(c) 2007-2009 Intel Corporation. All rights reserved. 56621Sbt150084 * The contents of this file are subject to the terms of the 66621Sbt150084 * Common Development and Distribution License (the "License"). 76621Sbt150084 * You may not use this file except in compliance with the License. 86621Sbt150084 * 97656SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107656SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing. 116621Sbt150084 * See the License for the specific language governing permissions 126621Sbt150084 * and limitations under the License. 136621Sbt150084 * 147656SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 157656SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 166621Sbt150084 * If applicable, add the following below this CDDL HEADER, with the 176621Sbt150084 * fields enclosed by brackets "[]" replaced with your own identifying 186621Sbt150084 * information: Portions Copyright [yyyy] [name of copyright owner] 196621Sbt150084 * 206621Sbt150084 * CDDL HEADER END 216621Sbt150084 */ 226621Sbt150084 236621Sbt150084 /* 248490SPaul.Guo@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 257656SSherry.Moore@Sun.COM * Use is subject to license terms. 267656SSherry.Moore@Sun.COM */ 277656SSherry.Moore@Sun.COM 286621Sbt150084 #include "ixgbe_sw.h" 296621Sbt150084 3010998SChenlu.Chen@Sun.COM static char ident[] = "Intel 10Gb Ethernet"; 31*11233SPaul.Guo@Sun.COM static char ixgbe_version[] = "ixgbe 1.1.3"; 326621Sbt150084 336621Sbt150084 /* 346621Sbt150084 * Local function protoypes 356621Sbt150084 */ 366621Sbt150084 static int ixgbe_register_mac(ixgbe_t *); 376621Sbt150084 static int ixgbe_identify_hardware(ixgbe_t *); 386621Sbt150084 static int ixgbe_regs_map(ixgbe_t *); 396621Sbt150084 static void ixgbe_init_properties(ixgbe_t *); 406621Sbt150084 static int ixgbe_init_driver_settings(ixgbe_t *); 416621Sbt150084 static void ixgbe_init_locks(ixgbe_t *); 426621Sbt150084 static void ixgbe_destroy_locks(ixgbe_t *); 436621Sbt150084 static int ixgbe_init(ixgbe_t *); 446621Sbt150084 static int ixgbe_chip_start(ixgbe_t *); 456621Sbt150084 static void ixgbe_chip_stop(ixgbe_t *); 466621Sbt150084 static int ixgbe_reset(ixgbe_t *); 476621Sbt150084 static void ixgbe_tx_clean(ixgbe_t *); 486621Sbt150084 static boolean_t ixgbe_tx_drain(ixgbe_t *); 496621Sbt150084 static boolean_t ixgbe_rx_drain(ixgbe_t *); 506621Sbt150084 static int ixgbe_alloc_rings(ixgbe_t *); 516621Sbt150084 static void ixgbe_free_rings(ixgbe_t *); 5210376SChenlu.Chen@Sun.COM static int ixgbe_alloc_rx_data(ixgbe_t *); 5310376SChenlu.Chen@Sun.COM static void ixgbe_free_rx_data(ixgbe_t *); 546621Sbt150084 static void ixgbe_setup_rings(ixgbe_t *); 556621Sbt150084 static void ixgbe_setup_rx(ixgbe_t *); 566621Sbt150084 static void ixgbe_setup_tx(ixgbe_t *); 576621Sbt150084 static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *); 586621Sbt150084 static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *); 596621Sbt150084 static void ixgbe_setup_rss(ixgbe_t *); 606621Sbt150084 static void ixgbe_init_unicst(ixgbe_t *); 618275SEric Cheng static int ixgbe_unicst_set(ixgbe_t *, const uint8_t *, int); 628275SEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *); 636621Sbt150084 static void ixgbe_setup_multicst(ixgbe_t *); 646621Sbt150084 static void ixgbe_get_hw_state(ixgbe_t *); 656621Sbt150084 static void ixgbe_get_conf(ixgbe_t *); 6610376SChenlu.Chen@Sun.COM static void ixgbe_init_params(ixgbe_t *); 676621Sbt150084 static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int); 68*11233SPaul.Guo@Sun.COM static void ixgbe_driver_link_check(ixgbe_t *); 699353SSamuel.Tu@Sun.COM static void ixgbe_sfp_check(void *); 70*11233SPaul.Guo@Sun.COM static void ixgbe_link_timer(void *); 716621Sbt150084 static void ixgbe_local_timer(void *); 726621Sbt150084 static void ixgbe_arm_watchdog_timer(ixgbe_t *); 736621Sbt150084 static void ixgbe_restart_watchdog_timer(ixgbe_t *); 746621Sbt150084 static void ixgbe_disable_adapter_interrupts(ixgbe_t *); 756621Sbt150084 static void ixgbe_enable_adapter_interrupts(ixgbe_t *); 766621Sbt150084 static boolean_t is_valid_mac_addr(uint8_t *); 776621Sbt150084 static boolean_t ixgbe_stall_check(ixgbe_t *); 786621Sbt150084 static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t); 796621Sbt150084 static void ixgbe_set_internal_mac_loopback(ixgbe_t *); 806621Sbt150084 static boolean_t ixgbe_find_mac_address(ixgbe_t *); 816621Sbt150084 static int ixgbe_alloc_intrs(ixgbe_t *); 826621Sbt150084 static int ixgbe_alloc_intr_handles(ixgbe_t *, int); 836621Sbt150084 static int ixgbe_add_intr_handlers(ixgbe_t *); 846621Sbt150084 static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int); 856621Sbt150084 static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int); 869353SSamuel.Tu@Sun.COM static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t); 879353SSamuel.Tu@Sun.COM static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t); 889353SSamuel.Tu@Sun.COM static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t); 899353SSamuel.Tu@Sun.COM static int ixgbe_map_intrs_to_vectors(ixgbe_t *); 906621Sbt150084 static void ixgbe_setup_adapter_vector(ixgbe_t *); 916621Sbt150084 static void ixgbe_rem_intr_handlers(ixgbe_t *); 926621Sbt150084 static void ixgbe_rem_intrs(ixgbe_t *); 936621Sbt150084 static int ixgbe_enable_intrs(ixgbe_t *); 946621Sbt150084 static int ixgbe_disable_intrs(ixgbe_t *); 956621Sbt150084 static uint_t ixgbe_intr_legacy(void *, void *); 966621Sbt150084 static uint_t ixgbe_intr_msi(void *, void *); 979353SSamuel.Tu@Sun.COM static uint_t ixgbe_intr_msix(void *, void *); 986621Sbt150084 static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *); 996621Sbt150084 static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *); 1008490SPaul.Guo@Sun.COM static void ixgbe_intr_other_work(ixgbe_t *, uint32_t); 1016621Sbt150084 static void ixgbe_get_driver_control(struct ixgbe_hw *); 1028275SEric Cheng static int ixgbe_addmac(void *, const uint8_t *); 1038275SEric Cheng static int ixgbe_remmac(void *, const uint8_t *); 1046621Sbt150084 static void ixgbe_release_driver_control(struct ixgbe_hw *); 1056621Sbt150084 1066621Sbt150084 static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t); 1076621Sbt150084 static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t); 1086621Sbt150084 static int ixgbe_resume(dev_info_t *); 1096621Sbt150084 static int ixgbe_suspend(dev_info_t *); 1106621Sbt150084 static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *); 1116621Sbt150084 static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *); 1126621Sbt150084 1136621Sbt150084 static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, 1146621Sbt150084 const void *impl_data); 1156621Sbt150084 static void ixgbe_fm_init(ixgbe_t *); 1166621Sbt150084 static void ixgbe_fm_fini(ixgbe_t *); 1176621Sbt150084 11810376SChenlu.Chen@Sun.COM mac_priv_prop_t ixgbe_priv_props[] = { 11910376SChenlu.Chen@Sun.COM {"_tx_copy_thresh", MAC_PROP_PERM_RW}, 12010376SChenlu.Chen@Sun.COM {"_tx_recycle_thresh", MAC_PROP_PERM_RW}, 12110376SChenlu.Chen@Sun.COM {"_tx_overload_thresh", MAC_PROP_PERM_RW}, 12210376SChenlu.Chen@Sun.COM {"_tx_resched_thresh", MAC_PROP_PERM_RW}, 12310376SChenlu.Chen@Sun.COM {"_rx_copy_thresh", MAC_PROP_PERM_RW}, 12410376SChenlu.Chen@Sun.COM {"_rx_limit_per_intr", MAC_PROP_PERM_RW}, 12510376SChenlu.Chen@Sun.COM {"_intr_throttling", MAC_PROP_PERM_RW}, 12610376SChenlu.Chen@Sun.COM {"_adv_pause_cap", MAC_PROP_PERM_READ}, 12710376SChenlu.Chen@Sun.COM {"_adv_asym_pause_cap", MAC_PROP_PERM_READ} 12810376SChenlu.Chen@Sun.COM }; 12910376SChenlu.Chen@Sun.COM 13010376SChenlu.Chen@Sun.COM #define IXGBE_MAX_PRIV_PROPS \ 13110376SChenlu.Chen@Sun.COM (sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t)) 13210376SChenlu.Chen@Sun.COM 1336621Sbt150084 static struct cb_ops ixgbe_cb_ops = { 1346621Sbt150084 nulldev, /* cb_open */ 1356621Sbt150084 nulldev, /* cb_close */ 1366621Sbt150084 nodev, /* cb_strategy */ 1376621Sbt150084 nodev, /* cb_print */ 1386621Sbt150084 nodev, /* cb_dump */ 1396621Sbt150084 nodev, /* cb_read */ 1406621Sbt150084 nodev, /* cb_write */ 1416621Sbt150084 nodev, /* cb_ioctl */ 1426621Sbt150084 nodev, /* cb_devmap */ 1436621Sbt150084 nodev, /* cb_mmap */ 1446621Sbt150084 nodev, /* cb_segmap */ 1456621Sbt150084 nochpoll, /* cb_chpoll */ 1466621Sbt150084 ddi_prop_op, /* cb_prop_op */ 1476621Sbt150084 NULL, /* cb_stream */ 1486621Sbt150084 D_MP | D_HOTPLUG, /* cb_flag */ 1496621Sbt150084 CB_REV, /* cb_rev */ 1506621Sbt150084 nodev, /* cb_aread */ 1516621Sbt150084 nodev /* cb_awrite */ 1526621Sbt150084 }; 1536621Sbt150084 1546621Sbt150084 static struct dev_ops ixgbe_dev_ops = { 1556621Sbt150084 DEVO_REV, /* devo_rev */ 1566621Sbt150084 0, /* devo_refcnt */ 1576621Sbt150084 NULL, /* devo_getinfo */ 1586621Sbt150084 nulldev, /* devo_identify */ 1596621Sbt150084 nulldev, /* devo_probe */ 1606621Sbt150084 ixgbe_attach, /* devo_attach */ 1616621Sbt150084 ixgbe_detach, /* devo_detach */ 1626621Sbt150084 nodev, /* devo_reset */ 1636621Sbt150084 &ixgbe_cb_ops, /* devo_cb_ops */ 1646621Sbt150084 NULL, /* devo_bus_ops */ 1657656SSherry.Moore@Sun.COM ddi_power, /* devo_power */ 1667656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 1676621Sbt150084 }; 1686621Sbt150084 1696621Sbt150084 static struct modldrv ixgbe_modldrv = { 1706621Sbt150084 &mod_driverops, /* Type of module. This one is a driver */ 1716621Sbt150084 ident, /* Discription string */ 1726621Sbt150084 &ixgbe_dev_ops /* driver ops */ 1736621Sbt150084 }; 1746621Sbt150084 1756621Sbt150084 static struct modlinkage ixgbe_modlinkage = { 1766621Sbt150084 MODREV_1, &ixgbe_modldrv, NULL 1776621Sbt150084 }; 1786621Sbt150084 1796621Sbt150084 /* 1806621Sbt150084 * Access attributes for register mapping 1816621Sbt150084 */ 1826621Sbt150084 ddi_device_acc_attr_t ixgbe_regs_acc_attr = { 1836621Sbt150084 DDI_DEVICE_ATTR_V0, 1846621Sbt150084 DDI_STRUCTURE_LE_ACC, 1856621Sbt150084 DDI_STRICTORDER_ACC, 1866621Sbt150084 DDI_FLAGERR_ACC 1876621Sbt150084 }; 1886621Sbt150084 1896621Sbt150084 /* 1906621Sbt150084 * Loopback property 1916621Sbt150084 */ 1926621Sbt150084 static lb_property_t lb_normal = { 1936621Sbt150084 normal, "normal", IXGBE_LB_NONE 1946621Sbt150084 }; 1956621Sbt150084 1966621Sbt150084 static lb_property_t lb_mac = { 1976621Sbt150084 internal, "MAC", IXGBE_LB_INTERNAL_MAC 1986621Sbt150084 }; 1996621Sbt150084 20011150SZhen.W@Sun.COM static lb_property_t lb_external = { 20111150SZhen.W@Sun.COM external, "External", IXGBE_LB_EXTERNAL 20211150SZhen.W@Sun.COM }; 20311150SZhen.W@Sun.COM 20410376SChenlu.Chen@Sun.COM #define IXGBE_M_CALLBACK_FLAGS \ 20510376SChenlu.Chen@Sun.COM (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) 2066621Sbt150084 2076621Sbt150084 static mac_callbacks_t ixgbe_m_callbacks = { 2086621Sbt150084 IXGBE_M_CALLBACK_FLAGS, 2096621Sbt150084 ixgbe_m_stat, 2106621Sbt150084 ixgbe_m_start, 2116621Sbt150084 ixgbe_m_stop, 2126621Sbt150084 ixgbe_m_promisc, 2136621Sbt150084 ixgbe_m_multicst, 2148275SEric Cheng NULL, 2156621Sbt150084 NULL, 2166621Sbt150084 ixgbe_m_ioctl, 21710376SChenlu.Chen@Sun.COM ixgbe_m_getcapab, 21810376SChenlu.Chen@Sun.COM NULL, 21910376SChenlu.Chen@Sun.COM NULL, 22010376SChenlu.Chen@Sun.COM ixgbe_m_setprop, 22110376SChenlu.Chen@Sun.COM ixgbe_m_getprop 2226621Sbt150084 }; 2236621Sbt150084 2246621Sbt150084 /* 2258490SPaul.Guo@Sun.COM * Initialize capabilities of each supported adapter type 2268490SPaul.Guo@Sun.COM */ 2278490SPaul.Guo@Sun.COM static adapter_info_t ixgbe_82598eb_cap = { 2288490SPaul.Guo@Sun.COM 64, /* maximum number of rx queues */ 2298490SPaul.Guo@Sun.COM 1, /* minimum number of rx queues */ 2308490SPaul.Guo@Sun.COM 8, /* default number of rx queues */ 2318490SPaul.Guo@Sun.COM 32, /* maximum number of tx queues */ 2328490SPaul.Guo@Sun.COM 1, /* minimum number of tx queues */ 2338490SPaul.Guo@Sun.COM 8, /* default number of tx queues */ 23411150SZhen.W@Sun.COM 16366, /* maximum MTU size */ 23510376SChenlu.Chen@Sun.COM 0xFFFF, /* maximum interrupt throttle rate */ 23610376SChenlu.Chen@Sun.COM 0, /* minimum interrupt throttle rate */ 23710376SChenlu.Chen@Sun.COM 200, /* default interrupt throttle rate */ 2388490SPaul.Guo@Sun.COM 18, /* maximum total msix vectors */ 2398490SPaul.Guo@Sun.COM 16, /* maximum number of ring vectors */ 2408490SPaul.Guo@Sun.COM 2, /* maximum number of other vectors */ 2418490SPaul.Guo@Sun.COM IXGBE_EICR_LSC, /* "other" interrupt types handled */ 2428490SPaul.Guo@Sun.COM (IXGBE_FLAG_DCA_CAPABLE /* capability flags */ 2438490SPaul.Guo@Sun.COM | IXGBE_FLAG_RSS_CAPABLE 2448490SPaul.Guo@Sun.COM | IXGBE_FLAG_VMDQ_CAPABLE) 2458490SPaul.Guo@Sun.COM }; 2468490SPaul.Guo@Sun.COM 2479353SSamuel.Tu@Sun.COM static adapter_info_t ixgbe_82599eb_cap = { 2489353SSamuel.Tu@Sun.COM 128, /* maximum number of rx queues */ 2499353SSamuel.Tu@Sun.COM 1, /* minimum number of rx queues */ 2509353SSamuel.Tu@Sun.COM 8, /* default number of rx queues */ 2519353SSamuel.Tu@Sun.COM 128, /* maximum number of tx queues */ 2529353SSamuel.Tu@Sun.COM 1, /* minimum number of tx queues */ 2539353SSamuel.Tu@Sun.COM 8, /* default number of tx queues */ 25411150SZhen.W@Sun.COM 15500, /* maximum MTU size */ 25510376SChenlu.Chen@Sun.COM 0xFF8, /* maximum interrupt throttle rate */ 25610376SChenlu.Chen@Sun.COM 0, /* minimum interrupt throttle rate */ 25710376SChenlu.Chen@Sun.COM 200, /* default interrupt throttle rate */ 2589353SSamuel.Tu@Sun.COM 64, /* maximum total msix vectors */ 2599353SSamuel.Tu@Sun.COM 16, /* maximum number of ring vectors */ 2609353SSamuel.Tu@Sun.COM 2, /* maximum number of other vectors */ 2619353SSamuel.Tu@Sun.COM IXGBE_EICR_LSC, /* "other" interrupt types handled */ 2629353SSamuel.Tu@Sun.COM (IXGBE_FLAG_DCA_CAPABLE /* capability flags */ 2639353SSamuel.Tu@Sun.COM | IXGBE_FLAG_RSS_CAPABLE 2649353SSamuel.Tu@Sun.COM | IXGBE_FLAG_VMDQ_CAPABLE) 2659353SSamuel.Tu@Sun.COM }; 2669353SSamuel.Tu@Sun.COM 2678490SPaul.Guo@Sun.COM /* 2686621Sbt150084 * Module Initialization Functions. 2696621Sbt150084 */ 2706621Sbt150084 2716621Sbt150084 int 2726621Sbt150084 _init(void) 2736621Sbt150084 { 2746621Sbt150084 int status; 2756621Sbt150084 2766621Sbt150084 mac_init_ops(&ixgbe_dev_ops, MODULE_NAME); 2776621Sbt150084 2786621Sbt150084 status = mod_install(&ixgbe_modlinkage); 2796621Sbt150084 2806621Sbt150084 if (status != DDI_SUCCESS) { 2816621Sbt150084 mac_fini_ops(&ixgbe_dev_ops); 2826621Sbt150084 } 2836621Sbt150084 2846621Sbt150084 return (status); 2856621Sbt150084 } 2866621Sbt150084 2876621Sbt150084 int 2886621Sbt150084 _fini(void) 2896621Sbt150084 { 2906621Sbt150084 int status; 2916621Sbt150084 2926621Sbt150084 status = mod_remove(&ixgbe_modlinkage); 2936621Sbt150084 2946621Sbt150084 if (status == DDI_SUCCESS) { 2956621Sbt150084 mac_fini_ops(&ixgbe_dev_ops); 2966621Sbt150084 } 2976621Sbt150084 2986621Sbt150084 return (status); 2996621Sbt150084 } 3006621Sbt150084 3016621Sbt150084 int 3026621Sbt150084 _info(struct modinfo *modinfop) 3036621Sbt150084 { 3046621Sbt150084 int status; 3056621Sbt150084 3066621Sbt150084 status = mod_info(&ixgbe_modlinkage, modinfop); 3076621Sbt150084 3086621Sbt150084 return (status); 3096621Sbt150084 } 3106621Sbt150084 3116621Sbt150084 /* 3126621Sbt150084 * ixgbe_attach - Driver attach. 3136621Sbt150084 * 3146621Sbt150084 * This function is the device specific initialization entry 3156621Sbt150084 * point. This entry point is required and must be written. 3166621Sbt150084 * The DDI_ATTACH command must be provided in the attach entry 3176621Sbt150084 * point. When attach() is called with cmd set to DDI_ATTACH, 3186621Sbt150084 * all normal kernel services (such as kmem_alloc(9F)) are 3196621Sbt150084 * available for use by the driver. 3206621Sbt150084 * 3216621Sbt150084 * The attach() function will be called once for each instance 3226621Sbt150084 * of the device on the system with cmd set to DDI_ATTACH. 3236621Sbt150084 * Until attach() succeeds, the only driver entry points which 3246621Sbt150084 * may be called are open(9E) and getinfo(9E). 3256621Sbt150084 */ 3266621Sbt150084 static int 3276621Sbt150084 ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 3286621Sbt150084 { 3296621Sbt150084 ixgbe_t *ixgbe; 3306621Sbt150084 struct ixgbe_osdep *osdep; 3316621Sbt150084 struct ixgbe_hw *hw; 3326621Sbt150084 int instance; 3338490SPaul.Guo@Sun.COM char taskqname[32]; 3346621Sbt150084 3356621Sbt150084 /* 3366621Sbt150084 * Check the command and perform corresponding operations 3376621Sbt150084 */ 3386621Sbt150084 switch (cmd) { 3396621Sbt150084 default: 3406621Sbt150084 return (DDI_FAILURE); 3416621Sbt150084 3426621Sbt150084 case DDI_RESUME: 3436621Sbt150084 return (ixgbe_resume(devinfo)); 3446621Sbt150084 3456621Sbt150084 case DDI_ATTACH: 3466621Sbt150084 break; 3476621Sbt150084 } 3486621Sbt150084 3496621Sbt150084 /* Get the device instance */ 3506621Sbt150084 instance = ddi_get_instance(devinfo); 3516621Sbt150084 3526621Sbt150084 /* Allocate memory for the instance data structure */ 3536621Sbt150084 ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP); 3546621Sbt150084 3556621Sbt150084 ixgbe->dip = devinfo; 3566621Sbt150084 ixgbe->instance = instance; 3576621Sbt150084 3586621Sbt150084 hw = &ixgbe->hw; 3596621Sbt150084 osdep = &ixgbe->osdep; 3606621Sbt150084 hw->back = osdep; 3616621Sbt150084 osdep->ixgbe = ixgbe; 3626621Sbt150084 3636621Sbt150084 /* Attach the instance pointer to the dev_info data structure */ 3646621Sbt150084 ddi_set_driver_private(devinfo, ixgbe); 3656621Sbt150084 3666621Sbt150084 /* 3676621Sbt150084 * Initialize for fma support 3686621Sbt150084 */ 3697167Sgg161487 ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE, 3706621Sbt150084 0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 3716621Sbt150084 DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 3726621Sbt150084 ixgbe_fm_init(ixgbe); 3736621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT; 3746621Sbt150084 3756621Sbt150084 /* 3766621Sbt150084 * Map PCI config space registers 3776621Sbt150084 */ 3786621Sbt150084 if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) { 3796621Sbt150084 ixgbe_error(ixgbe, "Failed to map PCI configurations"); 3806621Sbt150084 goto attach_fail; 3816621Sbt150084 } 3826621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG; 3836621Sbt150084 3846621Sbt150084 /* 3856621Sbt150084 * Identify the chipset family 3866621Sbt150084 */ 3876621Sbt150084 if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) { 3886621Sbt150084 ixgbe_error(ixgbe, "Failed to identify hardware"); 3896621Sbt150084 goto attach_fail; 3906621Sbt150084 } 3916621Sbt150084 3926621Sbt150084 /* 3936621Sbt150084 * Map device registers 3946621Sbt150084 */ 3956621Sbt150084 if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) { 3966621Sbt150084 ixgbe_error(ixgbe, "Failed to map device registers"); 3976621Sbt150084 goto attach_fail; 3986621Sbt150084 } 3996621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP; 4006621Sbt150084 4016621Sbt150084 /* 4026621Sbt150084 * Initialize driver parameters 4036621Sbt150084 */ 4046621Sbt150084 ixgbe_init_properties(ixgbe); 4056621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS; 4066621Sbt150084 4076621Sbt150084 /* 4086621Sbt150084 * Allocate interrupts 4096621Sbt150084 */ 4106621Sbt150084 if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) { 4116621Sbt150084 ixgbe_error(ixgbe, "Failed to allocate interrupts"); 4126621Sbt150084 goto attach_fail; 4136621Sbt150084 } 4146621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR; 4156621Sbt150084 4166621Sbt150084 /* 4176621Sbt150084 * Allocate rx/tx rings based on the ring numbers. 4186621Sbt150084 * The actual numbers of rx/tx rings are decided by the number of 4196621Sbt150084 * allocated interrupt vectors, so we should allocate the rings after 4206621Sbt150084 * interrupts are allocated. 4216621Sbt150084 */ 4226621Sbt150084 if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) { 4236621Sbt150084 ixgbe_error(ixgbe, "Failed to allocate rx and tx rings"); 4246621Sbt150084 goto attach_fail; 4256621Sbt150084 } 4266621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS; 4276621Sbt150084 4286621Sbt150084 /* 4296621Sbt150084 * Map rings to interrupt vectors 4306621Sbt150084 */ 4319353SSamuel.Tu@Sun.COM if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) { 4329353SSamuel.Tu@Sun.COM ixgbe_error(ixgbe, "Failed to map interrupts to vectors"); 4336621Sbt150084 goto attach_fail; 4346621Sbt150084 } 4356621Sbt150084 4366621Sbt150084 /* 4376621Sbt150084 * Add interrupt handlers 4386621Sbt150084 */ 4396621Sbt150084 if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) { 4406621Sbt150084 ixgbe_error(ixgbe, "Failed to add interrupt handlers"); 4416621Sbt150084 goto attach_fail; 4426621Sbt150084 } 4436621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 4446621Sbt150084 4456621Sbt150084 /* 446*11233SPaul.Guo@Sun.COM * Create a taskq for sfp-change 4478490SPaul.Guo@Sun.COM */ 4488490SPaul.Guo@Sun.COM (void) sprintf(taskqname, "ixgbe%d_taskq", instance); 449*11233SPaul.Guo@Sun.COM if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname, 4508490SPaul.Guo@Sun.COM 1, TASKQ_DEFAULTPRI, 0)) == NULL) { 4518490SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "taskq_create failed"); 4528490SPaul.Guo@Sun.COM goto attach_fail; 4538490SPaul.Guo@Sun.COM } 454*11233SPaul.Guo@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ; 4558490SPaul.Guo@Sun.COM 4568490SPaul.Guo@Sun.COM /* 4576621Sbt150084 * Initialize driver parameters 4586621Sbt150084 */ 4596621Sbt150084 if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) { 4606621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize driver settings"); 4616621Sbt150084 goto attach_fail; 4626621Sbt150084 } 4636621Sbt150084 4646621Sbt150084 /* 4656621Sbt150084 * Initialize mutexes for this device. 4666621Sbt150084 * Do this before enabling the interrupt handler and 4676621Sbt150084 * register the softint to avoid the condition where 4686621Sbt150084 * interrupt handler can try using uninitialized mutex. 4696621Sbt150084 */ 4706621Sbt150084 ixgbe_init_locks(ixgbe); 4716621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS; 4726621Sbt150084 4736621Sbt150084 /* 4746621Sbt150084 * Initialize chipset hardware 4756621Sbt150084 */ 4766621Sbt150084 if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) { 4776621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize adapter"); 4786621Sbt150084 goto attach_fail; 4796621Sbt150084 } 480*11233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 481*11233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 482*11233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 4836621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_INIT; 4846621Sbt150084 4856621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) { 4866621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 4876621Sbt150084 goto attach_fail; 4886621Sbt150084 } 4896621Sbt150084 4906621Sbt150084 /* 4916621Sbt150084 * Initialize statistics 4926621Sbt150084 */ 4936621Sbt150084 if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) { 4946621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize statistics"); 4956621Sbt150084 goto attach_fail; 4966621Sbt150084 } 4976621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_STATS; 4986621Sbt150084 4996621Sbt150084 /* 5006621Sbt150084 * Register the driver to the MAC 5016621Sbt150084 */ 5026621Sbt150084 if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) { 5036621Sbt150084 ixgbe_error(ixgbe, "Failed to register MAC"); 5046621Sbt150084 goto attach_fail; 5056621Sbt150084 } 5068490SPaul.Guo@Sun.COM mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN); 5076621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_MAC; 5086621Sbt150084 509*11233SPaul.Guo@Sun.COM ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe, 510*11233SPaul.Guo@Sun.COM IXGBE_CYCLIC_PERIOD, DDI_IPL_0); 511*11233SPaul.Guo@Sun.COM if (ixgbe->periodic_id == 0) { 512*11233SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "Failed to add the link check timer"); 513*11233SPaul.Guo@Sun.COM goto attach_fail; 514*11233SPaul.Guo@Sun.COM } 515*11233SPaul.Guo@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER; 516*11233SPaul.Guo@Sun.COM 5176621Sbt150084 /* 5186621Sbt150084 * Now that mutex locks are initialized, and the chip is also 5196621Sbt150084 * initialized, enable interrupts. 5206621Sbt150084 */ 5216621Sbt150084 if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) { 5226621Sbt150084 ixgbe_error(ixgbe, "Failed to enable DDI interrupts"); 5236621Sbt150084 goto attach_fail; 5246621Sbt150084 } 5256621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 5266621Sbt150084 52710998SChenlu.Chen@Sun.COM ixgbe_log(ixgbe, "%s", ixgbe_version); 528*11233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED); 5296621Sbt150084 5306621Sbt150084 return (DDI_SUCCESS); 5316621Sbt150084 5326621Sbt150084 attach_fail: 5336621Sbt150084 ixgbe_unconfigure(devinfo, ixgbe); 5346621Sbt150084 return (DDI_FAILURE); 5356621Sbt150084 } 5366621Sbt150084 5376621Sbt150084 /* 5386621Sbt150084 * ixgbe_detach - Driver detach. 5396621Sbt150084 * 5406621Sbt150084 * The detach() function is the complement of the attach routine. 5416621Sbt150084 * If cmd is set to DDI_DETACH, detach() is used to remove the 5426621Sbt150084 * state associated with a given instance of a device node 5436621Sbt150084 * prior to the removal of that instance from the system. 5446621Sbt150084 * 5456621Sbt150084 * The detach() function will be called once for each instance 5466621Sbt150084 * of the device for which there has been a successful attach() 5476621Sbt150084 * once there are no longer any opens on the device. 5486621Sbt150084 * 5496621Sbt150084 * Interrupts routine are disabled, All memory allocated by this 5506621Sbt150084 * driver are freed. 5516621Sbt150084 */ 5526621Sbt150084 static int 5536621Sbt150084 ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 5546621Sbt150084 { 5556621Sbt150084 ixgbe_t *ixgbe; 5566621Sbt150084 5576621Sbt150084 /* 5586621Sbt150084 * Check detach command 5596621Sbt150084 */ 5606621Sbt150084 switch (cmd) { 5616621Sbt150084 default: 5626621Sbt150084 return (DDI_FAILURE); 5636621Sbt150084 5646621Sbt150084 case DDI_SUSPEND: 5656621Sbt150084 return (ixgbe_suspend(devinfo)); 5666621Sbt150084 5676621Sbt150084 case DDI_DETACH: 5686621Sbt150084 break; 5696621Sbt150084 } 5706621Sbt150084 5716621Sbt150084 /* 5726621Sbt150084 * Get the pointer to the driver private data structure 5736621Sbt150084 */ 5746621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 5756621Sbt150084 if (ixgbe == NULL) 5766621Sbt150084 return (DDI_FAILURE); 5776621Sbt150084 5786621Sbt150084 /* 5796621Sbt150084 * If the device is still running, it needs to be stopped first. 5806621Sbt150084 * This check is necessary because under some specific circumstances, 5816621Sbt150084 * the detach routine can be called without stopping the interface 5826621Sbt150084 * first. 5836621Sbt150084 */ 5846621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 585*11233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 586*11233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 58710376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_TRUE); 5886621Sbt150084 mutex_exit(&ixgbe->gen_lock); 5896621Sbt150084 /* Disable and stop the watchdog timer */ 5906621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe); 591*11233SPaul.Guo@Sun.COM } 5926621Sbt150084 5936621Sbt150084 /* 5946621Sbt150084 * Check if there are still rx buffers held by the upper layer. 5956621Sbt150084 * If so, fail the detach. 5966621Sbt150084 */ 5976621Sbt150084 if (!ixgbe_rx_drain(ixgbe)) 5986621Sbt150084 return (DDI_FAILURE); 5996621Sbt150084 6006621Sbt150084 /* 6016621Sbt150084 * Do the remaining unconfigure routines 6026621Sbt150084 */ 6036621Sbt150084 ixgbe_unconfigure(devinfo, ixgbe); 6046621Sbt150084 6056621Sbt150084 return (DDI_SUCCESS); 6066621Sbt150084 } 6076621Sbt150084 6086621Sbt150084 static void 6096621Sbt150084 ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe) 6106621Sbt150084 { 6116621Sbt150084 /* 6126621Sbt150084 * Disable interrupt 6136621Sbt150084 */ 6146621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 6156621Sbt150084 (void) ixgbe_disable_intrs(ixgbe); 6166621Sbt150084 } 6176621Sbt150084 6186621Sbt150084 /* 619*11233SPaul.Guo@Sun.COM * remove the link check timer 620*11233SPaul.Guo@Sun.COM */ 621*11233SPaul.Guo@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) { 622*11233SPaul.Guo@Sun.COM if (ixgbe->periodic_id != NULL) { 623*11233SPaul.Guo@Sun.COM ddi_periodic_delete(ixgbe->periodic_id); 624*11233SPaul.Guo@Sun.COM ixgbe->periodic_id = NULL; 625*11233SPaul.Guo@Sun.COM } 626*11233SPaul.Guo@Sun.COM } 627*11233SPaul.Guo@Sun.COM 628*11233SPaul.Guo@Sun.COM /* 6296621Sbt150084 * Unregister MAC 6306621Sbt150084 */ 6316621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) { 6326621Sbt150084 (void) mac_unregister(ixgbe->mac_hdl); 6336621Sbt150084 } 6346621Sbt150084 6356621Sbt150084 /* 6366621Sbt150084 * Free statistics 6376621Sbt150084 */ 6386621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) { 6396621Sbt150084 kstat_delete((kstat_t *)ixgbe->ixgbe_ks); 6406621Sbt150084 } 6416621Sbt150084 6426621Sbt150084 /* 6436621Sbt150084 * Remove interrupt handlers 6446621Sbt150084 */ 6456621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 6466621Sbt150084 ixgbe_rem_intr_handlers(ixgbe); 6476621Sbt150084 } 6486621Sbt150084 6496621Sbt150084 /* 650*11233SPaul.Guo@Sun.COM * Remove taskq for sfp-status-change 6518490SPaul.Guo@Sun.COM */ 652*11233SPaul.Guo@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) { 653*11233SPaul.Guo@Sun.COM ddi_taskq_destroy(ixgbe->sfp_taskq); 6548490SPaul.Guo@Sun.COM } 6558490SPaul.Guo@Sun.COM 6568490SPaul.Guo@Sun.COM /* 6576621Sbt150084 * Remove interrupts 6586621Sbt150084 */ 6596621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) { 6606621Sbt150084 ixgbe_rem_intrs(ixgbe); 6616621Sbt150084 } 6626621Sbt150084 6636621Sbt150084 /* 6646621Sbt150084 * Remove driver properties 6656621Sbt150084 */ 6666621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) { 6676621Sbt150084 (void) ddi_prop_remove_all(devinfo); 6686621Sbt150084 } 6696621Sbt150084 6706621Sbt150084 /* 6716621Sbt150084 * Stop the chipset 6726621Sbt150084 */ 6736621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) { 6746621Sbt150084 mutex_enter(&ixgbe->gen_lock); 6756621Sbt150084 ixgbe_chip_stop(ixgbe); 6766621Sbt150084 mutex_exit(&ixgbe->gen_lock); 6776621Sbt150084 } 6786621Sbt150084 6796621Sbt150084 /* 6806621Sbt150084 * Free register handle 6816621Sbt150084 */ 6826621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) { 6836621Sbt150084 if (ixgbe->osdep.reg_handle != NULL) 6846621Sbt150084 ddi_regs_map_free(&ixgbe->osdep.reg_handle); 6856621Sbt150084 } 6866621Sbt150084 6876621Sbt150084 /* 6886621Sbt150084 * Free PCI config handle 6896621Sbt150084 */ 6906621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) { 6916621Sbt150084 if (ixgbe->osdep.cfg_handle != NULL) 6926621Sbt150084 pci_config_teardown(&ixgbe->osdep.cfg_handle); 6936621Sbt150084 } 6946621Sbt150084 6956621Sbt150084 /* 6966621Sbt150084 * Free locks 6976621Sbt150084 */ 6986621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) { 6996621Sbt150084 ixgbe_destroy_locks(ixgbe); 7006621Sbt150084 } 7016621Sbt150084 7026621Sbt150084 /* 7036621Sbt150084 * Free the rx/tx rings 7046621Sbt150084 */ 7056621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) { 7066621Sbt150084 ixgbe_free_rings(ixgbe); 7076621Sbt150084 } 7086621Sbt150084 7096621Sbt150084 /* 7106621Sbt150084 * Unregister FMA capabilities 7116621Sbt150084 */ 7126621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) { 7136621Sbt150084 ixgbe_fm_fini(ixgbe); 7146621Sbt150084 } 7156621Sbt150084 7166621Sbt150084 /* 7176621Sbt150084 * Free the driver data structure 7186621Sbt150084 */ 7196621Sbt150084 kmem_free(ixgbe, sizeof (ixgbe_t)); 7206621Sbt150084 7216621Sbt150084 ddi_set_driver_private(devinfo, NULL); 7226621Sbt150084 } 7236621Sbt150084 7246621Sbt150084 /* 7256621Sbt150084 * ixgbe_register_mac - Register the driver and its function pointers with 7266621Sbt150084 * the GLD interface. 7276621Sbt150084 */ 7286621Sbt150084 static int 7296621Sbt150084 ixgbe_register_mac(ixgbe_t *ixgbe) 7306621Sbt150084 { 7316621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 7326621Sbt150084 mac_register_t *mac; 7336621Sbt150084 int status; 7346621Sbt150084 7356621Sbt150084 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 7366621Sbt150084 return (IXGBE_FAILURE); 7376621Sbt150084 7386621Sbt150084 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7396621Sbt150084 mac->m_driver = ixgbe; 7406621Sbt150084 mac->m_dip = ixgbe->dip; 7416621Sbt150084 mac->m_src_addr = hw->mac.addr; 7426621Sbt150084 mac->m_callbacks = &ixgbe_m_callbacks; 7436621Sbt150084 mac->m_min_sdu = 0; 7446621Sbt150084 mac->m_max_sdu = ixgbe->default_mtu; 7456621Sbt150084 mac->m_margin = VLAN_TAGSZ; 74610376SChenlu.Chen@Sun.COM mac->m_priv_props = ixgbe_priv_props; 74710376SChenlu.Chen@Sun.COM mac->m_priv_prop_count = IXGBE_MAX_PRIV_PROPS; 7488275SEric Cheng mac->m_v12n = MAC_VIRT_LEVEL1; 7496621Sbt150084 7506621Sbt150084 status = mac_register(mac, &ixgbe->mac_hdl); 7516621Sbt150084 7526621Sbt150084 mac_free(mac); 7536621Sbt150084 7546621Sbt150084 return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE); 7556621Sbt150084 } 7566621Sbt150084 7576621Sbt150084 /* 7586621Sbt150084 * ixgbe_identify_hardware - Identify the type of the chipset. 7596621Sbt150084 */ 7606621Sbt150084 static int 7616621Sbt150084 ixgbe_identify_hardware(ixgbe_t *ixgbe) 7626621Sbt150084 { 7636621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 7646621Sbt150084 struct ixgbe_osdep *osdep = &ixgbe->osdep; 7656621Sbt150084 7666621Sbt150084 /* 7676621Sbt150084 * Get the device id 7686621Sbt150084 */ 7696621Sbt150084 hw->vendor_id = 7706621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID); 7716621Sbt150084 hw->device_id = 7726621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID); 7736621Sbt150084 hw->revision_id = 7746621Sbt150084 pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID); 7756621Sbt150084 hw->subsystem_device_id = 7766621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID); 7776621Sbt150084 hw->subsystem_vendor_id = 7786621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID); 7796621Sbt150084 7808490SPaul.Guo@Sun.COM /* 7818490SPaul.Guo@Sun.COM * Set the mac type of the adapter based on the device id 7828490SPaul.Guo@Sun.COM */ 7838490SPaul.Guo@Sun.COM if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) { 7848490SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 7858490SPaul.Guo@Sun.COM } 7868490SPaul.Guo@Sun.COM 7878490SPaul.Guo@Sun.COM /* 7888490SPaul.Guo@Sun.COM * Install adapter capabilities 7898490SPaul.Guo@Sun.COM */ 7908490SPaul.Guo@Sun.COM switch (hw->mac.type) { 7918490SPaul.Guo@Sun.COM case ixgbe_mac_82598EB: 7929353SSamuel.Tu@Sun.COM ixgbe_log(ixgbe, "identify 82598 adapter\n"); 7938490SPaul.Guo@Sun.COM ixgbe->capab = &ixgbe_82598eb_cap; 7948490SPaul.Guo@Sun.COM 7958490SPaul.Guo@Sun.COM if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) { 7968490SPaul.Guo@Sun.COM ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; 7978490SPaul.Guo@Sun.COM ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1; 7988490SPaul.Guo@Sun.COM } 7999353SSamuel.Tu@Sun.COM ixgbe->capab->other_intr |= IXGBE_EICR_LSC; 8009353SSamuel.Tu@Sun.COM 8019353SSamuel.Tu@Sun.COM break; 8029353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 8039353SSamuel.Tu@Sun.COM ixgbe_log(ixgbe, "identify 82599 adapter\n"); 8049353SSamuel.Tu@Sun.COM ixgbe->capab = &ixgbe_82599eb_cap; 8059353SSamuel.Tu@Sun.COM 8069353SSamuel.Tu@Sun.COM ixgbe->capab->other_intr = (IXGBE_EICR_GPI_SDP1 | 8079353SSamuel.Tu@Sun.COM IXGBE_EICR_GPI_SDP2 | IXGBE_EICR_LSC); 8088490SPaul.Guo@Sun.COM 8098490SPaul.Guo@Sun.COM break; 8108490SPaul.Guo@Sun.COM default: 8118490SPaul.Guo@Sun.COM ixgbe_log(ixgbe, 8128490SPaul.Guo@Sun.COM "adapter not supported in ixgbe_identify_hardware(): %d\n", 8138490SPaul.Guo@Sun.COM hw->mac.type); 8148490SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 8158490SPaul.Guo@Sun.COM } 8168490SPaul.Guo@Sun.COM 8176621Sbt150084 return (IXGBE_SUCCESS); 8186621Sbt150084 } 8196621Sbt150084 8206621Sbt150084 /* 8216621Sbt150084 * ixgbe_regs_map - Map the device registers. 8226621Sbt150084 * 8236621Sbt150084 */ 8246621Sbt150084 static int 8256621Sbt150084 ixgbe_regs_map(ixgbe_t *ixgbe) 8266621Sbt150084 { 8276621Sbt150084 dev_info_t *devinfo = ixgbe->dip; 8286621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 8296621Sbt150084 struct ixgbe_osdep *osdep = &ixgbe->osdep; 8306621Sbt150084 off_t mem_size; 8316621Sbt150084 8326621Sbt150084 /* 8336621Sbt150084 * First get the size of device registers to be mapped. 8346621Sbt150084 */ 8359353SSamuel.Tu@Sun.COM if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size) 8369353SSamuel.Tu@Sun.COM != DDI_SUCCESS) { 8376621Sbt150084 return (IXGBE_FAILURE); 8386621Sbt150084 } 8396621Sbt150084 8406621Sbt150084 /* 8416621Sbt150084 * Call ddi_regs_map_setup() to map registers 8426621Sbt150084 */ 8439353SSamuel.Tu@Sun.COM if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET, 8446621Sbt150084 (caddr_t *)&hw->hw_addr, 0, 8456621Sbt150084 mem_size, &ixgbe_regs_acc_attr, 8466621Sbt150084 &osdep->reg_handle)) != DDI_SUCCESS) { 8476621Sbt150084 return (IXGBE_FAILURE); 8486621Sbt150084 } 8496621Sbt150084 8506621Sbt150084 return (IXGBE_SUCCESS); 8516621Sbt150084 } 8526621Sbt150084 8536621Sbt150084 /* 8546621Sbt150084 * ixgbe_init_properties - Initialize driver properties. 8556621Sbt150084 */ 8566621Sbt150084 static void 8576621Sbt150084 ixgbe_init_properties(ixgbe_t *ixgbe) 8586621Sbt150084 { 8596621Sbt150084 /* 8606621Sbt150084 * Get conf file properties, including link settings 8616621Sbt150084 * jumbo frames, ring number, descriptor number, etc. 8626621Sbt150084 */ 8636621Sbt150084 ixgbe_get_conf(ixgbe); 86410376SChenlu.Chen@Sun.COM 86510376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe); 8666621Sbt150084 } 8676621Sbt150084 8686621Sbt150084 /* 8696621Sbt150084 * ixgbe_init_driver_settings - Initialize driver settings. 8706621Sbt150084 * 8716621Sbt150084 * The settings include hardware function pointers, bus information, 8726621Sbt150084 * rx/tx rings settings, link state, and any other parameters that 8736621Sbt150084 * need to be setup during driver initialization. 8746621Sbt150084 */ 8756621Sbt150084 static int 8766621Sbt150084 ixgbe_init_driver_settings(ixgbe_t *ixgbe) 8776621Sbt150084 { 8786621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 8798275SEric Cheng dev_info_t *devinfo = ixgbe->dip; 8806621Sbt150084 ixgbe_rx_ring_t *rx_ring; 8816621Sbt150084 ixgbe_tx_ring_t *tx_ring; 8826621Sbt150084 uint32_t rx_size; 8836621Sbt150084 uint32_t tx_size; 8846621Sbt150084 int i; 8856621Sbt150084 8866621Sbt150084 /* 8876621Sbt150084 * Initialize chipset specific hardware function pointers 8886621Sbt150084 */ 8896621Sbt150084 if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) { 8906621Sbt150084 return (IXGBE_FAILURE); 8916621Sbt150084 } 8926621Sbt150084 8936621Sbt150084 /* 8948275SEric Cheng * Get the system page size 8958275SEric Cheng */ 8968275SEric Cheng ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1); 8978275SEric Cheng 8988275SEric Cheng /* 8996621Sbt150084 * Set rx buffer size 9006621Sbt150084 * 9016621Sbt150084 * The IP header alignment room is counted in the calculation. 9026621Sbt150084 * The rx buffer size is in unit of 1K that is required by the 9036621Sbt150084 * chipset hardware. 9046621Sbt150084 */ 9056621Sbt150084 rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM; 9066621Sbt150084 ixgbe->rx_buf_size = ((rx_size >> 10) + 9076621Sbt150084 ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 9086621Sbt150084 9096621Sbt150084 /* 9106621Sbt150084 * Set tx buffer size 9116621Sbt150084 */ 9126621Sbt150084 tx_size = ixgbe->max_frame_size; 9136621Sbt150084 ixgbe->tx_buf_size = ((tx_size >> 10) + 9146621Sbt150084 ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 9156621Sbt150084 9166621Sbt150084 /* 9176621Sbt150084 * Initialize rx/tx rings parameters 9186621Sbt150084 */ 9196621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 9206621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 9216621Sbt150084 rx_ring->index = i; 9226621Sbt150084 rx_ring->ixgbe = ixgbe; 9236621Sbt150084 } 9246621Sbt150084 9256621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 9266621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 9276621Sbt150084 tx_ring->index = i; 9286621Sbt150084 tx_ring->ixgbe = ixgbe; 9296621Sbt150084 if (ixgbe->tx_head_wb_enable) 9306621Sbt150084 tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb; 9316621Sbt150084 else 9326621Sbt150084 tx_ring->tx_recycle = ixgbe_tx_recycle_legacy; 9336621Sbt150084 9346621Sbt150084 tx_ring->ring_size = ixgbe->tx_ring_size; 9356621Sbt150084 tx_ring->free_list_size = ixgbe->tx_ring_size + 9366621Sbt150084 (ixgbe->tx_ring_size >> 1); 9376621Sbt150084 } 9386621Sbt150084 9396621Sbt150084 /* 9406621Sbt150084 * Initialize values of interrupt throttling rate 9416621Sbt150084 */ 9429353SSamuel.Tu@Sun.COM for (i = 1; i < MAX_INTR_VECTOR; i++) 9436621Sbt150084 ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0]; 9446621Sbt150084 9456621Sbt150084 /* 9466621Sbt150084 * The initial link state should be "unknown" 9476621Sbt150084 */ 9486621Sbt150084 ixgbe->link_state = LINK_STATE_UNKNOWN; 9499353SSamuel.Tu@Sun.COM 9506621Sbt150084 return (IXGBE_SUCCESS); 9516621Sbt150084 } 9526621Sbt150084 9536621Sbt150084 /* 9546621Sbt150084 * ixgbe_init_locks - Initialize locks. 9556621Sbt150084 */ 9566621Sbt150084 static void 9576621Sbt150084 ixgbe_init_locks(ixgbe_t *ixgbe) 9586621Sbt150084 { 9596621Sbt150084 ixgbe_rx_ring_t *rx_ring; 9606621Sbt150084 ixgbe_tx_ring_t *tx_ring; 9616621Sbt150084 int i; 9626621Sbt150084 9636621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 9646621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 9656621Sbt150084 mutex_init(&rx_ring->rx_lock, NULL, 9666621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 9676621Sbt150084 } 9686621Sbt150084 9696621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 9706621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 9716621Sbt150084 mutex_init(&tx_ring->tx_lock, NULL, 9726621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 9736621Sbt150084 mutex_init(&tx_ring->recycle_lock, NULL, 9746621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 9756621Sbt150084 mutex_init(&tx_ring->tcb_head_lock, NULL, 9766621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 9776621Sbt150084 mutex_init(&tx_ring->tcb_tail_lock, NULL, 9786621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 9796621Sbt150084 } 9806621Sbt150084 9816621Sbt150084 mutex_init(&ixgbe->gen_lock, NULL, 9826621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 9836621Sbt150084 9846621Sbt150084 mutex_init(&ixgbe->watchdog_lock, NULL, 9856621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 9866621Sbt150084 } 9876621Sbt150084 9886621Sbt150084 /* 9896621Sbt150084 * ixgbe_destroy_locks - Destroy locks. 9906621Sbt150084 */ 9916621Sbt150084 static void 9926621Sbt150084 ixgbe_destroy_locks(ixgbe_t *ixgbe) 9936621Sbt150084 { 9946621Sbt150084 ixgbe_rx_ring_t *rx_ring; 9956621Sbt150084 ixgbe_tx_ring_t *tx_ring; 9966621Sbt150084 int i; 9976621Sbt150084 9986621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 9996621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 10006621Sbt150084 mutex_destroy(&rx_ring->rx_lock); 10016621Sbt150084 } 10026621Sbt150084 10036621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 10046621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 10056621Sbt150084 mutex_destroy(&tx_ring->tx_lock); 10066621Sbt150084 mutex_destroy(&tx_ring->recycle_lock); 10076621Sbt150084 mutex_destroy(&tx_ring->tcb_head_lock); 10086621Sbt150084 mutex_destroy(&tx_ring->tcb_tail_lock); 10096621Sbt150084 } 10106621Sbt150084 10116621Sbt150084 mutex_destroy(&ixgbe->gen_lock); 10126621Sbt150084 mutex_destroy(&ixgbe->watchdog_lock); 10136621Sbt150084 } 10146621Sbt150084 10156621Sbt150084 static int 10166621Sbt150084 ixgbe_resume(dev_info_t *devinfo) 10176621Sbt150084 { 10186621Sbt150084 ixgbe_t *ixgbe; 1019*11233SPaul.Guo@Sun.COM int i; 10206621Sbt150084 10216621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 10226621Sbt150084 if (ixgbe == NULL) 10236621Sbt150084 return (DDI_FAILURE); 10246621Sbt150084 10256621Sbt150084 mutex_enter(&ixgbe->gen_lock); 10266621Sbt150084 10276621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 102810376SChenlu.Chen@Sun.COM if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 10296621Sbt150084 mutex_exit(&ixgbe->gen_lock); 10306621Sbt150084 return (DDI_FAILURE); 10316621Sbt150084 } 10326621Sbt150084 10336621Sbt150084 /* 10346621Sbt150084 * Enable and start the watchdog timer 10356621Sbt150084 */ 10366621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe); 10376621Sbt150084 } 10386621Sbt150084 1039*11233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED); 1040*11233SPaul.Guo@Sun.COM 1041*11233SPaul.Guo@Sun.COM if (ixgbe->ixgbe_state & IXGBE_STARTED) { 1042*11233SPaul.Guo@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 1043*11233SPaul.Guo@Sun.COM mac_tx_ring_update(ixgbe->mac_hdl, 1044*11233SPaul.Guo@Sun.COM ixgbe->tx_rings[i].ring_handle); 1045*11233SPaul.Guo@Sun.COM } 1046*11233SPaul.Guo@Sun.COM } 10476621Sbt150084 10486621Sbt150084 mutex_exit(&ixgbe->gen_lock); 10496621Sbt150084 10506621Sbt150084 return (DDI_SUCCESS); 10516621Sbt150084 } 10526621Sbt150084 10536621Sbt150084 static int 10546621Sbt150084 ixgbe_suspend(dev_info_t *devinfo) 10556621Sbt150084 { 10566621Sbt150084 ixgbe_t *ixgbe; 10576621Sbt150084 10586621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 10596621Sbt150084 if (ixgbe == NULL) 10606621Sbt150084 return (DDI_FAILURE); 10616621Sbt150084 10626621Sbt150084 mutex_enter(&ixgbe->gen_lock); 10636621Sbt150084 1064*11233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED); 106510376SChenlu.Chen@Sun.COM if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) { 106610376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->gen_lock); 106710376SChenlu.Chen@Sun.COM return (DDI_SUCCESS); 106810376SChenlu.Chen@Sun.COM } 106910376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_FALSE); 10706621Sbt150084 10716621Sbt150084 mutex_exit(&ixgbe->gen_lock); 10726621Sbt150084 10736621Sbt150084 /* 10746621Sbt150084 * Disable and stop the watchdog timer 10756621Sbt150084 */ 10766621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe); 10776621Sbt150084 10786621Sbt150084 return (DDI_SUCCESS); 10796621Sbt150084 } 10806621Sbt150084 10816621Sbt150084 /* 10826621Sbt150084 * ixgbe_init - Initialize the device. 10836621Sbt150084 */ 10846621Sbt150084 static int 10856621Sbt150084 ixgbe_init(ixgbe_t *ixgbe) 10866621Sbt150084 { 10876621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 10886621Sbt150084 10896621Sbt150084 mutex_enter(&ixgbe->gen_lock); 10906621Sbt150084 10916621Sbt150084 /* 10926621Sbt150084 * Reset chipset to put the hardware in a known state 10936621Sbt150084 * before we try to do anything with the eeprom. 10946621Sbt150084 */ 10956621Sbt150084 if (ixgbe_reset_hw(hw) != IXGBE_SUCCESS) { 10966621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 10976621Sbt150084 goto init_fail; 10986621Sbt150084 } 10996621Sbt150084 11006621Sbt150084 /* 11016621Sbt150084 * Need to init eeprom before validating the checksum. 11026621Sbt150084 */ 11036621Sbt150084 if (ixgbe_init_eeprom_params(hw) < 0) { 11046621Sbt150084 ixgbe_error(ixgbe, 11056621Sbt150084 "Unable to intitialize the eeprom interface."); 11066621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11076621Sbt150084 goto init_fail; 11086621Sbt150084 } 11096621Sbt150084 11106621Sbt150084 /* 11116621Sbt150084 * NVM validation 11126621Sbt150084 */ 11136621Sbt150084 if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { 11146621Sbt150084 /* 11156621Sbt150084 * Some PCI-E parts fail the first check due to 11166621Sbt150084 * the link being in sleep state. Call it again, 11176621Sbt150084 * if it fails a second time it's a real issue. 11186621Sbt150084 */ 11196621Sbt150084 if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { 11206621Sbt150084 ixgbe_error(ixgbe, 11216621Sbt150084 "Invalid NVM checksum. Please contact " 11226621Sbt150084 "the vendor to update the NVM."); 11236621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11246621Sbt150084 goto init_fail; 11256621Sbt150084 } 11266621Sbt150084 } 11276621Sbt150084 11286621Sbt150084 /* 11296621Sbt150084 * Setup default flow control thresholds - enable/disable 11306621Sbt150084 * & flow control type is controlled by ixgbe.conf 11316621Sbt150084 */ 11326621Sbt150084 hw->fc.high_water = DEFAULT_FCRTH; 11336621Sbt150084 hw->fc.low_water = DEFAULT_FCRTL; 11346621Sbt150084 hw->fc.pause_time = DEFAULT_FCPAUSE; 11356621Sbt150084 hw->fc.send_xon = B_TRUE; 11366621Sbt150084 11376621Sbt150084 /* 11386621Sbt150084 * Initialize link settings 11396621Sbt150084 */ 11406621Sbt150084 (void) ixgbe_driver_setup_link(ixgbe, B_FALSE); 11416621Sbt150084 11426621Sbt150084 /* 11436621Sbt150084 * Initialize the chipset hardware 11446621Sbt150084 */ 11456621Sbt150084 if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { 11466621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11476621Sbt150084 goto init_fail; 11486621Sbt150084 } 11496621Sbt150084 11506621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 11516621Sbt150084 goto init_fail; 11526621Sbt150084 } 11536621Sbt150084 11546621Sbt150084 mutex_exit(&ixgbe->gen_lock); 11556621Sbt150084 return (IXGBE_SUCCESS); 11566621Sbt150084 11576621Sbt150084 init_fail: 11586621Sbt150084 /* 11596621Sbt150084 * Reset PHY 11606621Sbt150084 */ 11616621Sbt150084 (void) ixgbe_reset_phy(hw); 11626621Sbt150084 11636621Sbt150084 mutex_exit(&ixgbe->gen_lock); 11646621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 11656621Sbt150084 return (IXGBE_FAILURE); 11666621Sbt150084 } 11676621Sbt150084 11686621Sbt150084 /* 11696621Sbt150084 * ixgbe_chip_start - Initialize and start the chipset hardware. 11706621Sbt150084 */ 11716621Sbt150084 static int 11726621Sbt150084 ixgbe_chip_start(ixgbe_t *ixgbe) 11736621Sbt150084 { 11746621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 117510305SPaul.Guo@Sun.COM int ret_val, i; 11766621Sbt150084 11776621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 11786621Sbt150084 11796621Sbt150084 /* 11806621Sbt150084 * Get the mac address 11816621Sbt150084 * This function should handle SPARC case correctly. 11826621Sbt150084 */ 11836621Sbt150084 if (!ixgbe_find_mac_address(ixgbe)) { 11846621Sbt150084 ixgbe_error(ixgbe, "Failed to get the mac address"); 11856621Sbt150084 return (IXGBE_FAILURE); 11866621Sbt150084 } 11876621Sbt150084 11886621Sbt150084 /* 11896621Sbt150084 * Validate the mac address 11906621Sbt150084 */ 11916621Sbt150084 (void) ixgbe_init_rx_addrs(hw); 11926621Sbt150084 if (!is_valid_mac_addr(hw->mac.addr)) { 11936621Sbt150084 ixgbe_error(ixgbe, "Invalid mac address"); 11946621Sbt150084 return (IXGBE_FAILURE); 11956621Sbt150084 } 11966621Sbt150084 11976621Sbt150084 /* 11986621Sbt150084 * Configure/Initialize hardware 11996621Sbt150084 */ 120010305SPaul.Guo@Sun.COM ret_val = ixgbe_init_hw(hw); 120110305SPaul.Guo@Sun.COM if (ret_val != IXGBE_SUCCESS) { 120210305SPaul.Guo@Sun.COM if (ret_val == IXGBE_ERR_EEPROM_VERSION) { 120310305SPaul.Guo@Sun.COM ixgbe_error(ixgbe, 120410305SPaul.Guo@Sun.COM "This 82599 device is pre-release and contains" 120510305SPaul.Guo@Sun.COM " outdated firmware, please contact your hardware" 120610305SPaul.Guo@Sun.COM " vendor for a replacement."); 120710305SPaul.Guo@Sun.COM } else { 120810305SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "Failed to initialize hardware"); 120910305SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 121010305SPaul.Guo@Sun.COM } 12116621Sbt150084 } 12126621Sbt150084 12136621Sbt150084 /* 12146621Sbt150084 * Setup adapter interrupt vectors 12156621Sbt150084 */ 12166621Sbt150084 ixgbe_setup_adapter_vector(ixgbe); 12176621Sbt150084 12186621Sbt150084 /* 12196621Sbt150084 * Initialize unicast addresses. 12206621Sbt150084 */ 12216621Sbt150084 ixgbe_init_unicst(ixgbe); 12226621Sbt150084 12236621Sbt150084 /* 12246621Sbt150084 * Setup and initialize the mctable structures. 12256621Sbt150084 */ 12266621Sbt150084 ixgbe_setup_multicst(ixgbe); 12276621Sbt150084 12286621Sbt150084 /* 12296621Sbt150084 * Set interrupt throttling rate 12306621Sbt150084 */ 12319353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->intr_cnt; i++) { 12326621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]); 12339353SSamuel.Tu@Sun.COM } 12346621Sbt150084 12356621Sbt150084 /* 12366621Sbt150084 * Save the state of the phy 12376621Sbt150084 */ 12386621Sbt150084 ixgbe_get_hw_state(ixgbe); 12396621Sbt150084 12406621Sbt150084 /* 12416621Sbt150084 * Make sure driver has control 12426621Sbt150084 */ 12436621Sbt150084 ixgbe_get_driver_control(hw); 12446621Sbt150084 12456621Sbt150084 return (IXGBE_SUCCESS); 12466621Sbt150084 } 12476621Sbt150084 12486621Sbt150084 /* 12496621Sbt150084 * ixgbe_chip_stop - Stop the chipset hardware 12506621Sbt150084 */ 12516621Sbt150084 static void 12526621Sbt150084 ixgbe_chip_stop(ixgbe_t *ixgbe) 12536621Sbt150084 { 12546621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 12556621Sbt150084 12566621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 12576621Sbt150084 12586621Sbt150084 /* 12596621Sbt150084 * Tell firmware driver is no longer in control 12606621Sbt150084 */ 12616621Sbt150084 ixgbe_release_driver_control(hw); 12626621Sbt150084 12636621Sbt150084 /* 12646621Sbt150084 * Reset the chipset 12656621Sbt150084 */ 12666621Sbt150084 (void) ixgbe_reset_hw(hw); 12676621Sbt150084 12686621Sbt150084 /* 12696621Sbt150084 * Reset PHY 12706621Sbt150084 */ 12716621Sbt150084 (void) ixgbe_reset_phy(hw); 12726621Sbt150084 } 12736621Sbt150084 12746621Sbt150084 /* 12756621Sbt150084 * ixgbe_reset - Reset the chipset and re-start the driver. 12766621Sbt150084 * 12776621Sbt150084 * It involves stopping and re-starting the chipset, 12786621Sbt150084 * and re-configuring the rx/tx rings. 12796621Sbt150084 */ 12806621Sbt150084 static int 12816621Sbt150084 ixgbe_reset(ixgbe_t *ixgbe) 12826621Sbt150084 { 1283*11233SPaul.Guo@Sun.COM int i; 1284*11233SPaul.Guo@Sun.COM 128510376SChenlu.Chen@Sun.COM /* 128610376SChenlu.Chen@Sun.COM * Disable and stop the watchdog timer 128710376SChenlu.Chen@Sun.COM */ 128810376SChenlu.Chen@Sun.COM ixgbe_disable_watchdog_timer(ixgbe); 12896621Sbt150084 12906621Sbt150084 mutex_enter(&ixgbe->gen_lock); 12916621Sbt150084 12926621Sbt150084 ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED); 1293*11233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 12946621Sbt150084 129510376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_FALSE); 129610376SChenlu.Chen@Sun.COM 129710376SChenlu.Chen@Sun.COM if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 129810376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->gen_lock); 129910376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 13006621Sbt150084 } 13016621Sbt150084 1302*11233SPaul.Guo@Sun.COM /* 1303*11233SPaul.Guo@Sun.COM * After resetting, need to recheck the link status. 1304*11233SPaul.Guo@Sun.COM */ 1305*11233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 1306*11233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 1307*11233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 1308*11233SPaul.Guo@Sun.COM 1309*11233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED); 1310*11233SPaul.Guo@Sun.COM 1311*11233SPaul.Guo@Sun.COM if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) { 1312*11233SPaul.Guo@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 1313*11233SPaul.Guo@Sun.COM mac_tx_ring_update(ixgbe->mac_hdl, 1314*11233SPaul.Guo@Sun.COM ixgbe->tx_rings[i].ring_handle); 1315*11233SPaul.Guo@Sun.COM } 1316*11233SPaul.Guo@Sun.COM } 1317*11233SPaul.Guo@Sun.COM 13186621Sbt150084 mutex_exit(&ixgbe->gen_lock); 13196621Sbt150084 132010376SChenlu.Chen@Sun.COM /* 132110376SChenlu.Chen@Sun.COM * Enable and start the watchdog timer 132210376SChenlu.Chen@Sun.COM */ 132310376SChenlu.Chen@Sun.COM ixgbe_enable_watchdog_timer(ixgbe); 132410376SChenlu.Chen@Sun.COM 13256621Sbt150084 return (IXGBE_SUCCESS); 13266621Sbt150084 } 13276621Sbt150084 13286621Sbt150084 /* 13296621Sbt150084 * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources. 13306621Sbt150084 */ 13316621Sbt150084 static void 13326621Sbt150084 ixgbe_tx_clean(ixgbe_t *ixgbe) 13336621Sbt150084 { 13346621Sbt150084 ixgbe_tx_ring_t *tx_ring; 13356621Sbt150084 tx_control_block_t *tcb; 13366621Sbt150084 link_list_t pending_list; 13376621Sbt150084 uint32_t desc_num; 13386621Sbt150084 int i, j; 13396621Sbt150084 13406621Sbt150084 LINK_LIST_INIT(&pending_list); 13416621Sbt150084 13426621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 13436621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 13446621Sbt150084 13456621Sbt150084 mutex_enter(&tx_ring->recycle_lock); 13466621Sbt150084 13476621Sbt150084 /* 13486621Sbt150084 * Clean the pending tx data - the pending packets in the 13496621Sbt150084 * work_list that have no chances to be transmitted again. 13506621Sbt150084 * 13516621Sbt150084 * We must ensure the chipset is stopped or the link is down 13526621Sbt150084 * before cleaning the transmit packets. 13536621Sbt150084 */ 13546621Sbt150084 desc_num = 0; 13556621Sbt150084 for (j = 0; j < tx_ring->ring_size; j++) { 13566621Sbt150084 tcb = tx_ring->work_list[j]; 13576621Sbt150084 if (tcb != NULL) { 13586621Sbt150084 desc_num += tcb->desc_num; 13596621Sbt150084 13606621Sbt150084 tx_ring->work_list[j] = NULL; 13616621Sbt150084 13626621Sbt150084 ixgbe_free_tcb(tcb); 13636621Sbt150084 13646621Sbt150084 LIST_PUSH_TAIL(&pending_list, &tcb->link); 13656621Sbt150084 } 13666621Sbt150084 } 13676621Sbt150084 13686621Sbt150084 if (desc_num > 0) { 13696621Sbt150084 atomic_add_32(&tx_ring->tbd_free, desc_num); 13706621Sbt150084 ASSERT(tx_ring->tbd_free == tx_ring->ring_size); 13716621Sbt150084 13726621Sbt150084 /* 13736621Sbt150084 * Reset the head and tail pointers of the tbd ring; 13746621Sbt150084 * Reset the writeback head if it's enable. 13756621Sbt150084 */ 13766621Sbt150084 tx_ring->tbd_head = 0; 13776621Sbt150084 tx_ring->tbd_tail = 0; 13786621Sbt150084 if (ixgbe->tx_head_wb_enable) 13796621Sbt150084 *tx_ring->tbd_head_wb = 0; 13806621Sbt150084 13816621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, 13826621Sbt150084 IXGBE_TDH(tx_ring->index), 0); 13836621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, 13846621Sbt150084 IXGBE_TDT(tx_ring->index), 0); 13856621Sbt150084 } 13866621Sbt150084 13876621Sbt150084 mutex_exit(&tx_ring->recycle_lock); 13886621Sbt150084 13896621Sbt150084 /* 13906621Sbt150084 * Add the tx control blocks in the pending list to 13916621Sbt150084 * the free list. 13926621Sbt150084 */ 13936621Sbt150084 ixgbe_put_free_list(tx_ring, &pending_list); 13946621Sbt150084 } 13956621Sbt150084 } 13966621Sbt150084 13976621Sbt150084 /* 13986621Sbt150084 * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be 13996621Sbt150084 * transmitted. 14006621Sbt150084 */ 14016621Sbt150084 static boolean_t 14026621Sbt150084 ixgbe_tx_drain(ixgbe_t *ixgbe) 14036621Sbt150084 { 14046621Sbt150084 ixgbe_tx_ring_t *tx_ring; 14056621Sbt150084 boolean_t done; 14066621Sbt150084 int i, j; 14076621Sbt150084 14086621Sbt150084 /* 14096621Sbt150084 * Wait for a specific time to allow pending tx packets 14106621Sbt150084 * to be transmitted. 14116621Sbt150084 * 14126621Sbt150084 * Check the counter tbd_free to see if transmission is done. 14136621Sbt150084 * No lock protection is needed here. 14146621Sbt150084 * 14156621Sbt150084 * Return B_TRUE if all pending packets have been transmitted; 14166621Sbt150084 * Otherwise return B_FALSE; 14176621Sbt150084 */ 14186621Sbt150084 for (i = 0; i < TX_DRAIN_TIME; i++) { 14196621Sbt150084 14206621Sbt150084 done = B_TRUE; 14216621Sbt150084 for (j = 0; j < ixgbe->num_tx_rings; j++) { 14226621Sbt150084 tx_ring = &ixgbe->tx_rings[j]; 14236621Sbt150084 done = done && 14246621Sbt150084 (tx_ring->tbd_free == tx_ring->ring_size); 14256621Sbt150084 } 14266621Sbt150084 14276621Sbt150084 if (done) 14286621Sbt150084 break; 14296621Sbt150084 14306621Sbt150084 msec_delay(1); 14316621Sbt150084 } 14326621Sbt150084 14336621Sbt150084 return (done); 14346621Sbt150084 } 14356621Sbt150084 14366621Sbt150084 /* 14376621Sbt150084 * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer. 14386621Sbt150084 */ 14396621Sbt150084 static boolean_t 14406621Sbt150084 ixgbe_rx_drain(ixgbe_t *ixgbe) 14416621Sbt150084 { 144210376SChenlu.Chen@Sun.COM boolean_t done = B_TRUE; 144310376SChenlu.Chen@Sun.COM int i; 14446621Sbt150084 14456621Sbt150084 /* 14466621Sbt150084 * Polling the rx free list to check if those rx buffers held by 14476621Sbt150084 * the upper layer are released. 14486621Sbt150084 * 14496621Sbt150084 * Check the counter rcb_free to see if all pending buffers are 14506621Sbt150084 * released. No lock protection is needed here. 14516621Sbt150084 * 14526621Sbt150084 * Return B_TRUE if all pending buffers have been released; 14536621Sbt150084 * Otherwise return B_FALSE; 14546621Sbt150084 */ 14556621Sbt150084 for (i = 0; i < RX_DRAIN_TIME; i++) { 145610376SChenlu.Chen@Sun.COM done = (ixgbe->rcb_pending == 0); 14576621Sbt150084 14586621Sbt150084 if (done) 14596621Sbt150084 break; 14606621Sbt150084 14616621Sbt150084 msec_delay(1); 14626621Sbt150084 } 14636621Sbt150084 14646621Sbt150084 return (done); 14656621Sbt150084 } 14666621Sbt150084 14676621Sbt150084 /* 14686621Sbt150084 * ixgbe_start - Start the driver/chipset. 14696621Sbt150084 */ 14706621Sbt150084 int 147110376SChenlu.Chen@Sun.COM ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer) 14726621Sbt150084 { 14736621Sbt150084 int i; 14746621Sbt150084 14756621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 14766621Sbt150084 147710376SChenlu.Chen@Sun.COM if (alloc_buffer) { 147810376SChenlu.Chen@Sun.COM if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) { 147910376SChenlu.Chen@Sun.COM ixgbe_error(ixgbe, 148010376SChenlu.Chen@Sun.COM "Failed to allocate software receive rings"); 148110376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 148210376SChenlu.Chen@Sun.COM } 148310376SChenlu.Chen@Sun.COM 148410376SChenlu.Chen@Sun.COM /* Allocate buffers for all the rx/tx rings */ 148510376SChenlu.Chen@Sun.COM if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) { 148610376SChenlu.Chen@Sun.COM ixgbe_error(ixgbe, "Failed to allocate DMA resource"); 148710376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 148810376SChenlu.Chen@Sun.COM } 148910376SChenlu.Chen@Sun.COM 149010376SChenlu.Chen@Sun.COM ixgbe->tx_ring_init = B_TRUE; 149110376SChenlu.Chen@Sun.COM } else { 149210376SChenlu.Chen@Sun.COM ixgbe->tx_ring_init = B_FALSE; 149310376SChenlu.Chen@Sun.COM } 149410376SChenlu.Chen@Sun.COM 14956621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) 14966621Sbt150084 mutex_enter(&ixgbe->rx_rings[i].rx_lock); 14976621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) 14986621Sbt150084 mutex_enter(&ixgbe->tx_rings[i].tx_lock); 14996621Sbt150084 15006621Sbt150084 /* 15016621Sbt150084 * Start the chipset hardware 15026621Sbt150084 */ 15036621Sbt150084 if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { 15046621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 15056621Sbt150084 goto start_failure; 15066621Sbt150084 } 15076621Sbt150084 15086621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 15096621Sbt150084 goto start_failure; 15106621Sbt150084 } 15116621Sbt150084 15126621Sbt150084 /* 15136621Sbt150084 * Setup the rx/tx rings 15146621Sbt150084 */ 15156621Sbt150084 ixgbe_setup_rings(ixgbe); 15166621Sbt150084 15176621Sbt150084 /* 1518*11233SPaul.Guo@Sun.COM * ixgbe_start() will be called when resetting, however if reset 1519*11233SPaul.Guo@Sun.COM * happens, we need to clear the ERROR and STALL flags before 1520*11233SPaul.Guo@Sun.COM * enabling the interrupts. 1521*11233SPaul.Guo@Sun.COM */ 1522*11233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR | IXGBE_STALL)); 1523*11233SPaul.Guo@Sun.COM 1524*11233SPaul.Guo@Sun.COM /* 15256621Sbt150084 * Enable adapter interrupts 15266621Sbt150084 * The interrupts must be enabled after the driver state is START 15276621Sbt150084 */ 15286621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe); 15296621Sbt150084 15306621Sbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 15316621Sbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 15326621Sbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 15336621Sbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 15346621Sbt150084 15356621Sbt150084 return (IXGBE_SUCCESS); 15366621Sbt150084 15376621Sbt150084 start_failure: 15386621Sbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 15396621Sbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 15406621Sbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 15416621Sbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 15426621Sbt150084 15436621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 15446621Sbt150084 15456621Sbt150084 return (IXGBE_FAILURE); 15466621Sbt150084 } 15476621Sbt150084 15486621Sbt150084 /* 15496621Sbt150084 * ixgbe_stop - Stop the driver/chipset. 15506621Sbt150084 */ 15516621Sbt150084 void 155210376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer) 15536621Sbt150084 { 15546621Sbt150084 int i; 15556621Sbt150084 15566621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 15576621Sbt150084 15586621Sbt150084 /* 15596621Sbt150084 * Disable the adapter interrupts 15606621Sbt150084 */ 15616621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe); 15626621Sbt150084 15636621Sbt150084 /* 15646621Sbt150084 * Drain the pending tx packets 15656621Sbt150084 */ 15666621Sbt150084 (void) ixgbe_tx_drain(ixgbe); 15676621Sbt150084 15686621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) 15696621Sbt150084 mutex_enter(&ixgbe->rx_rings[i].rx_lock); 15706621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) 15716621Sbt150084 mutex_enter(&ixgbe->tx_rings[i].tx_lock); 15726621Sbt150084 15736621Sbt150084 /* 15746621Sbt150084 * Stop the chipset hardware 15756621Sbt150084 */ 15766621Sbt150084 ixgbe_chip_stop(ixgbe); 15776621Sbt150084 15786621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 15796621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 15806621Sbt150084 } 15816621Sbt150084 15826621Sbt150084 /* 15836621Sbt150084 * Clean the pending tx data/resources 15846621Sbt150084 */ 15856621Sbt150084 ixgbe_tx_clean(ixgbe); 15866621Sbt150084 15876621Sbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 15886621Sbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 15896621Sbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 15906621Sbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 159110376SChenlu.Chen@Sun.COM 159210376SChenlu.Chen@Sun.COM if (ixgbe->link_state == LINK_STATE_UP) { 159310376SChenlu.Chen@Sun.COM ixgbe->link_state = LINK_STATE_UNKNOWN; 159410376SChenlu.Chen@Sun.COM mac_link_update(ixgbe->mac_hdl, ixgbe->link_state); 159510376SChenlu.Chen@Sun.COM } 159610376SChenlu.Chen@Sun.COM 159710376SChenlu.Chen@Sun.COM if (free_buffer) { 159810376SChenlu.Chen@Sun.COM /* 159910376SChenlu.Chen@Sun.COM * Release the DMA/memory resources of rx/tx rings 160010376SChenlu.Chen@Sun.COM */ 160110376SChenlu.Chen@Sun.COM ixgbe_free_dma(ixgbe); 160210376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe); 160310376SChenlu.Chen@Sun.COM } 16046621Sbt150084 } 16056621Sbt150084 16066621Sbt150084 /* 16076621Sbt150084 * ixgbe_alloc_rings - Allocate memory space for rx/tx rings. 16086621Sbt150084 */ 16096621Sbt150084 static int 16106621Sbt150084 ixgbe_alloc_rings(ixgbe_t *ixgbe) 16116621Sbt150084 { 16126621Sbt150084 /* 16136621Sbt150084 * Allocate memory space for rx rings 16146621Sbt150084 */ 16156621Sbt150084 ixgbe->rx_rings = kmem_zalloc( 16166621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings, 16176621Sbt150084 KM_NOSLEEP); 16186621Sbt150084 16196621Sbt150084 if (ixgbe->rx_rings == NULL) { 16206621Sbt150084 return (IXGBE_FAILURE); 16216621Sbt150084 } 16226621Sbt150084 16236621Sbt150084 /* 16246621Sbt150084 * Allocate memory space for tx rings 16256621Sbt150084 */ 16266621Sbt150084 ixgbe->tx_rings = kmem_zalloc( 16276621Sbt150084 sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings, 16286621Sbt150084 KM_NOSLEEP); 16296621Sbt150084 16306621Sbt150084 if (ixgbe->tx_rings == NULL) { 16316621Sbt150084 kmem_free(ixgbe->rx_rings, 16326621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 16336621Sbt150084 ixgbe->rx_rings = NULL; 16346621Sbt150084 return (IXGBE_FAILURE); 16356621Sbt150084 } 16366621Sbt150084 16378275SEric Cheng /* 16388275SEric Cheng * Allocate memory space for rx ring groups 16398275SEric Cheng */ 16408275SEric Cheng ixgbe->rx_groups = kmem_zalloc( 16418275SEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups, 16428275SEric Cheng KM_NOSLEEP); 16438275SEric Cheng 16448275SEric Cheng if (ixgbe->rx_groups == NULL) { 16458275SEric Cheng kmem_free(ixgbe->rx_rings, 16468275SEric Cheng sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 16478275SEric Cheng kmem_free(ixgbe->tx_rings, 16488275SEric Cheng sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings); 16498275SEric Cheng ixgbe->rx_rings = NULL; 16508275SEric Cheng ixgbe->tx_rings = NULL; 16518275SEric Cheng return (IXGBE_FAILURE); 16528275SEric Cheng } 16538275SEric Cheng 16546621Sbt150084 return (IXGBE_SUCCESS); 16556621Sbt150084 } 16566621Sbt150084 16576621Sbt150084 /* 16586621Sbt150084 * ixgbe_free_rings - Free the memory space of rx/tx rings. 16596621Sbt150084 */ 16606621Sbt150084 static void 16616621Sbt150084 ixgbe_free_rings(ixgbe_t *ixgbe) 16626621Sbt150084 { 16636621Sbt150084 if (ixgbe->rx_rings != NULL) { 16646621Sbt150084 kmem_free(ixgbe->rx_rings, 16656621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 16666621Sbt150084 ixgbe->rx_rings = NULL; 16676621Sbt150084 } 16686621Sbt150084 16696621Sbt150084 if (ixgbe->tx_rings != NULL) { 16706621Sbt150084 kmem_free(ixgbe->tx_rings, 16716621Sbt150084 sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings); 16726621Sbt150084 ixgbe->tx_rings = NULL; 16736621Sbt150084 } 16748275SEric Cheng 16758275SEric Cheng if (ixgbe->rx_groups != NULL) { 16768275SEric Cheng kmem_free(ixgbe->rx_groups, 16778275SEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups); 16788275SEric Cheng ixgbe->rx_groups = NULL; 16798275SEric Cheng } 16806621Sbt150084 } 16816621Sbt150084 168210376SChenlu.Chen@Sun.COM static int 168310376SChenlu.Chen@Sun.COM ixgbe_alloc_rx_data(ixgbe_t *ixgbe) 168410376SChenlu.Chen@Sun.COM { 168510376SChenlu.Chen@Sun.COM ixgbe_rx_ring_t *rx_ring; 168610376SChenlu.Chen@Sun.COM int i; 168710376SChenlu.Chen@Sun.COM 168810376SChenlu.Chen@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 168910376SChenlu.Chen@Sun.COM rx_ring = &ixgbe->rx_rings[i]; 169010376SChenlu.Chen@Sun.COM if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS) 169110376SChenlu.Chen@Sun.COM goto alloc_rx_rings_failure; 169210376SChenlu.Chen@Sun.COM } 169310376SChenlu.Chen@Sun.COM return (IXGBE_SUCCESS); 169410376SChenlu.Chen@Sun.COM 169510376SChenlu.Chen@Sun.COM alloc_rx_rings_failure: 169610376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe); 169710376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 169810376SChenlu.Chen@Sun.COM } 169910376SChenlu.Chen@Sun.COM 170010376SChenlu.Chen@Sun.COM static void 170110376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe_t *ixgbe) 170210376SChenlu.Chen@Sun.COM { 170310376SChenlu.Chen@Sun.COM ixgbe_rx_ring_t *rx_ring; 170410376SChenlu.Chen@Sun.COM ixgbe_rx_data_t *rx_data; 170510376SChenlu.Chen@Sun.COM int i; 170610376SChenlu.Chen@Sun.COM 170710376SChenlu.Chen@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 170810376SChenlu.Chen@Sun.COM rx_ring = &ixgbe->rx_rings[i]; 170910376SChenlu.Chen@Sun.COM 171010376SChenlu.Chen@Sun.COM mutex_enter(&ixgbe->rx_pending_lock); 171110376SChenlu.Chen@Sun.COM rx_data = rx_ring->rx_data; 171210376SChenlu.Chen@Sun.COM 171310376SChenlu.Chen@Sun.COM if (rx_data != NULL) { 171410376SChenlu.Chen@Sun.COM rx_data->flag |= IXGBE_RX_STOPPED; 171510376SChenlu.Chen@Sun.COM 171610376SChenlu.Chen@Sun.COM if (rx_data->rcb_pending == 0) { 171710376SChenlu.Chen@Sun.COM ixgbe_free_rx_ring_data(rx_data); 171810376SChenlu.Chen@Sun.COM rx_ring->rx_data = NULL; 171910376SChenlu.Chen@Sun.COM } 172010376SChenlu.Chen@Sun.COM } 172110376SChenlu.Chen@Sun.COM 172210376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->rx_pending_lock); 172310376SChenlu.Chen@Sun.COM } 172410376SChenlu.Chen@Sun.COM } 172510376SChenlu.Chen@Sun.COM 17266621Sbt150084 /* 17276621Sbt150084 * ixgbe_setup_rings - Setup rx/tx rings. 17286621Sbt150084 */ 17296621Sbt150084 static void 17306621Sbt150084 ixgbe_setup_rings(ixgbe_t *ixgbe) 17316621Sbt150084 { 17326621Sbt150084 /* 17336621Sbt150084 * Setup the rx/tx rings, including the following: 17346621Sbt150084 * 17356621Sbt150084 * 1. Setup the descriptor ring and the control block buffers; 17366621Sbt150084 * 2. Initialize necessary registers for receive/transmit; 17376621Sbt150084 * 3. Initialize software pointers/parameters for receive/transmit; 17386621Sbt150084 */ 17396621Sbt150084 ixgbe_setup_rx(ixgbe); 17406621Sbt150084 17416621Sbt150084 ixgbe_setup_tx(ixgbe); 17426621Sbt150084 } 17436621Sbt150084 17446621Sbt150084 static void 17456621Sbt150084 ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring) 17466621Sbt150084 { 17476621Sbt150084 ixgbe_t *ixgbe = rx_ring->ixgbe; 174810376SChenlu.Chen@Sun.COM ixgbe_rx_data_t *rx_data = rx_ring->rx_data; 17496621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 17506621Sbt150084 rx_control_block_t *rcb; 17516621Sbt150084 union ixgbe_adv_rx_desc *rbd; 17526621Sbt150084 uint32_t size; 17536621Sbt150084 uint32_t buf_low; 17546621Sbt150084 uint32_t buf_high; 17556621Sbt150084 uint32_t reg_val; 17566621Sbt150084 int i; 17576621Sbt150084 17586621Sbt150084 ASSERT(mutex_owned(&rx_ring->rx_lock)); 17596621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 17606621Sbt150084 17616621Sbt150084 for (i = 0; i < ixgbe->rx_ring_size; i++) { 176210376SChenlu.Chen@Sun.COM rcb = rx_data->work_list[i]; 176310376SChenlu.Chen@Sun.COM rbd = &rx_data->rbd_ring[i]; 17646621Sbt150084 17656621Sbt150084 rbd->read.pkt_addr = rcb->rx_buf.dma_address; 17666621Sbt150084 rbd->read.hdr_addr = NULL; 17676621Sbt150084 } 17686621Sbt150084 17696621Sbt150084 /* 17706621Sbt150084 * Initialize the length register 17716621Sbt150084 */ 177210376SChenlu.Chen@Sun.COM size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc); 17736621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->index), size); 17746621Sbt150084 17756621Sbt150084 /* 17766621Sbt150084 * Initialize the base address registers 17776621Sbt150084 */ 177810376SChenlu.Chen@Sun.COM buf_low = (uint32_t)rx_data->rbd_area.dma_address; 177910376SChenlu.Chen@Sun.COM buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32); 17806621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->index), buf_high); 17816621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->index), buf_low); 17826621Sbt150084 17836621Sbt150084 /* 17846621Sbt150084 * Setup head & tail pointers 17856621Sbt150084 */ 178610376SChenlu.Chen@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->index), rx_data->ring_size - 1); 17876621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->index), 0); 17886621Sbt150084 178910376SChenlu.Chen@Sun.COM rx_data->rbd_next = 0; 17906621Sbt150084 17916621Sbt150084 /* 17926621Sbt150084 * Setup the Receive Descriptor Control Register (RXDCTL) 17936621Sbt150084 * PTHRESH=32 descriptors (half the internal cache) 17946621Sbt150084 * HTHRESH=0 descriptors (to minimize latency on fetch) 17956621Sbt150084 * WTHRESH defaults to 1 (writeback each descriptor) 17966621Sbt150084 */ 17976621Sbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->index)); 17986621Sbt150084 reg_val |= IXGBE_RXDCTL_ENABLE; /* enable queue */ 17999353SSamuel.Tu@Sun.COM 18009353SSamuel.Tu@Sun.COM /* Not a valid value for 82599 */ 18019353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 18029353SSamuel.Tu@Sun.COM reg_val |= 0x0020; /* pthresh */ 18039353SSamuel.Tu@Sun.COM } 18046621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->index), reg_val); 18056621Sbt150084 18069353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 18079353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 18089353SSamuel.Tu@Sun.COM reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS); 18099353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); 18109353SSamuel.Tu@Sun.COM } 18119353SSamuel.Tu@Sun.COM 18126621Sbt150084 /* 18136621Sbt150084 * Setup the Split and Replication Receive Control Register. 18146621Sbt150084 * Set the rx buffer size and the advanced descriptor type. 18156621Sbt150084 */ 18166621Sbt150084 reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) | 18176621Sbt150084 IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 18189353SSamuel.Tu@Sun.COM reg_val |= IXGBE_SRRCTL_DROP_EN; 18196621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->index), reg_val); 18206621Sbt150084 } 18216621Sbt150084 18226621Sbt150084 static void 18236621Sbt150084 ixgbe_setup_rx(ixgbe_t *ixgbe) 18246621Sbt150084 { 18256621Sbt150084 ixgbe_rx_ring_t *rx_ring; 18266621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 18278275SEric Cheng ixgbe_rx_group_t *rx_group; 18286621Sbt150084 uint32_t reg_val; 18298275SEric Cheng uint32_t ring_mapping; 18306621Sbt150084 int i; 18316621Sbt150084 18329353SSamuel.Tu@Sun.COM /* PSRTYPE must be configured for 82599 */ 18339353SSamuel.Tu@Sun.COM reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | 18349353SSamuel.Tu@Sun.COM IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR; 18359353SSamuel.Tu@Sun.COM #define IXGBE_PSRTYPE_L2_PKT 0x00001000 18369353SSamuel.Tu@Sun.COM reg_val |= IXGBE_PSRTYPE_L2_PKT; 18379353SSamuel.Tu@Sun.COM reg_val |= 0xE0000000; 18389353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val); 18399353SSamuel.Tu@Sun.COM 18406621Sbt150084 /* 18416621Sbt150084 * Set filter control in FCTRL to accept broadcast packets and do 18426621Sbt150084 * not pass pause frames to host. Flow control settings are already 18436621Sbt150084 * in this register, so preserve them. 18446621Sbt150084 */ 18456621Sbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL); 18466621Sbt150084 reg_val |= IXGBE_FCTRL_BAM; /* broadcast accept mode */ 18476621Sbt150084 reg_val |= IXGBE_FCTRL_DPF; /* discard pause frames */ 18486621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val); 18496621Sbt150084 18506621Sbt150084 /* 18516621Sbt150084 * Enable the receive unit. This must be done after filter 18526621Sbt150084 * control is set in FCTRL. 18536621Sbt150084 */ 18546621Sbt150084 reg_val = (IXGBE_RXCTRL_RXEN /* Enable Receive Unit */ 18556621Sbt150084 | IXGBE_RXCTRL_DMBYPS); /* descriptor monitor bypass */ 18566621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); 18576621Sbt150084 18586621Sbt150084 /* 18596621Sbt150084 * ixgbe_setup_rx_ring must be called after configuring RXCTRL 18606621Sbt150084 */ 18616621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 18626621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 18636621Sbt150084 ixgbe_setup_rx_ring(rx_ring); 18646621Sbt150084 } 18656621Sbt150084 18666621Sbt150084 /* 18678275SEric Cheng * Setup rx groups. 18688275SEric Cheng */ 18698275SEric Cheng for (i = 0; i < ixgbe->num_rx_groups; i++) { 18708275SEric Cheng rx_group = &ixgbe->rx_groups[i]; 18718275SEric Cheng rx_group->index = i; 18728275SEric Cheng rx_group->ixgbe = ixgbe; 18738275SEric Cheng } 18748275SEric Cheng 18758275SEric Cheng /* 18768275SEric Cheng * Setup the per-ring statistics mapping. 18778275SEric Cheng */ 18788275SEric Cheng ring_mapping = 0; 18798275SEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) { 18808275SEric Cheng ring_mapping |= (i & 0xF) << (8 * (i & 0x3)); 18818275SEric Cheng if ((i & 0x3) == 0x3) { 18828275SEric Cheng IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i >> 2), ring_mapping); 18838275SEric Cheng ring_mapping = 0; 18848275SEric Cheng } 18858275SEric Cheng } 18868275SEric Cheng if ((i & 0x3) != 0x3) 18878275SEric Cheng IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i >> 2), ring_mapping); 18888275SEric Cheng 18898275SEric Cheng /* 18909353SSamuel.Tu@Sun.COM * The Max Frame Size in MHADD/MAXFRS will be internally increased 18919353SSamuel.Tu@Sun.COM * by four bytes if the packet has a VLAN field, so includes MTU, 18929353SSamuel.Tu@Sun.COM * ethernet header and frame check sequence. 18939353SSamuel.Tu@Sun.COM * Register is MAXFRS in 82599. 18946621Sbt150084 */ 18956621Sbt150084 reg_val = (ixgbe->default_mtu + sizeof (struct ether_header) 18966621Sbt150084 + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT; 18976621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val); 18986621Sbt150084 18996621Sbt150084 /* 19006621Sbt150084 * Setup Jumbo Frame enable bit 19016621Sbt150084 */ 19026621Sbt150084 if (ixgbe->default_mtu > ETHERMTU) { 19036621Sbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); 19046621Sbt150084 reg_val |= IXGBE_HLREG0_JUMBOEN; 19056621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); 19066621Sbt150084 } 19076621Sbt150084 19086621Sbt150084 /* 19096621Sbt150084 * Hardware checksum settings 19106621Sbt150084 */ 19116621Sbt150084 if (ixgbe->rx_hcksum_enable) { 19126621Sbt150084 reg_val = IXGBE_RXCSUM_IPPCSE; /* IP checksum */ 19136621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val); 19146621Sbt150084 } 19156621Sbt150084 19166621Sbt150084 /* 19176621Sbt150084 * Setup RSS for multiple receive queues 19186621Sbt150084 */ 19196621Sbt150084 if (ixgbe->num_rx_rings > 1) 19206621Sbt150084 ixgbe_setup_rss(ixgbe); 19216621Sbt150084 } 19226621Sbt150084 19236621Sbt150084 static void 19246621Sbt150084 ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring) 19256621Sbt150084 { 19266621Sbt150084 ixgbe_t *ixgbe = tx_ring->ixgbe; 19276621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 19286621Sbt150084 uint32_t size; 19296621Sbt150084 uint32_t buf_low; 19306621Sbt150084 uint32_t buf_high; 19316621Sbt150084 uint32_t reg_val; 19326621Sbt150084 19336621Sbt150084 ASSERT(mutex_owned(&tx_ring->tx_lock)); 19346621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 19356621Sbt150084 19366621Sbt150084 /* 19376621Sbt150084 * Initialize the length register 19386621Sbt150084 */ 19396621Sbt150084 size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc); 19406621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size); 19416621Sbt150084 19426621Sbt150084 /* 19436621Sbt150084 * Initialize the base address registers 19446621Sbt150084 */ 19456621Sbt150084 buf_low = (uint32_t)tx_ring->tbd_area.dma_address; 19466621Sbt150084 buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32); 19476621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low); 19486621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high); 19496621Sbt150084 19506621Sbt150084 /* 19516621Sbt150084 * Setup head & tail pointers 19526621Sbt150084 */ 19536621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0); 19546621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0); 19556621Sbt150084 19566621Sbt150084 /* 19576621Sbt150084 * Setup head write-back 19586621Sbt150084 */ 19596621Sbt150084 if (ixgbe->tx_head_wb_enable) { 19606621Sbt150084 /* 19616621Sbt150084 * The memory of the head write-back is allocated using 19626621Sbt150084 * the extra tbd beyond the tail of the tbd ring. 19636621Sbt150084 */ 19646621Sbt150084 tx_ring->tbd_head_wb = (uint32_t *) 19656621Sbt150084 ((uintptr_t)tx_ring->tbd_area.address + size); 19666621Sbt150084 *tx_ring->tbd_head_wb = 0; 19676621Sbt150084 19686621Sbt150084 buf_low = (uint32_t) 19696621Sbt150084 (tx_ring->tbd_area.dma_address + size); 19706621Sbt150084 buf_high = (uint32_t) 19716621Sbt150084 ((tx_ring->tbd_area.dma_address + size) >> 32); 19726621Sbt150084 19736621Sbt150084 /* Set the head write-back enable bit */ 19746621Sbt150084 buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE; 19756621Sbt150084 19766621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low); 19776621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high); 19786621Sbt150084 19796621Sbt150084 /* 19806621Sbt150084 * Turn off relaxed ordering for head write back or it will 19816621Sbt150084 * cause problems with the tx recycling 19826621Sbt150084 */ 19836621Sbt150084 reg_val = IXGBE_READ_REG(hw, 19846621Sbt150084 IXGBE_DCA_TXCTRL(tx_ring->index)); 19856621Sbt150084 reg_val &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; 19866621Sbt150084 IXGBE_WRITE_REG(hw, 19876621Sbt150084 IXGBE_DCA_TXCTRL(tx_ring->index), reg_val); 19886621Sbt150084 } else { 19896621Sbt150084 tx_ring->tbd_head_wb = NULL; 19906621Sbt150084 } 19916621Sbt150084 19926621Sbt150084 tx_ring->tbd_head = 0; 19936621Sbt150084 tx_ring->tbd_tail = 0; 19946621Sbt150084 tx_ring->tbd_free = tx_ring->ring_size; 19956621Sbt150084 199610376SChenlu.Chen@Sun.COM if (ixgbe->tx_ring_init == B_TRUE) { 19976621Sbt150084 tx_ring->tcb_head = 0; 19986621Sbt150084 tx_ring->tcb_tail = 0; 19996621Sbt150084 tx_ring->tcb_free = tx_ring->free_list_size; 20006621Sbt150084 } 20016621Sbt150084 20026621Sbt150084 /* 20037245Sgg161487 * Initialize the s/w context structure 20046621Sbt150084 */ 20057245Sgg161487 bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t)); 20066621Sbt150084 } 20076621Sbt150084 20086621Sbt150084 static void 20096621Sbt150084 ixgbe_setup_tx(ixgbe_t *ixgbe) 20106621Sbt150084 { 20117167Sgg161487 struct ixgbe_hw *hw = &ixgbe->hw; 20126621Sbt150084 ixgbe_tx_ring_t *tx_ring; 20137167Sgg161487 uint32_t reg_val; 20148275SEric Cheng uint32_t ring_mapping; 20156621Sbt150084 int i; 20166621Sbt150084 20176621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 20186621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 20196621Sbt150084 ixgbe_setup_tx_ring(tx_ring); 20206621Sbt150084 } 20217167Sgg161487 20227167Sgg161487 /* 20238275SEric Cheng * Setup the per-ring statistics mapping. 20248275SEric Cheng */ 20258275SEric Cheng ring_mapping = 0; 20268275SEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) { 20278275SEric Cheng ring_mapping |= (i & 0xF) << (8 * (i & 0x3)); 20288275SEric Cheng if ((i & 0x3) == 0x3) { 20299353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 20309353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), 20319353SSamuel.Tu@Sun.COM ring_mapping); 20329353SSamuel.Tu@Sun.COM } else { 20339353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), 20349353SSamuel.Tu@Sun.COM ring_mapping); 20359353SSamuel.Tu@Sun.COM } 20368275SEric Cheng ring_mapping = 0; 20378275SEric Cheng } 20388275SEric Cheng } 20398275SEric Cheng if ((i & 0x3) != 0x3) 20409353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 20419353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping); 20429353SSamuel.Tu@Sun.COM } else { 20439353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping); 20449353SSamuel.Tu@Sun.COM } 20458275SEric Cheng 20468275SEric Cheng /* 20477167Sgg161487 * Enable CRC appending and TX padding (for short tx frames) 20487167Sgg161487 */ 20497167Sgg161487 reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); 20507167Sgg161487 reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN; 20517167Sgg161487 IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); 20529353SSamuel.Tu@Sun.COM 20539353SSamuel.Tu@Sun.COM /* 20549353SSamuel.Tu@Sun.COM * enable DMA for 82599 parts 20559353SSamuel.Tu@Sun.COM */ 20569353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 20579353SSamuel.Tu@Sun.COM /* DMATXCTL.TE must be set after all Tx config is complete */ 20589353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 20599353SSamuel.Tu@Sun.COM reg_val |= IXGBE_DMATXCTL_TE; 20609353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val); 20619353SSamuel.Tu@Sun.COM } 20629353SSamuel.Tu@Sun.COM 20639353SSamuel.Tu@Sun.COM /* 20649353SSamuel.Tu@Sun.COM * Enabling tx queues .. 20659353SSamuel.Tu@Sun.COM * For 82599 must be done after DMATXCTL.TE is set 20669353SSamuel.Tu@Sun.COM */ 20679353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 20689353SSamuel.Tu@Sun.COM tx_ring = &ixgbe->tx_rings[i]; 20699353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index)); 20709353SSamuel.Tu@Sun.COM reg_val |= IXGBE_TXDCTL_ENABLE; 20719353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val); 20729353SSamuel.Tu@Sun.COM } 20736621Sbt150084 } 20746621Sbt150084 20756621Sbt150084 /* 20766621Sbt150084 * ixgbe_setup_rss - Setup receive-side scaling feature. 20776621Sbt150084 */ 20786621Sbt150084 static void 20796621Sbt150084 ixgbe_setup_rss(ixgbe_t *ixgbe) 20806621Sbt150084 { 20816621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 20827167Sgg161487 uint32_t i, mrqc, rxcsum; 20836621Sbt150084 uint32_t random; 20846621Sbt150084 uint32_t reta; 20856621Sbt150084 20866621Sbt150084 /* 20876621Sbt150084 * Fill out redirection table 20886621Sbt150084 */ 20896621Sbt150084 reta = 0; 20906621Sbt150084 for (i = 0; i < 128; i++) { 20917167Sgg161487 reta = (reta << 8) | (i % ixgbe->num_rx_rings); 20927167Sgg161487 if ((i & 3) == 3) 20936621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 20946621Sbt150084 } 20956621Sbt150084 20966621Sbt150084 /* 20976621Sbt150084 * Fill out hash function seeds with a random constant 20986621Sbt150084 */ 20996621Sbt150084 for (i = 0; i < 10; i++) { 21006621Sbt150084 (void) random_get_pseudo_bytes((uint8_t *)&random, 21016621Sbt150084 sizeof (uint32_t)); 21026621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); 21036621Sbt150084 } 21046621Sbt150084 21056621Sbt150084 /* 21067167Sgg161487 * Enable RSS & perform hash on these packet types 21076621Sbt150084 */ 21086621Sbt150084 mrqc = IXGBE_MRQC_RSSEN | 21096621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4 | 21106621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 21116621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 21126621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 21136621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX | 21146621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6 | 21156621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 21166621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 21176621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 21186621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 21196621Sbt150084 21206621Sbt150084 /* 21216621Sbt150084 * Disable Packet Checksum to enable RSS for multiple receive queues. 21226621Sbt150084 * It is an adapter hardware limitation that Packet Checksum is 21236621Sbt150084 * mutually exclusive with RSS. 21246621Sbt150084 */ 21256621Sbt150084 rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 21266621Sbt150084 rxcsum |= IXGBE_RXCSUM_PCSD; 21276621Sbt150084 rxcsum &= ~IXGBE_RXCSUM_IPPCSE; 21286621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 21296621Sbt150084 } 21306621Sbt150084 21316621Sbt150084 /* 21326621Sbt150084 * ixgbe_init_unicst - Initialize the unicast addresses. 21336621Sbt150084 */ 21346621Sbt150084 static void 21356621Sbt150084 ixgbe_init_unicst(ixgbe_t *ixgbe) 21366621Sbt150084 { 21376621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 21388275SEric Cheng uint8_t *mac_addr; 21396621Sbt150084 int slot; 21406621Sbt150084 /* 21416621Sbt150084 * Here we should consider two situations: 21426621Sbt150084 * 21438275SEric Cheng * 1. Chipset is initialized at the first time, 21448275SEric Cheng * Clear all the multiple unicast addresses. 21456621Sbt150084 * 21466621Sbt150084 * 2. Chipset is reset 21476621Sbt150084 * Recover the multiple unicast addresses from the 21486621Sbt150084 * software data structure to the RAR registers. 21496621Sbt150084 */ 21506621Sbt150084 if (!ixgbe->unicst_init) { 21516621Sbt150084 /* 21526621Sbt150084 * Initialize the multiple unicast addresses 21536621Sbt150084 */ 21546621Sbt150084 ixgbe->unicst_total = MAX_NUM_UNICAST_ADDRESSES; 21558275SEric Cheng ixgbe->unicst_avail = ixgbe->unicst_total; 21568275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 21578275SEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr; 21588275SEric Cheng bzero(mac_addr, ETHERADDRL); 21598275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, NULL, NULL); 21606621Sbt150084 ixgbe->unicst_addr[slot].mac.set = 0; 21618275SEric Cheng } 21626621Sbt150084 ixgbe->unicst_init = B_TRUE; 21636621Sbt150084 } else { 21646621Sbt150084 /* Re-configure the RAR registers */ 21658275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 21668275SEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr; 21678275SEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 1) { 21688275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, 21698275SEric Cheng NULL, IXGBE_RAH_AV); 21708275SEric Cheng } else { 21718275SEric Cheng bzero(mac_addr, ETHERADDRL); 21728275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, 21738275SEric Cheng NULL, NULL); 21748275SEric Cheng } 21758275SEric Cheng } 21766621Sbt150084 } 21776621Sbt150084 } 21788275SEric Cheng 21796621Sbt150084 /* 21806621Sbt150084 * ixgbe_unicst_set - Set the unicast address to the specified slot. 21816621Sbt150084 */ 21826621Sbt150084 int 21836621Sbt150084 ixgbe_unicst_set(ixgbe_t *ixgbe, const uint8_t *mac_addr, 21848275SEric Cheng int slot) 21856621Sbt150084 { 21866621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 21876621Sbt150084 21886621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 21896621Sbt150084 21906621Sbt150084 /* 21916621Sbt150084 * Save the unicast address in the software data structure 21926621Sbt150084 */ 21936621Sbt150084 bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL); 21946621Sbt150084 21956621Sbt150084 /* 21966621Sbt150084 * Set the unicast address to the RAR register 21976621Sbt150084 */ 21988275SEric Cheng (void) ixgbe_set_rar(hw, slot, (uint8_t *)mac_addr, NULL, IXGBE_RAH_AV); 21996621Sbt150084 22006621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 22016621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 22026621Sbt150084 return (EIO); 22036621Sbt150084 } 22046621Sbt150084 22056621Sbt150084 return (0); 22066621Sbt150084 } 22076621Sbt150084 22086621Sbt150084 /* 22098275SEric Cheng * ixgbe_unicst_find - Find the slot for the specified unicast address 22108275SEric Cheng */ 22118275SEric Cheng int 22128275SEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr) 22138275SEric Cheng { 22148275SEric Cheng int slot; 22158275SEric Cheng 22168275SEric Cheng ASSERT(mutex_owned(&ixgbe->gen_lock)); 22178275SEric Cheng 22188275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 22198275SEric Cheng if (bcmp(ixgbe->unicst_addr[slot].mac.addr, 22208275SEric Cheng mac_addr, ETHERADDRL) == 0) 22218275SEric Cheng return (slot); 22228275SEric Cheng } 22238275SEric Cheng 22248275SEric Cheng return (-1); 22258275SEric Cheng } 22268275SEric Cheng 22278275SEric Cheng /* 22286621Sbt150084 * ixgbe_multicst_add - Add a multicst address. 22296621Sbt150084 */ 22306621Sbt150084 int 22316621Sbt150084 ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr) 22326621Sbt150084 { 22336621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 22346621Sbt150084 22356621Sbt150084 if ((multiaddr[0] & 01) == 0) { 22366621Sbt150084 return (EINVAL); 22376621Sbt150084 } 22386621Sbt150084 22396621Sbt150084 if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) { 22406621Sbt150084 return (ENOENT); 22416621Sbt150084 } 22426621Sbt150084 22436621Sbt150084 bcopy(multiaddr, 22446621Sbt150084 &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL); 22456621Sbt150084 ixgbe->mcast_count++; 22466621Sbt150084 22476621Sbt150084 /* 22486621Sbt150084 * Update the multicast table in the hardware 22496621Sbt150084 */ 22506621Sbt150084 ixgbe_setup_multicst(ixgbe); 22516621Sbt150084 22526621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 22536621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 22546621Sbt150084 return (EIO); 22556621Sbt150084 } 22566621Sbt150084 22576621Sbt150084 return (0); 22586621Sbt150084 } 22596621Sbt150084 22606621Sbt150084 /* 22616621Sbt150084 * ixgbe_multicst_remove - Remove a multicst address. 22626621Sbt150084 */ 22636621Sbt150084 int 22646621Sbt150084 ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr) 22656621Sbt150084 { 22666621Sbt150084 int i; 22676621Sbt150084 22686621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 22696621Sbt150084 22706621Sbt150084 for (i = 0; i < ixgbe->mcast_count; i++) { 22716621Sbt150084 if (bcmp(multiaddr, &ixgbe->mcast_table[i], 22726621Sbt150084 ETHERADDRL) == 0) { 22736621Sbt150084 for (i++; i < ixgbe->mcast_count; i++) { 22746621Sbt150084 ixgbe->mcast_table[i - 1] = 22756621Sbt150084 ixgbe->mcast_table[i]; 22766621Sbt150084 } 22776621Sbt150084 ixgbe->mcast_count--; 22786621Sbt150084 break; 22796621Sbt150084 } 22806621Sbt150084 } 22816621Sbt150084 22826621Sbt150084 /* 22836621Sbt150084 * Update the multicast table in the hardware 22846621Sbt150084 */ 22856621Sbt150084 ixgbe_setup_multicst(ixgbe); 22866621Sbt150084 22876621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 22886621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 22896621Sbt150084 return (EIO); 22906621Sbt150084 } 22916621Sbt150084 22926621Sbt150084 return (0); 22936621Sbt150084 } 22946621Sbt150084 22956621Sbt150084 /* 22966621Sbt150084 * ixgbe_setup_multicast - Setup multicast data structures. 22976621Sbt150084 * 22986621Sbt150084 * This routine initializes all of the multicast related structures 22996621Sbt150084 * and save them in the hardware registers. 23006621Sbt150084 */ 23016621Sbt150084 static void 23026621Sbt150084 ixgbe_setup_multicst(ixgbe_t *ixgbe) 23036621Sbt150084 { 23046621Sbt150084 uint8_t *mc_addr_list; 23056621Sbt150084 uint32_t mc_addr_count; 23066621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 23076621Sbt150084 23086621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 23096621Sbt150084 23106621Sbt150084 ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES); 23116621Sbt150084 23126621Sbt150084 mc_addr_list = (uint8_t *)ixgbe->mcast_table; 23136621Sbt150084 mc_addr_count = ixgbe->mcast_count; 23146621Sbt150084 23156621Sbt150084 /* 23166621Sbt150084 * Update the multicast addresses to the MTA registers 23176621Sbt150084 */ 23186621Sbt150084 (void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count, 23196621Sbt150084 ixgbe_mc_table_itr); 23206621Sbt150084 } 23216621Sbt150084 23226621Sbt150084 /* 23236621Sbt150084 * ixgbe_get_conf - Get driver configurations set in driver.conf. 23246621Sbt150084 * 23256621Sbt150084 * This routine gets user-configured values out of the configuration 23266621Sbt150084 * file ixgbe.conf. 23276621Sbt150084 * 23286621Sbt150084 * For each configurable value, there is a minimum, a maximum, and a 23296621Sbt150084 * default. 23306621Sbt150084 * If user does not configure a value, use the default. 23316621Sbt150084 * If user configures below the minimum, use the minumum. 23326621Sbt150084 * If user configures above the maximum, use the maxumum. 23336621Sbt150084 */ 23346621Sbt150084 static void 23356621Sbt150084 ixgbe_get_conf(ixgbe_t *ixgbe) 23366621Sbt150084 { 23376621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 23386621Sbt150084 uint32_t flow_control; 23396621Sbt150084 23406621Sbt150084 /* 23416621Sbt150084 * ixgbe driver supports the following user configurations: 23426621Sbt150084 * 23436621Sbt150084 * Jumbo frame configuration: 23446621Sbt150084 * default_mtu 23456621Sbt150084 * 23466621Sbt150084 * Ethernet flow control configuration: 23476621Sbt150084 * flow_control 23486621Sbt150084 * 23496621Sbt150084 * Multiple rings configurations: 23506621Sbt150084 * tx_queue_number 23516621Sbt150084 * tx_ring_size 23526621Sbt150084 * rx_queue_number 23536621Sbt150084 * rx_ring_size 23546621Sbt150084 * 23556621Sbt150084 * Call ixgbe_get_prop() to get the value for a specific 23566621Sbt150084 * configuration parameter. 23576621Sbt150084 */ 23586621Sbt150084 23596621Sbt150084 /* 23606621Sbt150084 * Jumbo frame configuration - max_frame_size controls host buffer 23616621Sbt150084 * allocation, so includes MTU, ethernet header, vlan tag and 23626621Sbt150084 * frame check sequence. 23636621Sbt150084 */ 23646621Sbt150084 ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU, 236511150SZhen.W@Sun.COM MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU); 23666621Sbt150084 23676621Sbt150084 ixgbe->max_frame_size = ixgbe->default_mtu + 23686621Sbt150084 sizeof (struct ether_vlan_header) + ETHERFCSL; 23696621Sbt150084 23706621Sbt150084 /* 23716621Sbt150084 * Ethernet flow control configuration 23726621Sbt150084 */ 23736621Sbt150084 flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL, 23748275SEric Cheng ixgbe_fc_none, 3, ixgbe_fc_none); 23756621Sbt150084 if (flow_control == 3) 23766621Sbt150084 flow_control = ixgbe_fc_default; 23776621Sbt150084 23789353SSamuel.Tu@Sun.COM /* 23799353SSamuel.Tu@Sun.COM * fc.requested mode is what the user requests. After autoneg, 23809353SSamuel.Tu@Sun.COM * fc.current_mode will be the flow_control mode that was negotiated. 23819353SSamuel.Tu@Sun.COM */ 23829353SSamuel.Tu@Sun.COM hw->fc.requested_mode = flow_control; 23836621Sbt150084 23846621Sbt150084 /* 23856621Sbt150084 * Multiple rings configurations 23866621Sbt150084 */ 23876621Sbt150084 ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM, 23888490SPaul.Guo@Sun.COM ixgbe->capab->min_tx_que_num, 23898490SPaul.Guo@Sun.COM ixgbe->capab->max_tx_que_num, 23908490SPaul.Guo@Sun.COM ixgbe->capab->def_tx_que_num); 23916621Sbt150084 ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE, 23926621Sbt150084 MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE); 23936621Sbt150084 23946621Sbt150084 ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM, 23958490SPaul.Guo@Sun.COM ixgbe->capab->min_rx_que_num, 23968490SPaul.Guo@Sun.COM ixgbe->capab->max_rx_que_num, 23978490SPaul.Guo@Sun.COM ixgbe->capab->def_rx_que_num); 23986621Sbt150084 ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE, 23996621Sbt150084 MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE); 24006621Sbt150084 24016621Sbt150084 /* 24028275SEric Cheng * Multiple groups configuration 24038275SEric Cheng */ 24048275SEric Cheng ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM, 24058275SEric Cheng MIN_RX_GROUP_NUM, MAX_RX_GROUP_NUM, DEFAULT_RX_GROUP_NUM); 24068275SEric Cheng 24078275SEric Cheng ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE, 24088275SEric Cheng 0, 1, DEFAULT_MR_ENABLE); 24098275SEric Cheng 24108275SEric Cheng if (ixgbe->mr_enable == B_FALSE) { 24118275SEric Cheng ixgbe->num_tx_rings = 1; 24128275SEric Cheng ixgbe->num_rx_rings = 1; 24138275SEric Cheng ixgbe->num_rx_groups = 1; 24148275SEric Cheng } 24158275SEric Cheng 24168275SEric Cheng /* 24176621Sbt150084 * Tunable used to force an interrupt type. The only use is 24186621Sbt150084 * for testing of the lesser interrupt types. 24196621Sbt150084 * 0 = don't force interrupt type 24208275SEric Cheng * 1 = force interrupt type MSI-X 24216621Sbt150084 * 2 = force interrupt type MSI 24226621Sbt150084 * 3 = force interrupt type Legacy 24236621Sbt150084 */ 24246621Sbt150084 ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE, 24256621Sbt150084 IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE); 24266621Sbt150084 24276621Sbt150084 ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE, 24287167Sgg161487 0, 1, DEFAULT_TX_HCKSUM_ENABLE); 24296621Sbt150084 ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE, 24307167Sgg161487 0, 1, DEFAULT_RX_HCKSUM_ENABLE); 24316621Sbt150084 ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE, 24327167Sgg161487 0, 1, DEFAULT_LSO_ENABLE); 24336621Sbt150084 ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE, 24347167Sgg161487 0, 1, DEFAULT_TX_HEAD_WB_ENABLE); 24357167Sgg161487 24369353SSamuel.Tu@Sun.COM /* Head Write Back not recommended for 82599 */ 24379353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 24389353SSamuel.Tu@Sun.COM ixgbe->tx_head_wb_enable = B_FALSE; 24399353SSamuel.Tu@Sun.COM } 24409353SSamuel.Tu@Sun.COM 24417167Sgg161487 /* 24427167Sgg161487 * ixgbe LSO needs the tx h/w checksum support. 24437167Sgg161487 * LSO will be disabled if tx h/w checksum is not 24447167Sgg161487 * enabled. 24457167Sgg161487 */ 24467167Sgg161487 if (ixgbe->tx_hcksum_enable == B_FALSE) { 24477167Sgg161487 ixgbe->lso_enable = B_FALSE; 24487167Sgg161487 } 24496621Sbt150084 24506621Sbt150084 ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD, 24516621Sbt150084 MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD, 24526621Sbt150084 DEFAULT_TX_COPY_THRESHOLD); 24536621Sbt150084 ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe, 24546621Sbt150084 PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD, 24556621Sbt150084 MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD); 24566621Sbt150084 ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe, 24576621Sbt150084 PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD, 24586621Sbt150084 MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD); 24596621Sbt150084 ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe, 24606621Sbt150084 PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD, 24616621Sbt150084 MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD); 24626621Sbt150084 24636621Sbt150084 ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD, 24646621Sbt150084 MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD, 24656621Sbt150084 DEFAULT_RX_COPY_THRESHOLD); 24666621Sbt150084 ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR, 24676621Sbt150084 MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR, 24686621Sbt150084 DEFAULT_RX_LIMIT_PER_INTR); 24696621Sbt150084 247010376SChenlu.Chen@Sun.COM ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING, 247110376SChenlu.Chen@Sun.COM ixgbe->capab->min_intr_throttle, 247210376SChenlu.Chen@Sun.COM ixgbe->capab->max_intr_throttle, 247310376SChenlu.Chen@Sun.COM ixgbe->capab->def_intr_throttle); 24749353SSamuel.Tu@Sun.COM /* 247510376SChenlu.Chen@Sun.COM * 82599 requires the interupt throttling rate is 247610376SChenlu.Chen@Sun.COM * a multiple of 8. This is enforced by the register 247710376SChenlu.Chen@Sun.COM * definiton. 24789353SSamuel.Tu@Sun.COM */ 247910376SChenlu.Chen@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) 248010376SChenlu.Chen@Sun.COM ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8; 248110376SChenlu.Chen@Sun.COM } 248210376SChenlu.Chen@Sun.COM 248310376SChenlu.Chen@Sun.COM static void 248410376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe_t *ixgbe) 248510376SChenlu.Chen@Sun.COM { 248610376SChenlu.Chen@Sun.COM ixgbe->param_en_10000fdx_cap = 1; 248710376SChenlu.Chen@Sun.COM ixgbe->param_en_1000fdx_cap = 1; 248810376SChenlu.Chen@Sun.COM ixgbe->param_en_100fdx_cap = 1; 248910376SChenlu.Chen@Sun.COM ixgbe->param_adv_10000fdx_cap = 1; 249010376SChenlu.Chen@Sun.COM ixgbe->param_adv_1000fdx_cap = 1; 249110376SChenlu.Chen@Sun.COM ixgbe->param_adv_100fdx_cap = 1; 249210376SChenlu.Chen@Sun.COM 249310376SChenlu.Chen@Sun.COM ixgbe->param_pause_cap = 1; 249410376SChenlu.Chen@Sun.COM ixgbe->param_asym_pause_cap = 1; 249510376SChenlu.Chen@Sun.COM ixgbe->param_rem_fault = 0; 249610376SChenlu.Chen@Sun.COM 249710376SChenlu.Chen@Sun.COM ixgbe->param_adv_autoneg_cap = 1; 249810376SChenlu.Chen@Sun.COM ixgbe->param_adv_pause_cap = 1; 249910376SChenlu.Chen@Sun.COM ixgbe->param_adv_asym_pause_cap = 1; 250010376SChenlu.Chen@Sun.COM ixgbe->param_adv_rem_fault = 0; 250110376SChenlu.Chen@Sun.COM 250210376SChenlu.Chen@Sun.COM ixgbe->param_lp_10000fdx_cap = 0; 250310376SChenlu.Chen@Sun.COM ixgbe->param_lp_1000fdx_cap = 0; 250410376SChenlu.Chen@Sun.COM ixgbe->param_lp_100fdx_cap = 0; 250510376SChenlu.Chen@Sun.COM ixgbe->param_lp_autoneg_cap = 0; 250610376SChenlu.Chen@Sun.COM ixgbe->param_lp_pause_cap = 0; 250710376SChenlu.Chen@Sun.COM ixgbe->param_lp_asym_pause_cap = 0; 250810376SChenlu.Chen@Sun.COM ixgbe->param_lp_rem_fault = 0; 25096621Sbt150084 } 25106621Sbt150084 25116621Sbt150084 /* 25126621Sbt150084 * ixgbe_get_prop - Get a property value out of the configuration file 25136621Sbt150084 * ixgbe.conf. 25146621Sbt150084 * 25156621Sbt150084 * Caller provides the name of the property, a default value, a minimum 25166621Sbt150084 * value, and a maximum value. 25176621Sbt150084 * 25186621Sbt150084 * Return configured value of the property, with default, minimum and 25196621Sbt150084 * maximum properly applied. 25206621Sbt150084 */ 25216621Sbt150084 static int 25226621Sbt150084 ixgbe_get_prop(ixgbe_t *ixgbe, 25236621Sbt150084 char *propname, /* name of the property */ 25246621Sbt150084 int minval, /* minimum acceptable value */ 25256621Sbt150084 int maxval, /* maximim acceptable value */ 25266621Sbt150084 int defval) /* default value */ 25276621Sbt150084 { 25286621Sbt150084 int value; 25296621Sbt150084 25306621Sbt150084 /* 25316621Sbt150084 * Call ddi_prop_get_int() to read the conf settings 25326621Sbt150084 */ 25336621Sbt150084 value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip, 25346621Sbt150084 DDI_PROP_DONTPASS, propname, defval); 25356621Sbt150084 if (value > maxval) 25366621Sbt150084 value = maxval; 25376621Sbt150084 25386621Sbt150084 if (value < minval) 25396621Sbt150084 value = minval; 25406621Sbt150084 25416621Sbt150084 return (value); 25426621Sbt150084 } 25436621Sbt150084 25446621Sbt150084 /* 25456621Sbt150084 * ixgbe_driver_setup_link - Using the link properties to setup the link. 25466621Sbt150084 */ 25476621Sbt150084 int 25486621Sbt150084 ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw) 25496621Sbt150084 { 255010998SChenlu.Chen@Sun.COM u32 autoneg_advertised = 0; 255110998SChenlu.Chen@Sun.COM 255210998SChenlu.Chen@Sun.COM /* 255310998SChenlu.Chen@Sun.COM * No half duplex support with 10Gb parts 255410998SChenlu.Chen@Sun.COM */ 255510998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_10000fdx_cap == 1) 255610998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; 255710998SChenlu.Chen@Sun.COM 255810998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_1000fdx_cap == 1) 255910998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; 256010998SChenlu.Chen@Sun.COM 256110998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_100fdx_cap == 1) 256210998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; 256310998SChenlu.Chen@Sun.COM 256410998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_autoneg_cap == 1 && autoneg_advertised == 0) { 256510998SChenlu.Chen@Sun.COM ixgbe_notice(ixgbe, "Invalid link settings. Setup link " 256610998SChenlu.Chen@Sun.COM "to autonegotiation with full link capabilities."); 256710998SChenlu.Chen@Sun.COM 256810998SChenlu.Chen@Sun.COM autoneg_advertised = IXGBE_LINK_SPEED_10GB_FULL | 256910998SChenlu.Chen@Sun.COM IXGBE_LINK_SPEED_1GB_FULL | 257010998SChenlu.Chen@Sun.COM IXGBE_LINK_SPEED_100_FULL; 25716621Sbt150084 } 25726621Sbt150084 25736621Sbt150084 if (setup_hw) { 257410998SChenlu.Chen@Sun.COM if (ixgbe_setup_link(&ixgbe->hw, autoneg_advertised, 257510998SChenlu.Chen@Sun.COM ixgbe->param_adv_autoneg_cap, B_TRUE) != IXGBE_SUCCESS) { 25769353SSamuel.Tu@Sun.COM ixgbe_notice(ixgbe, "Setup link failed on this " 25779353SSamuel.Tu@Sun.COM "device."); 25786621Sbt150084 return (IXGBE_FAILURE); 25799353SSamuel.Tu@Sun.COM } 25806621Sbt150084 } 25816621Sbt150084 25826621Sbt150084 return (IXGBE_SUCCESS); 25836621Sbt150084 } 25846621Sbt150084 25856621Sbt150084 /* 2586*11233SPaul.Guo@Sun.COM * ixgbe_driver_link_check - Link status processing. 2587*11233SPaul.Guo@Sun.COM * 2588*11233SPaul.Guo@Sun.COM * This function can be called in both kernel context and interrupt context 25896621Sbt150084 */ 25908490SPaul.Guo@Sun.COM static void 2591*11233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe_t *ixgbe) 25926621Sbt150084 { 25936621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 25946621Sbt150084 ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN; 25956621Sbt150084 boolean_t link_up = B_FALSE; 25966621Sbt150084 boolean_t link_changed = B_FALSE; 25976621Sbt150084 2598*11233SPaul.Guo@Sun.COM ASSERT(mutex_owned(&ixgbe->gen_lock)); 2599*11233SPaul.Guo@Sun.COM 2600*11233SPaul.Guo@Sun.COM (void) ixgbe_check_link(hw, &speed, &link_up, false); 26016621Sbt150084 if (link_up) { 2602*11233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_TRUE; 2603*11233SPaul.Guo@Sun.COM 26049353SSamuel.Tu@Sun.COM /* Link is up, enable flow control settings */ 26059353SSamuel.Tu@Sun.COM (void) ixgbe_fc_enable(hw, 0); 26069353SSamuel.Tu@Sun.COM 26076621Sbt150084 /* 26086621Sbt150084 * The Link is up, check whether it was marked as down earlier 26096621Sbt150084 */ 26106621Sbt150084 if (ixgbe->link_state != LINK_STATE_UP) { 26116621Sbt150084 switch (speed) { 26129353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_10GB_FULL: 26139353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_10GB; 26149353SSamuel.Tu@Sun.COM break; 26159353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_1GB_FULL: 26169353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_1GB; 26179353SSamuel.Tu@Sun.COM break; 26189353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_100_FULL: 26199353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_100; 26206621Sbt150084 } 26216621Sbt150084 ixgbe->link_duplex = LINK_DUPLEX_FULL; 26226621Sbt150084 ixgbe->link_state = LINK_STATE_UP; 26236621Sbt150084 ixgbe->link_down_timeout = 0; 26246621Sbt150084 link_changed = B_TRUE; 26256621Sbt150084 } 26266621Sbt150084 } else { 2627*11233SPaul.Guo@Sun.COM if (ixgbe->link_check_complete == B_TRUE || 2628*11233SPaul.Guo@Sun.COM (ixgbe->link_check_complete == B_FALSE && 2629*11233SPaul.Guo@Sun.COM gethrtime() >= ixgbe->link_check_hrtime)) { 2630*11233SPaul.Guo@Sun.COM /* 2631*11233SPaul.Guo@Sun.COM * The link is really down 2632*11233SPaul.Guo@Sun.COM */ 2633*11233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_TRUE; 2634*11233SPaul.Guo@Sun.COM 2635*11233SPaul.Guo@Sun.COM if (ixgbe->link_state != LINK_STATE_DOWN) { 2636*11233SPaul.Guo@Sun.COM ixgbe->link_speed = 0; 2637*11233SPaul.Guo@Sun.COM ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN; 2638*11233SPaul.Guo@Sun.COM ixgbe->link_state = LINK_STATE_DOWN; 2639*11233SPaul.Guo@Sun.COM link_changed = B_TRUE; 2640*11233SPaul.Guo@Sun.COM } 2641*11233SPaul.Guo@Sun.COM 2642*11233SPaul.Guo@Sun.COM if (ixgbe->ixgbe_state & IXGBE_STARTED) { 2643*11233SPaul.Guo@Sun.COM if (ixgbe->link_down_timeout < 2644*11233SPaul.Guo@Sun.COM MAX_LINK_DOWN_TIMEOUT) { 2645*11233SPaul.Guo@Sun.COM ixgbe->link_down_timeout++; 2646*11233SPaul.Guo@Sun.COM } else if (ixgbe->link_down_timeout == 2647*11233SPaul.Guo@Sun.COM MAX_LINK_DOWN_TIMEOUT) { 2648*11233SPaul.Guo@Sun.COM ixgbe_tx_clean(ixgbe); 2649*11233SPaul.Guo@Sun.COM ixgbe->link_down_timeout++; 2650*11233SPaul.Guo@Sun.COM } 26516621Sbt150084 } 26526621Sbt150084 } 26536621Sbt150084 } 26546621Sbt150084 26558490SPaul.Guo@Sun.COM /* 26568490SPaul.Guo@Sun.COM * this is only reached after a link-status-change interrupt 26578490SPaul.Guo@Sun.COM * so always get new phy state 26588490SPaul.Guo@Sun.COM */ 26598490SPaul.Guo@Sun.COM ixgbe_get_hw_state(ixgbe); 26608490SPaul.Guo@Sun.COM 2661*11233SPaul.Guo@Sun.COM /* 2662*11233SPaul.Guo@Sun.COM * If we are in an interrupt context, need to re-enable the 2663*11233SPaul.Guo@Sun.COM * interrupt, which was automasked 2664*11233SPaul.Guo@Sun.COM */ 2665*11233SPaul.Guo@Sun.COM if (servicing_interrupt() != 0) { 2666*11233SPaul.Guo@Sun.COM ixgbe->eims |= IXGBE_EICR_LSC; 2667*11233SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 2668*11233SPaul.Guo@Sun.COM } 2669*11233SPaul.Guo@Sun.COM 26708490SPaul.Guo@Sun.COM if (link_changed) { 26718490SPaul.Guo@Sun.COM mac_link_update(ixgbe->mac_hdl, ixgbe->link_state); 26728490SPaul.Guo@Sun.COM } 26736621Sbt150084 } 26746621Sbt150084 26756621Sbt150084 /* 26769353SSamuel.Tu@Sun.COM * ixgbe_sfp_check - sfp module processing done in taskq only for 82599. 26779353SSamuel.Tu@Sun.COM */ 26789353SSamuel.Tu@Sun.COM static void 26799353SSamuel.Tu@Sun.COM ixgbe_sfp_check(void *arg) 26809353SSamuel.Tu@Sun.COM { 26819353SSamuel.Tu@Sun.COM ixgbe_t *ixgbe = (ixgbe_t *)arg; 26829353SSamuel.Tu@Sun.COM uint32_t eicr = ixgbe->eicr; 26839353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 26849353SSamuel.Tu@Sun.COM 2685*11233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 26869353SSamuel.Tu@Sun.COM if (eicr & IXGBE_EICR_GPI_SDP1) { 26879353SSamuel.Tu@Sun.COM /* clear the interrupt */ 26889353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); 26899353SSamuel.Tu@Sun.COM 26909353SSamuel.Tu@Sun.COM /* if link up, do multispeed fiber setup */ 269110998SChenlu.Chen@Sun.COM (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, 269210998SChenlu.Chen@Sun.COM B_TRUE, B_TRUE); 26939353SSamuel.Tu@Sun.COM ixgbe_driver_link_check(ixgbe); 26949353SSamuel.Tu@Sun.COM } else if (eicr & IXGBE_EICR_GPI_SDP2) { 26959353SSamuel.Tu@Sun.COM /* clear the interrupt */ 26969353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); 26979353SSamuel.Tu@Sun.COM 26989353SSamuel.Tu@Sun.COM /* if link up, do sfp module setup */ 26999353SSamuel.Tu@Sun.COM (void) hw->mac.ops.setup_sfp(hw); 27009353SSamuel.Tu@Sun.COM 27019353SSamuel.Tu@Sun.COM /* do multispeed fiber setup */ 270210998SChenlu.Chen@Sun.COM (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, 270310998SChenlu.Chen@Sun.COM B_TRUE, B_TRUE); 27049353SSamuel.Tu@Sun.COM ixgbe_driver_link_check(ixgbe); 27059353SSamuel.Tu@Sun.COM } 2706*11233SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 2707*11233SPaul.Guo@Sun.COM } 2708*11233SPaul.Guo@Sun.COM 2709*11233SPaul.Guo@Sun.COM /* 2710*11233SPaul.Guo@Sun.COM * ixgbe_link_timer - timer for link status detection 2711*11233SPaul.Guo@Sun.COM */ 2712*11233SPaul.Guo@Sun.COM static void 2713*11233SPaul.Guo@Sun.COM ixgbe_link_timer(void *arg) 2714*11233SPaul.Guo@Sun.COM { 2715*11233SPaul.Guo@Sun.COM ixgbe_t *ixgbe = (ixgbe_t *)arg; 2716*11233SPaul.Guo@Sun.COM 2717*11233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 2718*11233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe); 2719*11233SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 27209353SSamuel.Tu@Sun.COM } 27219353SSamuel.Tu@Sun.COM 27229353SSamuel.Tu@Sun.COM /* 27236621Sbt150084 * ixgbe_local_timer - Driver watchdog function. 27246621Sbt150084 * 2725*11233SPaul.Guo@Sun.COM * This function will handle the transmit stall check and other routines. 27266621Sbt150084 */ 27276621Sbt150084 static void 27286621Sbt150084 ixgbe_local_timer(void *arg) 27296621Sbt150084 { 27306621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg; 27316621Sbt150084 2732*11233SPaul.Guo@Sun.COM if (ixgbe->ixgbe_state & IXGBE_ERROR) { 27336621Sbt150084 ixgbe->reset_count++; 27346621Sbt150084 if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS) 27356621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED); 2736*11233SPaul.Guo@Sun.COM ixgbe_restart_watchdog_timer(ixgbe); 2737*11233SPaul.Guo@Sun.COM return; 27386621Sbt150084 } 27396621Sbt150084 2740*11233SPaul.Guo@Sun.COM if (ixgbe_stall_check(ixgbe)) { 2741*11233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL); 2742*11233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 2743*11233SPaul.Guo@Sun.COM 2744*11233SPaul.Guo@Sun.COM ixgbe->reset_count++; 2745*11233SPaul.Guo@Sun.COM if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS) 2746*11233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED); 2747*11233SPaul.Guo@Sun.COM ixgbe_restart_watchdog_timer(ixgbe); 2748*11233SPaul.Guo@Sun.COM } 27496621Sbt150084 } 27506621Sbt150084 27516621Sbt150084 /* 27526621Sbt150084 * ixgbe_stall_check - Check for transmit stall. 27536621Sbt150084 * 27546621Sbt150084 * This function checks if the adapter is stalled (in transmit). 27556621Sbt150084 * 27566621Sbt150084 * It is called each time the watchdog timeout is invoked. 27576621Sbt150084 * If the transmit descriptor reclaim continuously fails, 27586621Sbt150084 * the watchdog value will increment by 1. If the watchdog 27596621Sbt150084 * value exceeds the threshold, the ixgbe is assumed to 27606621Sbt150084 * have stalled and need to be reset. 27616621Sbt150084 */ 27626621Sbt150084 static boolean_t 27636621Sbt150084 ixgbe_stall_check(ixgbe_t *ixgbe) 27646621Sbt150084 { 27656621Sbt150084 ixgbe_tx_ring_t *tx_ring; 27666621Sbt150084 boolean_t result; 27676621Sbt150084 int i; 27686621Sbt150084 27696621Sbt150084 if (ixgbe->link_state != LINK_STATE_UP) 27706621Sbt150084 return (B_FALSE); 27716621Sbt150084 27726621Sbt150084 /* 27736621Sbt150084 * If any tx ring is stalled, we'll reset the chipset 27746621Sbt150084 */ 27756621Sbt150084 result = B_FALSE; 27766621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 27776621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 277810376SChenlu.Chen@Sun.COM if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) { 277910305SPaul.Guo@Sun.COM tx_ring->tx_recycle(tx_ring); 278010305SPaul.Guo@Sun.COM } 27816621Sbt150084 27826621Sbt150084 if (tx_ring->recycle_fail > 0) 27836621Sbt150084 tx_ring->stall_watchdog++; 27846621Sbt150084 else 27856621Sbt150084 tx_ring->stall_watchdog = 0; 27866621Sbt150084 27876621Sbt150084 if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) { 27886621Sbt150084 result = B_TRUE; 27896621Sbt150084 break; 27906621Sbt150084 } 27916621Sbt150084 } 27926621Sbt150084 27936621Sbt150084 if (result) { 27946621Sbt150084 tx_ring->stall_watchdog = 0; 27956621Sbt150084 tx_ring->recycle_fail = 0; 27966621Sbt150084 } 27976621Sbt150084 27986621Sbt150084 return (result); 27996621Sbt150084 } 28006621Sbt150084 28016621Sbt150084 28026621Sbt150084 /* 28036621Sbt150084 * is_valid_mac_addr - Check if the mac address is valid. 28046621Sbt150084 */ 28056621Sbt150084 static boolean_t 28066621Sbt150084 is_valid_mac_addr(uint8_t *mac_addr) 28076621Sbt150084 { 28086621Sbt150084 const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 }; 28096621Sbt150084 const uint8_t addr_test2[6] = 28106621Sbt150084 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 28116621Sbt150084 28126621Sbt150084 if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) || 28136621Sbt150084 !(bcmp(addr_test2, mac_addr, ETHERADDRL))) 28146621Sbt150084 return (B_FALSE); 28156621Sbt150084 28166621Sbt150084 return (B_TRUE); 28176621Sbt150084 } 28186621Sbt150084 28196621Sbt150084 static boolean_t 28206621Sbt150084 ixgbe_find_mac_address(ixgbe_t *ixgbe) 28216621Sbt150084 { 28226621Sbt150084 #ifdef __sparc 28236621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 28246621Sbt150084 uchar_t *bytes; 28256621Sbt150084 struct ether_addr sysaddr; 28266621Sbt150084 uint_t nelts; 28276621Sbt150084 int err; 28286621Sbt150084 boolean_t found = B_FALSE; 28296621Sbt150084 28306621Sbt150084 /* 28316621Sbt150084 * The "vendor's factory-set address" may already have 28326621Sbt150084 * been extracted from the chip, but if the property 28336621Sbt150084 * "local-mac-address" is set we use that instead. 28346621Sbt150084 * 28356621Sbt150084 * We check whether it looks like an array of 6 28366621Sbt150084 * bytes (which it should, if OBP set it). If we can't 28376621Sbt150084 * make sense of it this way, we'll ignore it. 28386621Sbt150084 */ 28396621Sbt150084 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 28406621Sbt150084 DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts); 28416621Sbt150084 if (err == DDI_PROP_SUCCESS) { 28426621Sbt150084 if (nelts == ETHERADDRL) { 28436621Sbt150084 while (nelts--) 28446621Sbt150084 hw->mac.addr[nelts] = bytes[nelts]; 28456621Sbt150084 found = B_TRUE; 28466621Sbt150084 } 28476621Sbt150084 ddi_prop_free(bytes); 28486621Sbt150084 } 28496621Sbt150084 28506621Sbt150084 /* 28516621Sbt150084 * Look up the OBP property "local-mac-address?". If the user has set 28526621Sbt150084 * 'local-mac-address? = false', use "the system address" instead. 28536621Sbt150084 */ 28546621Sbt150084 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0, 28556621Sbt150084 "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) { 28566621Sbt150084 if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) { 28576621Sbt150084 if (localetheraddr(NULL, &sysaddr) != 0) { 28586621Sbt150084 bcopy(&sysaddr, hw->mac.addr, ETHERADDRL); 28596621Sbt150084 found = B_TRUE; 28606621Sbt150084 } 28616621Sbt150084 } 28626621Sbt150084 ddi_prop_free(bytes); 28636621Sbt150084 } 28646621Sbt150084 28656621Sbt150084 /* 28666621Sbt150084 * Finally(!), if there's a valid "mac-address" property (created 28676621Sbt150084 * if we netbooted from this interface), we must use this instead 28686621Sbt150084 * of any of the above to ensure that the NFS/install server doesn't 28696621Sbt150084 * get confused by the address changing as Solaris takes over! 28706621Sbt150084 */ 28716621Sbt150084 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 28726621Sbt150084 DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts); 28736621Sbt150084 if (err == DDI_PROP_SUCCESS) { 28746621Sbt150084 if (nelts == ETHERADDRL) { 28756621Sbt150084 while (nelts--) 28766621Sbt150084 hw->mac.addr[nelts] = bytes[nelts]; 28776621Sbt150084 found = B_TRUE; 28786621Sbt150084 } 28796621Sbt150084 ddi_prop_free(bytes); 28806621Sbt150084 } 28816621Sbt150084 28826621Sbt150084 if (found) { 28836621Sbt150084 bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL); 28846621Sbt150084 return (B_TRUE); 28856621Sbt150084 } 28866621Sbt150084 #else 28876621Sbt150084 _NOTE(ARGUNUSED(ixgbe)); 28886621Sbt150084 #endif 28896621Sbt150084 28906621Sbt150084 return (B_TRUE); 28916621Sbt150084 } 28926621Sbt150084 28936621Sbt150084 #pragma inline(ixgbe_arm_watchdog_timer) 28946621Sbt150084 static void 28956621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe) 28966621Sbt150084 { 28976621Sbt150084 /* 28986621Sbt150084 * Fire a watchdog timer 28996621Sbt150084 */ 29006621Sbt150084 ixgbe->watchdog_tid = 29016621Sbt150084 timeout(ixgbe_local_timer, 29026621Sbt150084 (void *)ixgbe, 1 * drv_usectohz(1000000)); 29036621Sbt150084 29046621Sbt150084 } 29056621Sbt150084 29066621Sbt150084 /* 29076621Sbt150084 * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer. 29086621Sbt150084 */ 29096621Sbt150084 void 29106621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe) 29116621Sbt150084 { 29126621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 29136621Sbt150084 29146621Sbt150084 if (!ixgbe->watchdog_enable) { 29156621Sbt150084 ixgbe->watchdog_enable = B_TRUE; 29166621Sbt150084 ixgbe->watchdog_start = B_TRUE; 29176621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 29186621Sbt150084 } 29196621Sbt150084 29206621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 29216621Sbt150084 } 29226621Sbt150084 29236621Sbt150084 /* 29246621Sbt150084 * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer. 29256621Sbt150084 */ 29266621Sbt150084 void 29276621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe) 29286621Sbt150084 { 29296621Sbt150084 timeout_id_t tid; 29306621Sbt150084 29316621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 29326621Sbt150084 29336621Sbt150084 ixgbe->watchdog_enable = B_FALSE; 29346621Sbt150084 ixgbe->watchdog_start = B_FALSE; 29356621Sbt150084 tid = ixgbe->watchdog_tid; 29366621Sbt150084 ixgbe->watchdog_tid = 0; 29376621Sbt150084 29386621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 29396621Sbt150084 29406621Sbt150084 if (tid != 0) 29416621Sbt150084 (void) untimeout(tid); 29426621Sbt150084 } 29436621Sbt150084 29446621Sbt150084 /* 29456621Sbt150084 * ixgbe_start_watchdog_timer - Start the driver watchdog timer. 29466621Sbt150084 */ 29478490SPaul.Guo@Sun.COM void 29486621Sbt150084 ixgbe_start_watchdog_timer(ixgbe_t *ixgbe) 29496621Sbt150084 { 29506621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 29516621Sbt150084 29526621Sbt150084 if (ixgbe->watchdog_enable) { 29536621Sbt150084 if (!ixgbe->watchdog_start) { 29546621Sbt150084 ixgbe->watchdog_start = B_TRUE; 29556621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 29566621Sbt150084 } 29576621Sbt150084 } 29586621Sbt150084 29596621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 29606621Sbt150084 } 29616621Sbt150084 29626621Sbt150084 /* 29636621Sbt150084 * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer. 29646621Sbt150084 */ 29656621Sbt150084 static void 29666621Sbt150084 ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe) 29676621Sbt150084 { 29686621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 29696621Sbt150084 29706621Sbt150084 if (ixgbe->watchdog_start) 29716621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 29726621Sbt150084 29736621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 29746621Sbt150084 } 29756621Sbt150084 29766621Sbt150084 /* 29776621Sbt150084 * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer. 29786621Sbt150084 */ 29798490SPaul.Guo@Sun.COM void 29806621Sbt150084 ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe) 29816621Sbt150084 { 29826621Sbt150084 timeout_id_t tid; 29836621Sbt150084 29846621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 29856621Sbt150084 29866621Sbt150084 ixgbe->watchdog_start = B_FALSE; 29876621Sbt150084 tid = ixgbe->watchdog_tid; 29886621Sbt150084 ixgbe->watchdog_tid = 0; 29896621Sbt150084 29906621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 29916621Sbt150084 29926621Sbt150084 if (tid != 0) 29936621Sbt150084 (void) untimeout(tid); 29946621Sbt150084 } 29956621Sbt150084 29966621Sbt150084 /* 29976621Sbt150084 * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts. 29986621Sbt150084 */ 29996621Sbt150084 static void 30006621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe) 30016621Sbt150084 { 30026621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 30036621Sbt150084 30046621Sbt150084 /* 30056621Sbt150084 * mask all interrupts off 30066621Sbt150084 */ 30076621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff); 30086621Sbt150084 30096621Sbt150084 /* 30106621Sbt150084 * for MSI-X, also disable autoclear 30116621Sbt150084 */ 30126621Sbt150084 if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) { 30136621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0); 30146621Sbt150084 } 30156621Sbt150084 30166621Sbt150084 IXGBE_WRITE_FLUSH(hw); 30176621Sbt150084 } 30186621Sbt150084 30196621Sbt150084 /* 30206621Sbt150084 * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts. 30216621Sbt150084 */ 30226621Sbt150084 static void 30236621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe) 30246621Sbt150084 { 30256621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 30268490SPaul.Guo@Sun.COM uint32_t eiac, eiam; 30278490SPaul.Guo@Sun.COM uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 30288490SPaul.Guo@Sun.COM 30298490SPaul.Guo@Sun.COM /* interrupt types to enable */ 30308490SPaul.Guo@Sun.COM ixgbe->eims = IXGBE_EIMS_ENABLE_MASK; /* shared code default */ 30318490SPaul.Guo@Sun.COM ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER; /* minus tcp timer */ 30328490SPaul.Guo@Sun.COM ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */ 30338490SPaul.Guo@Sun.COM 30348490SPaul.Guo@Sun.COM /* enable automask on "other" causes that this adapter can generate */ 30358490SPaul.Guo@Sun.COM eiam = ixgbe->capab->other_intr; 30366621Sbt150084 30376621Sbt150084 /* 30386621Sbt150084 * msi-x mode 30396621Sbt150084 */ 30406621Sbt150084 if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) { 30416621Sbt150084 /* enable autoclear but not on bits 29:20 */ 30428490SPaul.Guo@Sun.COM eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR); 30436621Sbt150084 30446621Sbt150084 /* general purpose interrupt enable */ 30458490SPaul.Guo@Sun.COM gpie |= (IXGBE_GPIE_MSIX_MODE 30468490SPaul.Guo@Sun.COM | IXGBE_GPIE_PBA_SUPPORT 30478490SPaul.Guo@Sun.COM | IXGBE_GPIE_OCD 30488490SPaul.Guo@Sun.COM | IXGBE_GPIE_EIAME); 30496621Sbt150084 /* 30506621Sbt150084 * non-msi-x mode 30516621Sbt150084 */ 30526621Sbt150084 } else { 30536621Sbt150084 30546621Sbt150084 /* disable autoclear, leave gpie at default */ 30556621Sbt150084 eiac = 0; 30568490SPaul.Guo@Sun.COM 30579353SSamuel.Tu@Sun.COM /* 30589353SSamuel.Tu@Sun.COM * General purpose interrupt enable. 30599353SSamuel.Tu@Sun.COM * For 82599, extended interrupt automask enable 30609353SSamuel.Tu@Sun.COM * only in MSI or MSI-X mode 30619353SSamuel.Tu@Sun.COM */ 30629353SSamuel.Tu@Sun.COM if ((hw->mac.type < ixgbe_mac_82599EB) || 30639353SSamuel.Tu@Sun.COM (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) { 30649353SSamuel.Tu@Sun.COM gpie |= IXGBE_GPIE_EIAME; 30659353SSamuel.Tu@Sun.COM } 30669353SSamuel.Tu@Sun.COM } 30679353SSamuel.Tu@Sun.COM /* Enable specific interrupts for 82599 */ 30689353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 30699353SSamuel.Tu@Sun.COM gpie |= IXGBE_SDP2_GPIEN; /* pluggable optics intr */ 30709353SSamuel.Tu@Sun.COM gpie |= IXGBE_SDP1_GPIEN; /* LSC interrupt */ 30716621Sbt150084 } 30726621Sbt150084 30738490SPaul.Guo@Sun.COM /* write to interrupt control registers */ 30748490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 30756621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac); 30768490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam); 30776621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 30786621Sbt150084 IXGBE_WRITE_FLUSH(hw); 30796621Sbt150084 } 30806621Sbt150084 30816621Sbt150084 /* 30826621Sbt150084 * ixgbe_loopback_ioctl - Loopback support. 30836621Sbt150084 */ 30846621Sbt150084 enum ioc_reply 30856621Sbt150084 ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp) 30866621Sbt150084 { 30876621Sbt150084 lb_info_sz_t *lbsp; 30886621Sbt150084 lb_property_t *lbpp; 30896621Sbt150084 uint32_t *lbmp; 30906621Sbt150084 uint32_t size; 30916621Sbt150084 uint32_t value; 30926621Sbt150084 30936621Sbt150084 if (mp->b_cont == NULL) 30946621Sbt150084 return (IOC_INVAL); 30956621Sbt150084 30966621Sbt150084 switch (iocp->ioc_cmd) { 30976621Sbt150084 default: 30986621Sbt150084 return (IOC_INVAL); 30996621Sbt150084 31006621Sbt150084 case LB_GET_INFO_SIZE: 31016621Sbt150084 size = sizeof (lb_info_sz_t); 31026621Sbt150084 if (iocp->ioc_count != size) 31036621Sbt150084 return (IOC_INVAL); 31046621Sbt150084 31056621Sbt150084 value = sizeof (lb_normal); 31066621Sbt150084 value += sizeof (lb_mac); 310711150SZhen.W@Sun.COM value += sizeof (lb_external); 31086621Sbt150084 31096621Sbt150084 lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr; 31106621Sbt150084 *lbsp = value; 31116621Sbt150084 break; 31126621Sbt150084 31136621Sbt150084 case LB_GET_INFO: 31146621Sbt150084 value = sizeof (lb_normal); 31156621Sbt150084 value += sizeof (lb_mac); 311611150SZhen.W@Sun.COM value += sizeof (lb_external); 31176621Sbt150084 31186621Sbt150084 size = value; 31196621Sbt150084 if (iocp->ioc_count != size) 31206621Sbt150084 return (IOC_INVAL); 31216621Sbt150084 31226621Sbt150084 value = 0; 31236621Sbt150084 lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr; 31246621Sbt150084 31256621Sbt150084 lbpp[value++] = lb_normal; 31266621Sbt150084 lbpp[value++] = lb_mac; 312711150SZhen.W@Sun.COM lbpp[value++] = lb_external; 31286621Sbt150084 break; 31296621Sbt150084 31306621Sbt150084 case LB_GET_MODE: 31316621Sbt150084 size = sizeof (uint32_t); 31326621Sbt150084 if (iocp->ioc_count != size) 31336621Sbt150084 return (IOC_INVAL); 31346621Sbt150084 31356621Sbt150084 lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 31366621Sbt150084 *lbmp = ixgbe->loopback_mode; 31376621Sbt150084 break; 31386621Sbt150084 31396621Sbt150084 case LB_SET_MODE: 31406621Sbt150084 size = 0; 31416621Sbt150084 if (iocp->ioc_count != sizeof (uint32_t)) 31426621Sbt150084 return (IOC_INVAL); 31436621Sbt150084 31446621Sbt150084 lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 31456621Sbt150084 if (!ixgbe_set_loopback_mode(ixgbe, *lbmp)) 31466621Sbt150084 return (IOC_INVAL); 31476621Sbt150084 break; 31486621Sbt150084 } 31496621Sbt150084 31506621Sbt150084 iocp->ioc_count = size; 31516621Sbt150084 iocp->ioc_error = 0; 31526621Sbt150084 31536621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 31546621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 31556621Sbt150084 return (IOC_INVAL); 31566621Sbt150084 } 31576621Sbt150084 31586621Sbt150084 return (IOC_REPLY); 31596621Sbt150084 } 31606621Sbt150084 31616621Sbt150084 /* 31626621Sbt150084 * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode. 31636621Sbt150084 */ 31646621Sbt150084 static boolean_t 31656621Sbt150084 ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode) 31666621Sbt150084 { 31676621Sbt150084 if (mode == ixgbe->loopback_mode) 31686621Sbt150084 return (B_TRUE); 31696621Sbt150084 31706621Sbt150084 ixgbe->loopback_mode = mode; 31716621Sbt150084 31726621Sbt150084 if (mode == IXGBE_LB_NONE) { 31736621Sbt150084 /* 31746621Sbt150084 * Reset the chip 31756621Sbt150084 */ 31766621Sbt150084 (void) ixgbe_reset(ixgbe); 31776621Sbt150084 return (B_TRUE); 31786621Sbt150084 } 31796621Sbt150084 31806621Sbt150084 mutex_enter(&ixgbe->gen_lock); 31816621Sbt150084 31826621Sbt150084 switch (mode) { 31836621Sbt150084 default: 31846621Sbt150084 mutex_exit(&ixgbe->gen_lock); 31856621Sbt150084 return (B_FALSE); 31866621Sbt150084 318711150SZhen.W@Sun.COM case IXGBE_LB_EXTERNAL: 318811150SZhen.W@Sun.COM break; 318911150SZhen.W@Sun.COM 31906621Sbt150084 case IXGBE_LB_INTERNAL_MAC: 31916621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe); 31926621Sbt150084 break; 31936621Sbt150084 } 31946621Sbt150084 31956621Sbt150084 mutex_exit(&ixgbe->gen_lock); 31966621Sbt150084 31976621Sbt150084 return (B_TRUE); 31986621Sbt150084 } 31996621Sbt150084 32006621Sbt150084 /* 32016621Sbt150084 * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode. 32026621Sbt150084 */ 32036621Sbt150084 static void 32046621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe) 32056621Sbt150084 { 32066621Sbt150084 struct ixgbe_hw *hw; 32076621Sbt150084 uint32_t reg; 32086621Sbt150084 uint8_t atlas; 32096621Sbt150084 32106621Sbt150084 hw = &ixgbe->hw; 32116621Sbt150084 32126621Sbt150084 /* 32136621Sbt150084 * Setup MAC loopback 32146621Sbt150084 */ 32156621Sbt150084 reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0); 32166621Sbt150084 reg |= IXGBE_HLREG0_LPBK; 32176621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg); 32186621Sbt150084 32196621Sbt150084 reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC); 32206621Sbt150084 reg &= ~IXGBE_AUTOC_LMS_MASK; 32216621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg); 32226621Sbt150084 32236621Sbt150084 /* 32246621Sbt150084 * Disable Atlas Tx lanes to keep packets in loopback and not on wire 32256621Sbt150084 */ 32266621Sbt150084 if (hw->mac.type == ixgbe_mac_82598EB) { 32276621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK, 32286621Sbt150084 &atlas); 32296621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_REG_EN; 32306621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK, 32316621Sbt150084 atlas); 32326621Sbt150084 32336621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G, 32346621Sbt150084 &atlas); 32356621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL; 32366621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G, 32376621Sbt150084 atlas); 32386621Sbt150084 32396621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G, 32406621Sbt150084 &atlas); 32416621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL; 32426621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G, 32436621Sbt150084 atlas); 32446621Sbt150084 32456621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN, 32466621Sbt150084 &atlas); 32476621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL; 32486621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN, 32496621Sbt150084 atlas); 32506621Sbt150084 } 32516621Sbt150084 } 32526621Sbt150084 32536621Sbt150084 #pragma inline(ixgbe_intr_rx_work) 32546621Sbt150084 /* 32556621Sbt150084 * ixgbe_intr_rx_work - RX processing of ISR. 32566621Sbt150084 */ 32576621Sbt150084 static void 32586621Sbt150084 ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring) 32596621Sbt150084 { 32606621Sbt150084 mblk_t *mp; 32616621Sbt150084 32626621Sbt150084 mutex_enter(&rx_ring->rx_lock); 32636621Sbt150084 32648275SEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL); 32656621Sbt150084 mutex_exit(&rx_ring->rx_lock); 32666621Sbt150084 32676621Sbt150084 if (mp != NULL) 32688275SEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp, 32698275SEric Cheng rx_ring->ring_gen_num); 32706621Sbt150084 } 32716621Sbt150084 32726621Sbt150084 #pragma inline(ixgbe_intr_tx_work) 32736621Sbt150084 /* 32746621Sbt150084 * ixgbe_intr_tx_work - TX processing of ISR. 32756621Sbt150084 */ 32766621Sbt150084 static void 32776621Sbt150084 ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring) 32786621Sbt150084 { 327910376SChenlu.Chen@Sun.COM ixgbe_t *ixgbe = tx_ring->ixgbe; 328010376SChenlu.Chen@Sun.COM 32816621Sbt150084 /* 32826621Sbt150084 * Recycle the tx descriptors 32836621Sbt150084 */ 32846621Sbt150084 tx_ring->tx_recycle(tx_ring); 32856621Sbt150084 32866621Sbt150084 /* 32876621Sbt150084 * Schedule the re-transmit 32886621Sbt150084 */ 32896621Sbt150084 if (tx_ring->reschedule && 329010376SChenlu.Chen@Sun.COM (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) { 32916621Sbt150084 tx_ring->reschedule = B_FALSE; 32928275SEric Cheng mac_tx_ring_update(tx_ring->ixgbe->mac_hdl, 32938275SEric Cheng tx_ring->ring_handle); 32946621Sbt150084 IXGBE_DEBUG_STAT(tx_ring->stat_reschedule); 32956621Sbt150084 } 32966621Sbt150084 } 32976621Sbt150084 32986621Sbt150084 #pragma inline(ixgbe_intr_other_work) 32996621Sbt150084 /* 33008490SPaul.Guo@Sun.COM * ixgbe_intr_other_work - Process interrupt types other than tx/rx 33016621Sbt150084 */ 33026621Sbt150084 static void 33038490SPaul.Guo@Sun.COM ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr) 33046621Sbt150084 { 33059353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 3306*11233SPaul.Guo@Sun.COM 3307*11233SPaul.Guo@Sun.COM ASSERT(mutex_owned(&ixgbe->gen_lock)); 3308*11233SPaul.Guo@Sun.COM 33098490SPaul.Guo@Sun.COM /* 3310*11233SPaul.Guo@Sun.COM * handle link status change 33118490SPaul.Guo@Sun.COM */ 33128490SPaul.Guo@Sun.COM if (eicr & IXGBE_EICR_LSC) { 3313*11233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe); 33148490SPaul.Guo@Sun.COM } 33156621Sbt150084 33166621Sbt150084 /* 33178490SPaul.Guo@Sun.COM * check for fan failure on adapters with fans 33186621Sbt150084 */ 33198490SPaul.Guo@Sun.COM if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) && 33208490SPaul.Guo@Sun.COM (eicr & IXGBE_EICR_GPI_SDP1)) { 33219353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 33229353SSamuel.Tu@Sun.COM ixgbe_log(ixgbe, 33239353SSamuel.Tu@Sun.COM "Fan has stopped, replace the adapter\n"); 33249353SSamuel.Tu@Sun.COM 33259353SSamuel.Tu@Sun.COM /* re-enable the interrupt, which was automasked */ 33269353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_GPI_SDP1; 33279353SSamuel.Tu@Sun.COM } 33289353SSamuel.Tu@Sun.COM } 33299353SSamuel.Tu@Sun.COM 33309353SSamuel.Tu@Sun.COM /* 33319353SSamuel.Tu@Sun.COM * Do SFP check for 82599 33329353SSamuel.Tu@Sun.COM */ 33339353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 3334*11233SPaul.Guo@Sun.COM if ((ddi_taskq_dispatch(ixgbe->sfp_taskq, 33359353SSamuel.Tu@Sun.COM ixgbe_sfp_check, (void *)ixgbe, 33369353SSamuel.Tu@Sun.COM DDI_NOSLEEP)) != DDI_SUCCESS) { 333710305SPaul.Guo@Sun.COM ixgbe_log(ixgbe, "No memory available to dispatch " 333810305SPaul.Guo@Sun.COM "taskq for SFP check"); 33399353SSamuel.Tu@Sun.COM } 3340*11233SPaul.Guo@Sun.COM 3341*11233SPaul.Guo@Sun.COM /* 3342*11233SPaul.Guo@Sun.COM * We need to fully re-check the link later. 3343*11233SPaul.Guo@Sun.COM */ 3344*11233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 3345*11233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 3346*11233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 33478490SPaul.Guo@Sun.COM } 33486621Sbt150084 } 33496621Sbt150084 33506621Sbt150084 /* 33516621Sbt150084 * ixgbe_intr_legacy - Interrupt handler for legacy interrupts. 33526621Sbt150084 */ 33536621Sbt150084 static uint_t 33546621Sbt150084 ixgbe_intr_legacy(void *arg1, void *arg2) 33556621Sbt150084 { 33566621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg1; 33576621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 33586621Sbt150084 ixgbe_tx_ring_t *tx_ring; 33598275SEric Cheng ixgbe_rx_ring_t *rx_ring; 33606621Sbt150084 uint32_t eicr; 33616621Sbt150084 mblk_t *mp; 33626621Sbt150084 boolean_t tx_reschedule; 33636621Sbt150084 uint_t result; 33646621Sbt150084 33658490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 33666621Sbt150084 33676621Sbt150084 mutex_enter(&ixgbe->gen_lock); 33686621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 33696621Sbt150084 mutex_exit(&ixgbe->gen_lock); 33706621Sbt150084 return (DDI_INTR_UNCLAIMED); 33716621Sbt150084 } 33726621Sbt150084 33736621Sbt150084 mp = NULL; 33746621Sbt150084 tx_reschedule = B_FALSE; 33756621Sbt150084 33766621Sbt150084 /* 33776621Sbt150084 * Any bit set in eicr: claim this interrupt 33786621Sbt150084 */ 33796621Sbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 3380*11233SPaul.Guo@Sun.COM 3381*11233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 3382*11233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 3383*11233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 3384*11233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 3385*11233SPaul.Guo@Sun.COM } 3386*11233SPaul.Guo@Sun.COM 33876621Sbt150084 if (eicr) { 33886621Sbt150084 /* 33896621Sbt150084 * For legacy interrupt, we have only one interrupt, 33906621Sbt150084 * so we have only one rx ring and one tx ring enabled. 33916621Sbt150084 */ 33926621Sbt150084 ASSERT(ixgbe->num_rx_rings == 1); 33936621Sbt150084 ASSERT(ixgbe->num_tx_rings == 1); 33946621Sbt150084 33956621Sbt150084 /* 33968275SEric Cheng * For legacy interrupt, rx rings[0] will use RTxQ[0]. 33976621Sbt150084 */ 33988275SEric Cheng if (eicr & 0x1) { 33999353SSamuel.Tu@Sun.COM ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE; 34009353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 34019353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; 34026621Sbt150084 /* 34036621Sbt150084 * Clean the rx descriptors 34046621Sbt150084 */ 34058275SEric Cheng rx_ring = &ixgbe->rx_rings[0]; 34068275SEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL); 34078275SEric Cheng } 34088275SEric Cheng 34098275SEric Cheng /* 34108275SEric Cheng * For legacy interrupt, tx rings[0] will use RTxQ[1]. 34118275SEric Cheng */ 34128275SEric Cheng if (eicr & 0x2) { 34136621Sbt150084 /* 34146621Sbt150084 * Recycle the tx descriptors 34156621Sbt150084 */ 34166621Sbt150084 tx_ring = &ixgbe->tx_rings[0]; 34176621Sbt150084 tx_ring->tx_recycle(tx_ring); 34186621Sbt150084 34196621Sbt150084 /* 34206621Sbt150084 * Schedule the re-transmit 34216621Sbt150084 */ 34226621Sbt150084 tx_reschedule = (tx_ring->reschedule && 342310376SChenlu.Chen@Sun.COM (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)); 34246621Sbt150084 } 34256621Sbt150084 34268490SPaul.Guo@Sun.COM /* any interrupt type other than tx/rx */ 34278490SPaul.Guo@Sun.COM if (eicr & ixgbe->capab->other_intr) { 34289353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 34299353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 34309353SSamuel.Tu@Sun.COM } 34319353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 34329353SSamuel.Tu@Sun.COM ixgbe->eimc = IXGBE_82599_OTHER_INTR; 34339353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 34349353SSamuel.Tu@Sun.COM } 34359353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 34368490SPaul.Guo@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 34376621Sbt150084 } 34386621Sbt150084 34398490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 34408490SPaul.Guo@Sun.COM 34416621Sbt150084 result = DDI_INTR_CLAIMED; 34426621Sbt150084 } else { 34438490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 34448490SPaul.Guo@Sun.COM 34456621Sbt150084 /* 34466621Sbt150084 * No interrupt cause bits set: don't claim this interrupt. 34476621Sbt150084 */ 34486621Sbt150084 result = DDI_INTR_UNCLAIMED; 34496621Sbt150084 } 34506621Sbt150084 34518490SPaul.Guo@Sun.COM /* re-enable the interrupts which were automasked */ 34528490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 34536621Sbt150084 34546621Sbt150084 /* 34556621Sbt150084 * Do the following work outside of the gen_lock 34566621Sbt150084 */ 34579353SSamuel.Tu@Sun.COM if (mp != NULL) { 34588275SEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp, 34598275SEric Cheng rx_ring->ring_gen_num); 34609353SSamuel.Tu@Sun.COM } 34616621Sbt150084 34626621Sbt150084 if (tx_reschedule) { 34636621Sbt150084 tx_ring->reschedule = B_FALSE; 34648275SEric Cheng mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle); 34656621Sbt150084 IXGBE_DEBUG_STAT(tx_ring->stat_reschedule); 34666621Sbt150084 } 34676621Sbt150084 34686621Sbt150084 return (result); 34696621Sbt150084 } 34706621Sbt150084 34716621Sbt150084 /* 34726621Sbt150084 * ixgbe_intr_msi - Interrupt handler for MSI. 34736621Sbt150084 */ 34746621Sbt150084 static uint_t 34756621Sbt150084 ixgbe_intr_msi(void *arg1, void *arg2) 34766621Sbt150084 { 34776621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg1; 34786621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 34796621Sbt150084 uint32_t eicr; 34806621Sbt150084 34818490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 34828490SPaul.Guo@Sun.COM 34836621Sbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 34846621Sbt150084 3485*11233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 3486*11233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 3487*11233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 3488*11233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 3489*11233SPaul.Guo@Sun.COM } 3490*11233SPaul.Guo@Sun.COM 34916621Sbt150084 /* 34926621Sbt150084 * For MSI interrupt, we have only one vector, 34936621Sbt150084 * so we have only one rx ring and one tx ring enabled. 34946621Sbt150084 */ 34956621Sbt150084 ASSERT(ixgbe->num_rx_rings == 1); 34966621Sbt150084 ASSERT(ixgbe->num_tx_rings == 1); 34976621Sbt150084 34986621Sbt150084 /* 34998275SEric Cheng * For MSI interrupt, rx rings[0] will use RTxQ[0]. 35006621Sbt150084 */ 35018275SEric Cheng if (eicr & 0x1) { 35026621Sbt150084 ixgbe_intr_rx_work(&ixgbe->rx_rings[0]); 35038275SEric Cheng } 35048275SEric Cheng 35058275SEric Cheng /* 35068275SEric Cheng * For MSI interrupt, tx rings[0] will use RTxQ[1]. 35078275SEric Cheng */ 35088275SEric Cheng if (eicr & 0x2) { 35096621Sbt150084 ixgbe_intr_tx_work(&ixgbe->tx_rings[0]); 35106621Sbt150084 } 35116621Sbt150084 35128490SPaul.Guo@Sun.COM /* any interrupt type other than tx/rx */ 35138490SPaul.Guo@Sun.COM if (eicr & ixgbe->capab->other_intr) { 35148490SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 35159353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 35169353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 35179353SSamuel.Tu@Sun.COM } 35189353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 35199353SSamuel.Tu@Sun.COM ixgbe->eimc = IXGBE_82599_OTHER_INTR; 35209353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 35219353SSamuel.Tu@Sun.COM } 35229353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 35238490SPaul.Guo@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 35248490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 35256621Sbt150084 } 35266621Sbt150084 35278490SPaul.Guo@Sun.COM /* re-enable the interrupts which were automasked */ 35288490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 35298490SPaul.Guo@Sun.COM 35306621Sbt150084 return (DDI_INTR_CLAIMED); 35316621Sbt150084 } 35326621Sbt150084 35336621Sbt150084 /* 35349353SSamuel.Tu@Sun.COM * ixgbe_intr_msix - Interrupt handler for MSI-X. 35356621Sbt150084 */ 35366621Sbt150084 static uint_t 35379353SSamuel.Tu@Sun.COM ixgbe_intr_msix(void *arg1, void *arg2) 35386621Sbt150084 { 35399353SSamuel.Tu@Sun.COM ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1; 35408275SEric Cheng ixgbe_t *ixgbe = vect->ixgbe; 35419353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 35429353SSamuel.Tu@Sun.COM uint32_t eicr; 35438275SEric Cheng int r_idx = 0; 35446621Sbt150084 35458490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 35468490SPaul.Guo@Sun.COM 35476621Sbt150084 /* 35488275SEric Cheng * Clean each rx ring that has its bit set in the map 35496621Sbt150084 */ 35506621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1)); 35516621Sbt150084 while (r_idx >= 0) { 35526621Sbt150084 ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]); 35536621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1), 35546621Sbt150084 (ixgbe->num_rx_rings - 1)); 35556621Sbt150084 } 35566621Sbt150084 35578275SEric Cheng /* 35588275SEric Cheng * Clean each tx ring that has its bit set in the map 35598275SEric Cheng */ 35608275SEric Cheng r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1)); 35618275SEric Cheng while (r_idx >= 0) { 35628275SEric Cheng ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]); 35638275SEric Cheng r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1), 35648275SEric Cheng (ixgbe->num_tx_rings - 1)); 35658275SEric Cheng } 35668275SEric Cheng 35676621Sbt150084 35686621Sbt150084 /* 35699353SSamuel.Tu@Sun.COM * Clean other interrupt (link change) that has its bit set in the map 35706621Sbt150084 */ 35719353SSamuel.Tu@Sun.COM if (BT_TEST(vect->other_map, 0) == 1) { 35729353SSamuel.Tu@Sun.COM eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 35739353SSamuel.Tu@Sun.COM 3574*11233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != 3575*11233SPaul.Guo@Sun.COM DDI_FM_OK) { 3576*11233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, 3577*11233SPaul.Guo@Sun.COM DDI_SERVICE_DEGRADED); 3578*11233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 3579*11233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 3580*11233SPaul.Guo@Sun.COM } 3581*11233SPaul.Guo@Sun.COM 35829353SSamuel.Tu@Sun.COM /* 35839353SSamuel.Tu@Sun.COM * Need check cause bits and only other causes will 35849353SSamuel.Tu@Sun.COM * be processed 35859353SSamuel.Tu@Sun.COM */ 35869353SSamuel.Tu@Sun.COM /* any interrupt type other than tx/rx */ 35879353SSamuel.Tu@Sun.COM if (eicr & ixgbe->capab->other_intr) { 35889353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 35899353SSamuel.Tu@Sun.COM mutex_enter(&ixgbe->gen_lock); 35909353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 35919353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 35929353SSamuel.Tu@Sun.COM mutex_exit(&ixgbe->gen_lock); 35939353SSamuel.Tu@Sun.COM } else { 35949353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 35959353SSamuel.Tu@Sun.COM mutex_enter(&ixgbe->gen_lock); 35969353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; 35979353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 35989353SSamuel.Tu@Sun.COM mutex_exit(&ixgbe->gen_lock); 35999353SSamuel.Tu@Sun.COM } 36009353SSamuel.Tu@Sun.COM } 36019353SSamuel.Tu@Sun.COM } 36029353SSamuel.Tu@Sun.COM 36039353SSamuel.Tu@Sun.COM /* re-enable the interrupts which were automasked */ 36049353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 36056621Sbt150084 } 36066621Sbt150084 36076621Sbt150084 return (DDI_INTR_CLAIMED); 36086621Sbt150084 } 36096621Sbt150084 36106621Sbt150084 /* 36116621Sbt150084 * ixgbe_alloc_intrs - Allocate interrupts for the driver. 36126621Sbt150084 * 36136621Sbt150084 * Normal sequence is to try MSI-X; if not sucessful, try MSI; 36146621Sbt150084 * if not successful, try Legacy. 36156621Sbt150084 * ixgbe->intr_force can be used to force sequence to start with 36166621Sbt150084 * any of the 3 types. 36176621Sbt150084 * If MSI-X is not used, number of tx/rx rings is forced to 1. 36186621Sbt150084 */ 36196621Sbt150084 static int 36206621Sbt150084 ixgbe_alloc_intrs(ixgbe_t *ixgbe) 36216621Sbt150084 { 36226621Sbt150084 dev_info_t *devinfo; 36236621Sbt150084 int intr_types; 36246621Sbt150084 int rc; 36256621Sbt150084 36266621Sbt150084 devinfo = ixgbe->dip; 36276621Sbt150084 36286621Sbt150084 /* 36296621Sbt150084 * Get supported interrupt types 36306621Sbt150084 */ 36316621Sbt150084 rc = ddi_intr_get_supported_types(devinfo, &intr_types); 36326621Sbt150084 36336621Sbt150084 if (rc != DDI_SUCCESS) { 36346621Sbt150084 ixgbe_log(ixgbe, 36356621Sbt150084 "Get supported interrupt types failed: %d", rc); 36366621Sbt150084 return (IXGBE_FAILURE); 36376621Sbt150084 } 36386621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types); 36396621Sbt150084 36406621Sbt150084 ixgbe->intr_type = 0; 36416621Sbt150084 36426621Sbt150084 /* 36436621Sbt150084 * Install MSI-X interrupts 36446621Sbt150084 */ 36456621Sbt150084 if ((intr_types & DDI_INTR_TYPE_MSIX) && 36466621Sbt150084 (ixgbe->intr_force <= IXGBE_INTR_MSIX)) { 36476621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX); 36486621Sbt150084 if (rc == IXGBE_SUCCESS) 36496621Sbt150084 return (IXGBE_SUCCESS); 36506621Sbt150084 36516621Sbt150084 ixgbe_log(ixgbe, 36526621Sbt150084 "Allocate MSI-X failed, trying MSI interrupts..."); 36536621Sbt150084 } 36546621Sbt150084 36556621Sbt150084 /* 36568275SEric Cheng * MSI-X not used, force rings and groups to 1 36576621Sbt150084 */ 36586621Sbt150084 ixgbe->num_rx_rings = 1; 36598275SEric Cheng ixgbe->num_rx_groups = 1; 36606621Sbt150084 ixgbe->num_tx_rings = 1; 36616621Sbt150084 ixgbe_log(ixgbe, 36628275SEric Cheng "MSI-X not used, force rings and groups number to 1"); 36636621Sbt150084 36646621Sbt150084 /* 36656621Sbt150084 * Install MSI interrupts 36666621Sbt150084 */ 36676621Sbt150084 if ((intr_types & DDI_INTR_TYPE_MSI) && 36686621Sbt150084 (ixgbe->intr_force <= IXGBE_INTR_MSI)) { 36696621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI); 36706621Sbt150084 if (rc == IXGBE_SUCCESS) 36716621Sbt150084 return (IXGBE_SUCCESS); 36726621Sbt150084 36736621Sbt150084 ixgbe_log(ixgbe, 36746621Sbt150084 "Allocate MSI failed, trying Legacy interrupts..."); 36756621Sbt150084 } 36766621Sbt150084 36776621Sbt150084 /* 36786621Sbt150084 * Install legacy interrupts 36796621Sbt150084 */ 36806621Sbt150084 if (intr_types & DDI_INTR_TYPE_FIXED) { 36816621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED); 36826621Sbt150084 if (rc == IXGBE_SUCCESS) 36836621Sbt150084 return (IXGBE_SUCCESS); 36846621Sbt150084 36856621Sbt150084 ixgbe_log(ixgbe, 36866621Sbt150084 "Allocate Legacy interrupts failed"); 36876621Sbt150084 } 36886621Sbt150084 36896621Sbt150084 /* 36906621Sbt150084 * If none of the 3 types succeeded, return failure 36916621Sbt150084 */ 36926621Sbt150084 return (IXGBE_FAILURE); 36936621Sbt150084 } 36946621Sbt150084 36956621Sbt150084 /* 36966621Sbt150084 * ixgbe_alloc_intr_handles - Allocate interrupt handles. 36976621Sbt150084 * 36986621Sbt150084 * For legacy and MSI, only 1 handle is needed. For MSI-X, 36996621Sbt150084 * if fewer than 2 handles are available, return failure. 37008275SEric Cheng * Upon success, this maps the vectors to rx and tx rings for 37018275SEric Cheng * interrupts. 37026621Sbt150084 */ 37036621Sbt150084 static int 37046621Sbt150084 ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type) 37056621Sbt150084 { 37066621Sbt150084 dev_info_t *devinfo; 37076621Sbt150084 int request, count, avail, actual; 37088275SEric Cheng int minimum; 37096621Sbt150084 int rc; 37106621Sbt150084 37116621Sbt150084 devinfo = ixgbe->dip; 37126621Sbt150084 37136621Sbt150084 switch (intr_type) { 37146621Sbt150084 case DDI_INTR_TYPE_FIXED: 37156621Sbt150084 request = 1; /* Request 1 legacy interrupt handle */ 37166621Sbt150084 minimum = 1; 37176621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy"); 37186621Sbt150084 break; 37196621Sbt150084 37206621Sbt150084 case DDI_INTR_TYPE_MSI: 37216621Sbt150084 request = 1; /* Request 1 MSI interrupt handle */ 37226621Sbt150084 minimum = 1; 37236621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI"); 37246621Sbt150084 break; 37256621Sbt150084 37266621Sbt150084 case DDI_INTR_TYPE_MSIX: 37276621Sbt150084 /* 37286621Sbt150084 * Best number of vectors for the adapter is 37299353SSamuel.Tu@Sun.COM * # rx rings + # tx rings. 37306621Sbt150084 */ 37319353SSamuel.Tu@Sun.COM request = ixgbe->num_rx_rings + ixgbe->num_tx_rings; 37329353SSamuel.Tu@Sun.COM if (request > ixgbe->capab->max_ring_vect) 37339353SSamuel.Tu@Sun.COM request = ixgbe->capab->max_ring_vect; 37346621Sbt150084 minimum = 2; 37356621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X"); 37366621Sbt150084 break; 37376621Sbt150084 37386621Sbt150084 default: 37396621Sbt150084 ixgbe_log(ixgbe, 37406621Sbt150084 "invalid call to ixgbe_alloc_intr_handles(): %d\n", 37416621Sbt150084 intr_type); 37426621Sbt150084 return (IXGBE_FAILURE); 37436621Sbt150084 } 37446621Sbt150084 IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d minimum: %d", 37456621Sbt150084 request, minimum); 37466621Sbt150084 37476621Sbt150084 /* 37486621Sbt150084 * Get number of supported interrupts 37496621Sbt150084 */ 37506621Sbt150084 rc = ddi_intr_get_nintrs(devinfo, intr_type, &count); 37516621Sbt150084 if ((rc != DDI_SUCCESS) || (count < minimum)) { 37526621Sbt150084 ixgbe_log(ixgbe, 37536621Sbt150084 "Get interrupt number failed. Return: %d, count: %d", 37546621Sbt150084 rc, count); 37556621Sbt150084 return (IXGBE_FAILURE); 37566621Sbt150084 } 37576621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count); 37586621Sbt150084 37596621Sbt150084 /* 37606621Sbt150084 * Get number of available interrupts 37616621Sbt150084 */ 37626621Sbt150084 rc = ddi_intr_get_navail(devinfo, intr_type, &avail); 37636621Sbt150084 if ((rc != DDI_SUCCESS) || (avail < minimum)) { 37646621Sbt150084 ixgbe_log(ixgbe, 37656621Sbt150084 "Get interrupt available number failed. " 37666621Sbt150084 "Return: %d, available: %d", rc, avail); 37676621Sbt150084 return (IXGBE_FAILURE); 37686621Sbt150084 } 37696621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts available: %d", avail); 37706621Sbt150084 37716621Sbt150084 if (avail < request) { 37726621Sbt150084 ixgbe_log(ixgbe, "Request %d handles, %d available", 37736621Sbt150084 request, avail); 37746621Sbt150084 request = avail; 37756621Sbt150084 } 37766621Sbt150084 37776621Sbt150084 actual = 0; 37786621Sbt150084 ixgbe->intr_cnt = 0; 37796621Sbt150084 37806621Sbt150084 /* 37816621Sbt150084 * Allocate an array of interrupt handles 37826621Sbt150084 */ 37836621Sbt150084 ixgbe->intr_size = request * sizeof (ddi_intr_handle_t); 37846621Sbt150084 ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP); 37856621Sbt150084 37866621Sbt150084 rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0, 37876621Sbt150084 request, &actual, DDI_INTR_ALLOC_NORMAL); 37886621Sbt150084 if (rc != DDI_SUCCESS) { 37896621Sbt150084 ixgbe_log(ixgbe, "Allocate interrupts failed. " 37906621Sbt150084 "return: %d, request: %d, actual: %d", 37916621Sbt150084 rc, request, actual); 37926621Sbt150084 goto alloc_handle_fail; 37936621Sbt150084 } 37946621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual); 37956621Sbt150084 37966621Sbt150084 ixgbe->intr_cnt = actual; 37976621Sbt150084 37986621Sbt150084 /* 37998275SEric Cheng * Now we know the actual number of vectors. Here we map the vector 38008275SEric Cheng * to other, rx rings and tx ring. 38016621Sbt150084 */ 38026621Sbt150084 if (actual < minimum) { 38036621Sbt150084 ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d", 38046621Sbt150084 actual); 38056621Sbt150084 goto alloc_handle_fail; 38066621Sbt150084 } 38076621Sbt150084 38086621Sbt150084 /* 38096621Sbt150084 * Get priority for first vector, assume remaining are all the same 38106621Sbt150084 */ 38116621Sbt150084 rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri); 38126621Sbt150084 if (rc != DDI_SUCCESS) { 38136621Sbt150084 ixgbe_log(ixgbe, 38146621Sbt150084 "Get interrupt priority failed: %d", rc); 38156621Sbt150084 goto alloc_handle_fail; 38166621Sbt150084 } 38176621Sbt150084 38186621Sbt150084 rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap); 38196621Sbt150084 if (rc != DDI_SUCCESS) { 38206621Sbt150084 ixgbe_log(ixgbe, 38216621Sbt150084 "Get interrupt cap failed: %d", rc); 38226621Sbt150084 goto alloc_handle_fail; 38236621Sbt150084 } 38246621Sbt150084 38256621Sbt150084 ixgbe->intr_type = intr_type; 38266621Sbt150084 38276621Sbt150084 return (IXGBE_SUCCESS); 38286621Sbt150084 38296621Sbt150084 alloc_handle_fail: 38306621Sbt150084 ixgbe_rem_intrs(ixgbe); 38316621Sbt150084 38326621Sbt150084 return (IXGBE_FAILURE); 38336621Sbt150084 } 38346621Sbt150084 38356621Sbt150084 /* 38366621Sbt150084 * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type. 38376621Sbt150084 * 38386621Sbt150084 * Before adding the interrupt handlers, the interrupt vectors have 38396621Sbt150084 * been allocated, and the rx/tx rings have also been allocated. 38406621Sbt150084 */ 38416621Sbt150084 static int 38426621Sbt150084 ixgbe_add_intr_handlers(ixgbe_t *ixgbe) 38436621Sbt150084 { 38448275SEric Cheng int vector = 0; 38456621Sbt150084 int rc; 38466621Sbt150084 38476621Sbt150084 switch (ixgbe->intr_type) { 38486621Sbt150084 case DDI_INTR_TYPE_MSIX: 38496621Sbt150084 /* 38509353SSamuel.Tu@Sun.COM * Add interrupt handler for all vectors 38516621Sbt150084 */ 38529353SSamuel.Tu@Sun.COM for (vector = 0; vector < ixgbe->intr_cnt; vector++) { 38536621Sbt150084 /* 38546621Sbt150084 * install pointer to vect_map[vector] 38556621Sbt150084 */ 38566621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 38579353SSamuel.Tu@Sun.COM (ddi_intr_handler_t *)ixgbe_intr_msix, 38586621Sbt150084 (void *)&ixgbe->vect_map[vector], NULL); 38596621Sbt150084 38606621Sbt150084 if (rc != DDI_SUCCESS) { 38616621Sbt150084 ixgbe_log(ixgbe, 38626621Sbt150084 "Add rx interrupt handler failed. " 38638275SEric Cheng "return: %d, vector: %d", rc, vector); 38646621Sbt150084 for (vector--; vector >= 0; vector--) { 38656621Sbt150084 (void) ddi_intr_remove_handler( 38666621Sbt150084 ixgbe->htable[vector]); 38676621Sbt150084 } 38686621Sbt150084 return (IXGBE_FAILURE); 38696621Sbt150084 } 38706621Sbt150084 } 38718275SEric Cheng 38726621Sbt150084 break; 38736621Sbt150084 38746621Sbt150084 case DDI_INTR_TYPE_MSI: 38756621Sbt150084 /* 38766621Sbt150084 * Add interrupt handlers for the only vector 38776621Sbt150084 */ 38786621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 38796621Sbt150084 (ddi_intr_handler_t *)ixgbe_intr_msi, 38806621Sbt150084 (void *)ixgbe, NULL); 38816621Sbt150084 38826621Sbt150084 if (rc != DDI_SUCCESS) { 38836621Sbt150084 ixgbe_log(ixgbe, 38846621Sbt150084 "Add MSI interrupt handler failed: %d", rc); 38856621Sbt150084 return (IXGBE_FAILURE); 38866621Sbt150084 } 38876621Sbt150084 38886621Sbt150084 break; 38896621Sbt150084 38906621Sbt150084 case DDI_INTR_TYPE_FIXED: 38916621Sbt150084 /* 38926621Sbt150084 * Add interrupt handlers for the only vector 38936621Sbt150084 */ 38946621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 38956621Sbt150084 (ddi_intr_handler_t *)ixgbe_intr_legacy, 38966621Sbt150084 (void *)ixgbe, NULL); 38976621Sbt150084 38986621Sbt150084 if (rc != DDI_SUCCESS) { 38996621Sbt150084 ixgbe_log(ixgbe, 39006621Sbt150084 "Add legacy interrupt handler failed: %d", rc); 39016621Sbt150084 return (IXGBE_FAILURE); 39026621Sbt150084 } 39036621Sbt150084 39046621Sbt150084 break; 39056621Sbt150084 39066621Sbt150084 default: 39076621Sbt150084 return (IXGBE_FAILURE); 39086621Sbt150084 } 39096621Sbt150084 39106621Sbt150084 return (IXGBE_SUCCESS); 39116621Sbt150084 } 39126621Sbt150084 39136621Sbt150084 #pragma inline(ixgbe_map_rxring_to_vector) 39146621Sbt150084 /* 39156621Sbt150084 * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector. 39166621Sbt150084 */ 39176621Sbt150084 static void 39186621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx) 39196621Sbt150084 { 39206621Sbt150084 /* 39216621Sbt150084 * Set bit in map 39226621Sbt150084 */ 39236621Sbt150084 BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx); 39246621Sbt150084 39256621Sbt150084 /* 39266621Sbt150084 * Count bits set 39276621Sbt150084 */ 39286621Sbt150084 ixgbe->vect_map[v_idx].rxr_cnt++; 39296621Sbt150084 39306621Sbt150084 /* 39316621Sbt150084 * Remember bit position 39326621Sbt150084 */ 39338275SEric Cheng ixgbe->rx_rings[r_idx].intr_vector = v_idx; 39346621Sbt150084 ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx; 39356621Sbt150084 } 39366621Sbt150084 39376621Sbt150084 #pragma inline(ixgbe_map_txring_to_vector) 39386621Sbt150084 /* 39396621Sbt150084 * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector. 39406621Sbt150084 */ 39416621Sbt150084 static void 39426621Sbt150084 ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx) 39436621Sbt150084 { 39446621Sbt150084 /* 39456621Sbt150084 * Set bit in map 39466621Sbt150084 */ 39476621Sbt150084 BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx); 39486621Sbt150084 39496621Sbt150084 /* 39506621Sbt150084 * Count bits set 39516621Sbt150084 */ 39526621Sbt150084 ixgbe->vect_map[v_idx].txr_cnt++; 39536621Sbt150084 39546621Sbt150084 /* 39556621Sbt150084 * Remember bit position 39566621Sbt150084 */ 39578275SEric Cheng ixgbe->tx_rings[t_idx].intr_vector = v_idx; 39586621Sbt150084 ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx; 39596621Sbt150084 } 39606621Sbt150084 39616621Sbt150084 /* 39628275SEric Cheng * ixgbe_setup_ivar - Set the given entry in the given interrupt vector 39636621Sbt150084 * allocation register (IVAR). 39649353SSamuel.Tu@Sun.COM * cause: 39659353SSamuel.Tu@Sun.COM * -1 : other cause 39669353SSamuel.Tu@Sun.COM * 0 : rx 39679353SSamuel.Tu@Sun.COM * 1 : tx 39686621Sbt150084 */ 39696621Sbt150084 static void 39709353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector, 39719353SSamuel.Tu@Sun.COM int8_t cause) 39726621Sbt150084 { 39736621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 39746621Sbt150084 u32 ivar, index; 39756621Sbt150084 39769353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 39779353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 39789353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 39799353SSamuel.Tu@Sun.COM if (cause == -1) { 39809353SSamuel.Tu@Sun.COM cause = 0; 39819353SSamuel.Tu@Sun.COM } 39829353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 39839353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 39849353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3))); 39859353SSamuel.Tu@Sun.COM ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3))); 39869353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 39879353SSamuel.Tu@Sun.COM break; 39889353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 39899353SSamuel.Tu@Sun.COM if (cause == -1) { 39909353SSamuel.Tu@Sun.COM /* other causes */ 39919353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 39929353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 39939353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 39949353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << index); 39959353SSamuel.Tu@Sun.COM ivar |= (msix_vector << index); 39969353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 39979353SSamuel.Tu@Sun.COM } else { 39989353SSamuel.Tu@Sun.COM /* tx or rx causes */ 39999353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 40009353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 40019353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 40029353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 40039353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << index); 40049353SSamuel.Tu@Sun.COM ivar |= (msix_vector << index); 40059353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 40069353SSamuel.Tu@Sun.COM ivar); 40079353SSamuel.Tu@Sun.COM } 40089353SSamuel.Tu@Sun.COM break; 40099353SSamuel.Tu@Sun.COM default: 40109353SSamuel.Tu@Sun.COM break; 40119353SSamuel.Tu@Sun.COM } 40128275SEric Cheng } 40138275SEric Cheng 40148275SEric Cheng /* 40158275SEric Cheng * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of 40168275SEric Cheng * given interrupt vector allocation register (IVAR). 40179353SSamuel.Tu@Sun.COM * cause: 40189353SSamuel.Tu@Sun.COM * -1 : other cause 40199353SSamuel.Tu@Sun.COM * 0 : rx 40209353SSamuel.Tu@Sun.COM * 1 : tx 40218275SEric Cheng */ 40228275SEric Cheng static void 40239353SSamuel.Tu@Sun.COM ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause) 40248275SEric Cheng { 40258275SEric Cheng struct ixgbe_hw *hw = &ixgbe->hw; 40268275SEric Cheng u32 ivar, index; 40278275SEric Cheng 40289353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 40299353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 40309353SSamuel.Tu@Sun.COM if (cause == -1) { 40319353SSamuel.Tu@Sun.COM cause = 0; 40329353SSamuel.Tu@Sun.COM } 40339353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 40349353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 40359353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 * 40369353SSamuel.Tu@Sun.COM (intr_alloc_entry & 0x3))); 40379353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 40389353SSamuel.Tu@Sun.COM break; 40399353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 40409353SSamuel.Tu@Sun.COM if (cause == -1) { 40419353SSamuel.Tu@Sun.COM /* other causes */ 40429353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 40439353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 40449353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << index); 40459353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 40469353SSamuel.Tu@Sun.COM } else { 40479353SSamuel.Tu@Sun.COM /* tx or rx causes */ 40489353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 40499353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 40509353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 40519353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << index); 40529353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 40539353SSamuel.Tu@Sun.COM ivar); 40549353SSamuel.Tu@Sun.COM } 40559353SSamuel.Tu@Sun.COM break; 40569353SSamuel.Tu@Sun.COM default: 40579353SSamuel.Tu@Sun.COM break; 40589353SSamuel.Tu@Sun.COM } 40598275SEric Cheng } 40608275SEric Cheng 40618275SEric Cheng /* 40629353SSamuel.Tu@Sun.COM * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of 40638275SEric Cheng * given interrupt vector allocation register (IVAR). 40649353SSamuel.Tu@Sun.COM * cause: 40659353SSamuel.Tu@Sun.COM * -1 : other cause 40669353SSamuel.Tu@Sun.COM * 0 : rx 40679353SSamuel.Tu@Sun.COM * 1 : tx 40688275SEric Cheng */ 40698275SEric Cheng static void 40709353SSamuel.Tu@Sun.COM ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause) 40718275SEric Cheng { 40728275SEric Cheng struct ixgbe_hw *hw = &ixgbe->hw; 40738275SEric Cheng u32 ivar, index; 40748275SEric Cheng 40759353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 40769353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 40779353SSamuel.Tu@Sun.COM if (cause == -1) { 40789353SSamuel.Tu@Sun.COM cause = 0; 40799353SSamuel.Tu@Sun.COM } 40809353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 40819353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 40829353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 * 40839353SSamuel.Tu@Sun.COM (intr_alloc_entry & 0x3))); 40849353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 40859353SSamuel.Tu@Sun.COM break; 40869353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 40879353SSamuel.Tu@Sun.COM if (cause == -1) { 40889353SSamuel.Tu@Sun.COM /* other causes */ 40899353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 40909353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 40919353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index); 40929353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 40939353SSamuel.Tu@Sun.COM } else { 40949353SSamuel.Tu@Sun.COM /* tx or rx causes */ 40959353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 40969353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 40979353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 40989353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index); 40999353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 41009353SSamuel.Tu@Sun.COM ivar); 41019353SSamuel.Tu@Sun.COM } 41029353SSamuel.Tu@Sun.COM break; 41039353SSamuel.Tu@Sun.COM default: 41049353SSamuel.Tu@Sun.COM break; 41059353SSamuel.Tu@Sun.COM } 41066621Sbt150084 } 41076621Sbt150084 41086621Sbt150084 /* 41099353SSamuel.Tu@Sun.COM * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors. 41106621Sbt150084 * 41119353SSamuel.Tu@Sun.COM * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt 41129353SSamuel.Tu@Sun.COM * to vector[0 - (intr_cnt -1)]. 41136621Sbt150084 */ 41146621Sbt150084 static int 41159353SSamuel.Tu@Sun.COM ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe) 41166621Sbt150084 { 41176621Sbt150084 int i, vector = 0; 41186621Sbt150084 41196621Sbt150084 /* initialize vector map */ 41206621Sbt150084 bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map)); 41219353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->intr_cnt; i++) { 41229353SSamuel.Tu@Sun.COM ixgbe->vect_map[i].ixgbe = ixgbe; 41239353SSamuel.Tu@Sun.COM } 41246621Sbt150084 41256621Sbt150084 /* 41268275SEric Cheng * non-MSI-X case is very simple: rx rings[0] on RTxQ[0], 41278275SEric Cheng * tx rings[0] on RTxQ[1]. 41286621Sbt150084 */ 41296621Sbt150084 if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) { 41306621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe, 0, 0); 41318275SEric Cheng ixgbe_map_txring_to_vector(ixgbe, 0, 1); 41326621Sbt150084 return (IXGBE_SUCCESS); 41336621Sbt150084 } 41346621Sbt150084 41356621Sbt150084 /* 41369353SSamuel.Tu@Sun.COM * Interrupts/vectors mapping for MSI-X 41376621Sbt150084 */ 41386621Sbt150084 41396621Sbt150084 /* 41409353SSamuel.Tu@Sun.COM * Map other interrupt to vector 0, 41419353SSamuel.Tu@Sun.COM * Set bit in map and count the bits set. 41429353SSamuel.Tu@Sun.COM */ 41439353SSamuel.Tu@Sun.COM BT_SET(ixgbe->vect_map[vector].other_map, 0); 41449353SSamuel.Tu@Sun.COM ixgbe->vect_map[vector].other_cnt++; 41459353SSamuel.Tu@Sun.COM vector++; 41469353SSamuel.Tu@Sun.COM 41479353SSamuel.Tu@Sun.COM /* 41489353SSamuel.Tu@Sun.COM * Map rx ring interrupts to vectors 41496621Sbt150084 */ 41508275SEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) { 41518275SEric Cheng ixgbe_map_rxring_to_vector(ixgbe, i, vector); 41529353SSamuel.Tu@Sun.COM vector = (vector +1) % ixgbe->intr_cnt; 41538275SEric Cheng } 41546621Sbt150084 41556621Sbt150084 /* 41569353SSamuel.Tu@Sun.COM * Map tx ring interrupts to vectors 41576621Sbt150084 */ 41588275SEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) { 41598275SEric Cheng ixgbe_map_txring_to_vector(ixgbe, i, vector); 41609353SSamuel.Tu@Sun.COM vector = (vector +1) % ixgbe->intr_cnt; 41616621Sbt150084 } 41626621Sbt150084 41636621Sbt150084 return (IXGBE_SUCCESS); 41646621Sbt150084 } 41656621Sbt150084 41666621Sbt150084 /* 41676621Sbt150084 * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s). 41686621Sbt150084 * 41698275SEric Cheng * This relies on ring/vector mapping already set up in the 41706621Sbt150084 * vect_map[] structures 41716621Sbt150084 */ 41726621Sbt150084 static void 41736621Sbt150084 ixgbe_setup_adapter_vector(ixgbe_t *ixgbe) 41746621Sbt150084 { 41756621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 41769353SSamuel.Tu@Sun.COM ixgbe_intr_vector_t *vect; /* vector bitmap */ 41778275SEric Cheng int r_idx; /* ring index */ 41788275SEric Cheng int v_idx; /* vector index */ 41796621Sbt150084 41806621Sbt150084 /* 41816621Sbt150084 * Clear any previous entries 41826621Sbt150084 */ 41839353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 41849353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 41859353SSamuel.Tu@Sun.COM for (v_idx = 0; v_idx < 25; v_idx++) 41869353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); 41879353SSamuel.Tu@Sun.COM 41889353SSamuel.Tu@Sun.COM break; 41899353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 41909353SSamuel.Tu@Sun.COM for (v_idx = 0; v_idx < 64; v_idx++) 41919353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); 41929353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0); 41939353SSamuel.Tu@Sun.COM 41949353SSamuel.Tu@Sun.COM break; 41959353SSamuel.Tu@Sun.COM default: 41969353SSamuel.Tu@Sun.COM break; 41979353SSamuel.Tu@Sun.COM } 41986621Sbt150084 41996621Sbt150084 /* 42008275SEric Cheng * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and 42018275SEric Cheng * tx rings[0] will use RTxQ[1]. 42026621Sbt150084 */ 42038275SEric Cheng if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) { 42049353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, 0, 0, 0); 42059353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, 0, 1, 1); 42068275SEric Cheng return; 42078275SEric Cheng } 42088275SEric Cheng 42098275SEric Cheng /* 42109353SSamuel.Tu@Sun.COM * For MSI-X interrupt, "Other" is always on vector[0]. 42118275SEric Cheng */ 42129353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1); 42136621Sbt150084 42146621Sbt150084 /* 42156621Sbt150084 * For each interrupt vector, populate the IVAR table 42166621Sbt150084 */ 42176621Sbt150084 for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) { 42186621Sbt150084 vect = &ixgbe->vect_map[v_idx]; 42196621Sbt150084 42206621Sbt150084 /* 42216621Sbt150084 * For each rx ring bit set 42226621Sbt150084 */ 42236621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, 0, 42246621Sbt150084 (ixgbe->num_rx_rings - 1)); 42256621Sbt150084 42266621Sbt150084 while (r_idx >= 0) { 42279353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 0); 42286621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1), 42296621Sbt150084 (ixgbe->num_rx_rings - 1)); 42306621Sbt150084 } 42316621Sbt150084 42326621Sbt150084 /* 42336621Sbt150084 * For each tx ring bit set 42346621Sbt150084 */ 42356621Sbt150084 r_idx = bt_getlowbit(vect->tx_map, 0, 42366621Sbt150084 (ixgbe->num_tx_rings - 1)); 42376621Sbt150084 42386621Sbt150084 while (r_idx >= 0) { 42399353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1); 42406621Sbt150084 r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1), 42416621Sbt150084 (ixgbe->num_tx_rings - 1)); 42426621Sbt150084 } 42436621Sbt150084 } 42446621Sbt150084 } 42456621Sbt150084 42466621Sbt150084 /* 42476621Sbt150084 * ixgbe_rem_intr_handlers - Remove the interrupt handlers. 42486621Sbt150084 */ 42496621Sbt150084 static void 42506621Sbt150084 ixgbe_rem_intr_handlers(ixgbe_t *ixgbe) 42516621Sbt150084 { 42526621Sbt150084 int i; 42536621Sbt150084 int rc; 42546621Sbt150084 42556621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 42566621Sbt150084 rc = ddi_intr_remove_handler(ixgbe->htable[i]); 42576621Sbt150084 if (rc != DDI_SUCCESS) { 42586621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, 42596621Sbt150084 "Remove intr handler failed: %d", rc); 42606621Sbt150084 } 42616621Sbt150084 } 42626621Sbt150084 } 42636621Sbt150084 42646621Sbt150084 /* 42656621Sbt150084 * ixgbe_rem_intrs - Remove the allocated interrupts. 42666621Sbt150084 */ 42676621Sbt150084 static void 42686621Sbt150084 ixgbe_rem_intrs(ixgbe_t *ixgbe) 42696621Sbt150084 { 42706621Sbt150084 int i; 42716621Sbt150084 int rc; 42726621Sbt150084 42736621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 42746621Sbt150084 rc = ddi_intr_free(ixgbe->htable[i]); 42756621Sbt150084 if (rc != DDI_SUCCESS) { 42766621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, 42776621Sbt150084 "Free intr failed: %d", rc); 42786621Sbt150084 } 42796621Sbt150084 } 42806621Sbt150084 42816621Sbt150084 kmem_free(ixgbe->htable, ixgbe->intr_size); 42826621Sbt150084 ixgbe->htable = NULL; 42836621Sbt150084 } 42846621Sbt150084 42856621Sbt150084 /* 42866621Sbt150084 * ixgbe_enable_intrs - Enable all the ddi interrupts. 42876621Sbt150084 */ 42886621Sbt150084 static int 42896621Sbt150084 ixgbe_enable_intrs(ixgbe_t *ixgbe) 42906621Sbt150084 { 42916621Sbt150084 int i; 42926621Sbt150084 int rc; 42936621Sbt150084 42946621Sbt150084 /* 42956621Sbt150084 * Enable interrupts 42966621Sbt150084 */ 42976621Sbt150084 if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) { 42986621Sbt150084 /* 42996621Sbt150084 * Call ddi_intr_block_enable() for MSI 43006621Sbt150084 */ 43016621Sbt150084 rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt); 43026621Sbt150084 if (rc != DDI_SUCCESS) { 43036621Sbt150084 ixgbe_log(ixgbe, 43046621Sbt150084 "Enable block intr failed: %d", rc); 43056621Sbt150084 return (IXGBE_FAILURE); 43066621Sbt150084 } 43076621Sbt150084 } else { 43086621Sbt150084 /* 43096621Sbt150084 * Call ddi_intr_enable() for Legacy/MSI non block enable 43106621Sbt150084 */ 43116621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 43126621Sbt150084 rc = ddi_intr_enable(ixgbe->htable[i]); 43136621Sbt150084 if (rc != DDI_SUCCESS) { 43146621Sbt150084 ixgbe_log(ixgbe, 43156621Sbt150084 "Enable intr failed: %d", rc); 43166621Sbt150084 return (IXGBE_FAILURE); 43176621Sbt150084 } 43186621Sbt150084 } 43196621Sbt150084 } 43206621Sbt150084 43216621Sbt150084 return (IXGBE_SUCCESS); 43226621Sbt150084 } 43236621Sbt150084 43246621Sbt150084 /* 43256621Sbt150084 * ixgbe_disable_intrs - Disable all the interrupts. 43266621Sbt150084 */ 43276621Sbt150084 static int 43286621Sbt150084 ixgbe_disable_intrs(ixgbe_t *ixgbe) 43296621Sbt150084 { 43306621Sbt150084 int i; 43316621Sbt150084 int rc; 43326621Sbt150084 43336621Sbt150084 /* 43346621Sbt150084 * Disable all interrupts 43356621Sbt150084 */ 43366621Sbt150084 if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) { 43376621Sbt150084 rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt); 43386621Sbt150084 if (rc != DDI_SUCCESS) { 43396621Sbt150084 ixgbe_log(ixgbe, 43406621Sbt150084 "Disable block intr failed: %d", rc); 43416621Sbt150084 return (IXGBE_FAILURE); 43426621Sbt150084 } 43436621Sbt150084 } else { 43446621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 43456621Sbt150084 rc = ddi_intr_disable(ixgbe->htable[i]); 43466621Sbt150084 if (rc != DDI_SUCCESS) { 43476621Sbt150084 ixgbe_log(ixgbe, 43486621Sbt150084 "Disable intr failed: %d", rc); 43496621Sbt150084 return (IXGBE_FAILURE); 43506621Sbt150084 } 43516621Sbt150084 } 43526621Sbt150084 } 43536621Sbt150084 43546621Sbt150084 return (IXGBE_SUCCESS); 43556621Sbt150084 } 43566621Sbt150084 43576621Sbt150084 /* 43586621Sbt150084 * ixgbe_get_hw_state - Get and save parameters related to adapter hardware. 43596621Sbt150084 */ 43606621Sbt150084 static void 43616621Sbt150084 ixgbe_get_hw_state(ixgbe_t *ixgbe) 43626621Sbt150084 { 43636621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 43648490SPaul.Guo@Sun.COM ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN; 43658490SPaul.Guo@Sun.COM boolean_t link_up = B_FALSE; 43666621Sbt150084 uint32_t pcs1g_anlp = 0; 43676621Sbt150084 uint32_t pcs1g_ana = 0; 43686621Sbt150084 43696621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 43706621Sbt150084 ixgbe->param_lp_1000fdx_cap = 0; 43716621Sbt150084 ixgbe->param_lp_100fdx_cap = 0; 43726621Sbt150084 43738490SPaul.Guo@Sun.COM /* check for link, don't wait */ 43748490SPaul.Guo@Sun.COM (void) ixgbe_check_link(hw, &speed, &link_up, false); 43758490SPaul.Guo@Sun.COM if (link_up) { 43766621Sbt150084 pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); 43776621Sbt150084 pcs1g_ana = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); 43786621Sbt150084 43796621Sbt150084 ixgbe->param_lp_1000fdx_cap = 43806621Sbt150084 (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; 43816621Sbt150084 ixgbe->param_lp_100fdx_cap = 43826621Sbt150084 (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; 43836621Sbt150084 } 43846621Sbt150084 438510376SChenlu.Chen@Sun.COM ixgbe->param_adv_1000fdx_cap = 438610376SChenlu.Chen@Sun.COM (pcs1g_ana & IXGBE_PCS1GANA_FDC) ? 1 : 0; 438710376SChenlu.Chen@Sun.COM ixgbe->param_adv_100fdx_cap = (pcs1g_ana & IXGBE_PCS1GANA_FDC) ? 1 : 0; 43886621Sbt150084 } 43896621Sbt150084 43906621Sbt150084 /* 43916621Sbt150084 * ixgbe_get_driver_control - Notify that driver is in control of device. 43926621Sbt150084 */ 43936621Sbt150084 static void 43946621Sbt150084 ixgbe_get_driver_control(struct ixgbe_hw *hw) 43956621Sbt150084 { 43966621Sbt150084 uint32_t ctrl_ext; 43976621Sbt150084 43986621Sbt150084 /* 43996621Sbt150084 * Notify firmware that driver is in control of device 44006621Sbt150084 */ 44016621Sbt150084 ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 44026621Sbt150084 ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 44036621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 44046621Sbt150084 } 44056621Sbt150084 44066621Sbt150084 /* 44076621Sbt150084 * ixgbe_release_driver_control - Notify that driver is no longer in control 44086621Sbt150084 * of device. 44096621Sbt150084 */ 44106621Sbt150084 static void 44116621Sbt150084 ixgbe_release_driver_control(struct ixgbe_hw *hw) 44126621Sbt150084 { 44136621Sbt150084 uint32_t ctrl_ext; 44146621Sbt150084 44156621Sbt150084 /* 44166621Sbt150084 * Notify firmware that driver is no longer in control of device 44176621Sbt150084 */ 44186621Sbt150084 ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 44196621Sbt150084 ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 44206621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 44216621Sbt150084 } 44226621Sbt150084 44236621Sbt150084 /* 44246621Sbt150084 * ixgbe_atomic_reserve - Atomic decrease operation. 44256621Sbt150084 */ 44266621Sbt150084 int 44276621Sbt150084 ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n) 44286621Sbt150084 { 44296621Sbt150084 uint32_t oldval; 44306621Sbt150084 uint32_t newval; 44316621Sbt150084 44326621Sbt150084 /* 44336621Sbt150084 * ATOMICALLY 44346621Sbt150084 */ 44356621Sbt150084 do { 44366621Sbt150084 oldval = *count_p; 44376621Sbt150084 if (oldval < n) 44386621Sbt150084 return (-1); 44396621Sbt150084 newval = oldval - n; 44406621Sbt150084 } while (atomic_cas_32(count_p, oldval, newval) != oldval); 44416621Sbt150084 44426621Sbt150084 return (newval); 44436621Sbt150084 } 44446621Sbt150084 44456621Sbt150084 /* 44466621Sbt150084 * ixgbe_mc_table_itr - Traverse the entries in the multicast table. 44476621Sbt150084 */ 44486621Sbt150084 static uint8_t * 44496621Sbt150084 ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq) 44506621Sbt150084 { 44518490SPaul.Guo@Sun.COM uint8_t *addr = *upd_ptr; 44528490SPaul.Guo@Sun.COM uint8_t *new_ptr; 44538490SPaul.Guo@Sun.COM 44546621Sbt150084 _NOTE(ARGUNUSED(hw)); 44556621Sbt150084 _NOTE(ARGUNUSED(vmdq)); 44566621Sbt150084 44576621Sbt150084 new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; 44586621Sbt150084 *upd_ptr = new_ptr; 44596621Sbt150084 return (addr); 44606621Sbt150084 } 44616621Sbt150084 44626621Sbt150084 /* 44636621Sbt150084 * FMA support 44646621Sbt150084 */ 44656621Sbt150084 int 44666621Sbt150084 ixgbe_check_acc_handle(ddi_acc_handle_t handle) 44676621Sbt150084 { 44686621Sbt150084 ddi_fm_error_t de; 44696621Sbt150084 44706621Sbt150084 ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 44716621Sbt150084 ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 44726621Sbt150084 return (de.fme_status); 44736621Sbt150084 } 44746621Sbt150084 44756621Sbt150084 int 44766621Sbt150084 ixgbe_check_dma_handle(ddi_dma_handle_t handle) 44776621Sbt150084 { 44786621Sbt150084 ddi_fm_error_t de; 44796621Sbt150084 44806621Sbt150084 ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 44816621Sbt150084 return (de.fme_status); 44826621Sbt150084 } 44836621Sbt150084 44846621Sbt150084 /* 44856621Sbt150084 * ixgbe_fm_error_cb - The IO fault service error handling callback function. 44866621Sbt150084 */ 44876621Sbt150084 static int 44886621Sbt150084 ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 44896621Sbt150084 { 44906621Sbt150084 _NOTE(ARGUNUSED(impl_data)); 44916621Sbt150084 /* 44926621Sbt150084 * as the driver can always deal with an error in any dma or 44936621Sbt150084 * access handle, we can just return the fme_status value. 44946621Sbt150084 */ 44956621Sbt150084 pci_ereport_post(dip, err, NULL); 44966621Sbt150084 return (err->fme_status); 44976621Sbt150084 } 44986621Sbt150084 44996621Sbt150084 static void 45006621Sbt150084 ixgbe_fm_init(ixgbe_t *ixgbe) 45016621Sbt150084 { 45026621Sbt150084 ddi_iblock_cookie_t iblk; 45036621Sbt150084 int fma_acc_flag, fma_dma_flag; 45046621Sbt150084 45056621Sbt150084 /* 45066621Sbt150084 * Only register with IO Fault Services if we have some capability 45076621Sbt150084 */ 45086621Sbt150084 if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) { 45096621Sbt150084 ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; 45106621Sbt150084 fma_acc_flag = 1; 45116621Sbt150084 } else { 45126621Sbt150084 ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; 45136621Sbt150084 fma_acc_flag = 0; 45146621Sbt150084 } 45156621Sbt150084 45166621Sbt150084 if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) { 45176621Sbt150084 fma_dma_flag = 1; 45186621Sbt150084 } else { 45196621Sbt150084 fma_dma_flag = 0; 45206621Sbt150084 } 45216621Sbt150084 45226621Sbt150084 ixgbe_set_fma_flags(fma_acc_flag, fma_dma_flag); 45236621Sbt150084 45246621Sbt150084 if (ixgbe->fm_capabilities) { 45256621Sbt150084 45266621Sbt150084 /* 45276621Sbt150084 * Register capabilities with IO Fault Services 45286621Sbt150084 */ 45296621Sbt150084 ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk); 45306621Sbt150084 45316621Sbt150084 /* 45326621Sbt150084 * Initialize pci ereport capabilities if ereport capable 45336621Sbt150084 */ 45346621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) || 45356621Sbt150084 DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 45366621Sbt150084 pci_ereport_setup(ixgbe->dip); 45376621Sbt150084 45386621Sbt150084 /* 45396621Sbt150084 * Register error callback if error callback capable 45406621Sbt150084 */ 45416621Sbt150084 if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 45426621Sbt150084 ddi_fm_handler_register(ixgbe->dip, 45436621Sbt150084 ixgbe_fm_error_cb, (void*) ixgbe); 45446621Sbt150084 } 45456621Sbt150084 } 45466621Sbt150084 45476621Sbt150084 static void 45486621Sbt150084 ixgbe_fm_fini(ixgbe_t *ixgbe) 45496621Sbt150084 { 45506621Sbt150084 /* 45516621Sbt150084 * Only unregister FMA capabilities if they are registered 45526621Sbt150084 */ 45536621Sbt150084 if (ixgbe->fm_capabilities) { 45546621Sbt150084 45556621Sbt150084 /* 45566621Sbt150084 * Release any resources allocated by pci_ereport_setup() 45576621Sbt150084 */ 45586621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) || 45596621Sbt150084 DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 45606621Sbt150084 pci_ereport_teardown(ixgbe->dip); 45616621Sbt150084 45626621Sbt150084 /* 45636621Sbt150084 * Un-register error callback if error callback capable 45646621Sbt150084 */ 45656621Sbt150084 if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 45666621Sbt150084 ddi_fm_handler_unregister(ixgbe->dip); 45676621Sbt150084 45686621Sbt150084 /* 45696621Sbt150084 * Unregister from IO Fault Service 45706621Sbt150084 */ 45716621Sbt150084 ddi_fm_fini(ixgbe->dip); 45726621Sbt150084 } 45736621Sbt150084 } 45746621Sbt150084 45756621Sbt150084 void 45766621Sbt150084 ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail) 45776621Sbt150084 { 45786621Sbt150084 uint64_t ena; 45796621Sbt150084 char buf[FM_MAX_CLASS]; 45806621Sbt150084 45816621Sbt150084 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 45826621Sbt150084 ena = fm_ena_generate(0, FM_ENA_FMT1); 45836621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) { 45846621Sbt150084 ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP, 45856621Sbt150084 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 45866621Sbt150084 } 45876621Sbt150084 } 45888275SEric Cheng 45898275SEric Cheng static int 45908275SEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 45918275SEric Cheng { 45928275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh; 45938275SEric Cheng 45948275SEric Cheng mutex_enter(&rx_ring->rx_lock); 45958275SEric Cheng rx_ring->ring_gen_num = mr_gen_num; 45968275SEric Cheng mutex_exit(&rx_ring->rx_lock); 45978275SEric Cheng return (0); 45988275SEric Cheng } 45998275SEric Cheng 46008275SEric Cheng /* 46018275SEric Cheng * Callback funtion for MAC layer to register all rings. 46028275SEric Cheng */ 46038275SEric Cheng /* ARGSUSED */ 46048275SEric Cheng void 46058275SEric Cheng ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index, 46068275SEric Cheng const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 46078275SEric Cheng { 46088275SEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg; 46098275SEric Cheng mac_intr_t *mintr = &infop->mri_intr; 46108275SEric Cheng 46118275SEric Cheng switch (rtype) { 46128275SEric Cheng case MAC_RING_TYPE_RX: { 46138275SEric Cheng ASSERT(rg_index == 0); 46148275SEric Cheng ASSERT(ring_index < ixgbe->num_rx_rings); 46158275SEric Cheng 46168275SEric Cheng ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[ring_index]; 46178275SEric Cheng rx_ring->ring_handle = rh; 46188275SEric Cheng 46198275SEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 46208275SEric Cheng infop->mri_start = ixgbe_ring_start; 46218275SEric Cheng infop->mri_stop = NULL; 46228275SEric Cheng infop->mri_poll = ixgbe_ring_rx_poll; 46238275SEric Cheng 46248275SEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring; 46258275SEric Cheng mintr->mi_enable = ixgbe_rx_ring_intr_enable; 46268275SEric Cheng mintr->mi_disable = ixgbe_rx_ring_intr_disable; 46278275SEric Cheng 46288275SEric Cheng break; 46298275SEric Cheng } 46308275SEric Cheng case MAC_RING_TYPE_TX: { 46318275SEric Cheng ASSERT(rg_index == -1); 46328275SEric Cheng ASSERT(ring_index < ixgbe->num_tx_rings); 46338275SEric Cheng 46348275SEric Cheng ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index]; 46358275SEric Cheng tx_ring->ring_handle = rh; 46368275SEric Cheng 46378275SEric Cheng infop->mri_driver = (mac_ring_driver_t)tx_ring; 46388275SEric Cheng infop->mri_start = NULL; 46398275SEric Cheng infop->mri_stop = NULL; 46408275SEric Cheng infop->mri_tx = ixgbe_ring_tx; 46418275SEric Cheng 46428275SEric Cheng break; 46438275SEric Cheng } 46448275SEric Cheng default: 46458275SEric Cheng break; 46468275SEric Cheng } 46478275SEric Cheng } 46488275SEric Cheng 46498275SEric Cheng /* 46508275SEric Cheng * Callback funtion for MAC layer to register all groups. 46518275SEric Cheng */ 46528275SEric Cheng void 46538275SEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index, 46548275SEric Cheng mac_group_info_t *infop, mac_group_handle_t gh) 46558275SEric Cheng { 46568275SEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg; 46578275SEric Cheng 46588275SEric Cheng switch (rtype) { 46598275SEric Cheng case MAC_RING_TYPE_RX: { 46608275SEric Cheng ixgbe_rx_group_t *rx_group; 46618275SEric Cheng 46628275SEric Cheng rx_group = &ixgbe->rx_groups[index]; 46638275SEric Cheng rx_group->group_handle = gh; 46648275SEric Cheng 46658275SEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_group; 46668275SEric Cheng infop->mgi_start = NULL; 46678275SEric Cheng infop->mgi_stop = NULL; 46688275SEric Cheng infop->mgi_addmac = ixgbe_addmac; 46698275SEric Cheng infop->mgi_remmac = ixgbe_remmac; 46708275SEric Cheng infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups); 46718275SEric Cheng 46728275SEric Cheng break; 46738275SEric Cheng } 46748275SEric Cheng case MAC_RING_TYPE_TX: 46758275SEric Cheng break; 46768275SEric Cheng default: 46778275SEric Cheng break; 46788275SEric Cheng } 46798275SEric Cheng } 46808275SEric Cheng 46818275SEric Cheng /* 46828275SEric Cheng * Enable interrupt on the specificed rx ring. 46838275SEric Cheng */ 46848275SEric Cheng int 46858275SEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh) 46868275SEric Cheng { 46878275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh; 46888275SEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe; 46898275SEric Cheng int r_idx = rx_ring->index; 46908275SEric Cheng int v_idx = rx_ring->intr_vector; 46918275SEric Cheng 46928275SEric Cheng mutex_enter(&ixgbe->gen_lock); 46938275SEric Cheng ASSERT(BT_TEST(ixgbe->vect_map[v_idx].rx_map, r_idx) == 0); 46948275SEric Cheng 46958275SEric Cheng /* 46968275SEric Cheng * To enable interrupt by setting the VAL bit of given interrupt 46978275SEric Cheng * vector allocation register (IVAR). 46988275SEric Cheng */ 46999353SSamuel.Tu@Sun.COM ixgbe_enable_ivar(ixgbe, r_idx, 0); 47008275SEric Cheng 47018275SEric Cheng BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx); 470210305SPaul.Guo@Sun.COM 470310305SPaul.Guo@Sun.COM /* 470410305SPaul.Guo@Sun.COM * To trigger a Rx interrupt to on this ring 470510305SPaul.Guo@Sun.COM */ 470610305SPaul.Guo@Sun.COM IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx)); 470710305SPaul.Guo@Sun.COM IXGBE_WRITE_FLUSH(&ixgbe->hw); 470810305SPaul.Guo@Sun.COM 47098275SEric Cheng mutex_exit(&ixgbe->gen_lock); 47108275SEric Cheng 47118275SEric Cheng return (0); 47128275SEric Cheng } 47138275SEric Cheng 47148275SEric Cheng /* 47158275SEric Cheng * Disable interrupt on the specificed rx ring. 47168275SEric Cheng */ 47178275SEric Cheng int 47188275SEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh) 47198275SEric Cheng { 47208275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh; 47218275SEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe; 47228275SEric Cheng int r_idx = rx_ring->index; 47238275SEric Cheng int v_idx = rx_ring->intr_vector; 47248275SEric Cheng 47258275SEric Cheng mutex_enter(&ixgbe->gen_lock); 47268275SEric Cheng ASSERT(BT_TEST(ixgbe->vect_map[v_idx].rx_map, r_idx) == 1); 47278275SEric Cheng 47288275SEric Cheng /* 47298275SEric Cheng * To disable interrupt by clearing the VAL bit of given interrupt 47308275SEric Cheng * vector allocation register (IVAR). 47318275SEric Cheng */ 47329353SSamuel.Tu@Sun.COM ixgbe_disable_ivar(ixgbe, r_idx, 0); 47338275SEric Cheng 47348275SEric Cheng BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx); 47358275SEric Cheng 47368275SEric Cheng mutex_exit(&ixgbe->gen_lock); 47378275SEric Cheng 47388275SEric Cheng return (0); 47398275SEric Cheng } 47408275SEric Cheng 47418275SEric Cheng /* 47428275SEric Cheng * Add a mac address. 47438275SEric Cheng */ 47448275SEric Cheng static int 47458275SEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr) 47468275SEric Cheng { 47478275SEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg; 47488275SEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe; 47498275SEric Cheng int slot; 47508275SEric Cheng int err; 47518275SEric Cheng 47528275SEric Cheng mutex_enter(&ixgbe->gen_lock); 47538275SEric Cheng 47548275SEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 47558275SEric Cheng mutex_exit(&ixgbe->gen_lock); 47568275SEric Cheng return (ECANCELED); 47578275SEric Cheng } 47588275SEric Cheng 47598275SEric Cheng if (ixgbe->unicst_avail == 0) { 47608275SEric Cheng /* no slots available */ 47618275SEric Cheng mutex_exit(&ixgbe->gen_lock); 47628275SEric Cheng return (ENOSPC); 47638275SEric Cheng } 47648275SEric Cheng 47658275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 47668275SEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 0) 47678275SEric Cheng break; 47688275SEric Cheng } 47698275SEric Cheng 47708275SEric Cheng ASSERT((slot >= 0) && (slot < ixgbe->unicst_total)); 47718275SEric Cheng 47728275SEric Cheng if ((err = ixgbe_unicst_set(ixgbe, mac_addr, slot)) == 0) { 47738275SEric Cheng ixgbe->unicst_addr[slot].mac.set = 1; 47748275SEric Cheng ixgbe->unicst_avail--; 47758275SEric Cheng } 47768275SEric Cheng 47778275SEric Cheng mutex_exit(&ixgbe->gen_lock); 47788275SEric Cheng 47798275SEric Cheng return (err); 47808275SEric Cheng } 47818275SEric Cheng 47828275SEric Cheng /* 47838275SEric Cheng * Remove a mac address. 47848275SEric Cheng */ 47858275SEric Cheng static int 47868275SEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr) 47878275SEric Cheng { 47888275SEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg; 47898275SEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe; 47908275SEric Cheng int slot; 47918275SEric Cheng int err; 47928275SEric Cheng 47938275SEric Cheng mutex_enter(&ixgbe->gen_lock); 47948275SEric Cheng 47958275SEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 47968275SEric Cheng mutex_exit(&ixgbe->gen_lock); 47978275SEric Cheng return (ECANCELED); 47988275SEric Cheng } 47998275SEric Cheng 48008275SEric Cheng slot = ixgbe_unicst_find(ixgbe, mac_addr); 48018275SEric Cheng if (slot == -1) { 48028275SEric Cheng mutex_exit(&ixgbe->gen_lock); 48038275SEric Cheng return (EINVAL); 48048275SEric Cheng } 48058275SEric Cheng 48068275SEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 0) { 48078275SEric Cheng mutex_exit(&ixgbe->gen_lock); 48088275SEric Cheng return (EINVAL); 48098275SEric Cheng } 48108275SEric Cheng 48118275SEric Cheng bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL); 48128275SEric Cheng if ((err = ixgbe_unicst_set(ixgbe, 48138275SEric Cheng ixgbe->unicst_addr[slot].mac.addr, slot)) == 0) { 48148275SEric Cheng ixgbe->unicst_addr[slot].mac.set = 0; 48158275SEric Cheng ixgbe->unicst_avail++; 48168275SEric Cheng } 48178275SEric Cheng 48188275SEric Cheng mutex_exit(&ixgbe->gen_lock); 48198275SEric Cheng 48208275SEric Cheng return (err); 48218275SEric Cheng } 4822