16621Sbt150084 /* 26621Sbt150084 * CDDL HEADER START 36621Sbt150084 * 46621Sbt150084 * The contents of this file are subject to the terms of the 56621Sbt150084 * Common Development and Distribution License (the "License"). 66621Sbt150084 * You may not use this file except in compliance with the License. 76621Sbt150084 * 87656SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97656SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing. 106621Sbt150084 * See the License for the specific language governing permissions 116621Sbt150084 * and limitations under the License. 126621Sbt150084 * 137656SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147656SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156621Sbt150084 * If applicable, add the following below this CDDL HEADER, with the 166621Sbt150084 * fields enclosed by brackets "[]" replaced with your own identifying 176621Sbt150084 * information: Portions Copyright [yyyy] [name of copyright owner] 186621Sbt150084 * 196621Sbt150084 * CDDL HEADER END 206621Sbt150084 */ 216621Sbt150084 226621Sbt150084 /* 23*12280SChenlu.Chen@Sun.COM * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. 24*12280SChenlu.Chen@Sun.COM */ 25*12280SChenlu.Chen@Sun.COM 26*12280SChenlu.Chen@Sun.COM /* 27*12280SChenlu.Chen@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 287656SSherry.Moore@Sun.COM */ 297656SSherry.Moore@Sun.COM 306621Sbt150084 #include "ixgbe_sw.h" 316621Sbt150084 3211486SZhen.W@Sun.COM static char ixgbe_ident[] = "Intel 10Gb Ethernet"; 33*12280SChenlu.Chen@Sun.COM static char ixgbe_version[] = "ixgbe 1.1.6"; 346621Sbt150084 356621Sbt150084 /* 366621Sbt150084 * Local function protoypes 376621Sbt150084 */ 386621Sbt150084 static int ixgbe_register_mac(ixgbe_t *); 396621Sbt150084 static int ixgbe_identify_hardware(ixgbe_t *); 406621Sbt150084 static int ixgbe_regs_map(ixgbe_t *); 416621Sbt150084 static void ixgbe_init_properties(ixgbe_t *); 426621Sbt150084 static int ixgbe_init_driver_settings(ixgbe_t *); 436621Sbt150084 static void ixgbe_init_locks(ixgbe_t *); 446621Sbt150084 static void ixgbe_destroy_locks(ixgbe_t *); 456621Sbt150084 static int ixgbe_init(ixgbe_t *); 466621Sbt150084 static int ixgbe_chip_start(ixgbe_t *); 476621Sbt150084 static void ixgbe_chip_stop(ixgbe_t *); 486621Sbt150084 static int ixgbe_reset(ixgbe_t *); 496621Sbt150084 static void ixgbe_tx_clean(ixgbe_t *); 506621Sbt150084 static boolean_t ixgbe_tx_drain(ixgbe_t *); 516621Sbt150084 static boolean_t ixgbe_rx_drain(ixgbe_t *); 526621Sbt150084 static int ixgbe_alloc_rings(ixgbe_t *); 536621Sbt150084 static void ixgbe_free_rings(ixgbe_t *); 5410376SChenlu.Chen@Sun.COM static int ixgbe_alloc_rx_data(ixgbe_t *); 5510376SChenlu.Chen@Sun.COM static void ixgbe_free_rx_data(ixgbe_t *); 566621Sbt150084 static void ixgbe_setup_rings(ixgbe_t *); 576621Sbt150084 static void ixgbe_setup_rx(ixgbe_t *); 586621Sbt150084 static void ixgbe_setup_tx(ixgbe_t *); 596621Sbt150084 static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *); 606621Sbt150084 static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *); 616621Sbt150084 static void ixgbe_setup_rss(ixgbe_t *); 6211878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq(ixgbe_t *); 6311878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq_rss(ixgbe_t *); 646621Sbt150084 static void ixgbe_init_unicst(ixgbe_t *); 658275SEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *); 666621Sbt150084 static void ixgbe_setup_multicst(ixgbe_t *); 676621Sbt150084 static void ixgbe_get_hw_state(ixgbe_t *); 6811878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe); 696621Sbt150084 static void ixgbe_get_conf(ixgbe_t *); 7010376SChenlu.Chen@Sun.COM static void ixgbe_init_params(ixgbe_t *); 716621Sbt150084 static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int); 7211233SPaul.Guo@Sun.COM static void ixgbe_driver_link_check(ixgbe_t *); 739353SSamuel.Tu@Sun.COM static void ixgbe_sfp_check(void *); 7411233SPaul.Guo@Sun.COM static void ixgbe_link_timer(void *); 756621Sbt150084 static void ixgbe_local_timer(void *); 766621Sbt150084 static void ixgbe_arm_watchdog_timer(ixgbe_t *); 776621Sbt150084 static void ixgbe_restart_watchdog_timer(ixgbe_t *); 786621Sbt150084 static void ixgbe_disable_adapter_interrupts(ixgbe_t *); 796621Sbt150084 static void ixgbe_enable_adapter_interrupts(ixgbe_t *); 806621Sbt150084 static boolean_t is_valid_mac_addr(uint8_t *); 816621Sbt150084 static boolean_t ixgbe_stall_check(ixgbe_t *); 826621Sbt150084 static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t); 836621Sbt150084 static void ixgbe_set_internal_mac_loopback(ixgbe_t *); 846621Sbt150084 static boolean_t ixgbe_find_mac_address(ixgbe_t *); 856621Sbt150084 static int ixgbe_alloc_intrs(ixgbe_t *); 866621Sbt150084 static int ixgbe_alloc_intr_handles(ixgbe_t *, int); 876621Sbt150084 static int ixgbe_add_intr_handlers(ixgbe_t *); 886621Sbt150084 static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int); 896621Sbt150084 static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int); 909353SSamuel.Tu@Sun.COM static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t); 919353SSamuel.Tu@Sun.COM static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t); 929353SSamuel.Tu@Sun.COM static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t); 9311878SVenu.Iyer@Sun.COM static uint32_t ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index); 949353SSamuel.Tu@Sun.COM static int ixgbe_map_intrs_to_vectors(ixgbe_t *); 956621Sbt150084 static void ixgbe_setup_adapter_vector(ixgbe_t *); 966621Sbt150084 static void ixgbe_rem_intr_handlers(ixgbe_t *); 976621Sbt150084 static void ixgbe_rem_intrs(ixgbe_t *); 986621Sbt150084 static int ixgbe_enable_intrs(ixgbe_t *); 996621Sbt150084 static int ixgbe_disable_intrs(ixgbe_t *); 1006621Sbt150084 static uint_t ixgbe_intr_legacy(void *, void *); 1016621Sbt150084 static uint_t ixgbe_intr_msi(void *, void *); 1029353SSamuel.Tu@Sun.COM static uint_t ixgbe_intr_msix(void *, void *); 1036621Sbt150084 static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *); 1046621Sbt150084 static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *); 1058490SPaul.Guo@Sun.COM static void ixgbe_intr_other_work(ixgbe_t *, uint32_t); 1066621Sbt150084 static void ixgbe_get_driver_control(struct ixgbe_hw *); 1078275SEric Cheng static int ixgbe_addmac(void *, const uint8_t *); 1088275SEric Cheng static int ixgbe_remmac(void *, const uint8_t *); 1096621Sbt150084 static void ixgbe_release_driver_control(struct ixgbe_hw *); 1106621Sbt150084 1116621Sbt150084 static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t); 1126621Sbt150084 static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t); 1136621Sbt150084 static int ixgbe_resume(dev_info_t *); 1146621Sbt150084 static int ixgbe_suspend(dev_info_t *); 1156621Sbt150084 static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *); 1166621Sbt150084 static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *); 11711878SVenu.Iyer@Sun.COM static int ixgbe_cbfunc(dev_info_t *, ddi_cb_action_t, void *, void *, void *); 11811878SVenu.Iyer@Sun.COM static int ixgbe_intr_cb_register(ixgbe_t *); 11911878SVenu.Iyer@Sun.COM static int ixgbe_intr_adjust(ixgbe_t *, ddi_cb_action_t, int); 1206621Sbt150084 1216621Sbt150084 static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, 1226621Sbt150084 const void *impl_data); 1236621Sbt150084 static void ixgbe_fm_init(ixgbe_t *); 1246621Sbt150084 static void ixgbe_fm_fini(ixgbe_t *); 1256621Sbt150084 12611878SVenu.Iyer@Sun.COM char *ixgbe_priv_props[] = { 12711878SVenu.Iyer@Sun.COM "_tx_copy_thresh", 12811878SVenu.Iyer@Sun.COM "_tx_recycle_thresh", 12911878SVenu.Iyer@Sun.COM "_tx_overload_thresh", 13011878SVenu.Iyer@Sun.COM "_tx_resched_thresh", 13111878SVenu.Iyer@Sun.COM "_rx_copy_thresh", 13211878SVenu.Iyer@Sun.COM "_rx_limit_per_intr", 13311878SVenu.Iyer@Sun.COM "_intr_throttling", 13411878SVenu.Iyer@Sun.COM "_adv_pause_cap", 13511878SVenu.Iyer@Sun.COM "_adv_asym_pause_cap", 13611878SVenu.Iyer@Sun.COM NULL 13710376SChenlu.Chen@Sun.COM }; 13810376SChenlu.Chen@Sun.COM 13910376SChenlu.Chen@Sun.COM #define IXGBE_MAX_PRIV_PROPS \ 14010376SChenlu.Chen@Sun.COM (sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t)) 14110376SChenlu.Chen@Sun.COM 1426621Sbt150084 static struct cb_ops ixgbe_cb_ops = { 1436621Sbt150084 nulldev, /* cb_open */ 1446621Sbt150084 nulldev, /* cb_close */ 1456621Sbt150084 nodev, /* cb_strategy */ 1466621Sbt150084 nodev, /* cb_print */ 1476621Sbt150084 nodev, /* cb_dump */ 1486621Sbt150084 nodev, /* cb_read */ 1496621Sbt150084 nodev, /* cb_write */ 1506621Sbt150084 nodev, /* cb_ioctl */ 1516621Sbt150084 nodev, /* cb_devmap */ 1526621Sbt150084 nodev, /* cb_mmap */ 1536621Sbt150084 nodev, /* cb_segmap */ 1546621Sbt150084 nochpoll, /* cb_chpoll */ 1556621Sbt150084 ddi_prop_op, /* cb_prop_op */ 1566621Sbt150084 NULL, /* cb_stream */ 1576621Sbt150084 D_MP | D_HOTPLUG, /* cb_flag */ 1586621Sbt150084 CB_REV, /* cb_rev */ 1596621Sbt150084 nodev, /* cb_aread */ 1606621Sbt150084 nodev /* cb_awrite */ 1616621Sbt150084 }; 1626621Sbt150084 1636621Sbt150084 static struct dev_ops ixgbe_dev_ops = { 1646621Sbt150084 DEVO_REV, /* devo_rev */ 1656621Sbt150084 0, /* devo_refcnt */ 1666621Sbt150084 NULL, /* devo_getinfo */ 1676621Sbt150084 nulldev, /* devo_identify */ 1686621Sbt150084 nulldev, /* devo_probe */ 1696621Sbt150084 ixgbe_attach, /* devo_attach */ 1706621Sbt150084 ixgbe_detach, /* devo_detach */ 1716621Sbt150084 nodev, /* devo_reset */ 1726621Sbt150084 &ixgbe_cb_ops, /* devo_cb_ops */ 1736621Sbt150084 NULL, /* devo_bus_ops */ 1747656SSherry.Moore@Sun.COM ddi_power, /* devo_power */ 1757656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 1766621Sbt150084 }; 1776621Sbt150084 1786621Sbt150084 static struct modldrv ixgbe_modldrv = { 1796621Sbt150084 &mod_driverops, /* Type of module. This one is a driver */ 18011486SZhen.W@Sun.COM ixgbe_ident, /* Discription string */ 1816621Sbt150084 &ixgbe_dev_ops /* driver ops */ 1826621Sbt150084 }; 1836621Sbt150084 1846621Sbt150084 static struct modlinkage ixgbe_modlinkage = { 1856621Sbt150084 MODREV_1, &ixgbe_modldrv, NULL 1866621Sbt150084 }; 1876621Sbt150084 1886621Sbt150084 /* 1896621Sbt150084 * Access attributes for register mapping 1906621Sbt150084 */ 1916621Sbt150084 ddi_device_acc_attr_t ixgbe_regs_acc_attr = { 19211236SStephen.Hanson@Sun.COM DDI_DEVICE_ATTR_V1, 1936621Sbt150084 DDI_STRUCTURE_LE_ACC, 1946621Sbt150084 DDI_STRICTORDER_ACC, 1956621Sbt150084 DDI_FLAGERR_ACC 1966621Sbt150084 }; 1976621Sbt150084 1986621Sbt150084 /* 1996621Sbt150084 * Loopback property 2006621Sbt150084 */ 2016621Sbt150084 static lb_property_t lb_normal = { 2026621Sbt150084 normal, "normal", IXGBE_LB_NONE 2036621Sbt150084 }; 2046621Sbt150084 2056621Sbt150084 static lb_property_t lb_mac = { 2066621Sbt150084 internal, "MAC", IXGBE_LB_INTERNAL_MAC 2076621Sbt150084 }; 2086621Sbt150084 20911150SZhen.W@Sun.COM static lb_property_t lb_external = { 21011150SZhen.W@Sun.COM external, "External", IXGBE_LB_EXTERNAL 21111150SZhen.W@Sun.COM }; 21211150SZhen.W@Sun.COM 21310376SChenlu.Chen@Sun.COM #define IXGBE_M_CALLBACK_FLAGS \ 21411878SVenu.Iyer@Sun.COM (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 2156621Sbt150084 2166621Sbt150084 static mac_callbacks_t ixgbe_m_callbacks = { 2176621Sbt150084 IXGBE_M_CALLBACK_FLAGS, 2186621Sbt150084 ixgbe_m_stat, 2196621Sbt150084 ixgbe_m_start, 2206621Sbt150084 ixgbe_m_stop, 2216621Sbt150084 ixgbe_m_promisc, 2226621Sbt150084 ixgbe_m_multicst, 2238275SEric Cheng NULL, 2246621Sbt150084 NULL, 22511878SVenu.Iyer@Sun.COM NULL, 2266621Sbt150084 ixgbe_m_ioctl, 22710376SChenlu.Chen@Sun.COM ixgbe_m_getcapab, 22810376SChenlu.Chen@Sun.COM NULL, 22910376SChenlu.Chen@Sun.COM NULL, 23010376SChenlu.Chen@Sun.COM ixgbe_m_setprop, 23111878SVenu.Iyer@Sun.COM ixgbe_m_getprop, 23211878SVenu.Iyer@Sun.COM ixgbe_m_propinfo 2336621Sbt150084 }; 2346621Sbt150084 2356621Sbt150084 /* 2368490SPaul.Guo@Sun.COM * Initialize capabilities of each supported adapter type 2378490SPaul.Guo@Sun.COM */ 2388490SPaul.Guo@Sun.COM static adapter_info_t ixgbe_82598eb_cap = { 2398490SPaul.Guo@Sun.COM 64, /* maximum number of rx queues */ 2408490SPaul.Guo@Sun.COM 1, /* minimum number of rx queues */ 24111878SVenu.Iyer@Sun.COM 64, /* default number of rx queues */ 24211878SVenu.Iyer@Sun.COM 16, /* maximum number of rx groups */ 24311878SVenu.Iyer@Sun.COM 1, /* minimum number of rx groups */ 24411878SVenu.Iyer@Sun.COM 1, /* default number of rx groups */ 2458490SPaul.Guo@Sun.COM 32, /* maximum number of tx queues */ 2468490SPaul.Guo@Sun.COM 1, /* minimum number of tx queues */ 2478490SPaul.Guo@Sun.COM 8, /* default number of tx queues */ 24811150SZhen.W@Sun.COM 16366, /* maximum MTU size */ 24910376SChenlu.Chen@Sun.COM 0xFFFF, /* maximum interrupt throttle rate */ 25010376SChenlu.Chen@Sun.COM 0, /* minimum interrupt throttle rate */ 25110376SChenlu.Chen@Sun.COM 200, /* default interrupt throttle rate */ 2528490SPaul.Guo@Sun.COM 18, /* maximum total msix vectors */ 2538490SPaul.Guo@Sun.COM 16, /* maximum number of ring vectors */ 2548490SPaul.Guo@Sun.COM 2, /* maximum number of other vectors */ 2558490SPaul.Guo@Sun.COM IXGBE_EICR_LSC, /* "other" interrupt types handled */ 2568490SPaul.Guo@Sun.COM (IXGBE_FLAG_DCA_CAPABLE /* capability flags */ 2578490SPaul.Guo@Sun.COM | IXGBE_FLAG_RSS_CAPABLE 2588490SPaul.Guo@Sun.COM | IXGBE_FLAG_VMDQ_CAPABLE) 2598490SPaul.Guo@Sun.COM }; 2608490SPaul.Guo@Sun.COM 2619353SSamuel.Tu@Sun.COM static adapter_info_t ixgbe_82599eb_cap = { 2629353SSamuel.Tu@Sun.COM 128, /* maximum number of rx queues */ 2639353SSamuel.Tu@Sun.COM 1, /* minimum number of rx queues */ 26411878SVenu.Iyer@Sun.COM 128, /* default number of rx queues */ 26511878SVenu.Iyer@Sun.COM 64, /* maximum number of rx groups */ 26611878SVenu.Iyer@Sun.COM 1, /* minimum number of rx groups */ 26711878SVenu.Iyer@Sun.COM 1, /* default number of rx groups */ 2689353SSamuel.Tu@Sun.COM 128, /* maximum number of tx queues */ 2699353SSamuel.Tu@Sun.COM 1, /* minimum number of tx queues */ 2709353SSamuel.Tu@Sun.COM 8, /* default number of tx queues */ 27111150SZhen.W@Sun.COM 15500, /* maximum MTU size */ 27210376SChenlu.Chen@Sun.COM 0xFF8, /* maximum interrupt throttle rate */ 27310376SChenlu.Chen@Sun.COM 0, /* minimum interrupt throttle rate */ 27410376SChenlu.Chen@Sun.COM 200, /* default interrupt throttle rate */ 2759353SSamuel.Tu@Sun.COM 64, /* maximum total msix vectors */ 2769353SSamuel.Tu@Sun.COM 16, /* maximum number of ring vectors */ 2779353SSamuel.Tu@Sun.COM 2, /* maximum number of other vectors */ 2789353SSamuel.Tu@Sun.COM IXGBE_EICR_LSC, /* "other" interrupt types handled */ 2799353SSamuel.Tu@Sun.COM (IXGBE_FLAG_DCA_CAPABLE /* capability flags */ 2809353SSamuel.Tu@Sun.COM | IXGBE_FLAG_RSS_CAPABLE 28111486SZhen.W@Sun.COM | IXGBE_FLAG_VMDQ_CAPABLE 28211486SZhen.W@Sun.COM | IXGBE_FLAG_RSC_CAPABLE) 2839353SSamuel.Tu@Sun.COM }; 2849353SSamuel.Tu@Sun.COM 2858490SPaul.Guo@Sun.COM /* 2866621Sbt150084 * Module Initialization Functions. 2876621Sbt150084 */ 2886621Sbt150084 2896621Sbt150084 int 2906621Sbt150084 _init(void) 2916621Sbt150084 { 2926621Sbt150084 int status; 2936621Sbt150084 2946621Sbt150084 mac_init_ops(&ixgbe_dev_ops, MODULE_NAME); 2956621Sbt150084 2966621Sbt150084 status = mod_install(&ixgbe_modlinkage); 2976621Sbt150084 2986621Sbt150084 if (status != DDI_SUCCESS) { 2996621Sbt150084 mac_fini_ops(&ixgbe_dev_ops); 3006621Sbt150084 } 3016621Sbt150084 3026621Sbt150084 return (status); 3036621Sbt150084 } 3046621Sbt150084 3056621Sbt150084 int 3066621Sbt150084 _fini(void) 3076621Sbt150084 { 3086621Sbt150084 int status; 3096621Sbt150084 3106621Sbt150084 status = mod_remove(&ixgbe_modlinkage); 3116621Sbt150084 3126621Sbt150084 if (status == DDI_SUCCESS) { 3136621Sbt150084 mac_fini_ops(&ixgbe_dev_ops); 3146621Sbt150084 } 3156621Sbt150084 3166621Sbt150084 return (status); 3176621Sbt150084 } 3186621Sbt150084 3196621Sbt150084 int 3206621Sbt150084 _info(struct modinfo *modinfop) 3216621Sbt150084 { 3226621Sbt150084 int status; 3236621Sbt150084 3246621Sbt150084 status = mod_info(&ixgbe_modlinkage, modinfop); 3256621Sbt150084 3266621Sbt150084 return (status); 3276621Sbt150084 } 3286621Sbt150084 3296621Sbt150084 /* 3306621Sbt150084 * ixgbe_attach - Driver attach. 3316621Sbt150084 * 3326621Sbt150084 * This function is the device specific initialization entry 3336621Sbt150084 * point. This entry point is required and must be written. 3346621Sbt150084 * The DDI_ATTACH command must be provided in the attach entry 3356621Sbt150084 * point. When attach() is called with cmd set to DDI_ATTACH, 3366621Sbt150084 * all normal kernel services (such as kmem_alloc(9F)) are 3376621Sbt150084 * available for use by the driver. 3386621Sbt150084 * 3396621Sbt150084 * The attach() function will be called once for each instance 3406621Sbt150084 * of the device on the system with cmd set to DDI_ATTACH. 3416621Sbt150084 * Until attach() succeeds, the only driver entry points which 3426621Sbt150084 * may be called are open(9E) and getinfo(9E). 3436621Sbt150084 */ 3446621Sbt150084 static int 3456621Sbt150084 ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 3466621Sbt150084 { 3476621Sbt150084 ixgbe_t *ixgbe; 3486621Sbt150084 struct ixgbe_osdep *osdep; 3496621Sbt150084 struct ixgbe_hw *hw; 3506621Sbt150084 int instance; 3518490SPaul.Guo@Sun.COM char taskqname[32]; 3526621Sbt150084 3536621Sbt150084 /* 3546621Sbt150084 * Check the command and perform corresponding operations 3556621Sbt150084 */ 3566621Sbt150084 switch (cmd) { 3576621Sbt150084 default: 3586621Sbt150084 return (DDI_FAILURE); 3596621Sbt150084 3606621Sbt150084 case DDI_RESUME: 3616621Sbt150084 return (ixgbe_resume(devinfo)); 3626621Sbt150084 3636621Sbt150084 case DDI_ATTACH: 3646621Sbt150084 break; 3656621Sbt150084 } 3666621Sbt150084 3676621Sbt150084 /* Get the device instance */ 3686621Sbt150084 instance = ddi_get_instance(devinfo); 3696621Sbt150084 3706621Sbt150084 /* Allocate memory for the instance data structure */ 3716621Sbt150084 ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP); 3726621Sbt150084 3736621Sbt150084 ixgbe->dip = devinfo; 3746621Sbt150084 ixgbe->instance = instance; 3756621Sbt150084 3766621Sbt150084 hw = &ixgbe->hw; 3776621Sbt150084 osdep = &ixgbe->osdep; 3786621Sbt150084 hw->back = osdep; 3796621Sbt150084 osdep->ixgbe = ixgbe; 3806621Sbt150084 3816621Sbt150084 /* Attach the instance pointer to the dev_info data structure */ 3826621Sbt150084 ddi_set_driver_private(devinfo, ixgbe); 3836621Sbt150084 3846621Sbt150084 /* 3856621Sbt150084 * Initialize for fma support 3866621Sbt150084 */ 3877167Sgg161487 ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE, 3886621Sbt150084 0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 3896621Sbt150084 DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 3906621Sbt150084 ixgbe_fm_init(ixgbe); 3916621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT; 3926621Sbt150084 3936621Sbt150084 /* 3946621Sbt150084 * Map PCI config space registers 3956621Sbt150084 */ 3966621Sbt150084 if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) { 3976621Sbt150084 ixgbe_error(ixgbe, "Failed to map PCI configurations"); 3986621Sbt150084 goto attach_fail; 3996621Sbt150084 } 4006621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG; 4016621Sbt150084 4026621Sbt150084 /* 4036621Sbt150084 * Identify the chipset family 4046621Sbt150084 */ 4056621Sbt150084 if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) { 4066621Sbt150084 ixgbe_error(ixgbe, "Failed to identify hardware"); 4076621Sbt150084 goto attach_fail; 4086621Sbt150084 } 4096621Sbt150084 4106621Sbt150084 /* 4116621Sbt150084 * Map device registers 4126621Sbt150084 */ 4136621Sbt150084 if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) { 4146621Sbt150084 ixgbe_error(ixgbe, "Failed to map device registers"); 4156621Sbt150084 goto attach_fail; 4166621Sbt150084 } 4176621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP; 4186621Sbt150084 4196621Sbt150084 /* 4206621Sbt150084 * Initialize driver parameters 4216621Sbt150084 */ 4226621Sbt150084 ixgbe_init_properties(ixgbe); 4236621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS; 4246621Sbt150084 4256621Sbt150084 /* 42611878SVenu.Iyer@Sun.COM * Register interrupt callback 42711878SVenu.Iyer@Sun.COM */ 42811878SVenu.Iyer@Sun.COM if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) { 42911878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, "Failed to register interrupt callback"); 43011878SVenu.Iyer@Sun.COM goto attach_fail; 43111878SVenu.Iyer@Sun.COM } 43211878SVenu.Iyer@Sun.COM 43311878SVenu.Iyer@Sun.COM /* 4346621Sbt150084 * Allocate interrupts 4356621Sbt150084 */ 4366621Sbt150084 if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) { 4376621Sbt150084 ixgbe_error(ixgbe, "Failed to allocate interrupts"); 4386621Sbt150084 goto attach_fail; 4396621Sbt150084 } 4406621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR; 4416621Sbt150084 4426621Sbt150084 /* 4436621Sbt150084 * Allocate rx/tx rings based on the ring numbers. 4446621Sbt150084 * The actual numbers of rx/tx rings are decided by the number of 4456621Sbt150084 * allocated interrupt vectors, so we should allocate the rings after 4466621Sbt150084 * interrupts are allocated. 4476621Sbt150084 */ 4486621Sbt150084 if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) { 4496621Sbt150084 ixgbe_error(ixgbe, "Failed to allocate rx and tx rings"); 4506621Sbt150084 goto attach_fail; 4516621Sbt150084 } 4526621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS; 4536621Sbt150084 4546621Sbt150084 /* 4556621Sbt150084 * Map rings to interrupt vectors 4566621Sbt150084 */ 4579353SSamuel.Tu@Sun.COM if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) { 4589353SSamuel.Tu@Sun.COM ixgbe_error(ixgbe, "Failed to map interrupts to vectors"); 4596621Sbt150084 goto attach_fail; 4606621Sbt150084 } 4616621Sbt150084 4626621Sbt150084 /* 4636621Sbt150084 * Add interrupt handlers 4646621Sbt150084 */ 4656621Sbt150084 if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) { 4666621Sbt150084 ixgbe_error(ixgbe, "Failed to add interrupt handlers"); 4676621Sbt150084 goto attach_fail; 4686621Sbt150084 } 4696621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 4706621Sbt150084 4716621Sbt150084 /* 47211233SPaul.Guo@Sun.COM * Create a taskq for sfp-change 4738490SPaul.Guo@Sun.COM */ 4748490SPaul.Guo@Sun.COM (void) sprintf(taskqname, "ixgbe%d_taskq", instance); 47511233SPaul.Guo@Sun.COM if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname, 4768490SPaul.Guo@Sun.COM 1, TASKQ_DEFAULTPRI, 0)) == NULL) { 4778490SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "taskq_create failed"); 4788490SPaul.Guo@Sun.COM goto attach_fail; 4798490SPaul.Guo@Sun.COM } 48011233SPaul.Guo@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ; 4818490SPaul.Guo@Sun.COM 4828490SPaul.Guo@Sun.COM /* 4836621Sbt150084 * Initialize driver parameters 4846621Sbt150084 */ 4856621Sbt150084 if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) { 4866621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize driver settings"); 4876621Sbt150084 goto attach_fail; 4886621Sbt150084 } 4896621Sbt150084 4906621Sbt150084 /* 4916621Sbt150084 * Initialize mutexes for this device. 4926621Sbt150084 * Do this before enabling the interrupt handler and 4936621Sbt150084 * register the softint to avoid the condition where 4946621Sbt150084 * interrupt handler can try using uninitialized mutex. 4956621Sbt150084 */ 4966621Sbt150084 ixgbe_init_locks(ixgbe); 4976621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS; 4986621Sbt150084 4996621Sbt150084 /* 5006621Sbt150084 * Initialize chipset hardware 5016621Sbt150084 */ 5026621Sbt150084 if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) { 5036621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize adapter"); 5046621Sbt150084 goto attach_fail; 5056621Sbt150084 } 50611233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 50711233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 50811233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 5096621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_INIT; 5106621Sbt150084 5116621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) { 5126621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 5136621Sbt150084 goto attach_fail; 5146621Sbt150084 } 5156621Sbt150084 5166621Sbt150084 /* 5176621Sbt150084 * Initialize statistics 5186621Sbt150084 */ 5196621Sbt150084 if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) { 5206621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize statistics"); 5216621Sbt150084 goto attach_fail; 5226621Sbt150084 } 5236621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_STATS; 5246621Sbt150084 5256621Sbt150084 /* 5266621Sbt150084 * Register the driver to the MAC 5276621Sbt150084 */ 5286621Sbt150084 if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) { 5296621Sbt150084 ixgbe_error(ixgbe, "Failed to register MAC"); 5306621Sbt150084 goto attach_fail; 5316621Sbt150084 } 5328490SPaul.Guo@Sun.COM mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN); 5336621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_MAC; 5346621Sbt150084 53511233SPaul.Guo@Sun.COM ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe, 53611233SPaul.Guo@Sun.COM IXGBE_CYCLIC_PERIOD, DDI_IPL_0); 53711233SPaul.Guo@Sun.COM if (ixgbe->periodic_id == 0) { 53811233SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "Failed to add the link check timer"); 53911233SPaul.Guo@Sun.COM goto attach_fail; 54011233SPaul.Guo@Sun.COM } 54111233SPaul.Guo@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER; 54211233SPaul.Guo@Sun.COM 5436621Sbt150084 /* 5446621Sbt150084 * Now that mutex locks are initialized, and the chip is also 5456621Sbt150084 * initialized, enable interrupts. 5466621Sbt150084 */ 5476621Sbt150084 if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) { 5486621Sbt150084 ixgbe_error(ixgbe, "Failed to enable DDI interrupts"); 5496621Sbt150084 goto attach_fail; 5506621Sbt150084 } 5516621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 5526621Sbt150084 55311486SZhen.W@Sun.COM ixgbe_log(ixgbe, "%s, %s", ixgbe_ident, ixgbe_version); 55411233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED); 5556621Sbt150084 5566621Sbt150084 return (DDI_SUCCESS); 5576621Sbt150084 5586621Sbt150084 attach_fail: 5596621Sbt150084 ixgbe_unconfigure(devinfo, ixgbe); 5606621Sbt150084 return (DDI_FAILURE); 5616621Sbt150084 } 5626621Sbt150084 5636621Sbt150084 /* 5646621Sbt150084 * ixgbe_detach - Driver detach. 5656621Sbt150084 * 5666621Sbt150084 * The detach() function is the complement of the attach routine. 5676621Sbt150084 * If cmd is set to DDI_DETACH, detach() is used to remove the 5686621Sbt150084 * state associated with a given instance of a device node 5696621Sbt150084 * prior to the removal of that instance from the system. 5706621Sbt150084 * 5716621Sbt150084 * The detach() function will be called once for each instance 5726621Sbt150084 * of the device for which there has been a successful attach() 5736621Sbt150084 * once there are no longer any opens on the device. 5746621Sbt150084 * 5756621Sbt150084 * Interrupts routine are disabled, All memory allocated by this 5766621Sbt150084 * driver are freed. 5776621Sbt150084 */ 5786621Sbt150084 static int 5796621Sbt150084 ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 5806621Sbt150084 { 5816621Sbt150084 ixgbe_t *ixgbe; 5826621Sbt150084 5836621Sbt150084 /* 5846621Sbt150084 * Check detach command 5856621Sbt150084 */ 5866621Sbt150084 switch (cmd) { 5876621Sbt150084 default: 5886621Sbt150084 return (DDI_FAILURE); 5896621Sbt150084 5906621Sbt150084 case DDI_SUSPEND: 5916621Sbt150084 return (ixgbe_suspend(devinfo)); 5926621Sbt150084 5936621Sbt150084 case DDI_DETACH: 5946621Sbt150084 break; 5956621Sbt150084 } 5966621Sbt150084 5976621Sbt150084 /* 5986621Sbt150084 * Get the pointer to the driver private data structure 5996621Sbt150084 */ 6006621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 6016621Sbt150084 if (ixgbe == NULL) 6026621Sbt150084 return (DDI_FAILURE); 6036621Sbt150084 6046621Sbt150084 /* 6056621Sbt150084 * If the device is still running, it needs to be stopped first. 6066621Sbt150084 * This check is necessary because under some specific circumstances, 6076621Sbt150084 * the detach routine can be called without stopping the interface 6086621Sbt150084 * first. 6096621Sbt150084 */ 6106621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 61111233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 61211233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 61310376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_TRUE); 6146621Sbt150084 mutex_exit(&ixgbe->gen_lock); 6156621Sbt150084 /* Disable and stop the watchdog timer */ 6166621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe); 61711233SPaul.Guo@Sun.COM } 6186621Sbt150084 6196621Sbt150084 /* 6206621Sbt150084 * Check if there are still rx buffers held by the upper layer. 6216621Sbt150084 * If so, fail the detach. 6226621Sbt150084 */ 6236621Sbt150084 if (!ixgbe_rx_drain(ixgbe)) 6246621Sbt150084 return (DDI_FAILURE); 6256621Sbt150084 6266621Sbt150084 /* 6276621Sbt150084 * Do the remaining unconfigure routines 6286621Sbt150084 */ 6296621Sbt150084 ixgbe_unconfigure(devinfo, ixgbe); 6306621Sbt150084 6316621Sbt150084 return (DDI_SUCCESS); 6326621Sbt150084 } 6336621Sbt150084 6346621Sbt150084 static void 6356621Sbt150084 ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe) 6366621Sbt150084 { 6376621Sbt150084 /* 6386621Sbt150084 * Disable interrupt 6396621Sbt150084 */ 6406621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 6416621Sbt150084 (void) ixgbe_disable_intrs(ixgbe); 6426621Sbt150084 } 6436621Sbt150084 6446621Sbt150084 /* 64511233SPaul.Guo@Sun.COM * remove the link check timer 64611233SPaul.Guo@Sun.COM */ 64711233SPaul.Guo@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) { 64811233SPaul.Guo@Sun.COM if (ixgbe->periodic_id != NULL) { 64911233SPaul.Guo@Sun.COM ddi_periodic_delete(ixgbe->periodic_id); 65011233SPaul.Guo@Sun.COM ixgbe->periodic_id = NULL; 65111233SPaul.Guo@Sun.COM } 65211233SPaul.Guo@Sun.COM } 65311233SPaul.Guo@Sun.COM 65411233SPaul.Guo@Sun.COM /* 6556621Sbt150084 * Unregister MAC 6566621Sbt150084 */ 6576621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) { 6586621Sbt150084 (void) mac_unregister(ixgbe->mac_hdl); 6596621Sbt150084 } 6606621Sbt150084 6616621Sbt150084 /* 6626621Sbt150084 * Free statistics 6636621Sbt150084 */ 6646621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) { 6656621Sbt150084 kstat_delete((kstat_t *)ixgbe->ixgbe_ks); 6666621Sbt150084 } 6676621Sbt150084 6686621Sbt150084 /* 6696621Sbt150084 * Remove interrupt handlers 6706621Sbt150084 */ 6716621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 6726621Sbt150084 ixgbe_rem_intr_handlers(ixgbe); 6736621Sbt150084 } 6746621Sbt150084 6756621Sbt150084 /* 67611233SPaul.Guo@Sun.COM * Remove taskq for sfp-status-change 6778490SPaul.Guo@Sun.COM */ 67811233SPaul.Guo@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) { 67911233SPaul.Guo@Sun.COM ddi_taskq_destroy(ixgbe->sfp_taskq); 6808490SPaul.Guo@Sun.COM } 6818490SPaul.Guo@Sun.COM 6828490SPaul.Guo@Sun.COM /* 6836621Sbt150084 * Remove interrupts 6846621Sbt150084 */ 6856621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) { 6866621Sbt150084 ixgbe_rem_intrs(ixgbe); 6876621Sbt150084 } 6886621Sbt150084 6896621Sbt150084 /* 69011878SVenu.Iyer@Sun.COM * Unregister interrupt callback handler 69111878SVenu.Iyer@Sun.COM */ 69211878SVenu.Iyer@Sun.COM (void) ddi_cb_unregister(ixgbe->cb_hdl); 69311878SVenu.Iyer@Sun.COM 69411878SVenu.Iyer@Sun.COM /* 6956621Sbt150084 * Remove driver properties 6966621Sbt150084 */ 6976621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) { 6986621Sbt150084 (void) ddi_prop_remove_all(devinfo); 6996621Sbt150084 } 7006621Sbt150084 7016621Sbt150084 /* 7026621Sbt150084 * Stop the chipset 7036621Sbt150084 */ 7046621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) { 7056621Sbt150084 mutex_enter(&ixgbe->gen_lock); 7066621Sbt150084 ixgbe_chip_stop(ixgbe); 7076621Sbt150084 mutex_exit(&ixgbe->gen_lock); 7086621Sbt150084 } 7096621Sbt150084 7106621Sbt150084 /* 7116621Sbt150084 * Free register handle 7126621Sbt150084 */ 7136621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) { 7146621Sbt150084 if (ixgbe->osdep.reg_handle != NULL) 7156621Sbt150084 ddi_regs_map_free(&ixgbe->osdep.reg_handle); 7166621Sbt150084 } 7176621Sbt150084 7186621Sbt150084 /* 7196621Sbt150084 * Free PCI config handle 7206621Sbt150084 */ 7216621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) { 7226621Sbt150084 if (ixgbe->osdep.cfg_handle != NULL) 7236621Sbt150084 pci_config_teardown(&ixgbe->osdep.cfg_handle); 7246621Sbt150084 } 7256621Sbt150084 7266621Sbt150084 /* 7276621Sbt150084 * Free locks 7286621Sbt150084 */ 7296621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) { 7306621Sbt150084 ixgbe_destroy_locks(ixgbe); 7316621Sbt150084 } 7326621Sbt150084 7336621Sbt150084 /* 7346621Sbt150084 * Free the rx/tx rings 7356621Sbt150084 */ 7366621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) { 7376621Sbt150084 ixgbe_free_rings(ixgbe); 7386621Sbt150084 } 7396621Sbt150084 7406621Sbt150084 /* 7416621Sbt150084 * Unregister FMA capabilities 7426621Sbt150084 */ 7436621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) { 7446621Sbt150084 ixgbe_fm_fini(ixgbe); 7456621Sbt150084 } 7466621Sbt150084 7476621Sbt150084 /* 7486621Sbt150084 * Free the driver data structure 7496621Sbt150084 */ 7506621Sbt150084 kmem_free(ixgbe, sizeof (ixgbe_t)); 7516621Sbt150084 7526621Sbt150084 ddi_set_driver_private(devinfo, NULL); 7536621Sbt150084 } 7546621Sbt150084 7556621Sbt150084 /* 7566621Sbt150084 * ixgbe_register_mac - Register the driver and its function pointers with 7576621Sbt150084 * the GLD interface. 7586621Sbt150084 */ 7596621Sbt150084 static int 7606621Sbt150084 ixgbe_register_mac(ixgbe_t *ixgbe) 7616621Sbt150084 { 7626621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 7636621Sbt150084 mac_register_t *mac; 7646621Sbt150084 int status; 7656621Sbt150084 7666621Sbt150084 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 7676621Sbt150084 return (IXGBE_FAILURE); 7686621Sbt150084 7696621Sbt150084 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7706621Sbt150084 mac->m_driver = ixgbe; 7716621Sbt150084 mac->m_dip = ixgbe->dip; 7726621Sbt150084 mac->m_src_addr = hw->mac.addr; 7736621Sbt150084 mac->m_callbacks = &ixgbe_m_callbacks; 7746621Sbt150084 mac->m_min_sdu = 0; 7756621Sbt150084 mac->m_max_sdu = ixgbe->default_mtu; 7766621Sbt150084 mac->m_margin = VLAN_TAGSZ; 77710376SChenlu.Chen@Sun.COM mac->m_priv_props = ixgbe_priv_props; 7788275SEric Cheng mac->m_v12n = MAC_VIRT_LEVEL1; 7796621Sbt150084 7806621Sbt150084 status = mac_register(mac, &ixgbe->mac_hdl); 7816621Sbt150084 7826621Sbt150084 mac_free(mac); 7836621Sbt150084 7846621Sbt150084 return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE); 7856621Sbt150084 } 7866621Sbt150084 7876621Sbt150084 /* 7886621Sbt150084 * ixgbe_identify_hardware - Identify the type of the chipset. 7896621Sbt150084 */ 7906621Sbt150084 static int 7916621Sbt150084 ixgbe_identify_hardware(ixgbe_t *ixgbe) 7926621Sbt150084 { 7936621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 7946621Sbt150084 struct ixgbe_osdep *osdep = &ixgbe->osdep; 7956621Sbt150084 7966621Sbt150084 /* 7976621Sbt150084 * Get the device id 7986621Sbt150084 */ 7996621Sbt150084 hw->vendor_id = 8006621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID); 8016621Sbt150084 hw->device_id = 8026621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID); 8036621Sbt150084 hw->revision_id = 8046621Sbt150084 pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID); 8056621Sbt150084 hw->subsystem_device_id = 8066621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID); 8076621Sbt150084 hw->subsystem_vendor_id = 8086621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID); 8096621Sbt150084 8108490SPaul.Guo@Sun.COM /* 8118490SPaul.Guo@Sun.COM * Set the mac type of the adapter based on the device id 8128490SPaul.Guo@Sun.COM */ 8138490SPaul.Guo@Sun.COM if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) { 8148490SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 8158490SPaul.Guo@Sun.COM } 8168490SPaul.Guo@Sun.COM 8178490SPaul.Guo@Sun.COM /* 8188490SPaul.Guo@Sun.COM * Install adapter capabilities 8198490SPaul.Guo@Sun.COM */ 8208490SPaul.Guo@Sun.COM switch (hw->mac.type) { 8218490SPaul.Guo@Sun.COM case ixgbe_mac_82598EB: 82212003SPaul.Guo@Sun.COM IXGBE_DEBUGLOG_0(ixgbe, "identify 82598 adapter\n"); 8238490SPaul.Guo@Sun.COM ixgbe->capab = &ixgbe_82598eb_cap; 8248490SPaul.Guo@Sun.COM 8258490SPaul.Guo@Sun.COM if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) { 8268490SPaul.Guo@Sun.COM ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; 8278490SPaul.Guo@Sun.COM ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1; 8288490SPaul.Guo@Sun.COM } 8299353SSamuel.Tu@Sun.COM ixgbe->capab->other_intr |= IXGBE_EICR_LSC; 8309353SSamuel.Tu@Sun.COM 8319353SSamuel.Tu@Sun.COM break; 8329353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 83312003SPaul.Guo@Sun.COM IXGBE_DEBUGLOG_0(ixgbe, "identify 82599 adapter\n"); 8349353SSamuel.Tu@Sun.COM ixgbe->capab = &ixgbe_82599eb_cap; 8359353SSamuel.Tu@Sun.COM 8369353SSamuel.Tu@Sun.COM ixgbe->capab->other_intr = (IXGBE_EICR_GPI_SDP1 | 8379353SSamuel.Tu@Sun.COM IXGBE_EICR_GPI_SDP2 | IXGBE_EICR_LSC); 8388490SPaul.Guo@Sun.COM 8398490SPaul.Guo@Sun.COM break; 8408490SPaul.Guo@Sun.COM default: 84112003SPaul.Guo@Sun.COM IXGBE_DEBUGLOG_1(ixgbe, 8428490SPaul.Guo@Sun.COM "adapter not supported in ixgbe_identify_hardware(): %d\n", 8438490SPaul.Guo@Sun.COM hw->mac.type); 8448490SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 8458490SPaul.Guo@Sun.COM } 8468490SPaul.Guo@Sun.COM 8476621Sbt150084 return (IXGBE_SUCCESS); 8486621Sbt150084 } 8496621Sbt150084 8506621Sbt150084 /* 8516621Sbt150084 * ixgbe_regs_map - Map the device registers. 8526621Sbt150084 * 8536621Sbt150084 */ 8546621Sbt150084 static int 8556621Sbt150084 ixgbe_regs_map(ixgbe_t *ixgbe) 8566621Sbt150084 { 8576621Sbt150084 dev_info_t *devinfo = ixgbe->dip; 8586621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 8596621Sbt150084 struct ixgbe_osdep *osdep = &ixgbe->osdep; 8606621Sbt150084 off_t mem_size; 8616621Sbt150084 8626621Sbt150084 /* 8636621Sbt150084 * First get the size of device registers to be mapped. 8646621Sbt150084 */ 8659353SSamuel.Tu@Sun.COM if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size) 8669353SSamuel.Tu@Sun.COM != DDI_SUCCESS) { 8676621Sbt150084 return (IXGBE_FAILURE); 8686621Sbt150084 } 8696621Sbt150084 8706621Sbt150084 /* 8716621Sbt150084 * Call ddi_regs_map_setup() to map registers 8726621Sbt150084 */ 8739353SSamuel.Tu@Sun.COM if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET, 8746621Sbt150084 (caddr_t *)&hw->hw_addr, 0, 8756621Sbt150084 mem_size, &ixgbe_regs_acc_attr, 8766621Sbt150084 &osdep->reg_handle)) != DDI_SUCCESS) { 8776621Sbt150084 return (IXGBE_FAILURE); 8786621Sbt150084 } 8796621Sbt150084 8806621Sbt150084 return (IXGBE_SUCCESS); 8816621Sbt150084 } 8826621Sbt150084 8836621Sbt150084 /* 8846621Sbt150084 * ixgbe_init_properties - Initialize driver properties. 8856621Sbt150084 */ 8866621Sbt150084 static void 8876621Sbt150084 ixgbe_init_properties(ixgbe_t *ixgbe) 8886621Sbt150084 { 8896621Sbt150084 /* 8906621Sbt150084 * Get conf file properties, including link settings 8916621Sbt150084 * jumbo frames, ring number, descriptor number, etc. 8926621Sbt150084 */ 8936621Sbt150084 ixgbe_get_conf(ixgbe); 89410376SChenlu.Chen@Sun.COM 89510376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe); 8966621Sbt150084 } 8976621Sbt150084 8986621Sbt150084 /* 8996621Sbt150084 * ixgbe_init_driver_settings - Initialize driver settings. 9006621Sbt150084 * 9016621Sbt150084 * The settings include hardware function pointers, bus information, 9026621Sbt150084 * rx/tx rings settings, link state, and any other parameters that 9036621Sbt150084 * need to be setup during driver initialization. 9046621Sbt150084 */ 9056621Sbt150084 static int 9066621Sbt150084 ixgbe_init_driver_settings(ixgbe_t *ixgbe) 9076621Sbt150084 { 9086621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 9098275SEric Cheng dev_info_t *devinfo = ixgbe->dip; 9106621Sbt150084 ixgbe_rx_ring_t *rx_ring; 91111878SVenu.Iyer@Sun.COM ixgbe_rx_group_t *rx_group; 9126621Sbt150084 ixgbe_tx_ring_t *tx_ring; 9136621Sbt150084 uint32_t rx_size; 9146621Sbt150084 uint32_t tx_size; 91511878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 9166621Sbt150084 int i; 9176621Sbt150084 9186621Sbt150084 /* 9196621Sbt150084 * Initialize chipset specific hardware function pointers 9206621Sbt150084 */ 9216621Sbt150084 if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) { 9226621Sbt150084 return (IXGBE_FAILURE); 9236621Sbt150084 } 9246621Sbt150084 9256621Sbt150084 /* 9268275SEric Cheng * Get the system page size 9278275SEric Cheng */ 9288275SEric Cheng ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1); 9298275SEric Cheng 9308275SEric Cheng /* 9316621Sbt150084 * Set rx buffer size 9326621Sbt150084 * 9336621Sbt150084 * The IP header alignment room is counted in the calculation. 9346621Sbt150084 * The rx buffer size is in unit of 1K that is required by the 9356621Sbt150084 * chipset hardware. 9366621Sbt150084 */ 9376621Sbt150084 rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM; 9386621Sbt150084 ixgbe->rx_buf_size = ((rx_size >> 10) + 9396621Sbt150084 ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 9406621Sbt150084 9416621Sbt150084 /* 9426621Sbt150084 * Set tx buffer size 9436621Sbt150084 */ 9446621Sbt150084 tx_size = ixgbe->max_frame_size; 9456621Sbt150084 ixgbe->tx_buf_size = ((tx_size >> 10) + 9466621Sbt150084 ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 9476621Sbt150084 9486621Sbt150084 /* 94911878SVenu.Iyer@Sun.COM * Initialize rx/tx rings/groups parameters 95011878SVenu.Iyer@Sun.COM */ 95111878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 9526621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 9536621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 9546621Sbt150084 rx_ring->index = i; 9556621Sbt150084 rx_ring->ixgbe = ixgbe; 95611878SVenu.Iyer@Sun.COM rx_ring->group_index = i / ring_per_group; 95711878SVenu.Iyer@Sun.COM rx_ring->hw_index = ixgbe_get_hw_rx_index(ixgbe, i); 95811878SVenu.Iyer@Sun.COM } 95911878SVenu.Iyer@Sun.COM 96011878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_groups; i++) { 96111878SVenu.Iyer@Sun.COM rx_group = &ixgbe->rx_groups[i]; 96211878SVenu.Iyer@Sun.COM rx_group->index = i; 96311878SVenu.Iyer@Sun.COM rx_group->ixgbe = ixgbe; 9646621Sbt150084 } 9656621Sbt150084 9666621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 9676621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 9686621Sbt150084 tx_ring->index = i; 9696621Sbt150084 tx_ring->ixgbe = ixgbe; 9706621Sbt150084 if (ixgbe->tx_head_wb_enable) 9716621Sbt150084 tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb; 9726621Sbt150084 else 9736621Sbt150084 tx_ring->tx_recycle = ixgbe_tx_recycle_legacy; 9746621Sbt150084 9756621Sbt150084 tx_ring->ring_size = ixgbe->tx_ring_size; 9766621Sbt150084 tx_ring->free_list_size = ixgbe->tx_ring_size + 9776621Sbt150084 (ixgbe->tx_ring_size >> 1); 9786621Sbt150084 } 9796621Sbt150084 9806621Sbt150084 /* 9816621Sbt150084 * Initialize values of interrupt throttling rate 9826621Sbt150084 */ 9839353SSamuel.Tu@Sun.COM for (i = 1; i < MAX_INTR_VECTOR; i++) 9846621Sbt150084 ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0]; 9856621Sbt150084 9866621Sbt150084 /* 9876621Sbt150084 * The initial link state should be "unknown" 9886621Sbt150084 */ 9896621Sbt150084 ixgbe->link_state = LINK_STATE_UNKNOWN; 9909353SSamuel.Tu@Sun.COM 9916621Sbt150084 return (IXGBE_SUCCESS); 9926621Sbt150084 } 9936621Sbt150084 9946621Sbt150084 /* 9956621Sbt150084 * ixgbe_init_locks - Initialize locks. 9966621Sbt150084 */ 9976621Sbt150084 static void 9986621Sbt150084 ixgbe_init_locks(ixgbe_t *ixgbe) 9996621Sbt150084 { 10006621Sbt150084 ixgbe_rx_ring_t *rx_ring; 10016621Sbt150084 ixgbe_tx_ring_t *tx_ring; 10026621Sbt150084 int i; 10036621Sbt150084 10046621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 10056621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 10066621Sbt150084 mutex_init(&rx_ring->rx_lock, NULL, 10076621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10086621Sbt150084 } 10096621Sbt150084 10106621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 10116621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 10126621Sbt150084 mutex_init(&tx_ring->tx_lock, NULL, 10136621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10146621Sbt150084 mutex_init(&tx_ring->recycle_lock, NULL, 10156621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10166621Sbt150084 mutex_init(&tx_ring->tcb_head_lock, NULL, 10176621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10186621Sbt150084 mutex_init(&tx_ring->tcb_tail_lock, NULL, 10196621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10206621Sbt150084 } 10216621Sbt150084 10226621Sbt150084 mutex_init(&ixgbe->gen_lock, NULL, 10236621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10246621Sbt150084 10256621Sbt150084 mutex_init(&ixgbe->watchdog_lock, NULL, 10266621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10276621Sbt150084 } 10286621Sbt150084 10296621Sbt150084 /* 10306621Sbt150084 * ixgbe_destroy_locks - Destroy locks. 10316621Sbt150084 */ 10326621Sbt150084 static void 10336621Sbt150084 ixgbe_destroy_locks(ixgbe_t *ixgbe) 10346621Sbt150084 { 10356621Sbt150084 ixgbe_rx_ring_t *rx_ring; 10366621Sbt150084 ixgbe_tx_ring_t *tx_ring; 10376621Sbt150084 int i; 10386621Sbt150084 10396621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 10406621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 10416621Sbt150084 mutex_destroy(&rx_ring->rx_lock); 10426621Sbt150084 } 10436621Sbt150084 10446621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 10456621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 10466621Sbt150084 mutex_destroy(&tx_ring->tx_lock); 10476621Sbt150084 mutex_destroy(&tx_ring->recycle_lock); 10486621Sbt150084 mutex_destroy(&tx_ring->tcb_head_lock); 10496621Sbt150084 mutex_destroy(&tx_ring->tcb_tail_lock); 10506621Sbt150084 } 10516621Sbt150084 10526621Sbt150084 mutex_destroy(&ixgbe->gen_lock); 10536621Sbt150084 mutex_destroy(&ixgbe->watchdog_lock); 10546621Sbt150084 } 10556621Sbt150084 10566621Sbt150084 static int 10576621Sbt150084 ixgbe_resume(dev_info_t *devinfo) 10586621Sbt150084 { 10596621Sbt150084 ixgbe_t *ixgbe; 106011233SPaul.Guo@Sun.COM int i; 10616621Sbt150084 10626621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 10636621Sbt150084 if (ixgbe == NULL) 10646621Sbt150084 return (DDI_FAILURE); 10656621Sbt150084 10666621Sbt150084 mutex_enter(&ixgbe->gen_lock); 10676621Sbt150084 10686621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 106910376SChenlu.Chen@Sun.COM if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 10706621Sbt150084 mutex_exit(&ixgbe->gen_lock); 10716621Sbt150084 return (DDI_FAILURE); 10726621Sbt150084 } 10736621Sbt150084 10746621Sbt150084 /* 10756621Sbt150084 * Enable and start the watchdog timer 10766621Sbt150084 */ 10776621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe); 10786621Sbt150084 } 10796621Sbt150084 108011233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED); 108111233SPaul.Guo@Sun.COM 108211233SPaul.Guo@Sun.COM if (ixgbe->ixgbe_state & IXGBE_STARTED) { 108311233SPaul.Guo@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 108411233SPaul.Guo@Sun.COM mac_tx_ring_update(ixgbe->mac_hdl, 108511233SPaul.Guo@Sun.COM ixgbe->tx_rings[i].ring_handle); 108611233SPaul.Guo@Sun.COM } 108711233SPaul.Guo@Sun.COM } 10886621Sbt150084 10896621Sbt150084 mutex_exit(&ixgbe->gen_lock); 10906621Sbt150084 10916621Sbt150084 return (DDI_SUCCESS); 10926621Sbt150084 } 10936621Sbt150084 10946621Sbt150084 static int 10956621Sbt150084 ixgbe_suspend(dev_info_t *devinfo) 10966621Sbt150084 { 10976621Sbt150084 ixgbe_t *ixgbe; 10986621Sbt150084 10996621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 11006621Sbt150084 if (ixgbe == NULL) 11016621Sbt150084 return (DDI_FAILURE); 11026621Sbt150084 11036621Sbt150084 mutex_enter(&ixgbe->gen_lock); 11046621Sbt150084 110511233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED); 110610376SChenlu.Chen@Sun.COM if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) { 110710376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->gen_lock); 110810376SChenlu.Chen@Sun.COM return (DDI_SUCCESS); 110910376SChenlu.Chen@Sun.COM } 111010376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_FALSE); 11116621Sbt150084 11126621Sbt150084 mutex_exit(&ixgbe->gen_lock); 11136621Sbt150084 11146621Sbt150084 /* 11156621Sbt150084 * Disable and stop the watchdog timer 11166621Sbt150084 */ 11176621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe); 11186621Sbt150084 11196621Sbt150084 return (DDI_SUCCESS); 11206621Sbt150084 } 11216621Sbt150084 11226621Sbt150084 /* 11236621Sbt150084 * ixgbe_init - Initialize the device. 11246621Sbt150084 */ 11256621Sbt150084 static int 11266621Sbt150084 ixgbe_init(ixgbe_t *ixgbe) 11276621Sbt150084 { 11286621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 11296621Sbt150084 11306621Sbt150084 mutex_enter(&ixgbe->gen_lock); 11316621Sbt150084 11326621Sbt150084 /* 11336621Sbt150084 * Reset chipset to put the hardware in a known state 11346621Sbt150084 * before we try to do anything with the eeprom. 11356621Sbt150084 */ 11366621Sbt150084 if (ixgbe_reset_hw(hw) != IXGBE_SUCCESS) { 11376621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11386621Sbt150084 goto init_fail; 11396621Sbt150084 } 11406621Sbt150084 11416621Sbt150084 /* 11426621Sbt150084 * Need to init eeprom before validating the checksum. 11436621Sbt150084 */ 11446621Sbt150084 if (ixgbe_init_eeprom_params(hw) < 0) { 11456621Sbt150084 ixgbe_error(ixgbe, 11466621Sbt150084 "Unable to intitialize the eeprom interface."); 11476621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11486621Sbt150084 goto init_fail; 11496621Sbt150084 } 11506621Sbt150084 11516621Sbt150084 /* 11526621Sbt150084 * NVM validation 11536621Sbt150084 */ 11546621Sbt150084 if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { 11556621Sbt150084 /* 11566621Sbt150084 * Some PCI-E parts fail the first check due to 11576621Sbt150084 * the link being in sleep state. Call it again, 11586621Sbt150084 * if it fails a second time it's a real issue. 11596621Sbt150084 */ 11606621Sbt150084 if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { 11616621Sbt150084 ixgbe_error(ixgbe, 11626621Sbt150084 "Invalid NVM checksum. Please contact " 11636621Sbt150084 "the vendor to update the NVM."); 11646621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11656621Sbt150084 goto init_fail; 11666621Sbt150084 } 11676621Sbt150084 } 11686621Sbt150084 11696621Sbt150084 /* 11706621Sbt150084 * Setup default flow control thresholds - enable/disable 11716621Sbt150084 * & flow control type is controlled by ixgbe.conf 11726621Sbt150084 */ 11736621Sbt150084 hw->fc.high_water = DEFAULT_FCRTH; 11746621Sbt150084 hw->fc.low_water = DEFAULT_FCRTL; 11756621Sbt150084 hw->fc.pause_time = DEFAULT_FCPAUSE; 11766621Sbt150084 hw->fc.send_xon = B_TRUE; 11776621Sbt150084 11786621Sbt150084 /* 11796621Sbt150084 * Initialize link settings 11806621Sbt150084 */ 11816621Sbt150084 (void) ixgbe_driver_setup_link(ixgbe, B_FALSE); 11826621Sbt150084 11836621Sbt150084 /* 11846621Sbt150084 * Initialize the chipset hardware 11856621Sbt150084 */ 11866621Sbt150084 if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { 11876621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11886621Sbt150084 goto init_fail; 11896621Sbt150084 } 11906621Sbt150084 11916621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 11926621Sbt150084 goto init_fail; 11936621Sbt150084 } 11946621Sbt150084 11956621Sbt150084 mutex_exit(&ixgbe->gen_lock); 11966621Sbt150084 return (IXGBE_SUCCESS); 11976621Sbt150084 11986621Sbt150084 init_fail: 11996621Sbt150084 /* 12006621Sbt150084 * Reset PHY 12016621Sbt150084 */ 12026621Sbt150084 (void) ixgbe_reset_phy(hw); 12036621Sbt150084 12046621Sbt150084 mutex_exit(&ixgbe->gen_lock); 12056621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 12066621Sbt150084 return (IXGBE_FAILURE); 12076621Sbt150084 } 12086621Sbt150084 12096621Sbt150084 /* 12106621Sbt150084 * ixgbe_chip_start - Initialize and start the chipset hardware. 12116621Sbt150084 */ 12126621Sbt150084 static int 12136621Sbt150084 ixgbe_chip_start(ixgbe_t *ixgbe) 12146621Sbt150084 { 12156621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 121610305SPaul.Guo@Sun.COM int ret_val, i; 12176621Sbt150084 12186621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 12196621Sbt150084 12206621Sbt150084 /* 12216621Sbt150084 * Get the mac address 12226621Sbt150084 * This function should handle SPARC case correctly. 12236621Sbt150084 */ 12246621Sbt150084 if (!ixgbe_find_mac_address(ixgbe)) { 12256621Sbt150084 ixgbe_error(ixgbe, "Failed to get the mac address"); 12266621Sbt150084 return (IXGBE_FAILURE); 12276621Sbt150084 } 12286621Sbt150084 12296621Sbt150084 /* 12306621Sbt150084 * Validate the mac address 12316621Sbt150084 */ 12326621Sbt150084 (void) ixgbe_init_rx_addrs(hw); 12336621Sbt150084 if (!is_valid_mac_addr(hw->mac.addr)) { 12346621Sbt150084 ixgbe_error(ixgbe, "Invalid mac address"); 12356621Sbt150084 return (IXGBE_FAILURE); 12366621Sbt150084 } 12376621Sbt150084 12386621Sbt150084 /* 12396621Sbt150084 * Configure/Initialize hardware 12406621Sbt150084 */ 124110305SPaul.Guo@Sun.COM ret_val = ixgbe_init_hw(hw); 124210305SPaul.Guo@Sun.COM if (ret_val != IXGBE_SUCCESS) { 124310305SPaul.Guo@Sun.COM if (ret_val == IXGBE_ERR_EEPROM_VERSION) { 124410305SPaul.Guo@Sun.COM ixgbe_error(ixgbe, 124510305SPaul.Guo@Sun.COM "This 82599 device is pre-release and contains" 124610305SPaul.Guo@Sun.COM " outdated firmware, please contact your hardware" 124710305SPaul.Guo@Sun.COM " vendor for a replacement."); 124810305SPaul.Guo@Sun.COM } else { 124910305SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "Failed to initialize hardware"); 125010305SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 125110305SPaul.Guo@Sun.COM } 12526621Sbt150084 } 12536621Sbt150084 12546621Sbt150084 /* 125512003SPaul.Guo@Sun.COM * Re-enable relaxed ordering for performance. It is disabled 125612003SPaul.Guo@Sun.COM * by default in the hardware init. 125712003SPaul.Guo@Sun.COM */ 125812003SPaul.Guo@Sun.COM ixgbe_enable_relaxed_ordering(hw); 125912003SPaul.Guo@Sun.COM 126012003SPaul.Guo@Sun.COM /* 12616621Sbt150084 * Setup adapter interrupt vectors 12626621Sbt150084 */ 12636621Sbt150084 ixgbe_setup_adapter_vector(ixgbe); 12646621Sbt150084 12656621Sbt150084 /* 12666621Sbt150084 * Initialize unicast addresses. 12676621Sbt150084 */ 12686621Sbt150084 ixgbe_init_unicst(ixgbe); 12696621Sbt150084 12706621Sbt150084 /* 12716621Sbt150084 * Setup and initialize the mctable structures. 12726621Sbt150084 */ 12736621Sbt150084 ixgbe_setup_multicst(ixgbe); 12746621Sbt150084 12756621Sbt150084 /* 12766621Sbt150084 * Set interrupt throttling rate 12776621Sbt150084 */ 12789353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->intr_cnt; i++) { 12796621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]); 12809353SSamuel.Tu@Sun.COM } 12816621Sbt150084 12826621Sbt150084 /* 12836621Sbt150084 * Save the state of the phy 12846621Sbt150084 */ 12856621Sbt150084 ixgbe_get_hw_state(ixgbe); 12866621Sbt150084 12876621Sbt150084 /* 12886621Sbt150084 * Make sure driver has control 12896621Sbt150084 */ 12906621Sbt150084 ixgbe_get_driver_control(hw); 12916621Sbt150084 12926621Sbt150084 return (IXGBE_SUCCESS); 12936621Sbt150084 } 12946621Sbt150084 12956621Sbt150084 /* 12966621Sbt150084 * ixgbe_chip_stop - Stop the chipset hardware 12976621Sbt150084 */ 12986621Sbt150084 static void 12996621Sbt150084 ixgbe_chip_stop(ixgbe_t *ixgbe) 13006621Sbt150084 { 13016621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 13026621Sbt150084 13036621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 13046621Sbt150084 13056621Sbt150084 /* 13066621Sbt150084 * Tell firmware driver is no longer in control 13076621Sbt150084 */ 13086621Sbt150084 ixgbe_release_driver_control(hw); 13096621Sbt150084 13106621Sbt150084 /* 13116621Sbt150084 * Reset the chipset 13126621Sbt150084 */ 13136621Sbt150084 (void) ixgbe_reset_hw(hw); 13146621Sbt150084 13156621Sbt150084 /* 13166621Sbt150084 * Reset PHY 13176621Sbt150084 */ 13186621Sbt150084 (void) ixgbe_reset_phy(hw); 13196621Sbt150084 } 13206621Sbt150084 13216621Sbt150084 /* 13226621Sbt150084 * ixgbe_reset - Reset the chipset and re-start the driver. 13236621Sbt150084 * 13246621Sbt150084 * It involves stopping and re-starting the chipset, 13256621Sbt150084 * and re-configuring the rx/tx rings. 13266621Sbt150084 */ 13276621Sbt150084 static int 13286621Sbt150084 ixgbe_reset(ixgbe_t *ixgbe) 13296621Sbt150084 { 133011233SPaul.Guo@Sun.COM int i; 133111233SPaul.Guo@Sun.COM 133210376SChenlu.Chen@Sun.COM /* 133310376SChenlu.Chen@Sun.COM * Disable and stop the watchdog timer 133410376SChenlu.Chen@Sun.COM */ 133510376SChenlu.Chen@Sun.COM ixgbe_disable_watchdog_timer(ixgbe); 13366621Sbt150084 13376621Sbt150084 mutex_enter(&ixgbe->gen_lock); 13386621Sbt150084 13396621Sbt150084 ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED); 134011233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 13416621Sbt150084 134210376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_FALSE); 134310376SChenlu.Chen@Sun.COM 134410376SChenlu.Chen@Sun.COM if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 134510376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->gen_lock); 134610376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 13476621Sbt150084 } 13486621Sbt150084 134911233SPaul.Guo@Sun.COM /* 135011233SPaul.Guo@Sun.COM * After resetting, need to recheck the link status. 135111233SPaul.Guo@Sun.COM */ 135211233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 135311233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 135411233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 135511233SPaul.Guo@Sun.COM 135611233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED); 135711233SPaul.Guo@Sun.COM 135811233SPaul.Guo@Sun.COM if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) { 135911233SPaul.Guo@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 136011233SPaul.Guo@Sun.COM mac_tx_ring_update(ixgbe->mac_hdl, 136111233SPaul.Guo@Sun.COM ixgbe->tx_rings[i].ring_handle); 136211233SPaul.Guo@Sun.COM } 136311233SPaul.Guo@Sun.COM } 136411233SPaul.Guo@Sun.COM 13656621Sbt150084 mutex_exit(&ixgbe->gen_lock); 13666621Sbt150084 136710376SChenlu.Chen@Sun.COM /* 136810376SChenlu.Chen@Sun.COM * Enable and start the watchdog timer 136910376SChenlu.Chen@Sun.COM */ 137010376SChenlu.Chen@Sun.COM ixgbe_enable_watchdog_timer(ixgbe); 137110376SChenlu.Chen@Sun.COM 13726621Sbt150084 return (IXGBE_SUCCESS); 13736621Sbt150084 } 13746621Sbt150084 13756621Sbt150084 /* 13766621Sbt150084 * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources. 13776621Sbt150084 */ 13786621Sbt150084 static void 13796621Sbt150084 ixgbe_tx_clean(ixgbe_t *ixgbe) 13806621Sbt150084 { 13816621Sbt150084 ixgbe_tx_ring_t *tx_ring; 13826621Sbt150084 tx_control_block_t *tcb; 13836621Sbt150084 link_list_t pending_list; 13846621Sbt150084 uint32_t desc_num; 13856621Sbt150084 int i, j; 13866621Sbt150084 13876621Sbt150084 LINK_LIST_INIT(&pending_list); 13886621Sbt150084 13896621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 13906621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 13916621Sbt150084 13926621Sbt150084 mutex_enter(&tx_ring->recycle_lock); 13936621Sbt150084 13946621Sbt150084 /* 13956621Sbt150084 * Clean the pending tx data - the pending packets in the 13966621Sbt150084 * work_list that have no chances to be transmitted again. 13976621Sbt150084 * 13986621Sbt150084 * We must ensure the chipset is stopped or the link is down 13996621Sbt150084 * before cleaning the transmit packets. 14006621Sbt150084 */ 14016621Sbt150084 desc_num = 0; 14026621Sbt150084 for (j = 0; j < tx_ring->ring_size; j++) { 14036621Sbt150084 tcb = tx_ring->work_list[j]; 14046621Sbt150084 if (tcb != NULL) { 14056621Sbt150084 desc_num += tcb->desc_num; 14066621Sbt150084 14076621Sbt150084 tx_ring->work_list[j] = NULL; 14086621Sbt150084 14096621Sbt150084 ixgbe_free_tcb(tcb); 14106621Sbt150084 14116621Sbt150084 LIST_PUSH_TAIL(&pending_list, &tcb->link); 14126621Sbt150084 } 14136621Sbt150084 } 14146621Sbt150084 14156621Sbt150084 if (desc_num > 0) { 14166621Sbt150084 atomic_add_32(&tx_ring->tbd_free, desc_num); 14176621Sbt150084 ASSERT(tx_ring->tbd_free == tx_ring->ring_size); 14186621Sbt150084 14196621Sbt150084 /* 14206621Sbt150084 * Reset the head and tail pointers of the tbd ring; 14216621Sbt150084 * Reset the writeback head if it's enable. 14226621Sbt150084 */ 14236621Sbt150084 tx_ring->tbd_head = 0; 14246621Sbt150084 tx_ring->tbd_tail = 0; 14256621Sbt150084 if (ixgbe->tx_head_wb_enable) 14266621Sbt150084 *tx_ring->tbd_head_wb = 0; 14276621Sbt150084 14286621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, 14296621Sbt150084 IXGBE_TDH(tx_ring->index), 0); 14306621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, 14316621Sbt150084 IXGBE_TDT(tx_ring->index), 0); 14326621Sbt150084 } 14336621Sbt150084 14346621Sbt150084 mutex_exit(&tx_ring->recycle_lock); 14356621Sbt150084 14366621Sbt150084 /* 14376621Sbt150084 * Add the tx control blocks in the pending list to 14386621Sbt150084 * the free list. 14396621Sbt150084 */ 14406621Sbt150084 ixgbe_put_free_list(tx_ring, &pending_list); 14416621Sbt150084 } 14426621Sbt150084 } 14436621Sbt150084 14446621Sbt150084 /* 14456621Sbt150084 * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be 14466621Sbt150084 * transmitted. 14476621Sbt150084 */ 14486621Sbt150084 static boolean_t 14496621Sbt150084 ixgbe_tx_drain(ixgbe_t *ixgbe) 14506621Sbt150084 { 14516621Sbt150084 ixgbe_tx_ring_t *tx_ring; 14526621Sbt150084 boolean_t done; 14536621Sbt150084 int i, j; 14546621Sbt150084 14556621Sbt150084 /* 14566621Sbt150084 * Wait for a specific time to allow pending tx packets 14576621Sbt150084 * to be transmitted. 14586621Sbt150084 * 14596621Sbt150084 * Check the counter tbd_free to see if transmission is done. 14606621Sbt150084 * No lock protection is needed here. 14616621Sbt150084 * 14626621Sbt150084 * Return B_TRUE if all pending packets have been transmitted; 14636621Sbt150084 * Otherwise return B_FALSE; 14646621Sbt150084 */ 14656621Sbt150084 for (i = 0; i < TX_DRAIN_TIME; i++) { 14666621Sbt150084 14676621Sbt150084 done = B_TRUE; 14686621Sbt150084 for (j = 0; j < ixgbe->num_tx_rings; j++) { 14696621Sbt150084 tx_ring = &ixgbe->tx_rings[j]; 14706621Sbt150084 done = done && 14716621Sbt150084 (tx_ring->tbd_free == tx_ring->ring_size); 14726621Sbt150084 } 14736621Sbt150084 14746621Sbt150084 if (done) 14756621Sbt150084 break; 14766621Sbt150084 14776621Sbt150084 msec_delay(1); 14786621Sbt150084 } 14796621Sbt150084 14806621Sbt150084 return (done); 14816621Sbt150084 } 14826621Sbt150084 14836621Sbt150084 /* 14846621Sbt150084 * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer. 14856621Sbt150084 */ 14866621Sbt150084 static boolean_t 14876621Sbt150084 ixgbe_rx_drain(ixgbe_t *ixgbe) 14886621Sbt150084 { 148910376SChenlu.Chen@Sun.COM boolean_t done = B_TRUE; 149010376SChenlu.Chen@Sun.COM int i; 14916621Sbt150084 14926621Sbt150084 /* 14936621Sbt150084 * Polling the rx free list to check if those rx buffers held by 14946621Sbt150084 * the upper layer are released. 14956621Sbt150084 * 14966621Sbt150084 * Check the counter rcb_free to see if all pending buffers are 14976621Sbt150084 * released. No lock protection is needed here. 14986621Sbt150084 * 14996621Sbt150084 * Return B_TRUE if all pending buffers have been released; 15006621Sbt150084 * Otherwise return B_FALSE; 15016621Sbt150084 */ 15026621Sbt150084 for (i = 0; i < RX_DRAIN_TIME; i++) { 150310376SChenlu.Chen@Sun.COM done = (ixgbe->rcb_pending == 0); 15046621Sbt150084 15056621Sbt150084 if (done) 15066621Sbt150084 break; 15076621Sbt150084 15086621Sbt150084 msec_delay(1); 15096621Sbt150084 } 15106621Sbt150084 15116621Sbt150084 return (done); 15126621Sbt150084 } 15136621Sbt150084 15146621Sbt150084 /* 15156621Sbt150084 * ixgbe_start - Start the driver/chipset. 15166621Sbt150084 */ 15176621Sbt150084 int 151810376SChenlu.Chen@Sun.COM ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer) 15196621Sbt150084 { 15206621Sbt150084 int i; 15216621Sbt150084 15226621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 15236621Sbt150084 152410376SChenlu.Chen@Sun.COM if (alloc_buffer) { 152510376SChenlu.Chen@Sun.COM if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) { 152610376SChenlu.Chen@Sun.COM ixgbe_error(ixgbe, 152710376SChenlu.Chen@Sun.COM "Failed to allocate software receive rings"); 152810376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 152910376SChenlu.Chen@Sun.COM } 153010376SChenlu.Chen@Sun.COM 153110376SChenlu.Chen@Sun.COM /* Allocate buffers for all the rx/tx rings */ 153210376SChenlu.Chen@Sun.COM if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) { 153310376SChenlu.Chen@Sun.COM ixgbe_error(ixgbe, "Failed to allocate DMA resource"); 153410376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 153510376SChenlu.Chen@Sun.COM } 153610376SChenlu.Chen@Sun.COM 153710376SChenlu.Chen@Sun.COM ixgbe->tx_ring_init = B_TRUE; 153810376SChenlu.Chen@Sun.COM } else { 153910376SChenlu.Chen@Sun.COM ixgbe->tx_ring_init = B_FALSE; 154010376SChenlu.Chen@Sun.COM } 154110376SChenlu.Chen@Sun.COM 15426621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) 15436621Sbt150084 mutex_enter(&ixgbe->rx_rings[i].rx_lock); 15446621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) 15456621Sbt150084 mutex_enter(&ixgbe->tx_rings[i].tx_lock); 15466621Sbt150084 15476621Sbt150084 /* 15486621Sbt150084 * Start the chipset hardware 15496621Sbt150084 */ 15506621Sbt150084 if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { 15516621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 15526621Sbt150084 goto start_failure; 15536621Sbt150084 } 15546621Sbt150084 15556621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 15566621Sbt150084 goto start_failure; 15576621Sbt150084 } 15586621Sbt150084 15596621Sbt150084 /* 15606621Sbt150084 * Setup the rx/tx rings 15616621Sbt150084 */ 15626621Sbt150084 ixgbe_setup_rings(ixgbe); 15636621Sbt150084 15646621Sbt150084 /* 156511233SPaul.Guo@Sun.COM * ixgbe_start() will be called when resetting, however if reset 156611233SPaul.Guo@Sun.COM * happens, we need to clear the ERROR and STALL flags before 156711233SPaul.Guo@Sun.COM * enabling the interrupts. 156811233SPaul.Guo@Sun.COM */ 156911233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR | IXGBE_STALL)); 157011233SPaul.Guo@Sun.COM 157111233SPaul.Guo@Sun.COM /* 15726621Sbt150084 * Enable adapter interrupts 15736621Sbt150084 * The interrupts must be enabled after the driver state is START 15746621Sbt150084 */ 15756621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe); 15766621Sbt150084 15776621Sbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 15786621Sbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 15796621Sbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 15806621Sbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 15816621Sbt150084 15826621Sbt150084 return (IXGBE_SUCCESS); 15836621Sbt150084 15846621Sbt150084 start_failure: 15856621Sbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 15866621Sbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 15876621Sbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 15886621Sbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 15896621Sbt150084 15906621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 15916621Sbt150084 15926621Sbt150084 return (IXGBE_FAILURE); 15936621Sbt150084 } 15946621Sbt150084 15956621Sbt150084 /* 15966621Sbt150084 * ixgbe_stop - Stop the driver/chipset. 15976621Sbt150084 */ 15986621Sbt150084 void 159910376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer) 16006621Sbt150084 { 16016621Sbt150084 int i; 16026621Sbt150084 16036621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 16046621Sbt150084 16056621Sbt150084 /* 16066621Sbt150084 * Disable the adapter interrupts 16076621Sbt150084 */ 16086621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe); 16096621Sbt150084 16106621Sbt150084 /* 16116621Sbt150084 * Drain the pending tx packets 16126621Sbt150084 */ 16136621Sbt150084 (void) ixgbe_tx_drain(ixgbe); 16146621Sbt150084 16156621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) 16166621Sbt150084 mutex_enter(&ixgbe->rx_rings[i].rx_lock); 16176621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) 16186621Sbt150084 mutex_enter(&ixgbe->tx_rings[i].tx_lock); 16196621Sbt150084 16206621Sbt150084 /* 16216621Sbt150084 * Stop the chipset hardware 16226621Sbt150084 */ 16236621Sbt150084 ixgbe_chip_stop(ixgbe); 16246621Sbt150084 16256621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 16266621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 16276621Sbt150084 } 16286621Sbt150084 16296621Sbt150084 /* 16306621Sbt150084 * Clean the pending tx data/resources 16316621Sbt150084 */ 16326621Sbt150084 ixgbe_tx_clean(ixgbe); 16336621Sbt150084 16346621Sbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 16356621Sbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 16366621Sbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 16376621Sbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 163810376SChenlu.Chen@Sun.COM 163910376SChenlu.Chen@Sun.COM if (ixgbe->link_state == LINK_STATE_UP) { 164010376SChenlu.Chen@Sun.COM ixgbe->link_state = LINK_STATE_UNKNOWN; 164110376SChenlu.Chen@Sun.COM mac_link_update(ixgbe->mac_hdl, ixgbe->link_state); 164210376SChenlu.Chen@Sun.COM } 164310376SChenlu.Chen@Sun.COM 164410376SChenlu.Chen@Sun.COM if (free_buffer) { 164510376SChenlu.Chen@Sun.COM /* 164610376SChenlu.Chen@Sun.COM * Release the DMA/memory resources of rx/tx rings 164710376SChenlu.Chen@Sun.COM */ 164810376SChenlu.Chen@Sun.COM ixgbe_free_dma(ixgbe); 164910376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe); 165010376SChenlu.Chen@Sun.COM } 16516621Sbt150084 } 16526621Sbt150084 16536621Sbt150084 /* 165411878SVenu.Iyer@Sun.COM * ixgbe_cbfunc - Driver interface for generic DDI callbacks 165511878SVenu.Iyer@Sun.COM */ 165611878SVenu.Iyer@Sun.COM /* ARGSUSED */ 165711878SVenu.Iyer@Sun.COM static int 165811878SVenu.Iyer@Sun.COM ixgbe_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg, 165911878SVenu.Iyer@Sun.COM void *arg1, void *arg2) 166011878SVenu.Iyer@Sun.COM { 166111878SVenu.Iyer@Sun.COM ixgbe_t *ixgbe = (ixgbe_t *)arg1; 166211878SVenu.Iyer@Sun.COM 166311878SVenu.Iyer@Sun.COM switch (cbaction) { 166411878SVenu.Iyer@Sun.COM /* IRM callback */ 166511878SVenu.Iyer@Sun.COM int count; 166611878SVenu.Iyer@Sun.COM case DDI_CB_INTR_ADD: 166711878SVenu.Iyer@Sun.COM case DDI_CB_INTR_REMOVE: 166811878SVenu.Iyer@Sun.COM count = (int)(uintptr_t)cbarg; 166911878SVenu.Iyer@Sun.COM ASSERT(ixgbe->intr_type == DDI_INTR_TYPE_MSIX); 167011878SVenu.Iyer@Sun.COM DTRACE_PROBE2(ixgbe__irm__callback, int, count, 167111878SVenu.Iyer@Sun.COM int, ixgbe->intr_cnt); 167211878SVenu.Iyer@Sun.COM if (ixgbe_intr_adjust(ixgbe, cbaction, count) != 167311878SVenu.Iyer@Sun.COM DDI_SUCCESS) { 167411878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, 167511878SVenu.Iyer@Sun.COM "IRM CB: Failed to adjust interrupts"); 167611878SVenu.Iyer@Sun.COM goto cb_fail; 167711878SVenu.Iyer@Sun.COM } 167811878SVenu.Iyer@Sun.COM break; 167911878SVenu.Iyer@Sun.COM default: 168011878SVenu.Iyer@Sun.COM IXGBE_DEBUGLOG_1(ixgbe, "DDI CB: action 0x%x NOT supported", 168111878SVenu.Iyer@Sun.COM cbaction); 168211878SVenu.Iyer@Sun.COM return (DDI_ENOTSUP); 168311878SVenu.Iyer@Sun.COM } 168411878SVenu.Iyer@Sun.COM return (DDI_SUCCESS); 168511878SVenu.Iyer@Sun.COM cb_fail: 168611878SVenu.Iyer@Sun.COM return (DDI_FAILURE); 168711878SVenu.Iyer@Sun.COM } 168811878SVenu.Iyer@Sun.COM 168911878SVenu.Iyer@Sun.COM /* 169011878SVenu.Iyer@Sun.COM * ixgbe_intr_adjust - Adjust interrupt to respond to IRM request. 169111878SVenu.Iyer@Sun.COM */ 169211878SVenu.Iyer@Sun.COM static int 169311878SVenu.Iyer@Sun.COM ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count) 169411878SVenu.Iyer@Sun.COM { 169511878SVenu.Iyer@Sun.COM int i, rc, actual; 169611878SVenu.Iyer@Sun.COM 169711878SVenu.Iyer@Sun.COM if (count == 0) 169811878SVenu.Iyer@Sun.COM return (DDI_SUCCESS); 169911878SVenu.Iyer@Sun.COM 170011878SVenu.Iyer@Sun.COM if ((cbaction == DDI_CB_INTR_ADD && 170111878SVenu.Iyer@Sun.COM ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) || 170211878SVenu.Iyer@Sun.COM (cbaction == DDI_CB_INTR_REMOVE && 170311878SVenu.Iyer@Sun.COM ixgbe->intr_cnt - count < ixgbe->intr_cnt_min)) 170411878SVenu.Iyer@Sun.COM return (DDI_FAILURE); 170511878SVenu.Iyer@Sun.COM 170611878SVenu.Iyer@Sun.COM if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) { 170711878SVenu.Iyer@Sun.COM return (DDI_FAILURE); 170811878SVenu.Iyer@Sun.COM } 170911878SVenu.Iyer@Sun.COM 171011878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) 171111878SVenu.Iyer@Sun.COM mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL); 171211878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) 171311878SVenu.Iyer@Sun.COM mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL); 171411878SVenu.Iyer@Sun.COM 171511878SVenu.Iyer@Sun.COM mutex_enter(&ixgbe->gen_lock); 171611878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state &= ~IXGBE_STARTED; 171711878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST; 171811878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state |= IXGBE_SUSPENDED; 171911878SVenu.Iyer@Sun.COM mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN); 172011878SVenu.Iyer@Sun.COM 172111878SVenu.Iyer@Sun.COM ixgbe_stop(ixgbe, B_FALSE); 172211878SVenu.Iyer@Sun.COM /* 172311878SVenu.Iyer@Sun.COM * Disable interrupts 172411878SVenu.Iyer@Sun.COM */ 172511878SVenu.Iyer@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 172611878SVenu.Iyer@Sun.COM rc = ixgbe_disable_intrs(ixgbe); 172711878SVenu.Iyer@Sun.COM ASSERT(rc == IXGBE_SUCCESS); 172811878SVenu.Iyer@Sun.COM } 172911878SVenu.Iyer@Sun.COM ixgbe->attach_progress &= ~ATTACH_PROGRESS_ENABLE_INTR; 173011878SVenu.Iyer@Sun.COM 173111878SVenu.Iyer@Sun.COM /* 173211878SVenu.Iyer@Sun.COM * Remove interrupt handlers 173311878SVenu.Iyer@Sun.COM */ 173411878SVenu.Iyer@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 173511878SVenu.Iyer@Sun.COM ixgbe_rem_intr_handlers(ixgbe); 173611878SVenu.Iyer@Sun.COM } 173711878SVenu.Iyer@Sun.COM ixgbe->attach_progress &= ~ATTACH_PROGRESS_ADD_INTR; 173811878SVenu.Iyer@Sun.COM 173911878SVenu.Iyer@Sun.COM /* 174011878SVenu.Iyer@Sun.COM * Clear vect_map 174111878SVenu.Iyer@Sun.COM */ 174211878SVenu.Iyer@Sun.COM bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map)); 174311878SVenu.Iyer@Sun.COM switch (cbaction) { 174411878SVenu.Iyer@Sun.COM case DDI_CB_INTR_ADD: 174511878SVenu.Iyer@Sun.COM rc = ddi_intr_alloc(ixgbe->dip, ixgbe->htable, 174611878SVenu.Iyer@Sun.COM DDI_INTR_TYPE_MSIX, ixgbe->intr_cnt, count, &actual, 174711878SVenu.Iyer@Sun.COM DDI_INTR_ALLOC_NORMAL); 174811878SVenu.Iyer@Sun.COM if (rc != DDI_SUCCESS || actual != count) { 174911878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, "Adjust interrupts failed." 175011878SVenu.Iyer@Sun.COM "return: %d, irm cb size: %d, actual: %d", 175111878SVenu.Iyer@Sun.COM rc, count, actual); 175211878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 175311878SVenu.Iyer@Sun.COM } 175411878SVenu.Iyer@Sun.COM ixgbe->intr_cnt += count; 175511878SVenu.Iyer@Sun.COM break; 175611878SVenu.Iyer@Sun.COM 175711878SVenu.Iyer@Sun.COM case DDI_CB_INTR_REMOVE: 175811878SVenu.Iyer@Sun.COM for (i = ixgbe->intr_cnt - count; 175911878SVenu.Iyer@Sun.COM i < ixgbe->intr_cnt; i ++) { 176011878SVenu.Iyer@Sun.COM rc = ddi_intr_free(ixgbe->htable[i]); 176111878SVenu.Iyer@Sun.COM ixgbe->htable[i] = NULL; 176211878SVenu.Iyer@Sun.COM if (rc != DDI_SUCCESS) { 176311878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, "Adjust interrupts failed." 176411878SVenu.Iyer@Sun.COM "return: %d, irm cb size: %d, actual: %d", 176511878SVenu.Iyer@Sun.COM rc, count, actual); 176611878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 176711878SVenu.Iyer@Sun.COM } 176811878SVenu.Iyer@Sun.COM } 176911878SVenu.Iyer@Sun.COM ixgbe->intr_cnt -= count; 177011878SVenu.Iyer@Sun.COM break; 177111878SVenu.Iyer@Sun.COM } 177211878SVenu.Iyer@Sun.COM 177311878SVenu.Iyer@Sun.COM /* 177411878SVenu.Iyer@Sun.COM * Get priority for first vector, assume remaining are all the same 177511878SVenu.Iyer@Sun.COM */ 177611878SVenu.Iyer@Sun.COM rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri); 177711878SVenu.Iyer@Sun.COM if (rc != DDI_SUCCESS) { 177811878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, 177911878SVenu.Iyer@Sun.COM "Get interrupt priority failed: %d", rc); 178011878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 178111878SVenu.Iyer@Sun.COM } 178211878SVenu.Iyer@Sun.COM rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap); 178311878SVenu.Iyer@Sun.COM if (rc != DDI_SUCCESS) { 178411878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, "Get interrupt cap failed: %d", rc); 178511878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 178611878SVenu.Iyer@Sun.COM } 178711878SVenu.Iyer@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR; 178811878SVenu.Iyer@Sun.COM 178911878SVenu.Iyer@Sun.COM /* 179011878SVenu.Iyer@Sun.COM * Map rings to interrupt vectors 179111878SVenu.Iyer@Sun.COM */ 179211878SVenu.Iyer@Sun.COM if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) { 179311878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, 179411878SVenu.Iyer@Sun.COM "IRM CB: Failed to map interrupts to vectors"); 179511878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 179611878SVenu.Iyer@Sun.COM } 179711878SVenu.Iyer@Sun.COM 179811878SVenu.Iyer@Sun.COM /* 179911878SVenu.Iyer@Sun.COM * Add interrupt handlers 180011878SVenu.Iyer@Sun.COM */ 180111878SVenu.Iyer@Sun.COM if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) { 180211878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, "IRM CB: Failed to add interrupt handlers"); 180311878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 180411878SVenu.Iyer@Sun.COM } 180511878SVenu.Iyer@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 180611878SVenu.Iyer@Sun.COM 180711878SVenu.Iyer@Sun.COM /* 180811878SVenu.Iyer@Sun.COM * Now that mutex locks are initialized, and the chip is also 180911878SVenu.Iyer@Sun.COM * initialized, enable interrupts. 181011878SVenu.Iyer@Sun.COM */ 181111878SVenu.Iyer@Sun.COM if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) { 181211878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts"); 181311878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 181411878SVenu.Iyer@Sun.COM } 181511878SVenu.Iyer@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 181611878SVenu.Iyer@Sun.COM if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 181711878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, "IRM CB: Failed to start"); 181811878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 181911878SVenu.Iyer@Sun.COM } 182011878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST; 182111878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED; 182211878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state |= IXGBE_STARTED; 182311878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 182411878SVenu.Iyer@Sun.COM 182511878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 182611878SVenu.Iyer@Sun.COM mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, 182711878SVenu.Iyer@Sun.COM ixgbe->htable[ixgbe->rx_rings[i].intr_vector]); 182811878SVenu.Iyer@Sun.COM } 182911878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 183011878SVenu.Iyer@Sun.COM mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, 183111878SVenu.Iyer@Sun.COM ixgbe->htable[ixgbe->tx_rings[i].intr_vector]); 183211878SVenu.Iyer@Sun.COM } 183311878SVenu.Iyer@Sun.COM 183411878SVenu.Iyer@Sun.COM /* Wakeup all Tx rings */ 183511878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 183611878SVenu.Iyer@Sun.COM mac_tx_ring_update(ixgbe->mac_hdl, 183711878SVenu.Iyer@Sun.COM ixgbe->tx_rings[i].ring_handle); 183811878SVenu.Iyer@Sun.COM } 183911878SVenu.Iyer@Sun.COM 184011878SVenu.Iyer@Sun.COM IXGBE_DEBUGLOG_3(ixgbe, 184111878SVenu.Iyer@Sun.COM "IRM CB: interrupts new value: 0x%x(0x%x:0x%x).", 184211878SVenu.Iyer@Sun.COM ixgbe->intr_cnt, ixgbe->intr_cnt_min, ixgbe->intr_cnt_max); 184311878SVenu.Iyer@Sun.COM return (DDI_SUCCESS); 184411878SVenu.Iyer@Sun.COM 184511878SVenu.Iyer@Sun.COM intr_adjust_fail: 184611878SVenu.Iyer@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 184711878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 184811878SVenu.Iyer@Sun.COM return (DDI_FAILURE); 184911878SVenu.Iyer@Sun.COM } 185011878SVenu.Iyer@Sun.COM 185111878SVenu.Iyer@Sun.COM /* 185211878SVenu.Iyer@Sun.COM * ixgbe_intr_cb_register - Register interrupt callback function. 185311878SVenu.Iyer@Sun.COM */ 185411878SVenu.Iyer@Sun.COM static int 185511878SVenu.Iyer@Sun.COM ixgbe_intr_cb_register(ixgbe_t *ixgbe) 185611878SVenu.Iyer@Sun.COM { 185711878SVenu.Iyer@Sun.COM if (ddi_cb_register(ixgbe->dip, DDI_CB_FLAG_INTR, ixgbe_cbfunc, 185811878SVenu.Iyer@Sun.COM ixgbe, NULL, &ixgbe->cb_hdl) != DDI_SUCCESS) { 185911878SVenu.Iyer@Sun.COM return (IXGBE_FAILURE); 186011878SVenu.Iyer@Sun.COM } 186111878SVenu.Iyer@Sun.COM IXGBE_DEBUGLOG_0(ixgbe, "Interrupt callback function registered."); 186211878SVenu.Iyer@Sun.COM return (IXGBE_SUCCESS); 186311878SVenu.Iyer@Sun.COM } 186411878SVenu.Iyer@Sun.COM 186511878SVenu.Iyer@Sun.COM /* 18666621Sbt150084 * ixgbe_alloc_rings - Allocate memory space for rx/tx rings. 18676621Sbt150084 */ 18686621Sbt150084 static int 18696621Sbt150084 ixgbe_alloc_rings(ixgbe_t *ixgbe) 18706621Sbt150084 { 18716621Sbt150084 /* 18726621Sbt150084 * Allocate memory space for rx rings 18736621Sbt150084 */ 18746621Sbt150084 ixgbe->rx_rings = kmem_zalloc( 18756621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings, 18766621Sbt150084 KM_NOSLEEP); 18776621Sbt150084 18786621Sbt150084 if (ixgbe->rx_rings == NULL) { 18796621Sbt150084 return (IXGBE_FAILURE); 18806621Sbt150084 } 18816621Sbt150084 18826621Sbt150084 /* 18836621Sbt150084 * Allocate memory space for tx rings 18846621Sbt150084 */ 18856621Sbt150084 ixgbe->tx_rings = kmem_zalloc( 18866621Sbt150084 sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings, 18876621Sbt150084 KM_NOSLEEP); 18886621Sbt150084 18896621Sbt150084 if (ixgbe->tx_rings == NULL) { 18906621Sbt150084 kmem_free(ixgbe->rx_rings, 18916621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 18926621Sbt150084 ixgbe->rx_rings = NULL; 18936621Sbt150084 return (IXGBE_FAILURE); 18946621Sbt150084 } 18956621Sbt150084 18968275SEric Cheng /* 18978275SEric Cheng * Allocate memory space for rx ring groups 18988275SEric Cheng */ 18998275SEric Cheng ixgbe->rx_groups = kmem_zalloc( 19008275SEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups, 19018275SEric Cheng KM_NOSLEEP); 19028275SEric Cheng 19038275SEric Cheng if (ixgbe->rx_groups == NULL) { 19048275SEric Cheng kmem_free(ixgbe->rx_rings, 19058275SEric Cheng sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 19068275SEric Cheng kmem_free(ixgbe->tx_rings, 19078275SEric Cheng sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings); 19088275SEric Cheng ixgbe->rx_rings = NULL; 19098275SEric Cheng ixgbe->tx_rings = NULL; 19108275SEric Cheng return (IXGBE_FAILURE); 19118275SEric Cheng } 19128275SEric Cheng 19136621Sbt150084 return (IXGBE_SUCCESS); 19146621Sbt150084 } 19156621Sbt150084 19166621Sbt150084 /* 19176621Sbt150084 * ixgbe_free_rings - Free the memory space of rx/tx rings. 19186621Sbt150084 */ 19196621Sbt150084 static void 19206621Sbt150084 ixgbe_free_rings(ixgbe_t *ixgbe) 19216621Sbt150084 { 19226621Sbt150084 if (ixgbe->rx_rings != NULL) { 19236621Sbt150084 kmem_free(ixgbe->rx_rings, 19246621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 19256621Sbt150084 ixgbe->rx_rings = NULL; 19266621Sbt150084 } 19276621Sbt150084 19286621Sbt150084 if (ixgbe->tx_rings != NULL) { 19296621Sbt150084 kmem_free(ixgbe->tx_rings, 19306621Sbt150084 sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings); 19316621Sbt150084 ixgbe->tx_rings = NULL; 19326621Sbt150084 } 19338275SEric Cheng 19348275SEric Cheng if (ixgbe->rx_groups != NULL) { 19358275SEric Cheng kmem_free(ixgbe->rx_groups, 19368275SEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups); 19378275SEric Cheng ixgbe->rx_groups = NULL; 19388275SEric Cheng } 19396621Sbt150084 } 19406621Sbt150084 194110376SChenlu.Chen@Sun.COM static int 194210376SChenlu.Chen@Sun.COM ixgbe_alloc_rx_data(ixgbe_t *ixgbe) 194310376SChenlu.Chen@Sun.COM { 194410376SChenlu.Chen@Sun.COM ixgbe_rx_ring_t *rx_ring; 194510376SChenlu.Chen@Sun.COM int i; 194610376SChenlu.Chen@Sun.COM 194710376SChenlu.Chen@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 194810376SChenlu.Chen@Sun.COM rx_ring = &ixgbe->rx_rings[i]; 194910376SChenlu.Chen@Sun.COM if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS) 195010376SChenlu.Chen@Sun.COM goto alloc_rx_rings_failure; 195110376SChenlu.Chen@Sun.COM } 195210376SChenlu.Chen@Sun.COM return (IXGBE_SUCCESS); 195310376SChenlu.Chen@Sun.COM 195410376SChenlu.Chen@Sun.COM alloc_rx_rings_failure: 195510376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe); 195610376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 195710376SChenlu.Chen@Sun.COM } 195810376SChenlu.Chen@Sun.COM 195910376SChenlu.Chen@Sun.COM static void 196010376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe_t *ixgbe) 196110376SChenlu.Chen@Sun.COM { 196210376SChenlu.Chen@Sun.COM ixgbe_rx_ring_t *rx_ring; 196310376SChenlu.Chen@Sun.COM ixgbe_rx_data_t *rx_data; 196410376SChenlu.Chen@Sun.COM int i; 196510376SChenlu.Chen@Sun.COM 196610376SChenlu.Chen@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 196710376SChenlu.Chen@Sun.COM rx_ring = &ixgbe->rx_rings[i]; 196810376SChenlu.Chen@Sun.COM 196910376SChenlu.Chen@Sun.COM mutex_enter(&ixgbe->rx_pending_lock); 197010376SChenlu.Chen@Sun.COM rx_data = rx_ring->rx_data; 197110376SChenlu.Chen@Sun.COM 197210376SChenlu.Chen@Sun.COM if (rx_data != NULL) { 197310376SChenlu.Chen@Sun.COM rx_data->flag |= IXGBE_RX_STOPPED; 197410376SChenlu.Chen@Sun.COM 197510376SChenlu.Chen@Sun.COM if (rx_data->rcb_pending == 0) { 197610376SChenlu.Chen@Sun.COM ixgbe_free_rx_ring_data(rx_data); 197710376SChenlu.Chen@Sun.COM rx_ring->rx_data = NULL; 197810376SChenlu.Chen@Sun.COM } 197910376SChenlu.Chen@Sun.COM } 198010376SChenlu.Chen@Sun.COM 198110376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->rx_pending_lock); 198210376SChenlu.Chen@Sun.COM } 198310376SChenlu.Chen@Sun.COM } 198410376SChenlu.Chen@Sun.COM 19856621Sbt150084 /* 19866621Sbt150084 * ixgbe_setup_rings - Setup rx/tx rings. 19876621Sbt150084 */ 19886621Sbt150084 static void 19896621Sbt150084 ixgbe_setup_rings(ixgbe_t *ixgbe) 19906621Sbt150084 { 19916621Sbt150084 /* 19926621Sbt150084 * Setup the rx/tx rings, including the following: 19936621Sbt150084 * 19946621Sbt150084 * 1. Setup the descriptor ring and the control block buffers; 19956621Sbt150084 * 2. Initialize necessary registers for receive/transmit; 19966621Sbt150084 * 3. Initialize software pointers/parameters for receive/transmit; 19976621Sbt150084 */ 19986621Sbt150084 ixgbe_setup_rx(ixgbe); 19996621Sbt150084 20006621Sbt150084 ixgbe_setup_tx(ixgbe); 20016621Sbt150084 } 20026621Sbt150084 20036621Sbt150084 static void 20046621Sbt150084 ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring) 20056621Sbt150084 { 20066621Sbt150084 ixgbe_t *ixgbe = rx_ring->ixgbe; 200710376SChenlu.Chen@Sun.COM ixgbe_rx_data_t *rx_data = rx_ring->rx_data; 20086621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 20096621Sbt150084 rx_control_block_t *rcb; 20106621Sbt150084 union ixgbe_adv_rx_desc *rbd; 20116621Sbt150084 uint32_t size; 20126621Sbt150084 uint32_t buf_low; 20136621Sbt150084 uint32_t buf_high; 20146621Sbt150084 uint32_t reg_val; 20156621Sbt150084 int i; 20166621Sbt150084 20176621Sbt150084 ASSERT(mutex_owned(&rx_ring->rx_lock)); 20186621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 20196621Sbt150084 20206621Sbt150084 for (i = 0; i < ixgbe->rx_ring_size; i++) { 202110376SChenlu.Chen@Sun.COM rcb = rx_data->work_list[i]; 202210376SChenlu.Chen@Sun.COM rbd = &rx_data->rbd_ring[i]; 20236621Sbt150084 20246621Sbt150084 rbd->read.pkt_addr = rcb->rx_buf.dma_address; 20256621Sbt150084 rbd->read.hdr_addr = NULL; 20266621Sbt150084 } 20276621Sbt150084 20286621Sbt150084 /* 20296621Sbt150084 * Initialize the length register 20306621Sbt150084 */ 203110376SChenlu.Chen@Sun.COM size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc); 203211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->hw_index), size); 20336621Sbt150084 20346621Sbt150084 /* 20356621Sbt150084 * Initialize the base address registers 20366621Sbt150084 */ 203710376SChenlu.Chen@Sun.COM buf_low = (uint32_t)rx_data->rbd_area.dma_address; 203810376SChenlu.Chen@Sun.COM buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32); 203911878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->hw_index), buf_high); 204011878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->hw_index), buf_low); 20416621Sbt150084 20426621Sbt150084 /* 20436621Sbt150084 * Setup head & tail pointers 20446621Sbt150084 */ 204511878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->hw_index), 204611878SVenu.Iyer@Sun.COM rx_data->ring_size - 1); 204711878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->hw_index), 0); 20486621Sbt150084 204910376SChenlu.Chen@Sun.COM rx_data->rbd_next = 0; 205011486SZhen.W@Sun.COM rx_data->lro_first = 0; 20516621Sbt150084 20526621Sbt150084 /* 20536621Sbt150084 * Setup the Receive Descriptor Control Register (RXDCTL) 20546621Sbt150084 * PTHRESH=32 descriptors (half the internal cache) 20556621Sbt150084 * HTHRESH=0 descriptors (to minimize latency on fetch) 20566621Sbt150084 * WTHRESH defaults to 1 (writeback each descriptor) 20576621Sbt150084 */ 205811878SVenu.Iyer@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index)); 20596621Sbt150084 reg_val |= IXGBE_RXDCTL_ENABLE; /* enable queue */ 20609353SSamuel.Tu@Sun.COM 20619353SSamuel.Tu@Sun.COM /* Not a valid value for 82599 */ 20629353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 20639353SSamuel.Tu@Sun.COM reg_val |= 0x0020; /* pthresh */ 20649353SSamuel.Tu@Sun.COM } 206511878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val); 20666621Sbt150084 20679353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 20689353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 20699353SSamuel.Tu@Sun.COM reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS); 20709353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); 20719353SSamuel.Tu@Sun.COM } 20729353SSamuel.Tu@Sun.COM 20736621Sbt150084 /* 20746621Sbt150084 * Setup the Split and Replication Receive Control Register. 20756621Sbt150084 * Set the rx buffer size and the advanced descriptor type. 20766621Sbt150084 */ 20776621Sbt150084 reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) | 20786621Sbt150084 IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 20799353SSamuel.Tu@Sun.COM reg_val |= IXGBE_SRRCTL_DROP_EN; 208011878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->hw_index), reg_val); 20816621Sbt150084 } 20826621Sbt150084 20836621Sbt150084 static void 20846621Sbt150084 ixgbe_setup_rx(ixgbe_t *ixgbe) 20856621Sbt150084 { 20866621Sbt150084 ixgbe_rx_ring_t *rx_ring; 20876621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 20886621Sbt150084 uint32_t reg_val; 20898275SEric Cheng uint32_t ring_mapping; 209011878SVenu.Iyer@Sun.COM uint32_t i, index; 209111878SVenu.Iyer@Sun.COM uint32_t psrtype_rss_bit; 20926621Sbt150084 20939353SSamuel.Tu@Sun.COM /* PSRTYPE must be configured for 82599 */ 209411878SVenu.Iyer@Sun.COM if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ && 209511878SVenu.Iyer@Sun.COM ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) { 209611878SVenu.Iyer@Sun.COM reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | 209711878SVenu.Iyer@Sun.COM IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR; 209811878SVenu.Iyer@Sun.COM reg_val |= IXGBE_PSRTYPE_L2HDR; 209911878SVenu.Iyer@Sun.COM reg_val |= 0x80000000; 210011878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val); 210111878SVenu.Iyer@Sun.COM } else { 210211878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups > 32) { 210311878SVenu.Iyer@Sun.COM psrtype_rss_bit = 0x20000000; 210411878SVenu.Iyer@Sun.COM } else { 210511878SVenu.Iyer@Sun.COM psrtype_rss_bit = 0x40000000; 210611878SVenu.Iyer@Sun.COM } 210711878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->capab->max_rx_grp_num; i++) { 210811878SVenu.Iyer@Sun.COM reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | 210911878SVenu.Iyer@Sun.COM IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR; 211011878SVenu.Iyer@Sun.COM reg_val |= IXGBE_PSRTYPE_L2HDR; 211111878SVenu.Iyer@Sun.COM reg_val |= psrtype_rss_bit; 211211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val); 211311878SVenu.Iyer@Sun.COM } 211411878SVenu.Iyer@Sun.COM } 21159353SSamuel.Tu@Sun.COM 21166621Sbt150084 /* 21176621Sbt150084 * Set filter control in FCTRL to accept broadcast packets and do 21186621Sbt150084 * not pass pause frames to host. Flow control settings are already 21196621Sbt150084 * in this register, so preserve them. 21206621Sbt150084 */ 21216621Sbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL); 21226621Sbt150084 reg_val |= IXGBE_FCTRL_BAM; /* broadcast accept mode */ 21236621Sbt150084 reg_val |= IXGBE_FCTRL_DPF; /* discard pause frames */ 21246621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val); 21256621Sbt150084 21266621Sbt150084 /* 212711878SVenu.Iyer@Sun.COM * Hardware checksum settings 212811878SVenu.Iyer@Sun.COM */ 212911878SVenu.Iyer@Sun.COM if (ixgbe->rx_hcksum_enable) { 213011878SVenu.Iyer@Sun.COM reg_val = IXGBE_RXCSUM_IPPCSE; /* IP checksum */ 213111878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val); 213211878SVenu.Iyer@Sun.COM } 213311878SVenu.Iyer@Sun.COM 213411878SVenu.Iyer@Sun.COM /* 213511878SVenu.Iyer@Sun.COM * Setup VMDq and RSS for multiple receive queues 213611878SVenu.Iyer@Sun.COM */ 213711878SVenu.Iyer@Sun.COM switch (ixgbe->classify_mode) { 213811878SVenu.Iyer@Sun.COM case IXGBE_CLASSIFY_RSS: 213911878SVenu.Iyer@Sun.COM /* 214011878SVenu.Iyer@Sun.COM * One group, only RSS is needed when more than 214111878SVenu.Iyer@Sun.COM * one ring enabled. 214211878SVenu.Iyer@Sun.COM */ 214311878SVenu.Iyer@Sun.COM ixgbe_setup_rss(ixgbe); 214411878SVenu.Iyer@Sun.COM break; 214511878SVenu.Iyer@Sun.COM 214611878SVenu.Iyer@Sun.COM case IXGBE_CLASSIFY_VMDQ: 214711878SVenu.Iyer@Sun.COM /* 214811878SVenu.Iyer@Sun.COM * Multiple groups, each group has one ring, 214911878SVenu.Iyer@Sun.COM * only VMDq is needed. 215011878SVenu.Iyer@Sun.COM */ 215111878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq(ixgbe); 215211878SVenu.Iyer@Sun.COM break; 215311878SVenu.Iyer@Sun.COM 215411878SVenu.Iyer@Sun.COM case IXGBE_CLASSIFY_VMDQ_RSS: 215511878SVenu.Iyer@Sun.COM /* 215611878SVenu.Iyer@Sun.COM * Multiple groups and multiple rings, both 215711878SVenu.Iyer@Sun.COM * VMDq and RSS are needed. 215811878SVenu.Iyer@Sun.COM */ 215911878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss(ixgbe); 216011878SVenu.Iyer@Sun.COM break; 216111878SVenu.Iyer@Sun.COM 216211878SVenu.Iyer@Sun.COM default: 216311878SVenu.Iyer@Sun.COM break; 216411878SVenu.Iyer@Sun.COM } 216511878SVenu.Iyer@Sun.COM 216611878SVenu.Iyer@Sun.COM /* 21676621Sbt150084 * Enable the receive unit. This must be done after filter 21686621Sbt150084 * control is set in FCTRL. 21696621Sbt150084 */ 21706621Sbt150084 reg_val = (IXGBE_RXCTRL_RXEN /* Enable Receive Unit */ 21716621Sbt150084 | IXGBE_RXCTRL_DMBYPS); /* descriptor monitor bypass */ 21726621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); 21736621Sbt150084 21746621Sbt150084 /* 21756621Sbt150084 * ixgbe_setup_rx_ring must be called after configuring RXCTRL 21766621Sbt150084 */ 21776621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 21786621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 21796621Sbt150084 ixgbe_setup_rx_ring(rx_ring); 21806621Sbt150084 } 21816621Sbt150084 21826621Sbt150084 /* 21838275SEric Cheng * Setup the per-ring statistics mapping. 21848275SEric Cheng */ 21858275SEric Cheng ring_mapping = 0; 21868275SEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) { 218711878SVenu.Iyer@Sun.COM index = ixgbe->rx_rings[i].hw_index; 218811878SVenu.Iyer@Sun.COM ring_mapping = IXGBE_READ_REG(hw, IXGBE_RQSMR(index >> 2)); 218911878SVenu.Iyer@Sun.COM ring_mapping |= (i & 0xF) << (8 * (index & 0x3)); 219011878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RQSMR(index >> 2), ring_mapping); 219111878SVenu.Iyer@Sun.COM } 21928275SEric Cheng 21938275SEric Cheng /* 21949353SSamuel.Tu@Sun.COM * The Max Frame Size in MHADD/MAXFRS will be internally increased 21959353SSamuel.Tu@Sun.COM * by four bytes if the packet has a VLAN field, so includes MTU, 21969353SSamuel.Tu@Sun.COM * ethernet header and frame check sequence. 21979353SSamuel.Tu@Sun.COM * Register is MAXFRS in 82599. 21986621Sbt150084 */ 21996621Sbt150084 reg_val = (ixgbe->default_mtu + sizeof (struct ether_header) 22006621Sbt150084 + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT; 22016621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val); 22026621Sbt150084 22036621Sbt150084 /* 22046621Sbt150084 * Setup Jumbo Frame enable bit 22056621Sbt150084 */ 22066621Sbt150084 if (ixgbe->default_mtu > ETHERMTU) { 22076621Sbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); 22086621Sbt150084 reg_val |= IXGBE_HLREG0_JUMBOEN; 22096621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); 22106621Sbt150084 } 221111891SVenu.Iyer@Sun.COM 221211891SVenu.Iyer@Sun.COM /* 221311891SVenu.Iyer@Sun.COM * Setup RSC for multiple receive queues. 221411891SVenu.Iyer@Sun.COM */ 221511891SVenu.Iyer@Sun.COM if (ixgbe->lro_enable) { 221611891SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 221711891SVenu.Iyer@Sun.COM /* 221811891SVenu.Iyer@Sun.COM * Make sure rx_buf_size * MAXDESC not greater 221911891SVenu.Iyer@Sun.COM * than 65535. 222011891SVenu.Iyer@Sun.COM * Intel recommends 4 for MAXDESC field value. 222111891SVenu.Iyer@Sun.COM */ 222211891SVenu.Iyer@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RSCCTL(i)); 222311891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RSCCTL_RSCEN; 222411891SVenu.Iyer@Sun.COM if (ixgbe->rx_buf_size == IXGBE_PKG_BUF_16k) 222511891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RSCCTL_MAXDESC_1; 222611891SVenu.Iyer@Sun.COM else 222711891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RSCCTL_MAXDESC_4; 222811891SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(i), reg_val); 222911891SVenu.Iyer@Sun.COM } 223011891SVenu.Iyer@Sun.COM 223111891SVenu.Iyer@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RSCDBU); 223211891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RSCDBU_RSCACKDIS; 223311891SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, reg_val); 223411891SVenu.Iyer@Sun.COM 223511891SVenu.Iyer@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 223611891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RDRXCTL_RSCACKC; 223712003SPaul.Guo@Sun.COM reg_val |= IXGBE_RDRXCTL_FCOE_WRFIX; 223811891SVenu.Iyer@Sun.COM reg_val &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; 223911891SVenu.Iyer@Sun.COM 224011891SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); 224111891SVenu.Iyer@Sun.COM } 22426621Sbt150084 } 22436621Sbt150084 22446621Sbt150084 static void 22456621Sbt150084 ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring) 22466621Sbt150084 { 22476621Sbt150084 ixgbe_t *ixgbe = tx_ring->ixgbe; 22486621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 22496621Sbt150084 uint32_t size; 22506621Sbt150084 uint32_t buf_low; 22516621Sbt150084 uint32_t buf_high; 22526621Sbt150084 uint32_t reg_val; 22536621Sbt150084 22546621Sbt150084 ASSERT(mutex_owned(&tx_ring->tx_lock)); 22556621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 22566621Sbt150084 22576621Sbt150084 /* 22586621Sbt150084 * Initialize the length register 22596621Sbt150084 */ 22606621Sbt150084 size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc); 22616621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size); 22626621Sbt150084 22636621Sbt150084 /* 22646621Sbt150084 * Initialize the base address registers 22656621Sbt150084 */ 22666621Sbt150084 buf_low = (uint32_t)tx_ring->tbd_area.dma_address; 22676621Sbt150084 buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32); 22686621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low); 22696621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high); 22706621Sbt150084 22716621Sbt150084 /* 22726621Sbt150084 * Setup head & tail pointers 22736621Sbt150084 */ 22746621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0); 22756621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0); 22766621Sbt150084 22776621Sbt150084 /* 22786621Sbt150084 * Setup head write-back 22796621Sbt150084 */ 22806621Sbt150084 if (ixgbe->tx_head_wb_enable) { 22816621Sbt150084 /* 22826621Sbt150084 * The memory of the head write-back is allocated using 22836621Sbt150084 * the extra tbd beyond the tail of the tbd ring. 22846621Sbt150084 */ 22856621Sbt150084 tx_ring->tbd_head_wb = (uint32_t *) 22866621Sbt150084 ((uintptr_t)tx_ring->tbd_area.address + size); 22876621Sbt150084 *tx_ring->tbd_head_wb = 0; 22886621Sbt150084 22896621Sbt150084 buf_low = (uint32_t) 22906621Sbt150084 (tx_ring->tbd_area.dma_address + size); 22916621Sbt150084 buf_high = (uint32_t) 22926621Sbt150084 ((tx_ring->tbd_area.dma_address + size) >> 32); 22936621Sbt150084 22946621Sbt150084 /* Set the head write-back enable bit */ 22956621Sbt150084 buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE; 22966621Sbt150084 22976621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low); 22986621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high); 22996621Sbt150084 23006621Sbt150084 /* 23016621Sbt150084 * Turn off relaxed ordering for head write back or it will 23026621Sbt150084 * cause problems with the tx recycling 23036621Sbt150084 */ 23046621Sbt150084 reg_val = IXGBE_READ_REG(hw, 23056621Sbt150084 IXGBE_DCA_TXCTRL(tx_ring->index)); 23066621Sbt150084 reg_val &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; 23076621Sbt150084 IXGBE_WRITE_REG(hw, 23086621Sbt150084 IXGBE_DCA_TXCTRL(tx_ring->index), reg_val); 23096621Sbt150084 } else { 23106621Sbt150084 tx_ring->tbd_head_wb = NULL; 23116621Sbt150084 } 23126621Sbt150084 23136621Sbt150084 tx_ring->tbd_head = 0; 23146621Sbt150084 tx_ring->tbd_tail = 0; 23156621Sbt150084 tx_ring->tbd_free = tx_ring->ring_size; 23166621Sbt150084 231710376SChenlu.Chen@Sun.COM if (ixgbe->tx_ring_init == B_TRUE) { 23186621Sbt150084 tx_ring->tcb_head = 0; 23196621Sbt150084 tx_ring->tcb_tail = 0; 23206621Sbt150084 tx_ring->tcb_free = tx_ring->free_list_size; 23216621Sbt150084 } 23226621Sbt150084 23236621Sbt150084 /* 23247245Sgg161487 * Initialize the s/w context structure 23256621Sbt150084 */ 23267245Sgg161487 bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t)); 23276621Sbt150084 } 23286621Sbt150084 23296621Sbt150084 static void 23306621Sbt150084 ixgbe_setup_tx(ixgbe_t *ixgbe) 23316621Sbt150084 { 23327167Sgg161487 struct ixgbe_hw *hw = &ixgbe->hw; 23336621Sbt150084 ixgbe_tx_ring_t *tx_ring; 23347167Sgg161487 uint32_t reg_val; 23358275SEric Cheng uint32_t ring_mapping; 23366621Sbt150084 int i; 23376621Sbt150084 23386621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 23396621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 23406621Sbt150084 ixgbe_setup_tx_ring(tx_ring); 23416621Sbt150084 } 23427167Sgg161487 23437167Sgg161487 /* 23448275SEric Cheng * Setup the per-ring statistics mapping. 23458275SEric Cheng */ 23468275SEric Cheng ring_mapping = 0; 23478275SEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) { 23488275SEric Cheng ring_mapping |= (i & 0xF) << (8 * (i & 0x3)); 23498275SEric Cheng if ((i & 0x3) == 0x3) { 23509353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 23519353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), 23529353SSamuel.Tu@Sun.COM ring_mapping); 23539353SSamuel.Tu@Sun.COM } else { 23549353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), 23559353SSamuel.Tu@Sun.COM ring_mapping); 23569353SSamuel.Tu@Sun.COM } 23578275SEric Cheng ring_mapping = 0; 23588275SEric Cheng } 23598275SEric Cheng } 23608275SEric Cheng if ((i & 0x3) != 0x3) 23619353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 23629353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping); 23639353SSamuel.Tu@Sun.COM } else { 23649353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping); 23659353SSamuel.Tu@Sun.COM } 23668275SEric Cheng 23678275SEric Cheng /* 23687167Sgg161487 * Enable CRC appending and TX padding (for short tx frames) 23697167Sgg161487 */ 23707167Sgg161487 reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); 23717167Sgg161487 reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN; 23727167Sgg161487 IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); 23739353SSamuel.Tu@Sun.COM 23749353SSamuel.Tu@Sun.COM /* 23759353SSamuel.Tu@Sun.COM * enable DMA for 82599 parts 23769353SSamuel.Tu@Sun.COM */ 23779353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 23789353SSamuel.Tu@Sun.COM /* DMATXCTL.TE must be set after all Tx config is complete */ 23799353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 23809353SSamuel.Tu@Sun.COM reg_val |= IXGBE_DMATXCTL_TE; 23819353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val); 23829353SSamuel.Tu@Sun.COM } 23839353SSamuel.Tu@Sun.COM 23849353SSamuel.Tu@Sun.COM /* 23859353SSamuel.Tu@Sun.COM * Enabling tx queues .. 23869353SSamuel.Tu@Sun.COM * For 82599 must be done after DMATXCTL.TE is set 23879353SSamuel.Tu@Sun.COM */ 23889353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 23899353SSamuel.Tu@Sun.COM tx_ring = &ixgbe->tx_rings[i]; 23909353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index)); 23919353SSamuel.Tu@Sun.COM reg_val |= IXGBE_TXDCTL_ENABLE; 23929353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val); 23939353SSamuel.Tu@Sun.COM } 23946621Sbt150084 } 23956621Sbt150084 23966621Sbt150084 /* 23976621Sbt150084 * ixgbe_setup_rss - Setup receive-side scaling feature. 23986621Sbt150084 */ 23996621Sbt150084 static void 24006621Sbt150084 ixgbe_setup_rss(ixgbe_t *ixgbe) 24016621Sbt150084 { 24026621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 24037167Sgg161487 uint32_t i, mrqc, rxcsum; 24046621Sbt150084 uint32_t random; 24056621Sbt150084 uint32_t reta; 240611878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 24076621Sbt150084 24086621Sbt150084 /* 24096621Sbt150084 * Fill out redirection table 24106621Sbt150084 */ 24116621Sbt150084 reta = 0; 241211878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 241311878SVenu.Iyer@Sun.COM 24146621Sbt150084 for (i = 0; i < 128; i++) { 241511878SVenu.Iyer@Sun.COM reta = (reta << 8) | (i % ring_per_group) | 241611878SVenu.Iyer@Sun.COM ((i % ring_per_group) << 4); 24177167Sgg161487 if ((i & 3) == 3) 24186621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 24196621Sbt150084 } 24206621Sbt150084 24216621Sbt150084 /* 24226621Sbt150084 * Fill out hash function seeds with a random constant 24236621Sbt150084 */ 24246621Sbt150084 for (i = 0; i < 10; i++) { 24256621Sbt150084 (void) random_get_pseudo_bytes((uint8_t *)&random, 24266621Sbt150084 sizeof (uint32_t)); 24276621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); 24286621Sbt150084 } 24296621Sbt150084 24306621Sbt150084 /* 24317167Sgg161487 * Enable RSS & perform hash on these packet types 24326621Sbt150084 */ 24336621Sbt150084 mrqc = IXGBE_MRQC_RSSEN | 24346621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4 | 24356621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 24366621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 24376621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 24386621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX | 24396621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6 | 24406621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 24416621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 24426621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 24436621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 24446621Sbt150084 24456621Sbt150084 /* 24466621Sbt150084 * Disable Packet Checksum to enable RSS for multiple receive queues. 24476621Sbt150084 * It is an adapter hardware limitation that Packet Checksum is 24486621Sbt150084 * mutually exclusive with RSS. 24496621Sbt150084 */ 24506621Sbt150084 rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 24516621Sbt150084 rxcsum |= IXGBE_RXCSUM_PCSD; 24526621Sbt150084 rxcsum &= ~IXGBE_RXCSUM_IPPCSE; 24536621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 24546621Sbt150084 } 24556621Sbt150084 24566621Sbt150084 /* 245711878SVenu.Iyer@Sun.COM * ixgbe_setup_vmdq - Setup MAC classification feature 245811878SVenu.Iyer@Sun.COM */ 245911878SVenu.Iyer@Sun.COM static void 246011878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq(ixgbe_t *ixgbe) 246111878SVenu.Iyer@Sun.COM { 246211878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 246311878SVenu.Iyer@Sun.COM uint32_t vmdctl, i, vtctl; 246411878SVenu.Iyer@Sun.COM 246511878SVenu.Iyer@Sun.COM /* 246611878SVenu.Iyer@Sun.COM * Setup the VMDq Control register, enable VMDq based on 246711878SVenu.Iyer@Sun.COM * packet destination MAC address: 246811878SVenu.Iyer@Sun.COM */ 246911878SVenu.Iyer@Sun.COM switch (hw->mac.type) { 247011878SVenu.Iyer@Sun.COM case ixgbe_mac_82598EB: 247111878SVenu.Iyer@Sun.COM /* 247211878SVenu.Iyer@Sun.COM * VMDq Enable = 1; 247311878SVenu.Iyer@Sun.COM * VMDq Filter = 0; MAC filtering 247411878SVenu.Iyer@Sun.COM * Default VMDq output index = 0; 247511878SVenu.Iyer@Sun.COM */ 247611878SVenu.Iyer@Sun.COM vmdctl = IXGBE_VMD_CTL_VMDQ_EN; 247711878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl); 247811878SVenu.Iyer@Sun.COM break; 247911878SVenu.Iyer@Sun.COM 248011878SVenu.Iyer@Sun.COM case ixgbe_mac_82599EB: 248111878SVenu.Iyer@Sun.COM /* 248211878SVenu.Iyer@Sun.COM * Enable VMDq-only. 248311878SVenu.Iyer@Sun.COM */ 248411878SVenu.Iyer@Sun.COM vmdctl = IXGBE_MRQC_VMDQEN; 248511878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl); 248611878SVenu.Iyer@Sun.COM 248711878SVenu.Iyer@Sun.COM for (i = 0; i < hw->mac.num_rar_entries; i++) { 248811878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0); 248911878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0); 249011878SVenu.Iyer@Sun.COM } 249111878SVenu.Iyer@Sun.COM 249211878SVenu.Iyer@Sun.COM /* 249311878SVenu.Iyer@Sun.COM * Enable Virtualization and Replication. 249411878SVenu.Iyer@Sun.COM */ 249511878SVenu.Iyer@Sun.COM vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 249611878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl); 249711878SVenu.Iyer@Sun.COM 249811878SVenu.Iyer@Sun.COM /* 249911878SVenu.Iyer@Sun.COM * Enable receiving packets to all VFs 250011878SVenu.Iyer@Sun.COM */ 250111878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL); 250211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL); 250311878SVenu.Iyer@Sun.COM 250411878SVenu.Iyer@Sun.COM break; 250511878SVenu.Iyer@Sun.COM 250611878SVenu.Iyer@Sun.COM default: 250711878SVenu.Iyer@Sun.COM break; 250811878SVenu.Iyer@Sun.COM } 250911878SVenu.Iyer@Sun.COM } 251011878SVenu.Iyer@Sun.COM 251111878SVenu.Iyer@Sun.COM /* 251211878SVenu.Iyer@Sun.COM * ixgbe_setup_vmdq_rss - Setup both vmdq feature and rss feature. 251311878SVenu.Iyer@Sun.COM */ 251411878SVenu.Iyer@Sun.COM static void 251511878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe) 251611878SVenu.Iyer@Sun.COM { 251711878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 251811878SVenu.Iyer@Sun.COM uint32_t i, mrqc, rxcsum; 251911878SVenu.Iyer@Sun.COM uint32_t random; 252011878SVenu.Iyer@Sun.COM uint32_t reta; 252111878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 252211878SVenu.Iyer@Sun.COM uint32_t vmdctl, vtctl; 252311878SVenu.Iyer@Sun.COM 252411878SVenu.Iyer@Sun.COM /* 252511878SVenu.Iyer@Sun.COM * Fill out redirection table 252611878SVenu.Iyer@Sun.COM */ 252711878SVenu.Iyer@Sun.COM reta = 0; 252811878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 252911878SVenu.Iyer@Sun.COM for (i = 0; i < 128; i++) { 253011878SVenu.Iyer@Sun.COM reta = (reta << 8) | (i % ring_per_group) | 253111878SVenu.Iyer@Sun.COM ((i % ring_per_group) << 4); 253211878SVenu.Iyer@Sun.COM if ((i & 3) == 3) 253311878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 253411878SVenu.Iyer@Sun.COM } 253511878SVenu.Iyer@Sun.COM 253611878SVenu.Iyer@Sun.COM /* 253711878SVenu.Iyer@Sun.COM * Fill out hash function seeds with a random constant 253811878SVenu.Iyer@Sun.COM */ 253911878SVenu.Iyer@Sun.COM for (i = 0; i < 10; i++) { 254011878SVenu.Iyer@Sun.COM (void) random_get_pseudo_bytes((uint8_t *)&random, 254111878SVenu.Iyer@Sun.COM sizeof (uint32_t)); 254211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); 254311878SVenu.Iyer@Sun.COM } 254411878SVenu.Iyer@Sun.COM 254511878SVenu.Iyer@Sun.COM /* 254611878SVenu.Iyer@Sun.COM * Enable and setup RSS and VMDq 254711878SVenu.Iyer@Sun.COM */ 254811878SVenu.Iyer@Sun.COM switch (hw->mac.type) { 254911878SVenu.Iyer@Sun.COM case ixgbe_mac_82598EB: 255011878SVenu.Iyer@Sun.COM /* 255111878SVenu.Iyer@Sun.COM * Enable RSS & Setup RSS Hash functions 255211878SVenu.Iyer@Sun.COM */ 255311878SVenu.Iyer@Sun.COM mrqc = IXGBE_MRQC_RSSEN | 255411878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4 | 255511878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 255611878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 255711878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 255811878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX | 255911878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6 | 256011878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 256111878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 256211878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 256311878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 256411878SVenu.Iyer@Sun.COM 256511878SVenu.Iyer@Sun.COM /* 256611878SVenu.Iyer@Sun.COM * Enable and Setup VMDq 256711878SVenu.Iyer@Sun.COM * VMDq Filter = 0; MAC filtering 256811878SVenu.Iyer@Sun.COM * Default VMDq output index = 0; 256911878SVenu.Iyer@Sun.COM */ 257011878SVenu.Iyer@Sun.COM vmdctl = IXGBE_VMD_CTL_VMDQ_EN; 257111878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl); 257211878SVenu.Iyer@Sun.COM break; 257311878SVenu.Iyer@Sun.COM 257411878SVenu.Iyer@Sun.COM case ixgbe_mac_82599EB: 257511878SVenu.Iyer@Sun.COM /* 257611878SVenu.Iyer@Sun.COM * Enable RSS & Setup RSS Hash functions 257711878SVenu.Iyer@Sun.COM */ 257811878SVenu.Iyer@Sun.COM mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 | 257911878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 258011878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 258111878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 258211878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX | 258311878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6 | 258411878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 258511878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 258611878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 258711878SVenu.Iyer@Sun.COM 258811878SVenu.Iyer@Sun.COM /* 258911878SVenu.Iyer@Sun.COM * Enable VMDq+RSS. 259011878SVenu.Iyer@Sun.COM */ 259111878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups > 32) { 259211878SVenu.Iyer@Sun.COM mrqc = mrqc | IXGBE_MRQC_VMDQRSS64EN; 259311878SVenu.Iyer@Sun.COM } else { 259411878SVenu.Iyer@Sun.COM mrqc = mrqc | IXGBE_MRQC_VMDQRSS32EN; 259511878SVenu.Iyer@Sun.COM } 259611878SVenu.Iyer@Sun.COM 259711878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 259811878SVenu.Iyer@Sun.COM 259911878SVenu.Iyer@Sun.COM for (i = 0; i < hw->mac.num_rar_entries; i++) { 260011878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0); 260111878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0); 260211878SVenu.Iyer@Sun.COM } 260311878SVenu.Iyer@Sun.COM break; 260411878SVenu.Iyer@Sun.COM 260511878SVenu.Iyer@Sun.COM default: 260611878SVenu.Iyer@Sun.COM break; 260711878SVenu.Iyer@Sun.COM 260811878SVenu.Iyer@Sun.COM } 260911878SVenu.Iyer@Sun.COM 261011878SVenu.Iyer@Sun.COM /* 261111878SVenu.Iyer@Sun.COM * Disable Packet Checksum to enable RSS for multiple receive queues. 261211878SVenu.Iyer@Sun.COM * It is an adapter hardware limitation that Packet Checksum is 261311878SVenu.Iyer@Sun.COM * mutually exclusive with RSS. 261411878SVenu.Iyer@Sun.COM */ 261511878SVenu.Iyer@Sun.COM rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 261611878SVenu.Iyer@Sun.COM rxcsum |= IXGBE_RXCSUM_PCSD; 261711878SVenu.Iyer@Sun.COM rxcsum &= ~IXGBE_RXCSUM_IPPCSE; 261811878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 261911878SVenu.Iyer@Sun.COM 262011878SVenu.Iyer@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 262111878SVenu.Iyer@Sun.COM /* 262211878SVenu.Iyer@Sun.COM * Enable Virtualization and Replication. 262311878SVenu.Iyer@Sun.COM */ 262411878SVenu.Iyer@Sun.COM vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 262511878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl); 262611878SVenu.Iyer@Sun.COM 262711878SVenu.Iyer@Sun.COM /* 262811878SVenu.Iyer@Sun.COM * Enable receiving packets to all VFs 262911878SVenu.Iyer@Sun.COM */ 263011878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL); 263111878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL); 263211878SVenu.Iyer@Sun.COM } 263311878SVenu.Iyer@Sun.COM } 263411878SVenu.Iyer@Sun.COM 263511878SVenu.Iyer@Sun.COM /* 26366621Sbt150084 * ixgbe_init_unicst - Initialize the unicast addresses. 26376621Sbt150084 */ 26386621Sbt150084 static void 26396621Sbt150084 ixgbe_init_unicst(ixgbe_t *ixgbe) 26406621Sbt150084 { 26416621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 26428275SEric Cheng uint8_t *mac_addr; 26436621Sbt150084 int slot; 26446621Sbt150084 /* 26456621Sbt150084 * Here we should consider two situations: 26466621Sbt150084 * 26478275SEric Cheng * 1. Chipset is initialized at the first time, 26488275SEric Cheng * Clear all the multiple unicast addresses. 26496621Sbt150084 * 26506621Sbt150084 * 2. Chipset is reset 26516621Sbt150084 * Recover the multiple unicast addresses from the 26526621Sbt150084 * software data structure to the RAR registers. 26536621Sbt150084 */ 26546621Sbt150084 if (!ixgbe->unicst_init) { 26556621Sbt150084 /* 26566621Sbt150084 * Initialize the multiple unicast addresses 26576621Sbt150084 */ 265811878SVenu.Iyer@Sun.COM ixgbe->unicst_total = hw->mac.num_rar_entries; 26598275SEric Cheng ixgbe->unicst_avail = ixgbe->unicst_total; 26608275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 26618275SEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr; 26628275SEric Cheng bzero(mac_addr, ETHERADDRL); 26638275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, NULL, NULL); 26646621Sbt150084 ixgbe->unicst_addr[slot].mac.set = 0; 26658275SEric Cheng } 26666621Sbt150084 ixgbe->unicst_init = B_TRUE; 26676621Sbt150084 } else { 26686621Sbt150084 /* Re-configure the RAR registers */ 26698275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 26708275SEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr; 26718275SEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 1) { 26728275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, 267311878SVenu.Iyer@Sun.COM ixgbe->unicst_addr[slot].mac.group_index, 267411878SVenu.Iyer@Sun.COM IXGBE_RAH_AV); 26758275SEric Cheng } else { 26768275SEric Cheng bzero(mac_addr, ETHERADDRL); 26778275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, 26788275SEric Cheng NULL, NULL); 26798275SEric Cheng } 26808275SEric Cheng } 26816621Sbt150084 } 26826621Sbt150084 } 26838275SEric Cheng 26846621Sbt150084 /* 26858275SEric Cheng * ixgbe_unicst_find - Find the slot for the specified unicast address 26868275SEric Cheng */ 26878275SEric Cheng int 26888275SEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr) 26898275SEric Cheng { 26908275SEric Cheng int slot; 26918275SEric Cheng 26928275SEric Cheng ASSERT(mutex_owned(&ixgbe->gen_lock)); 26938275SEric Cheng 26948275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 26958275SEric Cheng if (bcmp(ixgbe->unicst_addr[slot].mac.addr, 26968275SEric Cheng mac_addr, ETHERADDRL) == 0) 26978275SEric Cheng return (slot); 26988275SEric Cheng } 26998275SEric Cheng 27008275SEric Cheng return (-1); 27018275SEric Cheng } 27028275SEric Cheng 27038275SEric Cheng /* 27046621Sbt150084 * ixgbe_multicst_add - Add a multicst address. 27056621Sbt150084 */ 27066621Sbt150084 int 27076621Sbt150084 ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr) 27086621Sbt150084 { 27096621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 27106621Sbt150084 27116621Sbt150084 if ((multiaddr[0] & 01) == 0) { 27126621Sbt150084 return (EINVAL); 27136621Sbt150084 } 27146621Sbt150084 27156621Sbt150084 if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) { 27166621Sbt150084 return (ENOENT); 27176621Sbt150084 } 27186621Sbt150084 27196621Sbt150084 bcopy(multiaddr, 27206621Sbt150084 &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL); 27216621Sbt150084 ixgbe->mcast_count++; 27226621Sbt150084 27236621Sbt150084 /* 27246621Sbt150084 * Update the multicast table in the hardware 27256621Sbt150084 */ 27266621Sbt150084 ixgbe_setup_multicst(ixgbe); 27276621Sbt150084 27286621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 27296621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 27306621Sbt150084 return (EIO); 27316621Sbt150084 } 27326621Sbt150084 27336621Sbt150084 return (0); 27346621Sbt150084 } 27356621Sbt150084 27366621Sbt150084 /* 27376621Sbt150084 * ixgbe_multicst_remove - Remove a multicst address. 27386621Sbt150084 */ 27396621Sbt150084 int 27406621Sbt150084 ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr) 27416621Sbt150084 { 27426621Sbt150084 int i; 27436621Sbt150084 27446621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 27456621Sbt150084 27466621Sbt150084 for (i = 0; i < ixgbe->mcast_count; i++) { 27476621Sbt150084 if (bcmp(multiaddr, &ixgbe->mcast_table[i], 27486621Sbt150084 ETHERADDRL) == 0) { 27496621Sbt150084 for (i++; i < ixgbe->mcast_count; i++) { 27506621Sbt150084 ixgbe->mcast_table[i - 1] = 27516621Sbt150084 ixgbe->mcast_table[i]; 27526621Sbt150084 } 27536621Sbt150084 ixgbe->mcast_count--; 27546621Sbt150084 break; 27556621Sbt150084 } 27566621Sbt150084 } 27576621Sbt150084 27586621Sbt150084 /* 27596621Sbt150084 * Update the multicast table in the hardware 27606621Sbt150084 */ 27616621Sbt150084 ixgbe_setup_multicst(ixgbe); 27626621Sbt150084 27636621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 27646621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 27656621Sbt150084 return (EIO); 27666621Sbt150084 } 27676621Sbt150084 27686621Sbt150084 return (0); 27696621Sbt150084 } 27706621Sbt150084 27716621Sbt150084 /* 27726621Sbt150084 * ixgbe_setup_multicast - Setup multicast data structures. 27736621Sbt150084 * 27746621Sbt150084 * This routine initializes all of the multicast related structures 27756621Sbt150084 * and save them in the hardware registers. 27766621Sbt150084 */ 27776621Sbt150084 static void 27786621Sbt150084 ixgbe_setup_multicst(ixgbe_t *ixgbe) 27796621Sbt150084 { 27806621Sbt150084 uint8_t *mc_addr_list; 27816621Sbt150084 uint32_t mc_addr_count; 27826621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 27836621Sbt150084 27846621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 27856621Sbt150084 27866621Sbt150084 ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES); 27876621Sbt150084 27886621Sbt150084 mc_addr_list = (uint8_t *)ixgbe->mcast_table; 27896621Sbt150084 mc_addr_count = ixgbe->mcast_count; 27906621Sbt150084 27916621Sbt150084 /* 27926621Sbt150084 * Update the multicast addresses to the MTA registers 27936621Sbt150084 */ 27946621Sbt150084 (void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count, 27956621Sbt150084 ixgbe_mc_table_itr); 27966621Sbt150084 } 27976621Sbt150084 27986621Sbt150084 /* 279911878SVenu.Iyer@Sun.COM * ixgbe_setup_vmdq_rss_conf - Configure vmdq and rss (number and mode). 280011878SVenu.Iyer@Sun.COM * 280111878SVenu.Iyer@Sun.COM * Configure the rx classification mode (vmdq & rss) and vmdq & rss numbers. 280211878SVenu.Iyer@Sun.COM * Different chipsets may have different allowed configuration of vmdq and rss. 280311878SVenu.Iyer@Sun.COM */ 280411878SVenu.Iyer@Sun.COM static void 280511878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe) 280611878SVenu.Iyer@Sun.COM { 280711878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 280811878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 280911878SVenu.Iyer@Sun.COM 281011878SVenu.Iyer@Sun.COM switch (hw->mac.type) { 281111878SVenu.Iyer@Sun.COM case ixgbe_mac_82598EB: 281211878SVenu.Iyer@Sun.COM /* 281311878SVenu.Iyer@Sun.COM * 82598 supports the following combination: 281411878SVenu.Iyer@Sun.COM * vmdq no. x rss no. 281511878SVenu.Iyer@Sun.COM * [5..16] x 1 281611878SVenu.Iyer@Sun.COM * [1..4] x [1..16] 281711878SVenu.Iyer@Sun.COM * However 8 rss queue per pool (vmdq) is sufficient for 281811878SVenu.Iyer@Sun.COM * most cases. 281911878SVenu.Iyer@Sun.COM */ 282011878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 282111878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups > 4) { 282211878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups; 282311878SVenu.Iyer@Sun.COM } else { 282411878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 282511878SVenu.Iyer@Sun.COM min(8, ring_per_group); 282611878SVenu.Iyer@Sun.COM } 282711878SVenu.Iyer@Sun.COM 282811878SVenu.Iyer@Sun.COM break; 282911878SVenu.Iyer@Sun.COM 283011878SVenu.Iyer@Sun.COM case ixgbe_mac_82599EB: 283111878SVenu.Iyer@Sun.COM /* 283211878SVenu.Iyer@Sun.COM * 82599 supports the following combination: 283311878SVenu.Iyer@Sun.COM * vmdq no. x rss no. 283411878SVenu.Iyer@Sun.COM * [33..64] x [1..2] 283511878SVenu.Iyer@Sun.COM * [2..32] x [1..4] 283611878SVenu.Iyer@Sun.COM * 1 x [1..16] 283711878SVenu.Iyer@Sun.COM * However 8 rss queue per pool (vmdq) is sufficient for 283811878SVenu.Iyer@Sun.COM * most cases. 283911878SVenu.Iyer@Sun.COM */ 284011878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 284111878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups == 1) { 284211878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = min(8, ring_per_group); 284311878SVenu.Iyer@Sun.COM } else if (ixgbe->num_rx_groups <= 32) { 284411878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 284511878SVenu.Iyer@Sun.COM min(4, ring_per_group); 284611878SVenu.Iyer@Sun.COM } else if (ixgbe->num_rx_groups <= 64) { 284711878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 284811878SVenu.Iyer@Sun.COM min(2, ring_per_group); 284911878SVenu.Iyer@Sun.COM } 285011878SVenu.Iyer@Sun.COM 285111878SVenu.Iyer@Sun.COM break; 285211878SVenu.Iyer@Sun.COM 285311878SVenu.Iyer@Sun.COM default: 285411878SVenu.Iyer@Sun.COM break; 285511878SVenu.Iyer@Sun.COM } 285611878SVenu.Iyer@Sun.COM 285711878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 285811878SVenu.Iyer@Sun.COM 285911878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups == 1 && ring_per_group == 1) { 286011878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 286111878SVenu.Iyer@Sun.COM } else if (ixgbe->num_rx_groups != 1 && ring_per_group == 1) { 286211878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ; 286311878SVenu.Iyer@Sun.COM } else if (ixgbe->num_rx_groups != 1 && ring_per_group != 1) { 286411878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ_RSS; 286511878SVenu.Iyer@Sun.COM } else { 286611878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_RSS; 286711878SVenu.Iyer@Sun.COM } 286811878SVenu.Iyer@Sun.COM 286912003SPaul.Guo@Sun.COM IXGBE_DEBUGLOG_2(ixgbe, "rx group number:%d, rx ring number:%d", 287011878SVenu.Iyer@Sun.COM ixgbe->num_rx_groups, ixgbe->num_rx_rings); 287111878SVenu.Iyer@Sun.COM } 287211878SVenu.Iyer@Sun.COM 287311878SVenu.Iyer@Sun.COM /* 28746621Sbt150084 * ixgbe_get_conf - Get driver configurations set in driver.conf. 28756621Sbt150084 * 28766621Sbt150084 * This routine gets user-configured values out of the configuration 28776621Sbt150084 * file ixgbe.conf. 28786621Sbt150084 * 28796621Sbt150084 * For each configurable value, there is a minimum, a maximum, and a 28806621Sbt150084 * default. 28816621Sbt150084 * If user does not configure a value, use the default. 28826621Sbt150084 * If user configures below the minimum, use the minumum. 28836621Sbt150084 * If user configures above the maximum, use the maxumum. 28846621Sbt150084 */ 28856621Sbt150084 static void 28866621Sbt150084 ixgbe_get_conf(ixgbe_t *ixgbe) 28876621Sbt150084 { 28886621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 28896621Sbt150084 uint32_t flow_control; 28906621Sbt150084 28916621Sbt150084 /* 28926621Sbt150084 * ixgbe driver supports the following user configurations: 28936621Sbt150084 * 28946621Sbt150084 * Jumbo frame configuration: 28956621Sbt150084 * default_mtu 28966621Sbt150084 * 28976621Sbt150084 * Ethernet flow control configuration: 28986621Sbt150084 * flow_control 28996621Sbt150084 * 29006621Sbt150084 * Multiple rings configurations: 29016621Sbt150084 * tx_queue_number 29026621Sbt150084 * tx_ring_size 29036621Sbt150084 * rx_queue_number 29046621Sbt150084 * rx_ring_size 29056621Sbt150084 * 29066621Sbt150084 * Call ixgbe_get_prop() to get the value for a specific 29076621Sbt150084 * configuration parameter. 29086621Sbt150084 */ 29096621Sbt150084 29106621Sbt150084 /* 29116621Sbt150084 * Jumbo frame configuration - max_frame_size controls host buffer 29126621Sbt150084 * allocation, so includes MTU, ethernet header, vlan tag and 29136621Sbt150084 * frame check sequence. 29146621Sbt150084 */ 29156621Sbt150084 ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU, 291611150SZhen.W@Sun.COM MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU); 29176621Sbt150084 29186621Sbt150084 ixgbe->max_frame_size = ixgbe->default_mtu + 29196621Sbt150084 sizeof (struct ether_vlan_header) + ETHERFCSL; 29206621Sbt150084 29216621Sbt150084 /* 29226621Sbt150084 * Ethernet flow control configuration 29236621Sbt150084 */ 29246621Sbt150084 flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL, 29258275SEric Cheng ixgbe_fc_none, 3, ixgbe_fc_none); 29266621Sbt150084 if (flow_control == 3) 29276621Sbt150084 flow_control = ixgbe_fc_default; 29286621Sbt150084 29299353SSamuel.Tu@Sun.COM /* 29309353SSamuel.Tu@Sun.COM * fc.requested mode is what the user requests. After autoneg, 29319353SSamuel.Tu@Sun.COM * fc.current_mode will be the flow_control mode that was negotiated. 29329353SSamuel.Tu@Sun.COM */ 29339353SSamuel.Tu@Sun.COM hw->fc.requested_mode = flow_control; 29346621Sbt150084 29356621Sbt150084 /* 29366621Sbt150084 * Multiple rings configurations 29376621Sbt150084 */ 29386621Sbt150084 ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM, 29398490SPaul.Guo@Sun.COM ixgbe->capab->min_tx_que_num, 29408490SPaul.Guo@Sun.COM ixgbe->capab->max_tx_que_num, 29418490SPaul.Guo@Sun.COM ixgbe->capab->def_tx_que_num); 29426621Sbt150084 ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE, 29436621Sbt150084 MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE); 29446621Sbt150084 29456621Sbt150084 ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM, 29468490SPaul.Guo@Sun.COM ixgbe->capab->min_rx_que_num, 29478490SPaul.Guo@Sun.COM ixgbe->capab->max_rx_que_num, 29488490SPaul.Guo@Sun.COM ixgbe->capab->def_rx_que_num); 29496621Sbt150084 ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE, 29506621Sbt150084 MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE); 29516621Sbt150084 29526621Sbt150084 /* 29538275SEric Cheng * Multiple groups configuration 29548275SEric Cheng */ 29558275SEric Cheng ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM, 295611878SVenu.Iyer@Sun.COM ixgbe->capab->min_rx_grp_num, ixgbe->capab->max_rx_grp_num, 295711878SVenu.Iyer@Sun.COM ixgbe->capab->def_rx_grp_num); 29588275SEric Cheng 29598275SEric Cheng ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE, 29608275SEric Cheng 0, 1, DEFAULT_MR_ENABLE); 29618275SEric Cheng 29628275SEric Cheng if (ixgbe->mr_enable == B_FALSE) { 29638275SEric Cheng ixgbe->num_tx_rings = 1; 29648275SEric Cheng ixgbe->num_rx_rings = 1; 29658275SEric Cheng ixgbe->num_rx_groups = 1; 296611878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 296711878SVenu.Iyer@Sun.COM } else { 296811878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 296911878SVenu.Iyer@Sun.COM max(ixgbe->num_rx_rings / ixgbe->num_rx_groups, 1); 297011878SVenu.Iyer@Sun.COM /* 297111878SVenu.Iyer@Sun.COM * The combination of num_rx_rings and num_rx_groups 297211878SVenu.Iyer@Sun.COM * may be not supported by h/w. We need to adjust 297311878SVenu.Iyer@Sun.COM * them to appropriate values. 297411878SVenu.Iyer@Sun.COM */ 297511878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss_conf(ixgbe); 29768275SEric Cheng } 29778275SEric Cheng 29788275SEric Cheng /* 29796621Sbt150084 * Tunable used to force an interrupt type. The only use is 29806621Sbt150084 * for testing of the lesser interrupt types. 29816621Sbt150084 * 0 = don't force interrupt type 29828275SEric Cheng * 1 = force interrupt type MSI-X 29836621Sbt150084 * 2 = force interrupt type MSI 29846621Sbt150084 * 3 = force interrupt type Legacy 29856621Sbt150084 */ 29866621Sbt150084 ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE, 29876621Sbt150084 IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE); 29886621Sbt150084 29896621Sbt150084 ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE, 29907167Sgg161487 0, 1, DEFAULT_TX_HCKSUM_ENABLE); 29916621Sbt150084 ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE, 29927167Sgg161487 0, 1, DEFAULT_RX_HCKSUM_ENABLE); 29936621Sbt150084 ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE, 29947167Sgg161487 0, 1, DEFAULT_LSO_ENABLE); 299511486SZhen.W@Sun.COM ixgbe->lro_enable = ixgbe_get_prop(ixgbe, PROP_LRO_ENABLE, 299611486SZhen.W@Sun.COM 0, 1, DEFAULT_LRO_ENABLE); 29976621Sbt150084 ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE, 29987167Sgg161487 0, 1, DEFAULT_TX_HEAD_WB_ENABLE); 29997167Sgg161487 30009353SSamuel.Tu@Sun.COM /* Head Write Back not recommended for 82599 */ 30019353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 30029353SSamuel.Tu@Sun.COM ixgbe->tx_head_wb_enable = B_FALSE; 30039353SSamuel.Tu@Sun.COM } 30049353SSamuel.Tu@Sun.COM 30057167Sgg161487 /* 30067167Sgg161487 * ixgbe LSO needs the tx h/w checksum support. 30077167Sgg161487 * LSO will be disabled if tx h/w checksum is not 30087167Sgg161487 * enabled. 30097167Sgg161487 */ 30107167Sgg161487 if (ixgbe->tx_hcksum_enable == B_FALSE) { 30117167Sgg161487 ixgbe->lso_enable = B_FALSE; 30127167Sgg161487 } 30136621Sbt150084 301411486SZhen.W@Sun.COM /* 301511486SZhen.W@Sun.COM * ixgbe LRO needs the rx h/w checksum support. 301611486SZhen.W@Sun.COM * LRO will be disabled if rx h/w checksum is not 301711486SZhen.W@Sun.COM * enabled. 301811486SZhen.W@Sun.COM */ 301911486SZhen.W@Sun.COM if (ixgbe->rx_hcksum_enable == B_FALSE) { 302011486SZhen.W@Sun.COM ixgbe->lro_enable = B_FALSE; 302111486SZhen.W@Sun.COM } 302211486SZhen.W@Sun.COM 302311486SZhen.W@Sun.COM /* 302411486SZhen.W@Sun.COM * ixgbe LRO only been supported by 82599 now 302511486SZhen.W@Sun.COM */ 302611486SZhen.W@Sun.COM if (hw->mac.type != ixgbe_mac_82599EB) { 302711486SZhen.W@Sun.COM ixgbe->lro_enable = B_FALSE; 302811486SZhen.W@Sun.COM } 30296621Sbt150084 ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD, 30306621Sbt150084 MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD, 30316621Sbt150084 DEFAULT_TX_COPY_THRESHOLD); 30326621Sbt150084 ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe, 30336621Sbt150084 PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD, 30346621Sbt150084 MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD); 30356621Sbt150084 ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe, 30366621Sbt150084 PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD, 30376621Sbt150084 MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD); 30386621Sbt150084 ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe, 30396621Sbt150084 PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD, 30406621Sbt150084 MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD); 30416621Sbt150084 30426621Sbt150084 ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD, 30436621Sbt150084 MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD, 30446621Sbt150084 DEFAULT_RX_COPY_THRESHOLD); 30456621Sbt150084 ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR, 30466621Sbt150084 MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR, 30476621Sbt150084 DEFAULT_RX_LIMIT_PER_INTR); 30486621Sbt150084 304910376SChenlu.Chen@Sun.COM ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING, 305010376SChenlu.Chen@Sun.COM ixgbe->capab->min_intr_throttle, 305110376SChenlu.Chen@Sun.COM ixgbe->capab->max_intr_throttle, 305210376SChenlu.Chen@Sun.COM ixgbe->capab->def_intr_throttle); 30539353SSamuel.Tu@Sun.COM /* 305410376SChenlu.Chen@Sun.COM * 82599 requires the interupt throttling rate is 305510376SChenlu.Chen@Sun.COM * a multiple of 8. This is enforced by the register 305610376SChenlu.Chen@Sun.COM * definiton. 30579353SSamuel.Tu@Sun.COM */ 305810376SChenlu.Chen@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) 305910376SChenlu.Chen@Sun.COM ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8; 306010376SChenlu.Chen@Sun.COM } 306110376SChenlu.Chen@Sun.COM 306210376SChenlu.Chen@Sun.COM static void 306310376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe_t *ixgbe) 306410376SChenlu.Chen@Sun.COM { 306510376SChenlu.Chen@Sun.COM ixgbe->param_en_10000fdx_cap = 1; 306610376SChenlu.Chen@Sun.COM ixgbe->param_en_1000fdx_cap = 1; 306710376SChenlu.Chen@Sun.COM ixgbe->param_en_100fdx_cap = 1; 306810376SChenlu.Chen@Sun.COM ixgbe->param_adv_10000fdx_cap = 1; 306910376SChenlu.Chen@Sun.COM ixgbe->param_adv_1000fdx_cap = 1; 307010376SChenlu.Chen@Sun.COM ixgbe->param_adv_100fdx_cap = 1; 307110376SChenlu.Chen@Sun.COM 307210376SChenlu.Chen@Sun.COM ixgbe->param_pause_cap = 1; 307310376SChenlu.Chen@Sun.COM ixgbe->param_asym_pause_cap = 1; 307410376SChenlu.Chen@Sun.COM ixgbe->param_rem_fault = 0; 307510376SChenlu.Chen@Sun.COM 307610376SChenlu.Chen@Sun.COM ixgbe->param_adv_autoneg_cap = 1; 307710376SChenlu.Chen@Sun.COM ixgbe->param_adv_pause_cap = 1; 307810376SChenlu.Chen@Sun.COM ixgbe->param_adv_asym_pause_cap = 1; 307910376SChenlu.Chen@Sun.COM ixgbe->param_adv_rem_fault = 0; 308010376SChenlu.Chen@Sun.COM 308110376SChenlu.Chen@Sun.COM ixgbe->param_lp_10000fdx_cap = 0; 308210376SChenlu.Chen@Sun.COM ixgbe->param_lp_1000fdx_cap = 0; 308310376SChenlu.Chen@Sun.COM ixgbe->param_lp_100fdx_cap = 0; 308410376SChenlu.Chen@Sun.COM ixgbe->param_lp_autoneg_cap = 0; 308510376SChenlu.Chen@Sun.COM ixgbe->param_lp_pause_cap = 0; 308610376SChenlu.Chen@Sun.COM ixgbe->param_lp_asym_pause_cap = 0; 308710376SChenlu.Chen@Sun.COM ixgbe->param_lp_rem_fault = 0; 30886621Sbt150084 } 30896621Sbt150084 30906621Sbt150084 /* 30916621Sbt150084 * ixgbe_get_prop - Get a property value out of the configuration file 30926621Sbt150084 * ixgbe.conf. 30936621Sbt150084 * 30946621Sbt150084 * Caller provides the name of the property, a default value, a minimum 30956621Sbt150084 * value, and a maximum value. 30966621Sbt150084 * 30976621Sbt150084 * Return configured value of the property, with default, minimum and 30986621Sbt150084 * maximum properly applied. 30996621Sbt150084 */ 31006621Sbt150084 static int 31016621Sbt150084 ixgbe_get_prop(ixgbe_t *ixgbe, 31026621Sbt150084 char *propname, /* name of the property */ 31036621Sbt150084 int minval, /* minimum acceptable value */ 31046621Sbt150084 int maxval, /* maximim acceptable value */ 31056621Sbt150084 int defval) /* default value */ 31066621Sbt150084 { 31076621Sbt150084 int value; 31086621Sbt150084 31096621Sbt150084 /* 31106621Sbt150084 * Call ddi_prop_get_int() to read the conf settings 31116621Sbt150084 */ 31126621Sbt150084 value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip, 31136621Sbt150084 DDI_PROP_DONTPASS, propname, defval); 31146621Sbt150084 if (value > maxval) 31156621Sbt150084 value = maxval; 31166621Sbt150084 31176621Sbt150084 if (value < minval) 31186621Sbt150084 value = minval; 31196621Sbt150084 31206621Sbt150084 return (value); 31216621Sbt150084 } 31226621Sbt150084 31236621Sbt150084 /* 31246621Sbt150084 * ixgbe_driver_setup_link - Using the link properties to setup the link. 31256621Sbt150084 */ 31266621Sbt150084 int 31276621Sbt150084 ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw) 31286621Sbt150084 { 312910998SChenlu.Chen@Sun.COM u32 autoneg_advertised = 0; 313010998SChenlu.Chen@Sun.COM 313110998SChenlu.Chen@Sun.COM /* 313210998SChenlu.Chen@Sun.COM * No half duplex support with 10Gb parts 313310998SChenlu.Chen@Sun.COM */ 313410998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_10000fdx_cap == 1) 313510998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; 313610998SChenlu.Chen@Sun.COM 313710998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_1000fdx_cap == 1) 313810998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; 313910998SChenlu.Chen@Sun.COM 314010998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_100fdx_cap == 1) 314110998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; 314210998SChenlu.Chen@Sun.COM 314310998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_autoneg_cap == 1 && autoneg_advertised == 0) { 314410998SChenlu.Chen@Sun.COM ixgbe_notice(ixgbe, "Invalid link settings. Setup link " 314510998SChenlu.Chen@Sun.COM "to autonegotiation with full link capabilities."); 314610998SChenlu.Chen@Sun.COM 314710998SChenlu.Chen@Sun.COM autoneg_advertised = IXGBE_LINK_SPEED_10GB_FULL | 314810998SChenlu.Chen@Sun.COM IXGBE_LINK_SPEED_1GB_FULL | 314910998SChenlu.Chen@Sun.COM IXGBE_LINK_SPEED_100_FULL; 31506621Sbt150084 } 31516621Sbt150084 31526621Sbt150084 if (setup_hw) { 315310998SChenlu.Chen@Sun.COM if (ixgbe_setup_link(&ixgbe->hw, autoneg_advertised, 315410998SChenlu.Chen@Sun.COM ixgbe->param_adv_autoneg_cap, B_TRUE) != IXGBE_SUCCESS) { 31559353SSamuel.Tu@Sun.COM ixgbe_notice(ixgbe, "Setup link failed on this " 31569353SSamuel.Tu@Sun.COM "device."); 31576621Sbt150084 return (IXGBE_FAILURE); 31589353SSamuel.Tu@Sun.COM } 31596621Sbt150084 } 31606621Sbt150084 31616621Sbt150084 return (IXGBE_SUCCESS); 31626621Sbt150084 } 31636621Sbt150084 31646621Sbt150084 /* 316511233SPaul.Guo@Sun.COM * ixgbe_driver_link_check - Link status processing. 316611233SPaul.Guo@Sun.COM * 316711233SPaul.Guo@Sun.COM * This function can be called in both kernel context and interrupt context 31686621Sbt150084 */ 31698490SPaul.Guo@Sun.COM static void 317011233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe_t *ixgbe) 31716621Sbt150084 { 31726621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 31736621Sbt150084 ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN; 31746621Sbt150084 boolean_t link_up = B_FALSE; 31756621Sbt150084 boolean_t link_changed = B_FALSE; 31766621Sbt150084 317711233SPaul.Guo@Sun.COM ASSERT(mutex_owned(&ixgbe->gen_lock)); 317811233SPaul.Guo@Sun.COM 317911233SPaul.Guo@Sun.COM (void) ixgbe_check_link(hw, &speed, &link_up, false); 31806621Sbt150084 if (link_up) { 318111233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_TRUE; 318211233SPaul.Guo@Sun.COM 31839353SSamuel.Tu@Sun.COM /* Link is up, enable flow control settings */ 31849353SSamuel.Tu@Sun.COM (void) ixgbe_fc_enable(hw, 0); 31859353SSamuel.Tu@Sun.COM 31866621Sbt150084 /* 31876621Sbt150084 * The Link is up, check whether it was marked as down earlier 31886621Sbt150084 */ 31896621Sbt150084 if (ixgbe->link_state != LINK_STATE_UP) { 31906621Sbt150084 switch (speed) { 31919353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_10GB_FULL: 31929353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_10GB; 31939353SSamuel.Tu@Sun.COM break; 31949353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_1GB_FULL: 31959353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_1GB; 31969353SSamuel.Tu@Sun.COM break; 31979353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_100_FULL: 31989353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_100; 31996621Sbt150084 } 32006621Sbt150084 ixgbe->link_duplex = LINK_DUPLEX_FULL; 32016621Sbt150084 ixgbe->link_state = LINK_STATE_UP; 32026621Sbt150084 link_changed = B_TRUE; 32036621Sbt150084 } 32046621Sbt150084 } else { 320511233SPaul.Guo@Sun.COM if (ixgbe->link_check_complete == B_TRUE || 320611233SPaul.Guo@Sun.COM (ixgbe->link_check_complete == B_FALSE && 320711233SPaul.Guo@Sun.COM gethrtime() >= ixgbe->link_check_hrtime)) { 320811233SPaul.Guo@Sun.COM /* 320911233SPaul.Guo@Sun.COM * The link is really down 321011233SPaul.Guo@Sun.COM */ 321111233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_TRUE; 321211233SPaul.Guo@Sun.COM 321311233SPaul.Guo@Sun.COM if (ixgbe->link_state != LINK_STATE_DOWN) { 321411233SPaul.Guo@Sun.COM ixgbe->link_speed = 0; 321511233SPaul.Guo@Sun.COM ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN; 321611233SPaul.Guo@Sun.COM ixgbe->link_state = LINK_STATE_DOWN; 321711233SPaul.Guo@Sun.COM link_changed = B_TRUE; 321811233SPaul.Guo@Sun.COM } 32196621Sbt150084 } 32206621Sbt150084 } 32216621Sbt150084 32228490SPaul.Guo@Sun.COM /* 32238490SPaul.Guo@Sun.COM * this is only reached after a link-status-change interrupt 32248490SPaul.Guo@Sun.COM * so always get new phy state 32258490SPaul.Guo@Sun.COM */ 32268490SPaul.Guo@Sun.COM ixgbe_get_hw_state(ixgbe); 32278490SPaul.Guo@Sun.COM 322811233SPaul.Guo@Sun.COM /* 322911233SPaul.Guo@Sun.COM * If we are in an interrupt context, need to re-enable the 323011233SPaul.Guo@Sun.COM * interrupt, which was automasked 323111233SPaul.Guo@Sun.COM */ 323211233SPaul.Guo@Sun.COM if (servicing_interrupt() != 0) { 323311233SPaul.Guo@Sun.COM ixgbe->eims |= IXGBE_EICR_LSC; 323411233SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 323511233SPaul.Guo@Sun.COM } 323611233SPaul.Guo@Sun.COM 32378490SPaul.Guo@Sun.COM if (link_changed) { 32388490SPaul.Guo@Sun.COM mac_link_update(ixgbe->mac_hdl, ixgbe->link_state); 32398490SPaul.Guo@Sun.COM } 32406621Sbt150084 } 32416621Sbt150084 32426621Sbt150084 /* 32439353SSamuel.Tu@Sun.COM * ixgbe_sfp_check - sfp module processing done in taskq only for 82599. 32449353SSamuel.Tu@Sun.COM */ 32459353SSamuel.Tu@Sun.COM static void 32469353SSamuel.Tu@Sun.COM ixgbe_sfp_check(void *arg) 32479353SSamuel.Tu@Sun.COM { 32489353SSamuel.Tu@Sun.COM ixgbe_t *ixgbe = (ixgbe_t *)arg; 32499353SSamuel.Tu@Sun.COM uint32_t eicr = ixgbe->eicr; 32509353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 32519353SSamuel.Tu@Sun.COM 325211233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 32539353SSamuel.Tu@Sun.COM if (eicr & IXGBE_EICR_GPI_SDP1) { 32549353SSamuel.Tu@Sun.COM /* clear the interrupt */ 32559353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); 32569353SSamuel.Tu@Sun.COM 32579353SSamuel.Tu@Sun.COM /* if link up, do multispeed fiber setup */ 325810998SChenlu.Chen@Sun.COM (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, 325910998SChenlu.Chen@Sun.COM B_TRUE, B_TRUE); 32609353SSamuel.Tu@Sun.COM ixgbe_driver_link_check(ixgbe); 32619353SSamuel.Tu@Sun.COM } else if (eicr & IXGBE_EICR_GPI_SDP2) { 32629353SSamuel.Tu@Sun.COM /* clear the interrupt */ 32639353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); 32649353SSamuel.Tu@Sun.COM 32659353SSamuel.Tu@Sun.COM /* if link up, do sfp module setup */ 32669353SSamuel.Tu@Sun.COM (void) hw->mac.ops.setup_sfp(hw); 32679353SSamuel.Tu@Sun.COM 32689353SSamuel.Tu@Sun.COM /* do multispeed fiber setup */ 326910998SChenlu.Chen@Sun.COM (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, 327010998SChenlu.Chen@Sun.COM B_TRUE, B_TRUE); 32719353SSamuel.Tu@Sun.COM ixgbe_driver_link_check(ixgbe); 32729353SSamuel.Tu@Sun.COM } 327311233SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 327411233SPaul.Guo@Sun.COM } 327511233SPaul.Guo@Sun.COM 327611233SPaul.Guo@Sun.COM /* 327711233SPaul.Guo@Sun.COM * ixgbe_link_timer - timer for link status detection 327811233SPaul.Guo@Sun.COM */ 327911233SPaul.Guo@Sun.COM static void 328011233SPaul.Guo@Sun.COM ixgbe_link_timer(void *arg) 328111233SPaul.Guo@Sun.COM { 328211233SPaul.Guo@Sun.COM ixgbe_t *ixgbe = (ixgbe_t *)arg; 328311233SPaul.Guo@Sun.COM 328411233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 328511233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe); 328611233SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 32879353SSamuel.Tu@Sun.COM } 32889353SSamuel.Tu@Sun.COM 32899353SSamuel.Tu@Sun.COM /* 32906621Sbt150084 * ixgbe_local_timer - Driver watchdog function. 32916621Sbt150084 * 329211233SPaul.Guo@Sun.COM * This function will handle the transmit stall check and other routines. 32936621Sbt150084 */ 32946621Sbt150084 static void 32956621Sbt150084 ixgbe_local_timer(void *arg) 32966621Sbt150084 { 32976621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg; 32986621Sbt150084 329911233SPaul.Guo@Sun.COM if (ixgbe->ixgbe_state & IXGBE_ERROR) { 33006621Sbt150084 ixgbe->reset_count++; 33016621Sbt150084 if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS) 33026621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED); 330311233SPaul.Guo@Sun.COM ixgbe_restart_watchdog_timer(ixgbe); 330411233SPaul.Guo@Sun.COM return; 33056621Sbt150084 } 33066621Sbt150084 330711233SPaul.Guo@Sun.COM if (ixgbe_stall_check(ixgbe)) { 330811233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL); 330911233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 331011233SPaul.Guo@Sun.COM 331111233SPaul.Guo@Sun.COM ixgbe->reset_count++; 331211233SPaul.Guo@Sun.COM if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS) 331311233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED); 331411233SPaul.Guo@Sun.COM } 331511486SZhen.W@Sun.COM 331611486SZhen.W@Sun.COM ixgbe_restart_watchdog_timer(ixgbe); 33176621Sbt150084 } 33186621Sbt150084 33196621Sbt150084 /* 33206621Sbt150084 * ixgbe_stall_check - Check for transmit stall. 33216621Sbt150084 * 33226621Sbt150084 * This function checks if the adapter is stalled (in transmit). 33236621Sbt150084 * 33246621Sbt150084 * It is called each time the watchdog timeout is invoked. 33256621Sbt150084 * If the transmit descriptor reclaim continuously fails, 33266621Sbt150084 * the watchdog value will increment by 1. If the watchdog 33276621Sbt150084 * value exceeds the threshold, the ixgbe is assumed to 33286621Sbt150084 * have stalled and need to be reset. 33296621Sbt150084 */ 33306621Sbt150084 static boolean_t 33316621Sbt150084 ixgbe_stall_check(ixgbe_t *ixgbe) 33326621Sbt150084 { 33336621Sbt150084 ixgbe_tx_ring_t *tx_ring; 33346621Sbt150084 boolean_t result; 33356621Sbt150084 int i; 33366621Sbt150084 33376621Sbt150084 if (ixgbe->link_state != LINK_STATE_UP) 33386621Sbt150084 return (B_FALSE); 33396621Sbt150084 33406621Sbt150084 /* 33416621Sbt150084 * If any tx ring is stalled, we'll reset the chipset 33426621Sbt150084 */ 33436621Sbt150084 result = B_FALSE; 33446621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 33456621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 334610376SChenlu.Chen@Sun.COM if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) { 334710305SPaul.Guo@Sun.COM tx_ring->tx_recycle(tx_ring); 334810305SPaul.Guo@Sun.COM } 33496621Sbt150084 33506621Sbt150084 if (tx_ring->recycle_fail > 0) 33516621Sbt150084 tx_ring->stall_watchdog++; 33526621Sbt150084 else 33536621Sbt150084 tx_ring->stall_watchdog = 0; 33546621Sbt150084 33556621Sbt150084 if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) { 33566621Sbt150084 result = B_TRUE; 33576621Sbt150084 break; 33586621Sbt150084 } 33596621Sbt150084 } 33606621Sbt150084 33616621Sbt150084 if (result) { 33626621Sbt150084 tx_ring->stall_watchdog = 0; 33636621Sbt150084 tx_ring->recycle_fail = 0; 33646621Sbt150084 } 33656621Sbt150084 33666621Sbt150084 return (result); 33676621Sbt150084 } 33686621Sbt150084 33696621Sbt150084 33706621Sbt150084 /* 33716621Sbt150084 * is_valid_mac_addr - Check if the mac address is valid. 33726621Sbt150084 */ 33736621Sbt150084 static boolean_t 33746621Sbt150084 is_valid_mac_addr(uint8_t *mac_addr) 33756621Sbt150084 { 33766621Sbt150084 const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 }; 33776621Sbt150084 const uint8_t addr_test2[6] = 33786621Sbt150084 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 33796621Sbt150084 33806621Sbt150084 if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) || 33816621Sbt150084 !(bcmp(addr_test2, mac_addr, ETHERADDRL))) 33826621Sbt150084 return (B_FALSE); 33836621Sbt150084 33846621Sbt150084 return (B_TRUE); 33856621Sbt150084 } 33866621Sbt150084 33876621Sbt150084 static boolean_t 33886621Sbt150084 ixgbe_find_mac_address(ixgbe_t *ixgbe) 33896621Sbt150084 { 33906621Sbt150084 #ifdef __sparc 33916621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 33926621Sbt150084 uchar_t *bytes; 33936621Sbt150084 struct ether_addr sysaddr; 33946621Sbt150084 uint_t nelts; 33956621Sbt150084 int err; 33966621Sbt150084 boolean_t found = B_FALSE; 33976621Sbt150084 33986621Sbt150084 /* 33996621Sbt150084 * The "vendor's factory-set address" may already have 34006621Sbt150084 * been extracted from the chip, but if the property 34016621Sbt150084 * "local-mac-address" is set we use that instead. 34026621Sbt150084 * 34036621Sbt150084 * We check whether it looks like an array of 6 34046621Sbt150084 * bytes (which it should, if OBP set it). If we can't 34056621Sbt150084 * make sense of it this way, we'll ignore it. 34066621Sbt150084 */ 34076621Sbt150084 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 34086621Sbt150084 DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts); 34096621Sbt150084 if (err == DDI_PROP_SUCCESS) { 34106621Sbt150084 if (nelts == ETHERADDRL) { 34116621Sbt150084 while (nelts--) 34126621Sbt150084 hw->mac.addr[nelts] = bytes[nelts]; 34136621Sbt150084 found = B_TRUE; 34146621Sbt150084 } 34156621Sbt150084 ddi_prop_free(bytes); 34166621Sbt150084 } 34176621Sbt150084 34186621Sbt150084 /* 34196621Sbt150084 * Look up the OBP property "local-mac-address?". If the user has set 34206621Sbt150084 * 'local-mac-address? = false', use "the system address" instead. 34216621Sbt150084 */ 34226621Sbt150084 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0, 34236621Sbt150084 "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) { 34246621Sbt150084 if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) { 34256621Sbt150084 if (localetheraddr(NULL, &sysaddr) != 0) { 34266621Sbt150084 bcopy(&sysaddr, hw->mac.addr, ETHERADDRL); 34276621Sbt150084 found = B_TRUE; 34286621Sbt150084 } 34296621Sbt150084 } 34306621Sbt150084 ddi_prop_free(bytes); 34316621Sbt150084 } 34326621Sbt150084 34336621Sbt150084 /* 34346621Sbt150084 * Finally(!), if there's a valid "mac-address" property (created 34356621Sbt150084 * if we netbooted from this interface), we must use this instead 34366621Sbt150084 * of any of the above to ensure that the NFS/install server doesn't 34376621Sbt150084 * get confused by the address changing as Solaris takes over! 34386621Sbt150084 */ 34396621Sbt150084 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 34406621Sbt150084 DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts); 34416621Sbt150084 if (err == DDI_PROP_SUCCESS) { 34426621Sbt150084 if (nelts == ETHERADDRL) { 34436621Sbt150084 while (nelts--) 34446621Sbt150084 hw->mac.addr[nelts] = bytes[nelts]; 34456621Sbt150084 found = B_TRUE; 34466621Sbt150084 } 34476621Sbt150084 ddi_prop_free(bytes); 34486621Sbt150084 } 34496621Sbt150084 34506621Sbt150084 if (found) { 34516621Sbt150084 bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL); 34526621Sbt150084 return (B_TRUE); 34536621Sbt150084 } 34546621Sbt150084 #else 34556621Sbt150084 _NOTE(ARGUNUSED(ixgbe)); 34566621Sbt150084 #endif 34576621Sbt150084 34586621Sbt150084 return (B_TRUE); 34596621Sbt150084 } 34606621Sbt150084 34616621Sbt150084 #pragma inline(ixgbe_arm_watchdog_timer) 34626621Sbt150084 static void 34636621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe) 34646621Sbt150084 { 34656621Sbt150084 /* 34666621Sbt150084 * Fire a watchdog timer 34676621Sbt150084 */ 34686621Sbt150084 ixgbe->watchdog_tid = 34696621Sbt150084 timeout(ixgbe_local_timer, 34706621Sbt150084 (void *)ixgbe, 1 * drv_usectohz(1000000)); 34716621Sbt150084 34726621Sbt150084 } 34736621Sbt150084 34746621Sbt150084 /* 34756621Sbt150084 * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer. 34766621Sbt150084 */ 34776621Sbt150084 void 34786621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe) 34796621Sbt150084 { 34806621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 34816621Sbt150084 34826621Sbt150084 if (!ixgbe->watchdog_enable) { 34836621Sbt150084 ixgbe->watchdog_enable = B_TRUE; 34846621Sbt150084 ixgbe->watchdog_start = B_TRUE; 34856621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 34866621Sbt150084 } 34876621Sbt150084 34886621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 34896621Sbt150084 } 34906621Sbt150084 34916621Sbt150084 /* 34926621Sbt150084 * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer. 34936621Sbt150084 */ 34946621Sbt150084 void 34956621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe) 34966621Sbt150084 { 34976621Sbt150084 timeout_id_t tid; 34986621Sbt150084 34996621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 35006621Sbt150084 35016621Sbt150084 ixgbe->watchdog_enable = B_FALSE; 35026621Sbt150084 ixgbe->watchdog_start = B_FALSE; 35036621Sbt150084 tid = ixgbe->watchdog_tid; 35046621Sbt150084 ixgbe->watchdog_tid = 0; 35056621Sbt150084 35066621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 35076621Sbt150084 35086621Sbt150084 if (tid != 0) 35096621Sbt150084 (void) untimeout(tid); 35106621Sbt150084 } 35116621Sbt150084 35126621Sbt150084 /* 35136621Sbt150084 * ixgbe_start_watchdog_timer - Start the driver watchdog timer. 35146621Sbt150084 */ 35158490SPaul.Guo@Sun.COM void 35166621Sbt150084 ixgbe_start_watchdog_timer(ixgbe_t *ixgbe) 35176621Sbt150084 { 35186621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 35196621Sbt150084 35206621Sbt150084 if (ixgbe->watchdog_enable) { 35216621Sbt150084 if (!ixgbe->watchdog_start) { 35226621Sbt150084 ixgbe->watchdog_start = B_TRUE; 35236621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 35246621Sbt150084 } 35256621Sbt150084 } 35266621Sbt150084 35276621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 35286621Sbt150084 } 35296621Sbt150084 35306621Sbt150084 /* 35316621Sbt150084 * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer. 35326621Sbt150084 */ 35336621Sbt150084 static void 35346621Sbt150084 ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe) 35356621Sbt150084 { 35366621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 35376621Sbt150084 35386621Sbt150084 if (ixgbe->watchdog_start) 35396621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 35406621Sbt150084 35416621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 35426621Sbt150084 } 35436621Sbt150084 35446621Sbt150084 /* 35456621Sbt150084 * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer. 35466621Sbt150084 */ 35478490SPaul.Guo@Sun.COM void 35486621Sbt150084 ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe) 35496621Sbt150084 { 35506621Sbt150084 timeout_id_t tid; 35516621Sbt150084 35526621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 35536621Sbt150084 35546621Sbt150084 ixgbe->watchdog_start = B_FALSE; 35556621Sbt150084 tid = ixgbe->watchdog_tid; 35566621Sbt150084 ixgbe->watchdog_tid = 0; 35576621Sbt150084 35586621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 35596621Sbt150084 35606621Sbt150084 if (tid != 0) 35616621Sbt150084 (void) untimeout(tid); 35626621Sbt150084 } 35636621Sbt150084 35646621Sbt150084 /* 35656621Sbt150084 * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts. 35666621Sbt150084 */ 35676621Sbt150084 static void 35686621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe) 35696621Sbt150084 { 35706621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 35716621Sbt150084 35726621Sbt150084 /* 35736621Sbt150084 * mask all interrupts off 35746621Sbt150084 */ 35756621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff); 35766621Sbt150084 35776621Sbt150084 /* 35786621Sbt150084 * for MSI-X, also disable autoclear 35796621Sbt150084 */ 35806621Sbt150084 if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) { 35816621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0); 35826621Sbt150084 } 35836621Sbt150084 35846621Sbt150084 IXGBE_WRITE_FLUSH(hw); 35856621Sbt150084 } 35866621Sbt150084 35876621Sbt150084 /* 35886621Sbt150084 * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts. 35896621Sbt150084 */ 35906621Sbt150084 static void 35916621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe) 35926621Sbt150084 { 35936621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 35948490SPaul.Guo@Sun.COM uint32_t eiac, eiam; 35958490SPaul.Guo@Sun.COM uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 35968490SPaul.Guo@Sun.COM 35978490SPaul.Guo@Sun.COM /* interrupt types to enable */ 35988490SPaul.Guo@Sun.COM ixgbe->eims = IXGBE_EIMS_ENABLE_MASK; /* shared code default */ 35998490SPaul.Guo@Sun.COM ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER; /* minus tcp timer */ 36008490SPaul.Guo@Sun.COM ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */ 36018490SPaul.Guo@Sun.COM 36028490SPaul.Guo@Sun.COM /* enable automask on "other" causes that this adapter can generate */ 36038490SPaul.Guo@Sun.COM eiam = ixgbe->capab->other_intr; 36046621Sbt150084 36056621Sbt150084 /* 36066621Sbt150084 * msi-x mode 36076621Sbt150084 */ 36086621Sbt150084 if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) { 36096621Sbt150084 /* enable autoclear but not on bits 29:20 */ 36108490SPaul.Guo@Sun.COM eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR); 36116621Sbt150084 36126621Sbt150084 /* general purpose interrupt enable */ 36138490SPaul.Guo@Sun.COM gpie |= (IXGBE_GPIE_MSIX_MODE 36148490SPaul.Guo@Sun.COM | IXGBE_GPIE_PBA_SUPPORT 36158490SPaul.Guo@Sun.COM | IXGBE_GPIE_OCD 36168490SPaul.Guo@Sun.COM | IXGBE_GPIE_EIAME); 36176621Sbt150084 /* 36186621Sbt150084 * non-msi-x mode 36196621Sbt150084 */ 36206621Sbt150084 } else { 36216621Sbt150084 36226621Sbt150084 /* disable autoclear, leave gpie at default */ 36236621Sbt150084 eiac = 0; 36248490SPaul.Guo@Sun.COM 36259353SSamuel.Tu@Sun.COM /* 36269353SSamuel.Tu@Sun.COM * General purpose interrupt enable. 36279353SSamuel.Tu@Sun.COM * For 82599, extended interrupt automask enable 36289353SSamuel.Tu@Sun.COM * only in MSI or MSI-X mode 36299353SSamuel.Tu@Sun.COM */ 36309353SSamuel.Tu@Sun.COM if ((hw->mac.type < ixgbe_mac_82599EB) || 36319353SSamuel.Tu@Sun.COM (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) { 36329353SSamuel.Tu@Sun.COM gpie |= IXGBE_GPIE_EIAME; 36339353SSamuel.Tu@Sun.COM } 36349353SSamuel.Tu@Sun.COM } 36359353SSamuel.Tu@Sun.COM /* Enable specific interrupts for 82599 */ 36369353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 36379353SSamuel.Tu@Sun.COM gpie |= IXGBE_SDP2_GPIEN; /* pluggable optics intr */ 36389353SSamuel.Tu@Sun.COM gpie |= IXGBE_SDP1_GPIEN; /* LSC interrupt */ 36396621Sbt150084 } 364011486SZhen.W@Sun.COM /* Enable RSC Dealy 8us for 82599 */ 364111486SZhen.W@Sun.COM if (ixgbe->lro_enable) { 364211486SZhen.W@Sun.COM gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT); 364311486SZhen.W@Sun.COM } 36448490SPaul.Guo@Sun.COM /* write to interrupt control registers */ 36458490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 36466621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac); 36478490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam); 36486621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 36496621Sbt150084 IXGBE_WRITE_FLUSH(hw); 36506621Sbt150084 } 36516621Sbt150084 36526621Sbt150084 /* 36536621Sbt150084 * ixgbe_loopback_ioctl - Loopback support. 36546621Sbt150084 */ 36556621Sbt150084 enum ioc_reply 36566621Sbt150084 ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp) 36576621Sbt150084 { 36586621Sbt150084 lb_info_sz_t *lbsp; 36596621Sbt150084 lb_property_t *lbpp; 36606621Sbt150084 uint32_t *lbmp; 36616621Sbt150084 uint32_t size; 36626621Sbt150084 uint32_t value; 36636621Sbt150084 36646621Sbt150084 if (mp->b_cont == NULL) 36656621Sbt150084 return (IOC_INVAL); 36666621Sbt150084 36676621Sbt150084 switch (iocp->ioc_cmd) { 36686621Sbt150084 default: 36696621Sbt150084 return (IOC_INVAL); 36706621Sbt150084 36716621Sbt150084 case LB_GET_INFO_SIZE: 36726621Sbt150084 size = sizeof (lb_info_sz_t); 36736621Sbt150084 if (iocp->ioc_count != size) 36746621Sbt150084 return (IOC_INVAL); 36756621Sbt150084 36766621Sbt150084 value = sizeof (lb_normal); 36776621Sbt150084 value += sizeof (lb_mac); 367811150SZhen.W@Sun.COM value += sizeof (lb_external); 36796621Sbt150084 36806621Sbt150084 lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr; 36816621Sbt150084 *lbsp = value; 36826621Sbt150084 break; 36836621Sbt150084 36846621Sbt150084 case LB_GET_INFO: 36856621Sbt150084 value = sizeof (lb_normal); 36866621Sbt150084 value += sizeof (lb_mac); 368711150SZhen.W@Sun.COM value += sizeof (lb_external); 36886621Sbt150084 36896621Sbt150084 size = value; 36906621Sbt150084 if (iocp->ioc_count != size) 36916621Sbt150084 return (IOC_INVAL); 36926621Sbt150084 36936621Sbt150084 value = 0; 36946621Sbt150084 lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr; 36956621Sbt150084 36966621Sbt150084 lbpp[value++] = lb_normal; 36976621Sbt150084 lbpp[value++] = lb_mac; 369811150SZhen.W@Sun.COM lbpp[value++] = lb_external; 36996621Sbt150084 break; 37006621Sbt150084 37016621Sbt150084 case LB_GET_MODE: 37026621Sbt150084 size = sizeof (uint32_t); 37036621Sbt150084 if (iocp->ioc_count != size) 37046621Sbt150084 return (IOC_INVAL); 37056621Sbt150084 37066621Sbt150084 lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 37076621Sbt150084 *lbmp = ixgbe->loopback_mode; 37086621Sbt150084 break; 37096621Sbt150084 37106621Sbt150084 case LB_SET_MODE: 37116621Sbt150084 size = 0; 37126621Sbt150084 if (iocp->ioc_count != sizeof (uint32_t)) 37136621Sbt150084 return (IOC_INVAL); 37146621Sbt150084 37156621Sbt150084 lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 37166621Sbt150084 if (!ixgbe_set_loopback_mode(ixgbe, *lbmp)) 37176621Sbt150084 return (IOC_INVAL); 37186621Sbt150084 break; 37196621Sbt150084 } 37206621Sbt150084 37216621Sbt150084 iocp->ioc_count = size; 37226621Sbt150084 iocp->ioc_error = 0; 37236621Sbt150084 37246621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 37256621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 37266621Sbt150084 return (IOC_INVAL); 37276621Sbt150084 } 37286621Sbt150084 37296621Sbt150084 return (IOC_REPLY); 37306621Sbt150084 } 37316621Sbt150084 37326621Sbt150084 /* 37336621Sbt150084 * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode. 37346621Sbt150084 */ 37356621Sbt150084 static boolean_t 37366621Sbt150084 ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode) 37376621Sbt150084 { 37386621Sbt150084 if (mode == ixgbe->loopback_mode) 37396621Sbt150084 return (B_TRUE); 37406621Sbt150084 37416621Sbt150084 ixgbe->loopback_mode = mode; 37426621Sbt150084 37436621Sbt150084 if (mode == IXGBE_LB_NONE) { 37446621Sbt150084 /* 37456621Sbt150084 * Reset the chip 37466621Sbt150084 */ 37476621Sbt150084 (void) ixgbe_reset(ixgbe); 37486621Sbt150084 return (B_TRUE); 37496621Sbt150084 } 37506621Sbt150084 37516621Sbt150084 mutex_enter(&ixgbe->gen_lock); 37526621Sbt150084 37536621Sbt150084 switch (mode) { 37546621Sbt150084 default: 37556621Sbt150084 mutex_exit(&ixgbe->gen_lock); 37566621Sbt150084 return (B_FALSE); 37576621Sbt150084 375811150SZhen.W@Sun.COM case IXGBE_LB_EXTERNAL: 375911150SZhen.W@Sun.COM break; 376011150SZhen.W@Sun.COM 37616621Sbt150084 case IXGBE_LB_INTERNAL_MAC: 37626621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe); 37636621Sbt150084 break; 37646621Sbt150084 } 37656621Sbt150084 37666621Sbt150084 mutex_exit(&ixgbe->gen_lock); 37676621Sbt150084 37686621Sbt150084 return (B_TRUE); 37696621Sbt150084 } 37706621Sbt150084 37716621Sbt150084 /* 37726621Sbt150084 * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode. 37736621Sbt150084 */ 37746621Sbt150084 static void 37756621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe) 37766621Sbt150084 { 37776621Sbt150084 struct ixgbe_hw *hw; 37786621Sbt150084 uint32_t reg; 37796621Sbt150084 uint8_t atlas; 37806621Sbt150084 37816621Sbt150084 hw = &ixgbe->hw; 37826621Sbt150084 37836621Sbt150084 /* 37846621Sbt150084 * Setup MAC loopback 37856621Sbt150084 */ 37866621Sbt150084 reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0); 37876621Sbt150084 reg |= IXGBE_HLREG0_LPBK; 37886621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg); 37896621Sbt150084 37906621Sbt150084 reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC); 37916621Sbt150084 reg &= ~IXGBE_AUTOC_LMS_MASK; 37926621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg); 37936621Sbt150084 37946621Sbt150084 /* 37956621Sbt150084 * Disable Atlas Tx lanes to keep packets in loopback and not on wire 37966621Sbt150084 */ 37976621Sbt150084 if (hw->mac.type == ixgbe_mac_82598EB) { 37986621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK, 37996621Sbt150084 &atlas); 38006621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_REG_EN; 38016621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK, 38026621Sbt150084 atlas); 38036621Sbt150084 38046621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G, 38056621Sbt150084 &atlas); 38066621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL; 38076621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G, 38086621Sbt150084 atlas); 38096621Sbt150084 38106621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G, 38116621Sbt150084 &atlas); 38126621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL; 38136621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G, 38146621Sbt150084 atlas); 38156621Sbt150084 38166621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN, 38176621Sbt150084 &atlas); 38186621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL; 38196621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN, 38206621Sbt150084 atlas); 3821*12280SChenlu.Chen@Sun.COM } else if (hw->mac.type == ixgbe_mac_82599EB) { 3822*12280SChenlu.Chen@Sun.COM reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC); 3823*12280SChenlu.Chen@Sun.COM reg |= (IXGBE_AUTOC_FLU | 3824*12280SChenlu.Chen@Sun.COM IXGBE_AUTOC_10G_KX4); 3825*12280SChenlu.Chen@Sun.COM IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg); 3826*12280SChenlu.Chen@Sun.COM 3827*12280SChenlu.Chen@Sun.COM (void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL, 3828*12280SChenlu.Chen@Sun.COM B_FALSE, B_TRUE); 38296621Sbt150084 } 38306621Sbt150084 } 38316621Sbt150084 38326621Sbt150084 #pragma inline(ixgbe_intr_rx_work) 38336621Sbt150084 /* 38346621Sbt150084 * ixgbe_intr_rx_work - RX processing of ISR. 38356621Sbt150084 */ 38366621Sbt150084 static void 38376621Sbt150084 ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring) 38386621Sbt150084 { 38396621Sbt150084 mblk_t *mp; 38406621Sbt150084 38416621Sbt150084 mutex_enter(&rx_ring->rx_lock); 38426621Sbt150084 38438275SEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL); 38446621Sbt150084 mutex_exit(&rx_ring->rx_lock); 38456621Sbt150084 38466621Sbt150084 if (mp != NULL) 38478275SEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp, 38488275SEric Cheng rx_ring->ring_gen_num); 38496621Sbt150084 } 38506621Sbt150084 38516621Sbt150084 #pragma inline(ixgbe_intr_tx_work) 38526621Sbt150084 /* 38536621Sbt150084 * ixgbe_intr_tx_work - TX processing of ISR. 38546621Sbt150084 */ 38556621Sbt150084 static void 38566621Sbt150084 ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring) 38576621Sbt150084 { 385810376SChenlu.Chen@Sun.COM ixgbe_t *ixgbe = tx_ring->ixgbe; 385910376SChenlu.Chen@Sun.COM 38606621Sbt150084 /* 38616621Sbt150084 * Recycle the tx descriptors 38626621Sbt150084 */ 38636621Sbt150084 tx_ring->tx_recycle(tx_ring); 38646621Sbt150084 38656621Sbt150084 /* 38666621Sbt150084 * Schedule the re-transmit 38676621Sbt150084 */ 38686621Sbt150084 if (tx_ring->reschedule && 386910376SChenlu.Chen@Sun.COM (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) { 38706621Sbt150084 tx_ring->reschedule = B_FALSE; 38718275SEric Cheng mac_tx_ring_update(tx_ring->ixgbe->mac_hdl, 38728275SEric Cheng tx_ring->ring_handle); 38736621Sbt150084 IXGBE_DEBUG_STAT(tx_ring->stat_reschedule); 38746621Sbt150084 } 38756621Sbt150084 } 38766621Sbt150084 38776621Sbt150084 #pragma inline(ixgbe_intr_other_work) 38786621Sbt150084 /* 38798490SPaul.Guo@Sun.COM * ixgbe_intr_other_work - Process interrupt types other than tx/rx 38806621Sbt150084 */ 38816621Sbt150084 static void 38828490SPaul.Guo@Sun.COM ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr) 38836621Sbt150084 { 38849353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 388511233SPaul.Guo@Sun.COM 388611233SPaul.Guo@Sun.COM ASSERT(mutex_owned(&ixgbe->gen_lock)); 388711233SPaul.Guo@Sun.COM 38888490SPaul.Guo@Sun.COM /* 388911233SPaul.Guo@Sun.COM * handle link status change 38908490SPaul.Guo@Sun.COM */ 38918490SPaul.Guo@Sun.COM if (eicr & IXGBE_EICR_LSC) { 389211233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe); 38938490SPaul.Guo@Sun.COM } 38946621Sbt150084 38956621Sbt150084 /* 38968490SPaul.Guo@Sun.COM * check for fan failure on adapters with fans 38976621Sbt150084 */ 38988490SPaul.Guo@Sun.COM if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) && 38998490SPaul.Guo@Sun.COM (eicr & IXGBE_EICR_GPI_SDP1)) { 39009353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 39019353SSamuel.Tu@Sun.COM ixgbe_log(ixgbe, 39029353SSamuel.Tu@Sun.COM "Fan has stopped, replace the adapter\n"); 39039353SSamuel.Tu@Sun.COM 39049353SSamuel.Tu@Sun.COM /* re-enable the interrupt, which was automasked */ 39059353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_GPI_SDP1; 39069353SSamuel.Tu@Sun.COM } 39079353SSamuel.Tu@Sun.COM } 39089353SSamuel.Tu@Sun.COM 39099353SSamuel.Tu@Sun.COM /* 39109353SSamuel.Tu@Sun.COM * Do SFP check for 82599 39119353SSamuel.Tu@Sun.COM */ 39129353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 391311233SPaul.Guo@Sun.COM if ((ddi_taskq_dispatch(ixgbe->sfp_taskq, 39149353SSamuel.Tu@Sun.COM ixgbe_sfp_check, (void *)ixgbe, 39159353SSamuel.Tu@Sun.COM DDI_NOSLEEP)) != DDI_SUCCESS) { 391610305SPaul.Guo@Sun.COM ixgbe_log(ixgbe, "No memory available to dispatch " 391710305SPaul.Guo@Sun.COM "taskq for SFP check"); 39189353SSamuel.Tu@Sun.COM } 391911233SPaul.Guo@Sun.COM 392011233SPaul.Guo@Sun.COM /* 392111233SPaul.Guo@Sun.COM * We need to fully re-check the link later. 392211233SPaul.Guo@Sun.COM */ 392311233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 392411233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 392511233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 39268490SPaul.Guo@Sun.COM } 39276621Sbt150084 } 39286621Sbt150084 39296621Sbt150084 /* 39306621Sbt150084 * ixgbe_intr_legacy - Interrupt handler for legacy interrupts. 39316621Sbt150084 */ 39326621Sbt150084 static uint_t 39336621Sbt150084 ixgbe_intr_legacy(void *arg1, void *arg2) 39346621Sbt150084 { 39356621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg1; 39366621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 39376621Sbt150084 ixgbe_tx_ring_t *tx_ring; 39388275SEric Cheng ixgbe_rx_ring_t *rx_ring; 39396621Sbt150084 uint32_t eicr; 39406621Sbt150084 mblk_t *mp; 39416621Sbt150084 boolean_t tx_reschedule; 39426621Sbt150084 uint_t result; 39436621Sbt150084 39448490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 39456621Sbt150084 39466621Sbt150084 mutex_enter(&ixgbe->gen_lock); 39476621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 39486621Sbt150084 mutex_exit(&ixgbe->gen_lock); 39496621Sbt150084 return (DDI_INTR_UNCLAIMED); 39506621Sbt150084 } 39516621Sbt150084 39526621Sbt150084 mp = NULL; 39536621Sbt150084 tx_reschedule = B_FALSE; 39546621Sbt150084 39556621Sbt150084 /* 39566621Sbt150084 * Any bit set in eicr: claim this interrupt 39576621Sbt150084 */ 39586621Sbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 395911233SPaul.Guo@Sun.COM 396011233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 396112003SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 396211233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 396311233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 396411233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 396511233SPaul.Guo@Sun.COM } 396611233SPaul.Guo@Sun.COM 39676621Sbt150084 if (eicr) { 39686621Sbt150084 /* 39696621Sbt150084 * For legacy interrupt, we have only one interrupt, 39706621Sbt150084 * so we have only one rx ring and one tx ring enabled. 39716621Sbt150084 */ 39726621Sbt150084 ASSERT(ixgbe->num_rx_rings == 1); 39736621Sbt150084 ASSERT(ixgbe->num_tx_rings == 1); 39746621Sbt150084 39756621Sbt150084 /* 39768275SEric Cheng * For legacy interrupt, rx rings[0] will use RTxQ[0]. 39776621Sbt150084 */ 39788275SEric Cheng if (eicr & 0x1) { 39799353SSamuel.Tu@Sun.COM ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE; 39809353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 39819353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; 39826621Sbt150084 /* 39836621Sbt150084 * Clean the rx descriptors 39846621Sbt150084 */ 39858275SEric Cheng rx_ring = &ixgbe->rx_rings[0]; 39868275SEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL); 39878275SEric Cheng } 39888275SEric Cheng 39898275SEric Cheng /* 39908275SEric Cheng * For legacy interrupt, tx rings[0] will use RTxQ[1]. 39918275SEric Cheng */ 39928275SEric Cheng if (eicr & 0x2) { 39936621Sbt150084 /* 39946621Sbt150084 * Recycle the tx descriptors 39956621Sbt150084 */ 39966621Sbt150084 tx_ring = &ixgbe->tx_rings[0]; 39976621Sbt150084 tx_ring->tx_recycle(tx_ring); 39986621Sbt150084 39996621Sbt150084 /* 40006621Sbt150084 * Schedule the re-transmit 40016621Sbt150084 */ 40026621Sbt150084 tx_reschedule = (tx_ring->reschedule && 400310376SChenlu.Chen@Sun.COM (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)); 40046621Sbt150084 } 40056621Sbt150084 40068490SPaul.Guo@Sun.COM /* any interrupt type other than tx/rx */ 40078490SPaul.Guo@Sun.COM if (eicr & ixgbe->capab->other_intr) { 40089353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 40099353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 40109353SSamuel.Tu@Sun.COM } 40119353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 40129353SSamuel.Tu@Sun.COM ixgbe->eimc = IXGBE_82599_OTHER_INTR; 40139353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 40149353SSamuel.Tu@Sun.COM } 40159353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 40168490SPaul.Guo@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 40176621Sbt150084 } 40186621Sbt150084 40198490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 40208490SPaul.Guo@Sun.COM 40216621Sbt150084 result = DDI_INTR_CLAIMED; 40226621Sbt150084 } else { 40238490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 40248490SPaul.Guo@Sun.COM 40256621Sbt150084 /* 40266621Sbt150084 * No interrupt cause bits set: don't claim this interrupt. 40276621Sbt150084 */ 40286621Sbt150084 result = DDI_INTR_UNCLAIMED; 40296621Sbt150084 } 40306621Sbt150084 40318490SPaul.Guo@Sun.COM /* re-enable the interrupts which were automasked */ 40328490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 40336621Sbt150084 40346621Sbt150084 /* 40356621Sbt150084 * Do the following work outside of the gen_lock 40366621Sbt150084 */ 40379353SSamuel.Tu@Sun.COM if (mp != NULL) { 40388275SEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp, 40398275SEric Cheng rx_ring->ring_gen_num); 40409353SSamuel.Tu@Sun.COM } 40416621Sbt150084 40426621Sbt150084 if (tx_reschedule) { 40436621Sbt150084 tx_ring->reschedule = B_FALSE; 40448275SEric Cheng mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle); 40456621Sbt150084 IXGBE_DEBUG_STAT(tx_ring->stat_reschedule); 40466621Sbt150084 } 40476621Sbt150084 40486621Sbt150084 return (result); 40496621Sbt150084 } 40506621Sbt150084 40516621Sbt150084 /* 40526621Sbt150084 * ixgbe_intr_msi - Interrupt handler for MSI. 40536621Sbt150084 */ 40546621Sbt150084 static uint_t 40556621Sbt150084 ixgbe_intr_msi(void *arg1, void *arg2) 40566621Sbt150084 { 40576621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg1; 40586621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 40596621Sbt150084 uint32_t eicr; 40606621Sbt150084 40618490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 40628490SPaul.Guo@Sun.COM 40636621Sbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 40646621Sbt150084 406511233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 406611233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 406711233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 406811233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 406911233SPaul.Guo@Sun.COM } 407011233SPaul.Guo@Sun.COM 40716621Sbt150084 /* 40726621Sbt150084 * For MSI interrupt, we have only one vector, 40736621Sbt150084 * so we have only one rx ring and one tx ring enabled. 40746621Sbt150084 */ 40756621Sbt150084 ASSERT(ixgbe->num_rx_rings == 1); 40766621Sbt150084 ASSERT(ixgbe->num_tx_rings == 1); 40776621Sbt150084 40786621Sbt150084 /* 40798275SEric Cheng * For MSI interrupt, rx rings[0] will use RTxQ[0]. 40806621Sbt150084 */ 40818275SEric Cheng if (eicr & 0x1) { 40826621Sbt150084 ixgbe_intr_rx_work(&ixgbe->rx_rings[0]); 40838275SEric Cheng } 40848275SEric Cheng 40858275SEric Cheng /* 40868275SEric Cheng * For MSI interrupt, tx rings[0] will use RTxQ[1]. 40878275SEric Cheng */ 40888275SEric Cheng if (eicr & 0x2) { 40896621Sbt150084 ixgbe_intr_tx_work(&ixgbe->tx_rings[0]); 40906621Sbt150084 } 40916621Sbt150084 40928490SPaul.Guo@Sun.COM /* any interrupt type other than tx/rx */ 40938490SPaul.Guo@Sun.COM if (eicr & ixgbe->capab->other_intr) { 40948490SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 40959353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 40969353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 40979353SSamuel.Tu@Sun.COM } 40989353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 40999353SSamuel.Tu@Sun.COM ixgbe->eimc = IXGBE_82599_OTHER_INTR; 41009353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 41019353SSamuel.Tu@Sun.COM } 41029353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 41038490SPaul.Guo@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 41048490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 41056621Sbt150084 } 41066621Sbt150084 41078490SPaul.Guo@Sun.COM /* re-enable the interrupts which were automasked */ 41088490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 41098490SPaul.Guo@Sun.COM 41106621Sbt150084 return (DDI_INTR_CLAIMED); 41116621Sbt150084 } 41126621Sbt150084 41136621Sbt150084 /* 41149353SSamuel.Tu@Sun.COM * ixgbe_intr_msix - Interrupt handler for MSI-X. 41156621Sbt150084 */ 41166621Sbt150084 static uint_t 41179353SSamuel.Tu@Sun.COM ixgbe_intr_msix(void *arg1, void *arg2) 41186621Sbt150084 { 41199353SSamuel.Tu@Sun.COM ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1; 41208275SEric Cheng ixgbe_t *ixgbe = vect->ixgbe; 41219353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 41229353SSamuel.Tu@Sun.COM uint32_t eicr; 41238275SEric Cheng int r_idx = 0; 41246621Sbt150084 41258490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 41268490SPaul.Guo@Sun.COM 41276621Sbt150084 /* 41288275SEric Cheng * Clean each rx ring that has its bit set in the map 41296621Sbt150084 */ 41306621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1)); 41316621Sbt150084 while (r_idx >= 0) { 41326621Sbt150084 ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]); 41336621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1), 41346621Sbt150084 (ixgbe->num_rx_rings - 1)); 41356621Sbt150084 } 41366621Sbt150084 41378275SEric Cheng /* 41388275SEric Cheng * Clean each tx ring that has its bit set in the map 41398275SEric Cheng */ 41408275SEric Cheng r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1)); 41418275SEric Cheng while (r_idx >= 0) { 41428275SEric Cheng ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]); 41438275SEric Cheng r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1), 41448275SEric Cheng (ixgbe->num_tx_rings - 1)); 41458275SEric Cheng } 41468275SEric Cheng 41476621Sbt150084 41486621Sbt150084 /* 41499353SSamuel.Tu@Sun.COM * Clean other interrupt (link change) that has its bit set in the map 41506621Sbt150084 */ 41519353SSamuel.Tu@Sun.COM if (BT_TEST(vect->other_map, 0) == 1) { 41529353SSamuel.Tu@Sun.COM eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 41539353SSamuel.Tu@Sun.COM 415411233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != 415511233SPaul.Guo@Sun.COM DDI_FM_OK) { 415611233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, 415711233SPaul.Guo@Sun.COM DDI_SERVICE_DEGRADED); 415811233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 415911233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 416011233SPaul.Guo@Sun.COM } 416111233SPaul.Guo@Sun.COM 41629353SSamuel.Tu@Sun.COM /* 41639353SSamuel.Tu@Sun.COM * Need check cause bits and only other causes will 41649353SSamuel.Tu@Sun.COM * be processed 41659353SSamuel.Tu@Sun.COM */ 41669353SSamuel.Tu@Sun.COM /* any interrupt type other than tx/rx */ 41679353SSamuel.Tu@Sun.COM if (eicr & ixgbe->capab->other_intr) { 41689353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 41699353SSamuel.Tu@Sun.COM mutex_enter(&ixgbe->gen_lock); 41709353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 41719353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 41729353SSamuel.Tu@Sun.COM mutex_exit(&ixgbe->gen_lock); 41739353SSamuel.Tu@Sun.COM } else { 41749353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 41759353SSamuel.Tu@Sun.COM mutex_enter(&ixgbe->gen_lock); 41769353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; 41779353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 41789353SSamuel.Tu@Sun.COM mutex_exit(&ixgbe->gen_lock); 41799353SSamuel.Tu@Sun.COM } 41809353SSamuel.Tu@Sun.COM } 41819353SSamuel.Tu@Sun.COM } 41829353SSamuel.Tu@Sun.COM 41839353SSamuel.Tu@Sun.COM /* re-enable the interrupts which were automasked */ 41849353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 41856621Sbt150084 } 41866621Sbt150084 41876621Sbt150084 return (DDI_INTR_CLAIMED); 41886621Sbt150084 } 41896621Sbt150084 41906621Sbt150084 /* 41916621Sbt150084 * ixgbe_alloc_intrs - Allocate interrupts for the driver. 41926621Sbt150084 * 41936621Sbt150084 * Normal sequence is to try MSI-X; if not sucessful, try MSI; 41946621Sbt150084 * if not successful, try Legacy. 41956621Sbt150084 * ixgbe->intr_force can be used to force sequence to start with 41966621Sbt150084 * any of the 3 types. 41976621Sbt150084 * If MSI-X is not used, number of tx/rx rings is forced to 1. 41986621Sbt150084 */ 41996621Sbt150084 static int 42006621Sbt150084 ixgbe_alloc_intrs(ixgbe_t *ixgbe) 42016621Sbt150084 { 42026621Sbt150084 dev_info_t *devinfo; 42036621Sbt150084 int intr_types; 42046621Sbt150084 int rc; 42056621Sbt150084 42066621Sbt150084 devinfo = ixgbe->dip; 42076621Sbt150084 42086621Sbt150084 /* 42096621Sbt150084 * Get supported interrupt types 42106621Sbt150084 */ 42116621Sbt150084 rc = ddi_intr_get_supported_types(devinfo, &intr_types); 42126621Sbt150084 42136621Sbt150084 if (rc != DDI_SUCCESS) { 42146621Sbt150084 ixgbe_log(ixgbe, 42156621Sbt150084 "Get supported interrupt types failed: %d", rc); 42166621Sbt150084 return (IXGBE_FAILURE); 42176621Sbt150084 } 42186621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types); 42196621Sbt150084 42206621Sbt150084 ixgbe->intr_type = 0; 42216621Sbt150084 42226621Sbt150084 /* 42236621Sbt150084 * Install MSI-X interrupts 42246621Sbt150084 */ 42256621Sbt150084 if ((intr_types & DDI_INTR_TYPE_MSIX) && 42266621Sbt150084 (ixgbe->intr_force <= IXGBE_INTR_MSIX)) { 42276621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX); 42286621Sbt150084 if (rc == IXGBE_SUCCESS) 42296621Sbt150084 return (IXGBE_SUCCESS); 42306621Sbt150084 42316621Sbt150084 ixgbe_log(ixgbe, 42326621Sbt150084 "Allocate MSI-X failed, trying MSI interrupts..."); 42336621Sbt150084 } 42346621Sbt150084 42356621Sbt150084 /* 42368275SEric Cheng * MSI-X not used, force rings and groups to 1 42376621Sbt150084 */ 42386621Sbt150084 ixgbe->num_rx_rings = 1; 42398275SEric Cheng ixgbe->num_rx_groups = 1; 42406621Sbt150084 ixgbe->num_tx_rings = 1; 424111878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 42426621Sbt150084 ixgbe_log(ixgbe, 42438275SEric Cheng "MSI-X not used, force rings and groups number to 1"); 42446621Sbt150084 42456621Sbt150084 /* 42466621Sbt150084 * Install MSI interrupts 42476621Sbt150084 */ 42486621Sbt150084 if ((intr_types & DDI_INTR_TYPE_MSI) && 42496621Sbt150084 (ixgbe->intr_force <= IXGBE_INTR_MSI)) { 42506621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI); 42516621Sbt150084 if (rc == IXGBE_SUCCESS) 42526621Sbt150084 return (IXGBE_SUCCESS); 42536621Sbt150084 42546621Sbt150084 ixgbe_log(ixgbe, 42556621Sbt150084 "Allocate MSI failed, trying Legacy interrupts..."); 42566621Sbt150084 } 42576621Sbt150084 42586621Sbt150084 /* 42596621Sbt150084 * Install legacy interrupts 42606621Sbt150084 */ 42616621Sbt150084 if (intr_types & DDI_INTR_TYPE_FIXED) { 42626621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED); 42636621Sbt150084 if (rc == IXGBE_SUCCESS) 42646621Sbt150084 return (IXGBE_SUCCESS); 42656621Sbt150084 42666621Sbt150084 ixgbe_log(ixgbe, 42676621Sbt150084 "Allocate Legacy interrupts failed"); 42686621Sbt150084 } 42696621Sbt150084 42706621Sbt150084 /* 42716621Sbt150084 * If none of the 3 types succeeded, return failure 42726621Sbt150084 */ 42736621Sbt150084 return (IXGBE_FAILURE); 42746621Sbt150084 } 42756621Sbt150084 42766621Sbt150084 /* 42776621Sbt150084 * ixgbe_alloc_intr_handles - Allocate interrupt handles. 42786621Sbt150084 * 42796621Sbt150084 * For legacy and MSI, only 1 handle is needed. For MSI-X, 42806621Sbt150084 * if fewer than 2 handles are available, return failure. 42818275SEric Cheng * Upon success, this maps the vectors to rx and tx rings for 42828275SEric Cheng * interrupts. 42836621Sbt150084 */ 42846621Sbt150084 static int 42856621Sbt150084 ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type) 42866621Sbt150084 { 42876621Sbt150084 dev_info_t *devinfo; 428811878SVenu.Iyer@Sun.COM int request, count, actual; 42898275SEric Cheng int minimum; 42906621Sbt150084 int rc; 429111878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 42926621Sbt150084 42936621Sbt150084 devinfo = ixgbe->dip; 42946621Sbt150084 42956621Sbt150084 switch (intr_type) { 42966621Sbt150084 case DDI_INTR_TYPE_FIXED: 42976621Sbt150084 request = 1; /* Request 1 legacy interrupt handle */ 42986621Sbt150084 minimum = 1; 42996621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy"); 43006621Sbt150084 break; 43016621Sbt150084 43026621Sbt150084 case DDI_INTR_TYPE_MSI: 43036621Sbt150084 request = 1; /* Request 1 MSI interrupt handle */ 43046621Sbt150084 minimum = 1; 43056621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI"); 43066621Sbt150084 break; 43076621Sbt150084 43086621Sbt150084 case DDI_INTR_TYPE_MSIX: 43096621Sbt150084 /* 43106621Sbt150084 * Best number of vectors for the adapter is 431111878SVenu.Iyer@Sun.COM * (# rx rings + # tx rings), however we will 431211878SVenu.Iyer@Sun.COM * limit the request number. 43136621Sbt150084 */ 431411878SVenu.Iyer@Sun.COM request = min(16, ixgbe->num_rx_rings + ixgbe->num_tx_rings); 43159353SSamuel.Tu@Sun.COM if (request > ixgbe->capab->max_ring_vect) 43169353SSamuel.Tu@Sun.COM request = ixgbe->capab->max_ring_vect; 431711878SVenu.Iyer@Sun.COM minimum = 1; 43186621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X"); 43196621Sbt150084 break; 43206621Sbt150084 43216621Sbt150084 default: 43226621Sbt150084 ixgbe_log(ixgbe, 43236621Sbt150084 "invalid call to ixgbe_alloc_intr_handles(): %d\n", 43246621Sbt150084 intr_type); 43256621Sbt150084 return (IXGBE_FAILURE); 43266621Sbt150084 } 43276621Sbt150084 IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d minimum: %d", 43286621Sbt150084 request, minimum); 43296621Sbt150084 43306621Sbt150084 /* 43316621Sbt150084 * Get number of supported interrupts 43326621Sbt150084 */ 43336621Sbt150084 rc = ddi_intr_get_nintrs(devinfo, intr_type, &count); 43346621Sbt150084 if ((rc != DDI_SUCCESS) || (count < minimum)) { 43356621Sbt150084 ixgbe_log(ixgbe, 43366621Sbt150084 "Get interrupt number failed. Return: %d, count: %d", 43376621Sbt150084 rc, count); 43386621Sbt150084 return (IXGBE_FAILURE); 43396621Sbt150084 } 43406621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count); 43416621Sbt150084 43426621Sbt150084 actual = 0; 43436621Sbt150084 ixgbe->intr_cnt = 0; 434411878SVenu.Iyer@Sun.COM ixgbe->intr_cnt_max = 0; 434511878SVenu.Iyer@Sun.COM ixgbe->intr_cnt_min = 0; 43466621Sbt150084 43476621Sbt150084 /* 43486621Sbt150084 * Allocate an array of interrupt handles 43496621Sbt150084 */ 43506621Sbt150084 ixgbe->intr_size = request * sizeof (ddi_intr_handle_t); 43516621Sbt150084 ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP); 43526621Sbt150084 43536621Sbt150084 rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0, 43546621Sbt150084 request, &actual, DDI_INTR_ALLOC_NORMAL); 43556621Sbt150084 if (rc != DDI_SUCCESS) { 43566621Sbt150084 ixgbe_log(ixgbe, "Allocate interrupts failed. " 43576621Sbt150084 "return: %d, request: %d, actual: %d", 43586621Sbt150084 rc, request, actual); 43596621Sbt150084 goto alloc_handle_fail; 43606621Sbt150084 } 43616621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual); 43626621Sbt150084 436311878SVenu.Iyer@Sun.COM /* 436411878SVenu.Iyer@Sun.COM * upper/lower limit of interrupts 436511878SVenu.Iyer@Sun.COM */ 43666621Sbt150084 ixgbe->intr_cnt = actual; 436711878SVenu.Iyer@Sun.COM ixgbe->intr_cnt_max = request; 436811878SVenu.Iyer@Sun.COM ixgbe->intr_cnt_min = minimum; 436911878SVenu.Iyer@Sun.COM 437011878SVenu.Iyer@Sun.COM /* 437111878SVenu.Iyer@Sun.COM * rss number per group should not exceed the rx interrupt number, 437211878SVenu.Iyer@Sun.COM * else need to adjust rx ring number. 437311878SVenu.Iyer@Sun.COM */ 437411878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 437511878SVenu.Iyer@Sun.COM ASSERT((ixgbe->num_rx_rings % ixgbe->num_rx_groups) == 0); 437611878SVenu.Iyer@Sun.COM if (min(actual, ixgbe->num_rx_rings) < ring_per_group) { 437711878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 437811878SVenu.Iyer@Sun.COM min(actual, ixgbe->num_rx_rings); 437911878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss_conf(ixgbe); 438011878SVenu.Iyer@Sun.COM } 43816621Sbt150084 43826621Sbt150084 /* 43838275SEric Cheng * Now we know the actual number of vectors. Here we map the vector 43848275SEric Cheng * to other, rx rings and tx ring. 43856621Sbt150084 */ 43866621Sbt150084 if (actual < minimum) { 43876621Sbt150084 ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d", 43886621Sbt150084 actual); 43896621Sbt150084 goto alloc_handle_fail; 43906621Sbt150084 } 43916621Sbt150084 43926621Sbt150084 /* 43936621Sbt150084 * Get priority for first vector, assume remaining are all the same 43946621Sbt150084 */ 43956621Sbt150084 rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri); 43966621Sbt150084 if (rc != DDI_SUCCESS) { 43976621Sbt150084 ixgbe_log(ixgbe, 43986621Sbt150084 "Get interrupt priority failed: %d", rc); 43996621Sbt150084 goto alloc_handle_fail; 44006621Sbt150084 } 44016621Sbt150084 44026621Sbt150084 rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap); 44036621Sbt150084 if (rc != DDI_SUCCESS) { 44046621Sbt150084 ixgbe_log(ixgbe, 44056621Sbt150084 "Get interrupt cap failed: %d", rc); 44066621Sbt150084 goto alloc_handle_fail; 44076621Sbt150084 } 44086621Sbt150084 44096621Sbt150084 ixgbe->intr_type = intr_type; 44106621Sbt150084 44116621Sbt150084 return (IXGBE_SUCCESS); 44126621Sbt150084 44136621Sbt150084 alloc_handle_fail: 44146621Sbt150084 ixgbe_rem_intrs(ixgbe); 44156621Sbt150084 44166621Sbt150084 return (IXGBE_FAILURE); 44176621Sbt150084 } 44186621Sbt150084 44196621Sbt150084 /* 44206621Sbt150084 * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type. 44216621Sbt150084 * 44226621Sbt150084 * Before adding the interrupt handlers, the interrupt vectors have 44236621Sbt150084 * been allocated, and the rx/tx rings have also been allocated. 44246621Sbt150084 */ 44256621Sbt150084 static int 44266621Sbt150084 ixgbe_add_intr_handlers(ixgbe_t *ixgbe) 44276621Sbt150084 { 44288275SEric Cheng int vector = 0; 44296621Sbt150084 int rc; 44306621Sbt150084 44316621Sbt150084 switch (ixgbe->intr_type) { 44326621Sbt150084 case DDI_INTR_TYPE_MSIX: 44336621Sbt150084 /* 44349353SSamuel.Tu@Sun.COM * Add interrupt handler for all vectors 44356621Sbt150084 */ 44369353SSamuel.Tu@Sun.COM for (vector = 0; vector < ixgbe->intr_cnt; vector++) { 44376621Sbt150084 /* 44386621Sbt150084 * install pointer to vect_map[vector] 44396621Sbt150084 */ 44406621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 44419353SSamuel.Tu@Sun.COM (ddi_intr_handler_t *)ixgbe_intr_msix, 44426621Sbt150084 (void *)&ixgbe->vect_map[vector], NULL); 44436621Sbt150084 44446621Sbt150084 if (rc != DDI_SUCCESS) { 44456621Sbt150084 ixgbe_log(ixgbe, 444612003SPaul.Guo@Sun.COM "Add interrupt handler failed. " 44478275SEric Cheng "return: %d, vector: %d", rc, vector); 44486621Sbt150084 for (vector--; vector >= 0; vector--) { 44496621Sbt150084 (void) ddi_intr_remove_handler( 44506621Sbt150084 ixgbe->htable[vector]); 44516621Sbt150084 } 44526621Sbt150084 return (IXGBE_FAILURE); 44536621Sbt150084 } 44546621Sbt150084 } 44558275SEric Cheng 44566621Sbt150084 break; 44576621Sbt150084 44586621Sbt150084 case DDI_INTR_TYPE_MSI: 44596621Sbt150084 /* 44606621Sbt150084 * Add interrupt handlers for the only vector 44616621Sbt150084 */ 44626621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 44636621Sbt150084 (ddi_intr_handler_t *)ixgbe_intr_msi, 44646621Sbt150084 (void *)ixgbe, NULL); 44656621Sbt150084 44666621Sbt150084 if (rc != DDI_SUCCESS) { 44676621Sbt150084 ixgbe_log(ixgbe, 44686621Sbt150084 "Add MSI interrupt handler failed: %d", rc); 44696621Sbt150084 return (IXGBE_FAILURE); 44706621Sbt150084 } 44716621Sbt150084 44726621Sbt150084 break; 44736621Sbt150084 44746621Sbt150084 case DDI_INTR_TYPE_FIXED: 44756621Sbt150084 /* 44766621Sbt150084 * Add interrupt handlers for the only vector 44776621Sbt150084 */ 44786621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 44796621Sbt150084 (ddi_intr_handler_t *)ixgbe_intr_legacy, 44806621Sbt150084 (void *)ixgbe, NULL); 44816621Sbt150084 44826621Sbt150084 if (rc != DDI_SUCCESS) { 44836621Sbt150084 ixgbe_log(ixgbe, 44846621Sbt150084 "Add legacy interrupt handler failed: %d", rc); 44856621Sbt150084 return (IXGBE_FAILURE); 44866621Sbt150084 } 44876621Sbt150084 44886621Sbt150084 break; 44896621Sbt150084 44906621Sbt150084 default: 44916621Sbt150084 return (IXGBE_FAILURE); 44926621Sbt150084 } 44936621Sbt150084 44946621Sbt150084 return (IXGBE_SUCCESS); 44956621Sbt150084 } 44966621Sbt150084 44976621Sbt150084 #pragma inline(ixgbe_map_rxring_to_vector) 44986621Sbt150084 /* 44996621Sbt150084 * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector. 45006621Sbt150084 */ 45016621Sbt150084 static void 45026621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx) 45036621Sbt150084 { 45046621Sbt150084 /* 45056621Sbt150084 * Set bit in map 45066621Sbt150084 */ 45076621Sbt150084 BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx); 45086621Sbt150084 45096621Sbt150084 /* 45106621Sbt150084 * Count bits set 45116621Sbt150084 */ 45126621Sbt150084 ixgbe->vect_map[v_idx].rxr_cnt++; 45136621Sbt150084 45146621Sbt150084 /* 45156621Sbt150084 * Remember bit position 45166621Sbt150084 */ 45178275SEric Cheng ixgbe->rx_rings[r_idx].intr_vector = v_idx; 45186621Sbt150084 ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx; 45196621Sbt150084 } 45206621Sbt150084 45216621Sbt150084 #pragma inline(ixgbe_map_txring_to_vector) 45226621Sbt150084 /* 45236621Sbt150084 * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector. 45246621Sbt150084 */ 45256621Sbt150084 static void 45266621Sbt150084 ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx) 45276621Sbt150084 { 45286621Sbt150084 /* 45296621Sbt150084 * Set bit in map 45306621Sbt150084 */ 45316621Sbt150084 BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx); 45326621Sbt150084 45336621Sbt150084 /* 45346621Sbt150084 * Count bits set 45356621Sbt150084 */ 45366621Sbt150084 ixgbe->vect_map[v_idx].txr_cnt++; 45376621Sbt150084 45386621Sbt150084 /* 45396621Sbt150084 * Remember bit position 45406621Sbt150084 */ 45418275SEric Cheng ixgbe->tx_rings[t_idx].intr_vector = v_idx; 45426621Sbt150084 ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx; 45436621Sbt150084 } 45446621Sbt150084 45456621Sbt150084 /* 45468275SEric Cheng * ixgbe_setup_ivar - Set the given entry in the given interrupt vector 45476621Sbt150084 * allocation register (IVAR). 45489353SSamuel.Tu@Sun.COM * cause: 45499353SSamuel.Tu@Sun.COM * -1 : other cause 45509353SSamuel.Tu@Sun.COM * 0 : rx 45519353SSamuel.Tu@Sun.COM * 1 : tx 45526621Sbt150084 */ 45536621Sbt150084 static void 45549353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector, 45559353SSamuel.Tu@Sun.COM int8_t cause) 45566621Sbt150084 { 45576621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 45586621Sbt150084 u32 ivar, index; 45596621Sbt150084 45609353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 45619353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 45629353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 45639353SSamuel.Tu@Sun.COM if (cause == -1) { 45649353SSamuel.Tu@Sun.COM cause = 0; 45659353SSamuel.Tu@Sun.COM } 45669353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 45679353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 45689353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3))); 45699353SSamuel.Tu@Sun.COM ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3))); 45709353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 45719353SSamuel.Tu@Sun.COM break; 45729353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 45739353SSamuel.Tu@Sun.COM if (cause == -1) { 45749353SSamuel.Tu@Sun.COM /* other causes */ 45759353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 45769353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 45779353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 45789353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << index); 45799353SSamuel.Tu@Sun.COM ivar |= (msix_vector << index); 45809353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 45819353SSamuel.Tu@Sun.COM } else { 45829353SSamuel.Tu@Sun.COM /* tx or rx causes */ 45839353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 45849353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 45859353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 45869353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 45879353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << index); 45889353SSamuel.Tu@Sun.COM ivar |= (msix_vector << index); 45899353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 45909353SSamuel.Tu@Sun.COM ivar); 45919353SSamuel.Tu@Sun.COM } 45929353SSamuel.Tu@Sun.COM break; 45939353SSamuel.Tu@Sun.COM default: 45949353SSamuel.Tu@Sun.COM break; 45959353SSamuel.Tu@Sun.COM } 45968275SEric Cheng } 45978275SEric Cheng 45988275SEric Cheng /* 45998275SEric Cheng * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of 46008275SEric Cheng * given interrupt vector allocation register (IVAR). 46019353SSamuel.Tu@Sun.COM * cause: 46029353SSamuel.Tu@Sun.COM * -1 : other cause 46039353SSamuel.Tu@Sun.COM * 0 : rx 46049353SSamuel.Tu@Sun.COM * 1 : tx 46058275SEric Cheng */ 46068275SEric Cheng static void 46079353SSamuel.Tu@Sun.COM ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause) 46088275SEric Cheng { 46098275SEric Cheng struct ixgbe_hw *hw = &ixgbe->hw; 46108275SEric Cheng u32 ivar, index; 46118275SEric Cheng 46129353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 46139353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 46149353SSamuel.Tu@Sun.COM if (cause == -1) { 46159353SSamuel.Tu@Sun.COM cause = 0; 46169353SSamuel.Tu@Sun.COM } 46179353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 46189353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 46199353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 * 46209353SSamuel.Tu@Sun.COM (intr_alloc_entry & 0x3))); 46219353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 46229353SSamuel.Tu@Sun.COM break; 46239353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 46249353SSamuel.Tu@Sun.COM if (cause == -1) { 46259353SSamuel.Tu@Sun.COM /* other causes */ 46269353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 46279353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 46289353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << index); 46299353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 46309353SSamuel.Tu@Sun.COM } else { 46319353SSamuel.Tu@Sun.COM /* tx or rx causes */ 46329353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 46339353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 46349353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 46359353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << index); 46369353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 46379353SSamuel.Tu@Sun.COM ivar); 46389353SSamuel.Tu@Sun.COM } 46399353SSamuel.Tu@Sun.COM break; 46409353SSamuel.Tu@Sun.COM default: 46419353SSamuel.Tu@Sun.COM break; 46429353SSamuel.Tu@Sun.COM } 46438275SEric Cheng } 46448275SEric Cheng 46458275SEric Cheng /* 46469353SSamuel.Tu@Sun.COM * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of 46478275SEric Cheng * given interrupt vector allocation register (IVAR). 46489353SSamuel.Tu@Sun.COM * cause: 46499353SSamuel.Tu@Sun.COM * -1 : other cause 46509353SSamuel.Tu@Sun.COM * 0 : rx 46519353SSamuel.Tu@Sun.COM * 1 : tx 46528275SEric Cheng */ 46538275SEric Cheng static void 46549353SSamuel.Tu@Sun.COM ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause) 46558275SEric Cheng { 46568275SEric Cheng struct ixgbe_hw *hw = &ixgbe->hw; 46578275SEric Cheng u32 ivar, index; 46588275SEric Cheng 46599353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 46609353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 46619353SSamuel.Tu@Sun.COM if (cause == -1) { 46629353SSamuel.Tu@Sun.COM cause = 0; 46639353SSamuel.Tu@Sun.COM } 46649353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 46659353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 46669353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 * 46679353SSamuel.Tu@Sun.COM (intr_alloc_entry & 0x3))); 46689353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 46699353SSamuel.Tu@Sun.COM break; 46709353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 46719353SSamuel.Tu@Sun.COM if (cause == -1) { 46729353SSamuel.Tu@Sun.COM /* other causes */ 46739353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 46749353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 46759353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index); 46769353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 46779353SSamuel.Tu@Sun.COM } else { 46789353SSamuel.Tu@Sun.COM /* tx or rx causes */ 46799353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 46809353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 46819353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 46829353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index); 46839353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 46849353SSamuel.Tu@Sun.COM ivar); 46859353SSamuel.Tu@Sun.COM } 46869353SSamuel.Tu@Sun.COM break; 46879353SSamuel.Tu@Sun.COM default: 46889353SSamuel.Tu@Sun.COM break; 46899353SSamuel.Tu@Sun.COM } 46906621Sbt150084 } 46916621Sbt150084 46926621Sbt150084 /* 469311878SVenu.Iyer@Sun.COM * Convert the rx ring index driver maintained to the rx ring index 469411878SVenu.Iyer@Sun.COM * in h/w. 469511878SVenu.Iyer@Sun.COM */ 469611878SVenu.Iyer@Sun.COM static uint32_t 469711878SVenu.Iyer@Sun.COM ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index) 469811878SVenu.Iyer@Sun.COM { 469911878SVenu.Iyer@Sun.COM 470011878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 470111878SVenu.Iyer@Sun.COM uint32_t rx_ring_per_group, hw_rx_index; 470211878SVenu.Iyer@Sun.COM 470311878SVenu.Iyer@Sun.COM if (ixgbe->classify_mode == IXGBE_CLASSIFY_RSS || 470411878SVenu.Iyer@Sun.COM ixgbe->classify_mode == IXGBE_CLASSIFY_NONE) { 470511878SVenu.Iyer@Sun.COM return (sw_rx_index); 470611878SVenu.Iyer@Sun.COM } else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ) { 470711878SVenu.Iyer@Sun.COM if (hw->mac.type == ixgbe_mac_82598EB) { 470811878SVenu.Iyer@Sun.COM return (sw_rx_index); 470911878SVenu.Iyer@Sun.COM } else if (hw->mac.type == ixgbe_mac_82599EB) { 471011878SVenu.Iyer@Sun.COM return (sw_rx_index * 2); 471111878SVenu.Iyer@Sun.COM } 471211878SVenu.Iyer@Sun.COM } else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) { 471311878SVenu.Iyer@Sun.COM rx_ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 471411878SVenu.Iyer@Sun.COM 471511878SVenu.Iyer@Sun.COM if (hw->mac.type == ixgbe_mac_82598EB) { 471611878SVenu.Iyer@Sun.COM hw_rx_index = (sw_rx_index / rx_ring_per_group) * 471711878SVenu.Iyer@Sun.COM 16 + (sw_rx_index % rx_ring_per_group); 471811878SVenu.Iyer@Sun.COM return (hw_rx_index); 471911878SVenu.Iyer@Sun.COM } else if (hw->mac.type == ixgbe_mac_82599EB) { 472011878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups > 32) { 472111878SVenu.Iyer@Sun.COM hw_rx_index = (sw_rx_index / 472211878SVenu.Iyer@Sun.COM rx_ring_per_group) * 2 + 472311878SVenu.Iyer@Sun.COM (sw_rx_index % rx_ring_per_group); 472411878SVenu.Iyer@Sun.COM } else { 472511878SVenu.Iyer@Sun.COM hw_rx_index = (sw_rx_index / 472611878SVenu.Iyer@Sun.COM rx_ring_per_group) * 4 + 472711878SVenu.Iyer@Sun.COM (sw_rx_index % rx_ring_per_group); 472811878SVenu.Iyer@Sun.COM } 472911878SVenu.Iyer@Sun.COM return (hw_rx_index); 473011878SVenu.Iyer@Sun.COM } 473111878SVenu.Iyer@Sun.COM } 473211878SVenu.Iyer@Sun.COM 473311878SVenu.Iyer@Sun.COM /* 473411878SVenu.Iyer@Sun.COM * Should never reach. Just to make compiler happy. 473511878SVenu.Iyer@Sun.COM */ 473611878SVenu.Iyer@Sun.COM return (sw_rx_index); 473711878SVenu.Iyer@Sun.COM } 473811878SVenu.Iyer@Sun.COM 473911878SVenu.Iyer@Sun.COM /* 47409353SSamuel.Tu@Sun.COM * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors. 47416621Sbt150084 * 47429353SSamuel.Tu@Sun.COM * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt 47439353SSamuel.Tu@Sun.COM * to vector[0 - (intr_cnt -1)]. 47446621Sbt150084 */ 47456621Sbt150084 static int 47469353SSamuel.Tu@Sun.COM ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe) 47476621Sbt150084 { 47486621Sbt150084 int i, vector = 0; 47496621Sbt150084 47506621Sbt150084 /* initialize vector map */ 47516621Sbt150084 bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map)); 47529353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->intr_cnt; i++) { 47539353SSamuel.Tu@Sun.COM ixgbe->vect_map[i].ixgbe = ixgbe; 47549353SSamuel.Tu@Sun.COM } 47556621Sbt150084 47566621Sbt150084 /* 47578275SEric Cheng * non-MSI-X case is very simple: rx rings[0] on RTxQ[0], 47588275SEric Cheng * tx rings[0] on RTxQ[1]. 47596621Sbt150084 */ 47606621Sbt150084 if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) { 47616621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe, 0, 0); 47628275SEric Cheng ixgbe_map_txring_to_vector(ixgbe, 0, 1); 47636621Sbt150084 return (IXGBE_SUCCESS); 47646621Sbt150084 } 47656621Sbt150084 47666621Sbt150084 /* 47679353SSamuel.Tu@Sun.COM * Interrupts/vectors mapping for MSI-X 47686621Sbt150084 */ 47696621Sbt150084 47706621Sbt150084 /* 47719353SSamuel.Tu@Sun.COM * Map other interrupt to vector 0, 47729353SSamuel.Tu@Sun.COM * Set bit in map and count the bits set. 47739353SSamuel.Tu@Sun.COM */ 47749353SSamuel.Tu@Sun.COM BT_SET(ixgbe->vect_map[vector].other_map, 0); 47759353SSamuel.Tu@Sun.COM ixgbe->vect_map[vector].other_cnt++; 47769353SSamuel.Tu@Sun.COM 47779353SSamuel.Tu@Sun.COM /* 47789353SSamuel.Tu@Sun.COM * Map rx ring interrupts to vectors 47796621Sbt150084 */ 47808275SEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) { 47818275SEric Cheng ixgbe_map_rxring_to_vector(ixgbe, i, vector); 47829353SSamuel.Tu@Sun.COM vector = (vector +1) % ixgbe->intr_cnt; 47838275SEric Cheng } 47846621Sbt150084 47856621Sbt150084 /* 47869353SSamuel.Tu@Sun.COM * Map tx ring interrupts to vectors 47876621Sbt150084 */ 47888275SEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) { 47898275SEric Cheng ixgbe_map_txring_to_vector(ixgbe, i, vector); 47909353SSamuel.Tu@Sun.COM vector = (vector +1) % ixgbe->intr_cnt; 47916621Sbt150084 } 47926621Sbt150084 47936621Sbt150084 return (IXGBE_SUCCESS); 47946621Sbt150084 } 47956621Sbt150084 47966621Sbt150084 /* 47976621Sbt150084 * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s). 47986621Sbt150084 * 47998275SEric Cheng * This relies on ring/vector mapping already set up in the 48006621Sbt150084 * vect_map[] structures 48016621Sbt150084 */ 48026621Sbt150084 static void 48036621Sbt150084 ixgbe_setup_adapter_vector(ixgbe_t *ixgbe) 48046621Sbt150084 { 48056621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 48069353SSamuel.Tu@Sun.COM ixgbe_intr_vector_t *vect; /* vector bitmap */ 48078275SEric Cheng int r_idx; /* ring index */ 48088275SEric Cheng int v_idx; /* vector index */ 480911878SVenu.Iyer@Sun.COM uint32_t hw_index; 48106621Sbt150084 48116621Sbt150084 /* 48126621Sbt150084 * Clear any previous entries 48136621Sbt150084 */ 48149353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 48159353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 48169353SSamuel.Tu@Sun.COM for (v_idx = 0; v_idx < 25; v_idx++) 48179353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); 48189353SSamuel.Tu@Sun.COM 48199353SSamuel.Tu@Sun.COM break; 48209353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 48219353SSamuel.Tu@Sun.COM for (v_idx = 0; v_idx < 64; v_idx++) 48229353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); 48239353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0); 48249353SSamuel.Tu@Sun.COM 48259353SSamuel.Tu@Sun.COM break; 48269353SSamuel.Tu@Sun.COM default: 48279353SSamuel.Tu@Sun.COM break; 48289353SSamuel.Tu@Sun.COM } 48296621Sbt150084 48306621Sbt150084 /* 48318275SEric Cheng * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and 48328275SEric Cheng * tx rings[0] will use RTxQ[1]. 48336621Sbt150084 */ 48348275SEric Cheng if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) { 48359353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, 0, 0, 0); 48369353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, 0, 1, 1); 48378275SEric Cheng return; 48388275SEric Cheng } 48398275SEric Cheng 48408275SEric Cheng /* 48419353SSamuel.Tu@Sun.COM * For MSI-X interrupt, "Other" is always on vector[0]. 48428275SEric Cheng */ 48439353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1); 48446621Sbt150084 48456621Sbt150084 /* 48466621Sbt150084 * For each interrupt vector, populate the IVAR table 48476621Sbt150084 */ 48486621Sbt150084 for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) { 48496621Sbt150084 vect = &ixgbe->vect_map[v_idx]; 48506621Sbt150084 48516621Sbt150084 /* 48526621Sbt150084 * For each rx ring bit set 48536621Sbt150084 */ 48546621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, 0, 48556621Sbt150084 (ixgbe->num_rx_rings - 1)); 48566621Sbt150084 48576621Sbt150084 while (r_idx >= 0) { 485811878SVenu.Iyer@Sun.COM hw_index = ixgbe->rx_rings[r_idx].hw_index; 485911878SVenu.Iyer@Sun.COM ixgbe_setup_ivar(ixgbe, hw_index, v_idx, 0); 48606621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1), 48616621Sbt150084 (ixgbe->num_rx_rings - 1)); 48626621Sbt150084 } 48636621Sbt150084 48646621Sbt150084 /* 48656621Sbt150084 * For each tx ring bit set 48666621Sbt150084 */ 48676621Sbt150084 r_idx = bt_getlowbit(vect->tx_map, 0, 48686621Sbt150084 (ixgbe->num_tx_rings - 1)); 48696621Sbt150084 48706621Sbt150084 while (r_idx >= 0) { 48719353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1); 48726621Sbt150084 r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1), 48736621Sbt150084 (ixgbe->num_tx_rings - 1)); 48746621Sbt150084 } 48756621Sbt150084 } 48766621Sbt150084 } 48776621Sbt150084 48786621Sbt150084 /* 48796621Sbt150084 * ixgbe_rem_intr_handlers - Remove the interrupt handlers. 48806621Sbt150084 */ 48816621Sbt150084 static void 48826621Sbt150084 ixgbe_rem_intr_handlers(ixgbe_t *ixgbe) 48836621Sbt150084 { 48846621Sbt150084 int i; 48856621Sbt150084 int rc; 48866621Sbt150084 48876621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 48886621Sbt150084 rc = ddi_intr_remove_handler(ixgbe->htable[i]); 48896621Sbt150084 if (rc != DDI_SUCCESS) { 48906621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, 48916621Sbt150084 "Remove intr handler failed: %d", rc); 48926621Sbt150084 } 48936621Sbt150084 } 48946621Sbt150084 } 48956621Sbt150084 48966621Sbt150084 /* 48976621Sbt150084 * ixgbe_rem_intrs - Remove the allocated interrupts. 48986621Sbt150084 */ 48996621Sbt150084 static void 49006621Sbt150084 ixgbe_rem_intrs(ixgbe_t *ixgbe) 49016621Sbt150084 { 49026621Sbt150084 int i; 49036621Sbt150084 int rc; 49046621Sbt150084 49056621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 49066621Sbt150084 rc = ddi_intr_free(ixgbe->htable[i]); 49076621Sbt150084 if (rc != DDI_SUCCESS) { 49086621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, 49096621Sbt150084 "Free intr failed: %d", rc); 49106621Sbt150084 } 49116621Sbt150084 } 49126621Sbt150084 49136621Sbt150084 kmem_free(ixgbe->htable, ixgbe->intr_size); 49146621Sbt150084 ixgbe->htable = NULL; 49156621Sbt150084 } 49166621Sbt150084 49176621Sbt150084 /* 49186621Sbt150084 * ixgbe_enable_intrs - Enable all the ddi interrupts. 49196621Sbt150084 */ 49206621Sbt150084 static int 49216621Sbt150084 ixgbe_enable_intrs(ixgbe_t *ixgbe) 49226621Sbt150084 { 49236621Sbt150084 int i; 49246621Sbt150084 int rc; 49256621Sbt150084 49266621Sbt150084 /* 49276621Sbt150084 * Enable interrupts 49286621Sbt150084 */ 49296621Sbt150084 if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) { 49306621Sbt150084 /* 49316621Sbt150084 * Call ddi_intr_block_enable() for MSI 49326621Sbt150084 */ 49336621Sbt150084 rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt); 49346621Sbt150084 if (rc != DDI_SUCCESS) { 49356621Sbt150084 ixgbe_log(ixgbe, 49366621Sbt150084 "Enable block intr failed: %d", rc); 49376621Sbt150084 return (IXGBE_FAILURE); 49386621Sbt150084 } 49396621Sbt150084 } else { 49406621Sbt150084 /* 49416621Sbt150084 * Call ddi_intr_enable() for Legacy/MSI non block enable 49426621Sbt150084 */ 49436621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 49446621Sbt150084 rc = ddi_intr_enable(ixgbe->htable[i]); 49456621Sbt150084 if (rc != DDI_SUCCESS) { 49466621Sbt150084 ixgbe_log(ixgbe, 49476621Sbt150084 "Enable intr failed: %d", rc); 49486621Sbt150084 return (IXGBE_FAILURE); 49496621Sbt150084 } 49506621Sbt150084 } 49516621Sbt150084 } 49526621Sbt150084 49536621Sbt150084 return (IXGBE_SUCCESS); 49546621Sbt150084 } 49556621Sbt150084 49566621Sbt150084 /* 49576621Sbt150084 * ixgbe_disable_intrs - Disable all the interrupts. 49586621Sbt150084 */ 49596621Sbt150084 static int 49606621Sbt150084 ixgbe_disable_intrs(ixgbe_t *ixgbe) 49616621Sbt150084 { 49626621Sbt150084 int i; 49636621Sbt150084 int rc; 49646621Sbt150084 49656621Sbt150084 /* 49666621Sbt150084 * Disable all interrupts 49676621Sbt150084 */ 49686621Sbt150084 if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) { 49696621Sbt150084 rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt); 49706621Sbt150084 if (rc != DDI_SUCCESS) { 49716621Sbt150084 ixgbe_log(ixgbe, 49726621Sbt150084 "Disable block intr failed: %d", rc); 49736621Sbt150084 return (IXGBE_FAILURE); 49746621Sbt150084 } 49756621Sbt150084 } else { 49766621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 49776621Sbt150084 rc = ddi_intr_disable(ixgbe->htable[i]); 49786621Sbt150084 if (rc != DDI_SUCCESS) { 49796621Sbt150084 ixgbe_log(ixgbe, 49806621Sbt150084 "Disable intr failed: %d", rc); 49816621Sbt150084 return (IXGBE_FAILURE); 49826621Sbt150084 } 49836621Sbt150084 } 49846621Sbt150084 } 49856621Sbt150084 49866621Sbt150084 return (IXGBE_SUCCESS); 49876621Sbt150084 } 49886621Sbt150084 49896621Sbt150084 /* 49906621Sbt150084 * ixgbe_get_hw_state - Get and save parameters related to adapter hardware. 49916621Sbt150084 */ 49926621Sbt150084 static void 49936621Sbt150084 ixgbe_get_hw_state(ixgbe_t *ixgbe) 49946621Sbt150084 { 49956621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 49968490SPaul.Guo@Sun.COM ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN; 49978490SPaul.Guo@Sun.COM boolean_t link_up = B_FALSE; 49986621Sbt150084 uint32_t pcs1g_anlp = 0; 49996621Sbt150084 uint32_t pcs1g_ana = 0; 50006621Sbt150084 50016621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 50026621Sbt150084 ixgbe->param_lp_1000fdx_cap = 0; 50036621Sbt150084 ixgbe->param_lp_100fdx_cap = 0; 50046621Sbt150084 50058490SPaul.Guo@Sun.COM /* check for link, don't wait */ 50068490SPaul.Guo@Sun.COM (void) ixgbe_check_link(hw, &speed, &link_up, false); 50078490SPaul.Guo@Sun.COM if (link_up) { 50086621Sbt150084 pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); 50096621Sbt150084 pcs1g_ana = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); 50106621Sbt150084 50116621Sbt150084 ixgbe->param_lp_1000fdx_cap = 50126621Sbt150084 (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; 50136621Sbt150084 ixgbe->param_lp_100fdx_cap = 50146621Sbt150084 (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; 50156621Sbt150084 } 50166621Sbt150084 501710376SChenlu.Chen@Sun.COM ixgbe->param_adv_1000fdx_cap = 501810376SChenlu.Chen@Sun.COM (pcs1g_ana & IXGBE_PCS1GANA_FDC) ? 1 : 0; 501910376SChenlu.Chen@Sun.COM ixgbe->param_adv_100fdx_cap = (pcs1g_ana & IXGBE_PCS1GANA_FDC) ? 1 : 0; 50206621Sbt150084 } 50216621Sbt150084 50226621Sbt150084 /* 50236621Sbt150084 * ixgbe_get_driver_control - Notify that driver is in control of device. 50246621Sbt150084 */ 50256621Sbt150084 static void 50266621Sbt150084 ixgbe_get_driver_control(struct ixgbe_hw *hw) 50276621Sbt150084 { 50286621Sbt150084 uint32_t ctrl_ext; 50296621Sbt150084 50306621Sbt150084 /* 50316621Sbt150084 * Notify firmware that driver is in control of device 50326621Sbt150084 */ 50336621Sbt150084 ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 50346621Sbt150084 ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 50356621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 50366621Sbt150084 } 50376621Sbt150084 50386621Sbt150084 /* 50396621Sbt150084 * ixgbe_release_driver_control - Notify that driver is no longer in control 50406621Sbt150084 * of device. 50416621Sbt150084 */ 50426621Sbt150084 static void 50436621Sbt150084 ixgbe_release_driver_control(struct ixgbe_hw *hw) 50446621Sbt150084 { 50456621Sbt150084 uint32_t ctrl_ext; 50466621Sbt150084 50476621Sbt150084 /* 50486621Sbt150084 * Notify firmware that driver is no longer in control of device 50496621Sbt150084 */ 50506621Sbt150084 ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 50516621Sbt150084 ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 50526621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 50536621Sbt150084 } 50546621Sbt150084 50556621Sbt150084 /* 50566621Sbt150084 * ixgbe_atomic_reserve - Atomic decrease operation. 50576621Sbt150084 */ 50586621Sbt150084 int 50596621Sbt150084 ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n) 50606621Sbt150084 { 50616621Sbt150084 uint32_t oldval; 50626621Sbt150084 uint32_t newval; 50636621Sbt150084 50646621Sbt150084 /* 50656621Sbt150084 * ATOMICALLY 50666621Sbt150084 */ 50676621Sbt150084 do { 50686621Sbt150084 oldval = *count_p; 50696621Sbt150084 if (oldval < n) 50706621Sbt150084 return (-1); 50716621Sbt150084 newval = oldval - n; 50726621Sbt150084 } while (atomic_cas_32(count_p, oldval, newval) != oldval); 50736621Sbt150084 50746621Sbt150084 return (newval); 50756621Sbt150084 } 50766621Sbt150084 50776621Sbt150084 /* 50786621Sbt150084 * ixgbe_mc_table_itr - Traverse the entries in the multicast table. 50796621Sbt150084 */ 50806621Sbt150084 static uint8_t * 50816621Sbt150084 ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq) 50826621Sbt150084 { 50838490SPaul.Guo@Sun.COM uint8_t *addr = *upd_ptr; 50848490SPaul.Guo@Sun.COM uint8_t *new_ptr; 50858490SPaul.Guo@Sun.COM 50866621Sbt150084 _NOTE(ARGUNUSED(hw)); 50876621Sbt150084 _NOTE(ARGUNUSED(vmdq)); 50886621Sbt150084 50896621Sbt150084 new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; 50906621Sbt150084 *upd_ptr = new_ptr; 50916621Sbt150084 return (addr); 50926621Sbt150084 } 50936621Sbt150084 50946621Sbt150084 /* 50956621Sbt150084 * FMA support 50966621Sbt150084 */ 50976621Sbt150084 int 50986621Sbt150084 ixgbe_check_acc_handle(ddi_acc_handle_t handle) 50996621Sbt150084 { 51006621Sbt150084 ddi_fm_error_t de; 51016621Sbt150084 51026621Sbt150084 ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 51036621Sbt150084 ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 51046621Sbt150084 return (de.fme_status); 51056621Sbt150084 } 51066621Sbt150084 51076621Sbt150084 int 51086621Sbt150084 ixgbe_check_dma_handle(ddi_dma_handle_t handle) 51096621Sbt150084 { 51106621Sbt150084 ddi_fm_error_t de; 51116621Sbt150084 51126621Sbt150084 ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 51136621Sbt150084 return (de.fme_status); 51146621Sbt150084 } 51156621Sbt150084 51166621Sbt150084 /* 51176621Sbt150084 * ixgbe_fm_error_cb - The IO fault service error handling callback function. 51186621Sbt150084 */ 51196621Sbt150084 static int 51206621Sbt150084 ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 51216621Sbt150084 { 51226621Sbt150084 _NOTE(ARGUNUSED(impl_data)); 51236621Sbt150084 /* 51246621Sbt150084 * as the driver can always deal with an error in any dma or 51256621Sbt150084 * access handle, we can just return the fme_status value. 51266621Sbt150084 */ 51276621Sbt150084 pci_ereport_post(dip, err, NULL); 51286621Sbt150084 return (err->fme_status); 51296621Sbt150084 } 51306621Sbt150084 51316621Sbt150084 static void 51326621Sbt150084 ixgbe_fm_init(ixgbe_t *ixgbe) 51336621Sbt150084 { 51346621Sbt150084 ddi_iblock_cookie_t iblk; 513511236SStephen.Hanson@Sun.COM int fma_dma_flag; 51366621Sbt150084 51376621Sbt150084 /* 51386621Sbt150084 * Only register with IO Fault Services if we have some capability 51396621Sbt150084 */ 51406621Sbt150084 if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) { 51416621Sbt150084 ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; 51426621Sbt150084 } else { 51436621Sbt150084 ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; 51446621Sbt150084 } 51456621Sbt150084 51466621Sbt150084 if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) { 51476621Sbt150084 fma_dma_flag = 1; 51486621Sbt150084 } else { 51496621Sbt150084 fma_dma_flag = 0; 51506621Sbt150084 } 51516621Sbt150084 515211236SStephen.Hanson@Sun.COM ixgbe_set_fma_flags(fma_dma_flag); 51536621Sbt150084 51546621Sbt150084 if (ixgbe->fm_capabilities) { 51556621Sbt150084 51566621Sbt150084 /* 51576621Sbt150084 * Register capabilities with IO Fault Services 51586621Sbt150084 */ 51596621Sbt150084 ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk); 51606621Sbt150084 51616621Sbt150084 /* 51626621Sbt150084 * Initialize pci ereport capabilities if ereport capable 51636621Sbt150084 */ 51646621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) || 51656621Sbt150084 DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 51666621Sbt150084 pci_ereport_setup(ixgbe->dip); 51676621Sbt150084 51686621Sbt150084 /* 51696621Sbt150084 * Register error callback if error callback capable 51706621Sbt150084 */ 51716621Sbt150084 if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 51726621Sbt150084 ddi_fm_handler_register(ixgbe->dip, 51736621Sbt150084 ixgbe_fm_error_cb, (void*) ixgbe); 51746621Sbt150084 } 51756621Sbt150084 } 51766621Sbt150084 51776621Sbt150084 static void 51786621Sbt150084 ixgbe_fm_fini(ixgbe_t *ixgbe) 51796621Sbt150084 { 51806621Sbt150084 /* 51816621Sbt150084 * Only unregister FMA capabilities if they are registered 51826621Sbt150084 */ 51836621Sbt150084 if (ixgbe->fm_capabilities) { 51846621Sbt150084 51856621Sbt150084 /* 51866621Sbt150084 * Release any resources allocated by pci_ereport_setup() 51876621Sbt150084 */ 51886621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) || 51896621Sbt150084 DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 51906621Sbt150084 pci_ereport_teardown(ixgbe->dip); 51916621Sbt150084 51926621Sbt150084 /* 51936621Sbt150084 * Un-register error callback if error callback capable 51946621Sbt150084 */ 51956621Sbt150084 if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 51966621Sbt150084 ddi_fm_handler_unregister(ixgbe->dip); 51976621Sbt150084 51986621Sbt150084 /* 51996621Sbt150084 * Unregister from IO Fault Service 52006621Sbt150084 */ 52016621Sbt150084 ddi_fm_fini(ixgbe->dip); 52026621Sbt150084 } 52036621Sbt150084 } 52046621Sbt150084 52056621Sbt150084 void 52066621Sbt150084 ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail) 52076621Sbt150084 { 52086621Sbt150084 uint64_t ena; 52096621Sbt150084 char buf[FM_MAX_CLASS]; 52106621Sbt150084 52116621Sbt150084 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 52126621Sbt150084 ena = fm_ena_generate(0, FM_ENA_FMT1); 52136621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) { 52146621Sbt150084 ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP, 52156621Sbt150084 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 52166621Sbt150084 } 52176621Sbt150084 } 52188275SEric Cheng 52198275SEric Cheng static int 52208275SEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 52218275SEric Cheng { 52228275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh; 52238275SEric Cheng 52248275SEric Cheng mutex_enter(&rx_ring->rx_lock); 52258275SEric Cheng rx_ring->ring_gen_num = mr_gen_num; 52268275SEric Cheng mutex_exit(&rx_ring->rx_lock); 52278275SEric Cheng return (0); 52288275SEric Cheng } 52298275SEric Cheng 52308275SEric Cheng /* 523111878SVenu.Iyer@Sun.COM * Get the global ring index by a ring index within a group. 523211878SVenu.Iyer@Sun.COM */ 523311878SVenu.Iyer@Sun.COM static int 523411878SVenu.Iyer@Sun.COM ixgbe_get_rx_ring_index(ixgbe_t *ixgbe, int gindex, int rindex) 523511878SVenu.Iyer@Sun.COM { 523611878SVenu.Iyer@Sun.COM ixgbe_rx_ring_t *rx_ring; 523711878SVenu.Iyer@Sun.COM int i; 523811878SVenu.Iyer@Sun.COM 523911878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 524011878SVenu.Iyer@Sun.COM rx_ring = &ixgbe->rx_rings[i]; 524111878SVenu.Iyer@Sun.COM if (rx_ring->group_index == gindex) 524211878SVenu.Iyer@Sun.COM rindex--; 524311878SVenu.Iyer@Sun.COM if (rindex < 0) 524411878SVenu.Iyer@Sun.COM return (i); 524511878SVenu.Iyer@Sun.COM } 524611878SVenu.Iyer@Sun.COM 524711878SVenu.Iyer@Sun.COM return (-1); 524811878SVenu.Iyer@Sun.COM } 524911878SVenu.Iyer@Sun.COM 525011878SVenu.Iyer@Sun.COM /* 52518275SEric Cheng * Callback funtion for MAC layer to register all rings. 52528275SEric Cheng */ 52538275SEric Cheng /* ARGSUSED */ 52548275SEric Cheng void 525511878SVenu.Iyer@Sun.COM ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index, 52568275SEric Cheng const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 52578275SEric Cheng { 52588275SEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg; 52598275SEric Cheng mac_intr_t *mintr = &infop->mri_intr; 52608275SEric Cheng 52618275SEric Cheng switch (rtype) { 52628275SEric Cheng case MAC_RING_TYPE_RX: { 526311878SVenu.Iyer@Sun.COM /* 526411878SVenu.Iyer@Sun.COM * 'index' is the ring index within the group. 526511878SVenu.Iyer@Sun.COM * Need to get the global ring index by searching in groups. 526611878SVenu.Iyer@Sun.COM */ 526711878SVenu.Iyer@Sun.COM int global_ring_index = ixgbe_get_rx_ring_index( 526811878SVenu.Iyer@Sun.COM ixgbe, group_index, ring_index); 526911878SVenu.Iyer@Sun.COM 527011878SVenu.Iyer@Sun.COM ASSERT(global_ring_index >= 0); 527111878SVenu.Iyer@Sun.COM 527211878SVenu.Iyer@Sun.COM ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[global_ring_index]; 52738275SEric Cheng rx_ring->ring_handle = rh; 52748275SEric Cheng 52758275SEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 52768275SEric Cheng infop->mri_start = ixgbe_ring_start; 52778275SEric Cheng infop->mri_stop = NULL; 52788275SEric Cheng infop->mri_poll = ixgbe_ring_rx_poll; 527911878SVenu.Iyer@Sun.COM infop->mri_stat = ixgbe_rx_ring_stat; 52808275SEric Cheng 52818275SEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring; 52828275SEric Cheng mintr->mi_enable = ixgbe_rx_ring_intr_enable; 52838275SEric Cheng mintr->mi_disable = ixgbe_rx_ring_intr_disable; 528411878SVenu.Iyer@Sun.COM if (ixgbe->intr_type & 528511878SVenu.Iyer@Sun.COM (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) { 528611878SVenu.Iyer@Sun.COM mintr->mi_ddi_handle = 528711878SVenu.Iyer@Sun.COM ixgbe->htable[rx_ring->intr_vector]; 528811878SVenu.Iyer@Sun.COM } 52898275SEric Cheng 52908275SEric Cheng break; 52918275SEric Cheng } 52928275SEric Cheng case MAC_RING_TYPE_TX: { 529311878SVenu.Iyer@Sun.COM ASSERT(group_index == -1); 52948275SEric Cheng ASSERT(ring_index < ixgbe->num_tx_rings); 52958275SEric Cheng 52968275SEric Cheng ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index]; 52978275SEric Cheng tx_ring->ring_handle = rh; 52988275SEric Cheng 52998275SEric Cheng infop->mri_driver = (mac_ring_driver_t)tx_ring; 53008275SEric Cheng infop->mri_start = NULL; 53018275SEric Cheng infop->mri_stop = NULL; 53028275SEric Cheng infop->mri_tx = ixgbe_ring_tx; 530311878SVenu.Iyer@Sun.COM infop->mri_stat = ixgbe_tx_ring_stat; 530411878SVenu.Iyer@Sun.COM if (ixgbe->intr_type & 530511878SVenu.Iyer@Sun.COM (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) { 530611878SVenu.Iyer@Sun.COM mintr->mi_ddi_handle = 530711878SVenu.Iyer@Sun.COM ixgbe->htable[tx_ring->intr_vector]; 530811878SVenu.Iyer@Sun.COM } 53098275SEric Cheng break; 53108275SEric Cheng } 53118275SEric Cheng default: 53128275SEric Cheng break; 53138275SEric Cheng } 53148275SEric Cheng } 53158275SEric Cheng 53168275SEric Cheng /* 53178275SEric Cheng * Callback funtion for MAC layer to register all groups. 53188275SEric Cheng */ 53198275SEric Cheng void 53208275SEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index, 53218275SEric Cheng mac_group_info_t *infop, mac_group_handle_t gh) 53228275SEric Cheng { 53238275SEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg; 53248275SEric Cheng 53258275SEric Cheng switch (rtype) { 53268275SEric Cheng case MAC_RING_TYPE_RX: { 53278275SEric Cheng ixgbe_rx_group_t *rx_group; 53288275SEric Cheng 53298275SEric Cheng rx_group = &ixgbe->rx_groups[index]; 53308275SEric Cheng rx_group->group_handle = gh; 53318275SEric Cheng 53328275SEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_group; 53338275SEric Cheng infop->mgi_start = NULL; 53348275SEric Cheng infop->mgi_stop = NULL; 53358275SEric Cheng infop->mgi_addmac = ixgbe_addmac; 53368275SEric Cheng infop->mgi_remmac = ixgbe_remmac; 53378275SEric Cheng infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups); 53388275SEric Cheng 53398275SEric Cheng break; 53408275SEric Cheng } 53418275SEric Cheng case MAC_RING_TYPE_TX: 53428275SEric Cheng break; 53438275SEric Cheng default: 53448275SEric Cheng break; 53458275SEric Cheng } 53468275SEric Cheng } 53478275SEric Cheng 53488275SEric Cheng /* 53498275SEric Cheng * Enable interrupt on the specificed rx ring. 53508275SEric Cheng */ 53518275SEric Cheng int 53528275SEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh) 53538275SEric Cheng { 53548275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh; 53558275SEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe; 53568275SEric Cheng int r_idx = rx_ring->index; 535711878SVenu.Iyer@Sun.COM int hw_r_idx = rx_ring->hw_index; 53588275SEric Cheng int v_idx = rx_ring->intr_vector; 53598275SEric Cheng 53608275SEric Cheng mutex_enter(&ixgbe->gen_lock); 536111878SVenu.Iyer@Sun.COM if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) { 536211878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 536311878SVenu.Iyer@Sun.COM /* 536411878SVenu.Iyer@Sun.COM * Simply return 0. 536511878SVenu.Iyer@Sun.COM * Interrupts are being adjusted. ixgbe_intr_adjust() 536611878SVenu.Iyer@Sun.COM * will eventually re-enable the interrupt when it's 536711878SVenu.Iyer@Sun.COM * done with the adjustment. 536811878SVenu.Iyer@Sun.COM */ 536911878SVenu.Iyer@Sun.COM return (0); 537011878SVenu.Iyer@Sun.COM } 53718275SEric Cheng 53728275SEric Cheng /* 53738275SEric Cheng * To enable interrupt by setting the VAL bit of given interrupt 53748275SEric Cheng * vector allocation register (IVAR). 53758275SEric Cheng */ 537611878SVenu.Iyer@Sun.COM ixgbe_enable_ivar(ixgbe, hw_r_idx, 0); 53778275SEric Cheng 53788275SEric Cheng BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx); 537910305SPaul.Guo@Sun.COM 538010305SPaul.Guo@Sun.COM /* 538112003SPaul.Guo@Sun.COM * Trigger a Rx interrupt on this ring 538210305SPaul.Guo@Sun.COM */ 538310305SPaul.Guo@Sun.COM IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx)); 538410305SPaul.Guo@Sun.COM IXGBE_WRITE_FLUSH(&ixgbe->hw); 538510305SPaul.Guo@Sun.COM 53868275SEric Cheng mutex_exit(&ixgbe->gen_lock); 53878275SEric Cheng 53888275SEric Cheng return (0); 53898275SEric Cheng } 53908275SEric Cheng 53918275SEric Cheng /* 53928275SEric Cheng * Disable interrupt on the specificed rx ring. 53938275SEric Cheng */ 53948275SEric Cheng int 53958275SEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh) 53968275SEric Cheng { 53978275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh; 53988275SEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe; 53998275SEric Cheng int r_idx = rx_ring->index; 540011878SVenu.Iyer@Sun.COM int hw_r_idx = rx_ring->hw_index; 54018275SEric Cheng int v_idx = rx_ring->intr_vector; 54028275SEric Cheng 54038275SEric Cheng mutex_enter(&ixgbe->gen_lock); 540411878SVenu.Iyer@Sun.COM if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) { 540511878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 540611878SVenu.Iyer@Sun.COM /* 540711878SVenu.Iyer@Sun.COM * Simply return 0. 540811878SVenu.Iyer@Sun.COM * In the rare case where an interrupt is being 540911878SVenu.Iyer@Sun.COM * disabled while interrupts are being adjusted, 541011878SVenu.Iyer@Sun.COM * we don't fail the operation. No interrupts will 541111878SVenu.Iyer@Sun.COM * be generated while they are adjusted, and 541211878SVenu.Iyer@Sun.COM * ixgbe_intr_adjust() will cause the interrupts 541311878SVenu.Iyer@Sun.COM * to be re-enabled once it completes. Note that 541411878SVenu.Iyer@Sun.COM * in this case, packets may be delivered to the 541511878SVenu.Iyer@Sun.COM * stack via interrupts before xgbe_rx_ring_intr_enable() 541611878SVenu.Iyer@Sun.COM * is called again. This is acceptable since interrupt 541711878SVenu.Iyer@Sun.COM * adjustment is infrequent, and the stack will be 541811878SVenu.Iyer@Sun.COM * able to handle these packets. 541911878SVenu.Iyer@Sun.COM */ 542011878SVenu.Iyer@Sun.COM return (0); 542111878SVenu.Iyer@Sun.COM } 54228275SEric Cheng 54238275SEric Cheng /* 54248275SEric Cheng * To disable interrupt by clearing the VAL bit of given interrupt 54258275SEric Cheng * vector allocation register (IVAR). 54268275SEric Cheng */ 542711878SVenu.Iyer@Sun.COM ixgbe_disable_ivar(ixgbe, hw_r_idx, 0); 54288275SEric Cheng 54298275SEric Cheng BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx); 54308275SEric Cheng 54318275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54328275SEric Cheng 54338275SEric Cheng return (0); 54348275SEric Cheng } 54358275SEric Cheng 54368275SEric Cheng /* 54378275SEric Cheng * Add a mac address. 54388275SEric Cheng */ 54398275SEric Cheng static int 54408275SEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr) 54418275SEric Cheng { 54428275SEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg; 54438275SEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe; 544411878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 544511878SVenu.Iyer@Sun.COM int slot, i; 54468275SEric Cheng 54478275SEric Cheng mutex_enter(&ixgbe->gen_lock); 54488275SEric Cheng 54498275SEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 54508275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54518275SEric Cheng return (ECANCELED); 54528275SEric Cheng } 54538275SEric Cheng 54548275SEric Cheng if (ixgbe->unicst_avail == 0) { 54558275SEric Cheng /* no slots available */ 54568275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54578275SEric Cheng return (ENOSPC); 54588275SEric Cheng } 54598275SEric Cheng 546011878SVenu.Iyer@Sun.COM /* 546111878SVenu.Iyer@Sun.COM * The first ixgbe->num_rx_groups slots are reserved for each respective 546211878SVenu.Iyer@Sun.COM * group. The rest slots are shared by all groups. While adding a 546311878SVenu.Iyer@Sun.COM * MAC address, reserved slots are firstly checked then the shared 546411878SVenu.Iyer@Sun.COM * slots are searched. 546511878SVenu.Iyer@Sun.COM */ 546611878SVenu.Iyer@Sun.COM slot = -1; 546711878SVenu.Iyer@Sun.COM if (ixgbe->unicst_addr[rx_group->index].mac.set == 1) { 546811878SVenu.Iyer@Sun.COM for (i = ixgbe->num_rx_groups; i < ixgbe->unicst_total; i++) { 546911878SVenu.Iyer@Sun.COM if (ixgbe->unicst_addr[i].mac.set == 0) { 547011878SVenu.Iyer@Sun.COM slot = i; 547111878SVenu.Iyer@Sun.COM break; 547211878SVenu.Iyer@Sun.COM } 547311878SVenu.Iyer@Sun.COM } 547411878SVenu.Iyer@Sun.COM } else { 547511878SVenu.Iyer@Sun.COM slot = rx_group->index; 547611878SVenu.Iyer@Sun.COM } 547711878SVenu.Iyer@Sun.COM 547811878SVenu.Iyer@Sun.COM if (slot == -1) { 547911878SVenu.Iyer@Sun.COM /* no slots available */ 548011878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 548111878SVenu.Iyer@Sun.COM return (ENOSPC); 548211878SVenu.Iyer@Sun.COM } 548311878SVenu.Iyer@Sun.COM 548411878SVenu.Iyer@Sun.COM bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL); 548511878SVenu.Iyer@Sun.COM (void) ixgbe_set_rar(hw, slot, ixgbe->unicst_addr[slot].mac.addr, 548611878SVenu.Iyer@Sun.COM rx_group->index, IXGBE_RAH_AV); 548711878SVenu.Iyer@Sun.COM ixgbe->unicst_addr[slot].mac.set = 1; 548811878SVenu.Iyer@Sun.COM ixgbe->unicst_addr[slot].mac.group_index = rx_group->index; 548911878SVenu.Iyer@Sun.COM ixgbe->unicst_avail--; 54908275SEric Cheng 54918275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54928275SEric Cheng 549311878SVenu.Iyer@Sun.COM return (0); 54948275SEric Cheng } 54958275SEric Cheng 54968275SEric Cheng /* 54978275SEric Cheng * Remove a mac address. 54988275SEric Cheng */ 54998275SEric Cheng static int 55008275SEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr) 55018275SEric Cheng { 55028275SEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg; 55038275SEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe; 550411878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 55058275SEric Cheng int slot; 55068275SEric Cheng 55078275SEric Cheng mutex_enter(&ixgbe->gen_lock); 55088275SEric Cheng 55098275SEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 55108275SEric Cheng mutex_exit(&ixgbe->gen_lock); 55118275SEric Cheng return (ECANCELED); 55128275SEric Cheng } 55138275SEric Cheng 55148275SEric Cheng slot = ixgbe_unicst_find(ixgbe, mac_addr); 55158275SEric Cheng if (slot == -1) { 55168275SEric Cheng mutex_exit(&ixgbe->gen_lock); 55178275SEric Cheng return (EINVAL); 55188275SEric Cheng } 55198275SEric Cheng 55208275SEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 0) { 55218275SEric Cheng mutex_exit(&ixgbe->gen_lock); 55228275SEric Cheng return (EINVAL); 55238275SEric Cheng } 55248275SEric Cheng 55258275SEric Cheng bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL); 552611878SVenu.Iyer@Sun.COM (void) ixgbe_clear_rar(hw, slot); 552711878SVenu.Iyer@Sun.COM ixgbe->unicst_addr[slot].mac.set = 0; 552811878SVenu.Iyer@Sun.COM ixgbe->unicst_avail++; 55298275SEric Cheng 55308275SEric Cheng mutex_exit(&ixgbe->gen_lock); 55318275SEric Cheng 553211878SVenu.Iyer@Sun.COM return (0); 55338275SEric Cheng } 5534