16621Sbt150084 /* 26621Sbt150084 * CDDL HEADER START 36621Sbt150084 * 49353SSamuel.Tu@Sun.COM * Copyright(c) 2007-2009 Intel Corporation. All rights reserved. 56621Sbt150084 * The contents of this file are subject to the terms of the 66621Sbt150084 * Common Development and Distribution License (the "License"). 76621Sbt150084 * You may not use this file except in compliance with the License. 86621Sbt150084 * 97656SSherry.Moore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107656SSherry.Moore@Sun.COM * or http://www.opensolaris.org/os/licensing. 116621Sbt150084 * See the License for the specific language governing permissions 126621Sbt150084 * and limitations under the License. 136621Sbt150084 * 147656SSherry.Moore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 157656SSherry.Moore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 166621Sbt150084 * If applicable, add the following below this CDDL HEADER, with the 176621Sbt150084 * fields enclosed by brackets "[]" replaced with your own identifying 186621Sbt150084 * information: Portions Copyright [yyyy] [name of copyright owner] 196621Sbt150084 * 206621Sbt150084 * CDDL HEADER END 216621Sbt150084 */ 226621Sbt150084 236621Sbt150084 /* 2411486SZhen.W@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 257656SSherry.Moore@Sun.COM * Use is subject to license terms. 267656SSherry.Moore@Sun.COM */ 277656SSherry.Moore@Sun.COM 286621Sbt150084 #include "ixgbe_sw.h" 296621Sbt150084 3011486SZhen.W@Sun.COM static char ixgbe_ident[] = "Intel 10Gb Ethernet"; 3111878SVenu.Iyer@Sun.COM static char ixgbe_version[] = "ixgbe 1.1.4"; 326621Sbt150084 336621Sbt150084 /* 346621Sbt150084 * Local function protoypes 356621Sbt150084 */ 366621Sbt150084 static int ixgbe_register_mac(ixgbe_t *); 376621Sbt150084 static int ixgbe_identify_hardware(ixgbe_t *); 386621Sbt150084 static int ixgbe_regs_map(ixgbe_t *); 396621Sbt150084 static void ixgbe_init_properties(ixgbe_t *); 406621Sbt150084 static int ixgbe_init_driver_settings(ixgbe_t *); 416621Sbt150084 static void ixgbe_init_locks(ixgbe_t *); 426621Sbt150084 static void ixgbe_destroy_locks(ixgbe_t *); 436621Sbt150084 static int ixgbe_init(ixgbe_t *); 446621Sbt150084 static int ixgbe_chip_start(ixgbe_t *); 456621Sbt150084 static void ixgbe_chip_stop(ixgbe_t *); 466621Sbt150084 static int ixgbe_reset(ixgbe_t *); 476621Sbt150084 static void ixgbe_tx_clean(ixgbe_t *); 486621Sbt150084 static boolean_t ixgbe_tx_drain(ixgbe_t *); 496621Sbt150084 static boolean_t ixgbe_rx_drain(ixgbe_t *); 506621Sbt150084 static int ixgbe_alloc_rings(ixgbe_t *); 516621Sbt150084 static void ixgbe_free_rings(ixgbe_t *); 5210376SChenlu.Chen@Sun.COM static int ixgbe_alloc_rx_data(ixgbe_t *); 5310376SChenlu.Chen@Sun.COM static void ixgbe_free_rx_data(ixgbe_t *); 546621Sbt150084 static void ixgbe_setup_rings(ixgbe_t *); 556621Sbt150084 static void ixgbe_setup_rx(ixgbe_t *); 566621Sbt150084 static void ixgbe_setup_tx(ixgbe_t *); 576621Sbt150084 static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *); 586621Sbt150084 static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *); 596621Sbt150084 static void ixgbe_setup_rss(ixgbe_t *); 6011878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq(ixgbe_t *); 6111878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq_rss(ixgbe_t *); 626621Sbt150084 static void ixgbe_init_unicst(ixgbe_t *); 638275SEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *); 646621Sbt150084 static void ixgbe_setup_multicst(ixgbe_t *); 656621Sbt150084 static void ixgbe_get_hw_state(ixgbe_t *); 6611878SVenu.Iyer@Sun.COM static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe); 676621Sbt150084 static void ixgbe_get_conf(ixgbe_t *); 6810376SChenlu.Chen@Sun.COM static void ixgbe_init_params(ixgbe_t *); 696621Sbt150084 static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int); 7011233SPaul.Guo@Sun.COM static void ixgbe_driver_link_check(ixgbe_t *); 719353SSamuel.Tu@Sun.COM static void ixgbe_sfp_check(void *); 7211233SPaul.Guo@Sun.COM static void ixgbe_link_timer(void *); 736621Sbt150084 static void ixgbe_local_timer(void *); 746621Sbt150084 static void ixgbe_arm_watchdog_timer(ixgbe_t *); 756621Sbt150084 static void ixgbe_restart_watchdog_timer(ixgbe_t *); 766621Sbt150084 static void ixgbe_disable_adapter_interrupts(ixgbe_t *); 776621Sbt150084 static void ixgbe_enable_adapter_interrupts(ixgbe_t *); 786621Sbt150084 static boolean_t is_valid_mac_addr(uint8_t *); 796621Sbt150084 static boolean_t ixgbe_stall_check(ixgbe_t *); 806621Sbt150084 static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t); 816621Sbt150084 static void ixgbe_set_internal_mac_loopback(ixgbe_t *); 826621Sbt150084 static boolean_t ixgbe_find_mac_address(ixgbe_t *); 836621Sbt150084 static int ixgbe_alloc_intrs(ixgbe_t *); 846621Sbt150084 static int ixgbe_alloc_intr_handles(ixgbe_t *, int); 856621Sbt150084 static int ixgbe_add_intr_handlers(ixgbe_t *); 866621Sbt150084 static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int); 876621Sbt150084 static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int); 889353SSamuel.Tu@Sun.COM static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t); 899353SSamuel.Tu@Sun.COM static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t); 909353SSamuel.Tu@Sun.COM static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t); 9111878SVenu.Iyer@Sun.COM static uint32_t ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index); 929353SSamuel.Tu@Sun.COM static int ixgbe_map_intrs_to_vectors(ixgbe_t *); 936621Sbt150084 static void ixgbe_setup_adapter_vector(ixgbe_t *); 946621Sbt150084 static void ixgbe_rem_intr_handlers(ixgbe_t *); 956621Sbt150084 static void ixgbe_rem_intrs(ixgbe_t *); 966621Sbt150084 static int ixgbe_enable_intrs(ixgbe_t *); 976621Sbt150084 static int ixgbe_disable_intrs(ixgbe_t *); 986621Sbt150084 static uint_t ixgbe_intr_legacy(void *, void *); 996621Sbt150084 static uint_t ixgbe_intr_msi(void *, void *); 1009353SSamuel.Tu@Sun.COM static uint_t ixgbe_intr_msix(void *, void *); 1016621Sbt150084 static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *); 1026621Sbt150084 static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *); 1038490SPaul.Guo@Sun.COM static void ixgbe_intr_other_work(ixgbe_t *, uint32_t); 1046621Sbt150084 static void ixgbe_get_driver_control(struct ixgbe_hw *); 1058275SEric Cheng static int ixgbe_addmac(void *, const uint8_t *); 1068275SEric Cheng static int ixgbe_remmac(void *, const uint8_t *); 1076621Sbt150084 static void ixgbe_release_driver_control(struct ixgbe_hw *); 1086621Sbt150084 1096621Sbt150084 static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t); 1106621Sbt150084 static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t); 1116621Sbt150084 static int ixgbe_resume(dev_info_t *); 1126621Sbt150084 static int ixgbe_suspend(dev_info_t *); 1136621Sbt150084 static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *); 1146621Sbt150084 static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *); 11511878SVenu.Iyer@Sun.COM static int ixgbe_cbfunc(dev_info_t *, ddi_cb_action_t, void *, void *, void *); 11611878SVenu.Iyer@Sun.COM static int ixgbe_intr_cb_register(ixgbe_t *); 11711878SVenu.Iyer@Sun.COM static int ixgbe_intr_adjust(ixgbe_t *, ddi_cb_action_t, int); 1186621Sbt150084 1196621Sbt150084 static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, 1206621Sbt150084 const void *impl_data); 1216621Sbt150084 static void ixgbe_fm_init(ixgbe_t *); 1226621Sbt150084 static void ixgbe_fm_fini(ixgbe_t *); 1236621Sbt150084 12411878SVenu.Iyer@Sun.COM char *ixgbe_priv_props[] = { 12511878SVenu.Iyer@Sun.COM "_tx_copy_thresh", 12611878SVenu.Iyer@Sun.COM "_tx_recycle_thresh", 12711878SVenu.Iyer@Sun.COM "_tx_overload_thresh", 12811878SVenu.Iyer@Sun.COM "_tx_resched_thresh", 12911878SVenu.Iyer@Sun.COM "_rx_copy_thresh", 13011878SVenu.Iyer@Sun.COM "_rx_limit_per_intr", 13111878SVenu.Iyer@Sun.COM "_intr_throttling", 13211878SVenu.Iyer@Sun.COM "_adv_pause_cap", 13311878SVenu.Iyer@Sun.COM "_adv_asym_pause_cap", 13411878SVenu.Iyer@Sun.COM NULL 13510376SChenlu.Chen@Sun.COM }; 13610376SChenlu.Chen@Sun.COM 13710376SChenlu.Chen@Sun.COM #define IXGBE_MAX_PRIV_PROPS \ 13810376SChenlu.Chen@Sun.COM (sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t)) 13910376SChenlu.Chen@Sun.COM 1406621Sbt150084 static struct cb_ops ixgbe_cb_ops = { 1416621Sbt150084 nulldev, /* cb_open */ 1426621Sbt150084 nulldev, /* cb_close */ 1436621Sbt150084 nodev, /* cb_strategy */ 1446621Sbt150084 nodev, /* cb_print */ 1456621Sbt150084 nodev, /* cb_dump */ 1466621Sbt150084 nodev, /* cb_read */ 1476621Sbt150084 nodev, /* cb_write */ 1486621Sbt150084 nodev, /* cb_ioctl */ 1496621Sbt150084 nodev, /* cb_devmap */ 1506621Sbt150084 nodev, /* cb_mmap */ 1516621Sbt150084 nodev, /* cb_segmap */ 1526621Sbt150084 nochpoll, /* cb_chpoll */ 1536621Sbt150084 ddi_prop_op, /* cb_prop_op */ 1546621Sbt150084 NULL, /* cb_stream */ 1556621Sbt150084 D_MP | D_HOTPLUG, /* cb_flag */ 1566621Sbt150084 CB_REV, /* cb_rev */ 1576621Sbt150084 nodev, /* cb_aread */ 1586621Sbt150084 nodev /* cb_awrite */ 1596621Sbt150084 }; 1606621Sbt150084 1616621Sbt150084 static struct dev_ops ixgbe_dev_ops = { 1626621Sbt150084 DEVO_REV, /* devo_rev */ 1636621Sbt150084 0, /* devo_refcnt */ 1646621Sbt150084 NULL, /* devo_getinfo */ 1656621Sbt150084 nulldev, /* devo_identify */ 1666621Sbt150084 nulldev, /* devo_probe */ 1676621Sbt150084 ixgbe_attach, /* devo_attach */ 1686621Sbt150084 ixgbe_detach, /* devo_detach */ 1696621Sbt150084 nodev, /* devo_reset */ 1706621Sbt150084 &ixgbe_cb_ops, /* devo_cb_ops */ 1716621Sbt150084 NULL, /* devo_bus_ops */ 1727656SSherry.Moore@Sun.COM ddi_power, /* devo_power */ 1737656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 1746621Sbt150084 }; 1756621Sbt150084 1766621Sbt150084 static struct modldrv ixgbe_modldrv = { 1776621Sbt150084 &mod_driverops, /* Type of module. This one is a driver */ 17811486SZhen.W@Sun.COM ixgbe_ident, /* Discription string */ 1796621Sbt150084 &ixgbe_dev_ops /* driver ops */ 1806621Sbt150084 }; 1816621Sbt150084 1826621Sbt150084 static struct modlinkage ixgbe_modlinkage = { 1836621Sbt150084 MODREV_1, &ixgbe_modldrv, NULL 1846621Sbt150084 }; 1856621Sbt150084 1866621Sbt150084 /* 1876621Sbt150084 * Access attributes for register mapping 1886621Sbt150084 */ 1896621Sbt150084 ddi_device_acc_attr_t ixgbe_regs_acc_attr = { 19011236SStephen.Hanson@Sun.COM DDI_DEVICE_ATTR_V1, 1916621Sbt150084 DDI_STRUCTURE_LE_ACC, 1926621Sbt150084 DDI_STRICTORDER_ACC, 1936621Sbt150084 DDI_FLAGERR_ACC 1946621Sbt150084 }; 1956621Sbt150084 1966621Sbt150084 /* 1976621Sbt150084 * Loopback property 1986621Sbt150084 */ 1996621Sbt150084 static lb_property_t lb_normal = { 2006621Sbt150084 normal, "normal", IXGBE_LB_NONE 2016621Sbt150084 }; 2026621Sbt150084 2036621Sbt150084 static lb_property_t lb_mac = { 2046621Sbt150084 internal, "MAC", IXGBE_LB_INTERNAL_MAC 2056621Sbt150084 }; 2066621Sbt150084 20711150SZhen.W@Sun.COM static lb_property_t lb_external = { 20811150SZhen.W@Sun.COM external, "External", IXGBE_LB_EXTERNAL 20911150SZhen.W@Sun.COM }; 21011150SZhen.W@Sun.COM 21110376SChenlu.Chen@Sun.COM #define IXGBE_M_CALLBACK_FLAGS \ 21211878SVenu.Iyer@Sun.COM (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 2136621Sbt150084 2146621Sbt150084 static mac_callbacks_t ixgbe_m_callbacks = { 2156621Sbt150084 IXGBE_M_CALLBACK_FLAGS, 2166621Sbt150084 ixgbe_m_stat, 2176621Sbt150084 ixgbe_m_start, 2186621Sbt150084 ixgbe_m_stop, 2196621Sbt150084 ixgbe_m_promisc, 2206621Sbt150084 ixgbe_m_multicst, 2218275SEric Cheng NULL, 2226621Sbt150084 NULL, 22311878SVenu.Iyer@Sun.COM NULL, 2246621Sbt150084 ixgbe_m_ioctl, 22510376SChenlu.Chen@Sun.COM ixgbe_m_getcapab, 22610376SChenlu.Chen@Sun.COM NULL, 22710376SChenlu.Chen@Sun.COM NULL, 22810376SChenlu.Chen@Sun.COM ixgbe_m_setprop, 22911878SVenu.Iyer@Sun.COM ixgbe_m_getprop, 23011878SVenu.Iyer@Sun.COM ixgbe_m_propinfo 2316621Sbt150084 }; 2326621Sbt150084 2336621Sbt150084 /* 2348490SPaul.Guo@Sun.COM * Initialize capabilities of each supported adapter type 2358490SPaul.Guo@Sun.COM */ 2368490SPaul.Guo@Sun.COM static adapter_info_t ixgbe_82598eb_cap = { 2378490SPaul.Guo@Sun.COM 64, /* maximum number of rx queues */ 2388490SPaul.Guo@Sun.COM 1, /* minimum number of rx queues */ 23911878SVenu.Iyer@Sun.COM 64, /* default number of rx queues */ 24011878SVenu.Iyer@Sun.COM 16, /* maximum number of rx groups */ 24111878SVenu.Iyer@Sun.COM 1, /* minimum number of rx groups */ 24211878SVenu.Iyer@Sun.COM 1, /* default number of rx groups */ 2438490SPaul.Guo@Sun.COM 32, /* maximum number of tx queues */ 2448490SPaul.Guo@Sun.COM 1, /* minimum number of tx queues */ 2458490SPaul.Guo@Sun.COM 8, /* default number of tx queues */ 24611150SZhen.W@Sun.COM 16366, /* maximum MTU size */ 24710376SChenlu.Chen@Sun.COM 0xFFFF, /* maximum interrupt throttle rate */ 24810376SChenlu.Chen@Sun.COM 0, /* minimum interrupt throttle rate */ 24910376SChenlu.Chen@Sun.COM 200, /* default interrupt throttle rate */ 2508490SPaul.Guo@Sun.COM 18, /* maximum total msix vectors */ 2518490SPaul.Guo@Sun.COM 16, /* maximum number of ring vectors */ 2528490SPaul.Guo@Sun.COM 2, /* maximum number of other vectors */ 2538490SPaul.Guo@Sun.COM IXGBE_EICR_LSC, /* "other" interrupt types handled */ 2548490SPaul.Guo@Sun.COM (IXGBE_FLAG_DCA_CAPABLE /* capability flags */ 2558490SPaul.Guo@Sun.COM | IXGBE_FLAG_RSS_CAPABLE 2568490SPaul.Guo@Sun.COM | IXGBE_FLAG_VMDQ_CAPABLE) 2578490SPaul.Guo@Sun.COM }; 2588490SPaul.Guo@Sun.COM 2599353SSamuel.Tu@Sun.COM static adapter_info_t ixgbe_82599eb_cap = { 2609353SSamuel.Tu@Sun.COM 128, /* maximum number of rx queues */ 2619353SSamuel.Tu@Sun.COM 1, /* minimum number of rx queues */ 26211878SVenu.Iyer@Sun.COM 128, /* default number of rx queues */ 26311878SVenu.Iyer@Sun.COM 64, /* maximum number of rx groups */ 26411878SVenu.Iyer@Sun.COM 1, /* minimum number of rx groups */ 26511878SVenu.Iyer@Sun.COM 1, /* default number of rx groups */ 2669353SSamuel.Tu@Sun.COM 128, /* maximum number of tx queues */ 2679353SSamuel.Tu@Sun.COM 1, /* minimum number of tx queues */ 2689353SSamuel.Tu@Sun.COM 8, /* default number of tx queues */ 26911150SZhen.W@Sun.COM 15500, /* maximum MTU size */ 27010376SChenlu.Chen@Sun.COM 0xFF8, /* maximum interrupt throttle rate */ 27110376SChenlu.Chen@Sun.COM 0, /* minimum interrupt throttle rate */ 27210376SChenlu.Chen@Sun.COM 200, /* default interrupt throttle rate */ 2739353SSamuel.Tu@Sun.COM 64, /* maximum total msix vectors */ 2749353SSamuel.Tu@Sun.COM 16, /* maximum number of ring vectors */ 2759353SSamuel.Tu@Sun.COM 2, /* maximum number of other vectors */ 2769353SSamuel.Tu@Sun.COM IXGBE_EICR_LSC, /* "other" interrupt types handled */ 2779353SSamuel.Tu@Sun.COM (IXGBE_FLAG_DCA_CAPABLE /* capability flags */ 2789353SSamuel.Tu@Sun.COM | IXGBE_FLAG_RSS_CAPABLE 27911486SZhen.W@Sun.COM | IXGBE_FLAG_VMDQ_CAPABLE 28011486SZhen.W@Sun.COM | IXGBE_FLAG_RSC_CAPABLE) 2819353SSamuel.Tu@Sun.COM }; 2829353SSamuel.Tu@Sun.COM 2838490SPaul.Guo@Sun.COM /* 2846621Sbt150084 * Module Initialization Functions. 2856621Sbt150084 */ 2866621Sbt150084 2876621Sbt150084 int 2886621Sbt150084 _init(void) 2896621Sbt150084 { 2906621Sbt150084 int status; 2916621Sbt150084 2926621Sbt150084 mac_init_ops(&ixgbe_dev_ops, MODULE_NAME); 2936621Sbt150084 2946621Sbt150084 status = mod_install(&ixgbe_modlinkage); 2956621Sbt150084 2966621Sbt150084 if (status != DDI_SUCCESS) { 2976621Sbt150084 mac_fini_ops(&ixgbe_dev_ops); 2986621Sbt150084 } 2996621Sbt150084 3006621Sbt150084 return (status); 3016621Sbt150084 } 3026621Sbt150084 3036621Sbt150084 int 3046621Sbt150084 _fini(void) 3056621Sbt150084 { 3066621Sbt150084 int status; 3076621Sbt150084 3086621Sbt150084 status = mod_remove(&ixgbe_modlinkage); 3096621Sbt150084 3106621Sbt150084 if (status == DDI_SUCCESS) { 3116621Sbt150084 mac_fini_ops(&ixgbe_dev_ops); 3126621Sbt150084 } 3136621Sbt150084 3146621Sbt150084 return (status); 3156621Sbt150084 } 3166621Sbt150084 3176621Sbt150084 int 3186621Sbt150084 _info(struct modinfo *modinfop) 3196621Sbt150084 { 3206621Sbt150084 int status; 3216621Sbt150084 3226621Sbt150084 status = mod_info(&ixgbe_modlinkage, modinfop); 3236621Sbt150084 3246621Sbt150084 return (status); 3256621Sbt150084 } 3266621Sbt150084 3276621Sbt150084 /* 3286621Sbt150084 * ixgbe_attach - Driver attach. 3296621Sbt150084 * 3306621Sbt150084 * This function is the device specific initialization entry 3316621Sbt150084 * point. This entry point is required and must be written. 3326621Sbt150084 * The DDI_ATTACH command must be provided in the attach entry 3336621Sbt150084 * point. When attach() is called with cmd set to DDI_ATTACH, 3346621Sbt150084 * all normal kernel services (such as kmem_alloc(9F)) are 3356621Sbt150084 * available for use by the driver. 3366621Sbt150084 * 3376621Sbt150084 * The attach() function will be called once for each instance 3386621Sbt150084 * of the device on the system with cmd set to DDI_ATTACH. 3396621Sbt150084 * Until attach() succeeds, the only driver entry points which 3406621Sbt150084 * may be called are open(9E) and getinfo(9E). 3416621Sbt150084 */ 3426621Sbt150084 static int 3436621Sbt150084 ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 3446621Sbt150084 { 3456621Sbt150084 ixgbe_t *ixgbe; 3466621Sbt150084 struct ixgbe_osdep *osdep; 3476621Sbt150084 struct ixgbe_hw *hw; 3486621Sbt150084 int instance; 3498490SPaul.Guo@Sun.COM char taskqname[32]; 3506621Sbt150084 3516621Sbt150084 /* 3526621Sbt150084 * Check the command and perform corresponding operations 3536621Sbt150084 */ 3546621Sbt150084 switch (cmd) { 3556621Sbt150084 default: 3566621Sbt150084 return (DDI_FAILURE); 3576621Sbt150084 3586621Sbt150084 case DDI_RESUME: 3596621Sbt150084 return (ixgbe_resume(devinfo)); 3606621Sbt150084 3616621Sbt150084 case DDI_ATTACH: 3626621Sbt150084 break; 3636621Sbt150084 } 3646621Sbt150084 3656621Sbt150084 /* Get the device instance */ 3666621Sbt150084 instance = ddi_get_instance(devinfo); 3676621Sbt150084 3686621Sbt150084 /* Allocate memory for the instance data structure */ 3696621Sbt150084 ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP); 3706621Sbt150084 3716621Sbt150084 ixgbe->dip = devinfo; 3726621Sbt150084 ixgbe->instance = instance; 3736621Sbt150084 3746621Sbt150084 hw = &ixgbe->hw; 3756621Sbt150084 osdep = &ixgbe->osdep; 3766621Sbt150084 hw->back = osdep; 3776621Sbt150084 osdep->ixgbe = ixgbe; 3786621Sbt150084 3796621Sbt150084 /* Attach the instance pointer to the dev_info data structure */ 3806621Sbt150084 ddi_set_driver_private(devinfo, ixgbe); 3816621Sbt150084 3826621Sbt150084 /* 3836621Sbt150084 * Initialize for fma support 3846621Sbt150084 */ 3857167Sgg161487 ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE, 3866621Sbt150084 0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 3876621Sbt150084 DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 3886621Sbt150084 ixgbe_fm_init(ixgbe); 3896621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT; 3906621Sbt150084 3916621Sbt150084 /* 3926621Sbt150084 * Map PCI config space registers 3936621Sbt150084 */ 3946621Sbt150084 if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) { 3956621Sbt150084 ixgbe_error(ixgbe, "Failed to map PCI configurations"); 3966621Sbt150084 goto attach_fail; 3976621Sbt150084 } 3986621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG; 3996621Sbt150084 4006621Sbt150084 /* 4016621Sbt150084 * Identify the chipset family 4026621Sbt150084 */ 4036621Sbt150084 if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) { 4046621Sbt150084 ixgbe_error(ixgbe, "Failed to identify hardware"); 4056621Sbt150084 goto attach_fail; 4066621Sbt150084 } 4076621Sbt150084 4086621Sbt150084 /* 4096621Sbt150084 * Map device registers 4106621Sbt150084 */ 4116621Sbt150084 if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) { 4126621Sbt150084 ixgbe_error(ixgbe, "Failed to map device registers"); 4136621Sbt150084 goto attach_fail; 4146621Sbt150084 } 4156621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP; 4166621Sbt150084 4176621Sbt150084 /* 4186621Sbt150084 * Initialize driver parameters 4196621Sbt150084 */ 4206621Sbt150084 ixgbe_init_properties(ixgbe); 4216621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS; 4226621Sbt150084 4236621Sbt150084 /* 42411878SVenu.Iyer@Sun.COM * Register interrupt callback 42511878SVenu.Iyer@Sun.COM */ 42611878SVenu.Iyer@Sun.COM if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) { 42711878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, "Failed to register interrupt callback"); 42811878SVenu.Iyer@Sun.COM goto attach_fail; 42911878SVenu.Iyer@Sun.COM } 43011878SVenu.Iyer@Sun.COM 43111878SVenu.Iyer@Sun.COM /* 4326621Sbt150084 * Allocate interrupts 4336621Sbt150084 */ 4346621Sbt150084 if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) { 4356621Sbt150084 ixgbe_error(ixgbe, "Failed to allocate interrupts"); 4366621Sbt150084 goto attach_fail; 4376621Sbt150084 } 4386621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR; 4396621Sbt150084 4406621Sbt150084 /* 4416621Sbt150084 * Allocate rx/tx rings based on the ring numbers. 4426621Sbt150084 * The actual numbers of rx/tx rings are decided by the number of 4436621Sbt150084 * allocated interrupt vectors, so we should allocate the rings after 4446621Sbt150084 * interrupts are allocated. 4456621Sbt150084 */ 4466621Sbt150084 if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) { 4476621Sbt150084 ixgbe_error(ixgbe, "Failed to allocate rx and tx rings"); 4486621Sbt150084 goto attach_fail; 4496621Sbt150084 } 4506621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS; 4516621Sbt150084 4526621Sbt150084 /* 4536621Sbt150084 * Map rings to interrupt vectors 4546621Sbt150084 */ 4559353SSamuel.Tu@Sun.COM if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) { 4569353SSamuel.Tu@Sun.COM ixgbe_error(ixgbe, "Failed to map interrupts to vectors"); 4576621Sbt150084 goto attach_fail; 4586621Sbt150084 } 4596621Sbt150084 4606621Sbt150084 /* 4616621Sbt150084 * Add interrupt handlers 4626621Sbt150084 */ 4636621Sbt150084 if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) { 4646621Sbt150084 ixgbe_error(ixgbe, "Failed to add interrupt handlers"); 4656621Sbt150084 goto attach_fail; 4666621Sbt150084 } 4676621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 4686621Sbt150084 4696621Sbt150084 /* 47011233SPaul.Guo@Sun.COM * Create a taskq for sfp-change 4718490SPaul.Guo@Sun.COM */ 4728490SPaul.Guo@Sun.COM (void) sprintf(taskqname, "ixgbe%d_taskq", instance); 47311233SPaul.Guo@Sun.COM if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname, 4748490SPaul.Guo@Sun.COM 1, TASKQ_DEFAULTPRI, 0)) == NULL) { 4758490SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "taskq_create failed"); 4768490SPaul.Guo@Sun.COM goto attach_fail; 4778490SPaul.Guo@Sun.COM } 47811233SPaul.Guo@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ; 4798490SPaul.Guo@Sun.COM 4808490SPaul.Guo@Sun.COM /* 4816621Sbt150084 * Initialize driver parameters 4826621Sbt150084 */ 4836621Sbt150084 if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) { 4846621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize driver settings"); 4856621Sbt150084 goto attach_fail; 4866621Sbt150084 } 4876621Sbt150084 4886621Sbt150084 /* 4896621Sbt150084 * Initialize mutexes for this device. 4906621Sbt150084 * Do this before enabling the interrupt handler and 4916621Sbt150084 * register the softint to avoid the condition where 4926621Sbt150084 * interrupt handler can try using uninitialized mutex. 4936621Sbt150084 */ 4946621Sbt150084 ixgbe_init_locks(ixgbe); 4956621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS; 4966621Sbt150084 4976621Sbt150084 /* 4986621Sbt150084 * Initialize chipset hardware 4996621Sbt150084 */ 5006621Sbt150084 if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) { 5016621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize adapter"); 5026621Sbt150084 goto attach_fail; 5036621Sbt150084 } 50411233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 50511233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 50611233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 5076621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_INIT; 5086621Sbt150084 5096621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) { 5106621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 5116621Sbt150084 goto attach_fail; 5126621Sbt150084 } 5136621Sbt150084 5146621Sbt150084 /* 5156621Sbt150084 * Initialize statistics 5166621Sbt150084 */ 5176621Sbt150084 if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) { 5186621Sbt150084 ixgbe_error(ixgbe, "Failed to initialize statistics"); 5196621Sbt150084 goto attach_fail; 5206621Sbt150084 } 5216621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_STATS; 5226621Sbt150084 5236621Sbt150084 /* 5246621Sbt150084 * Register the driver to the MAC 5256621Sbt150084 */ 5266621Sbt150084 if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) { 5276621Sbt150084 ixgbe_error(ixgbe, "Failed to register MAC"); 5286621Sbt150084 goto attach_fail; 5296621Sbt150084 } 5308490SPaul.Guo@Sun.COM mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN); 5316621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_MAC; 5326621Sbt150084 53311233SPaul.Guo@Sun.COM ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe, 53411233SPaul.Guo@Sun.COM IXGBE_CYCLIC_PERIOD, DDI_IPL_0); 53511233SPaul.Guo@Sun.COM if (ixgbe->periodic_id == 0) { 53611233SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "Failed to add the link check timer"); 53711233SPaul.Guo@Sun.COM goto attach_fail; 53811233SPaul.Guo@Sun.COM } 53911233SPaul.Guo@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER; 54011233SPaul.Guo@Sun.COM 5416621Sbt150084 /* 5426621Sbt150084 * Now that mutex locks are initialized, and the chip is also 5436621Sbt150084 * initialized, enable interrupts. 5446621Sbt150084 */ 5456621Sbt150084 if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) { 5466621Sbt150084 ixgbe_error(ixgbe, "Failed to enable DDI interrupts"); 5476621Sbt150084 goto attach_fail; 5486621Sbt150084 } 5496621Sbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 5506621Sbt150084 55111486SZhen.W@Sun.COM ixgbe_log(ixgbe, "%s, %s", ixgbe_ident, ixgbe_version); 55211233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED); 5536621Sbt150084 5546621Sbt150084 return (DDI_SUCCESS); 5556621Sbt150084 5566621Sbt150084 attach_fail: 5576621Sbt150084 ixgbe_unconfigure(devinfo, ixgbe); 5586621Sbt150084 return (DDI_FAILURE); 5596621Sbt150084 } 5606621Sbt150084 5616621Sbt150084 /* 5626621Sbt150084 * ixgbe_detach - Driver detach. 5636621Sbt150084 * 5646621Sbt150084 * The detach() function is the complement of the attach routine. 5656621Sbt150084 * If cmd is set to DDI_DETACH, detach() is used to remove the 5666621Sbt150084 * state associated with a given instance of a device node 5676621Sbt150084 * prior to the removal of that instance from the system. 5686621Sbt150084 * 5696621Sbt150084 * The detach() function will be called once for each instance 5706621Sbt150084 * of the device for which there has been a successful attach() 5716621Sbt150084 * once there are no longer any opens on the device. 5726621Sbt150084 * 5736621Sbt150084 * Interrupts routine are disabled, All memory allocated by this 5746621Sbt150084 * driver are freed. 5756621Sbt150084 */ 5766621Sbt150084 static int 5776621Sbt150084 ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 5786621Sbt150084 { 5796621Sbt150084 ixgbe_t *ixgbe; 5806621Sbt150084 5816621Sbt150084 /* 5826621Sbt150084 * Check detach command 5836621Sbt150084 */ 5846621Sbt150084 switch (cmd) { 5856621Sbt150084 default: 5866621Sbt150084 return (DDI_FAILURE); 5876621Sbt150084 5886621Sbt150084 case DDI_SUSPEND: 5896621Sbt150084 return (ixgbe_suspend(devinfo)); 5906621Sbt150084 5916621Sbt150084 case DDI_DETACH: 5926621Sbt150084 break; 5936621Sbt150084 } 5946621Sbt150084 5956621Sbt150084 /* 5966621Sbt150084 * Get the pointer to the driver private data structure 5976621Sbt150084 */ 5986621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 5996621Sbt150084 if (ixgbe == NULL) 6006621Sbt150084 return (DDI_FAILURE); 6016621Sbt150084 6026621Sbt150084 /* 6036621Sbt150084 * If the device is still running, it needs to be stopped first. 6046621Sbt150084 * This check is necessary because under some specific circumstances, 6056621Sbt150084 * the detach routine can be called without stopping the interface 6066621Sbt150084 * first. 6076621Sbt150084 */ 6086621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 60911233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 61011233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 61110376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_TRUE); 6126621Sbt150084 mutex_exit(&ixgbe->gen_lock); 6136621Sbt150084 /* Disable and stop the watchdog timer */ 6146621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe); 61511233SPaul.Guo@Sun.COM } 6166621Sbt150084 6176621Sbt150084 /* 6186621Sbt150084 * Check if there are still rx buffers held by the upper layer. 6196621Sbt150084 * If so, fail the detach. 6206621Sbt150084 */ 6216621Sbt150084 if (!ixgbe_rx_drain(ixgbe)) 6226621Sbt150084 return (DDI_FAILURE); 6236621Sbt150084 6246621Sbt150084 /* 6256621Sbt150084 * Do the remaining unconfigure routines 6266621Sbt150084 */ 6276621Sbt150084 ixgbe_unconfigure(devinfo, ixgbe); 6286621Sbt150084 6296621Sbt150084 return (DDI_SUCCESS); 6306621Sbt150084 } 6316621Sbt150084 6326621Sbt150084 static void 6336621Sbt150084 ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe) 6346621Sbt150084 { 6356621Sbt150084 /* 6366621Sbt150084 * Disable interrupt 6376621Sbt150084 */ 6386621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 6396621Sbt150084 (void) ixgbe_disable_intrs(ixgbe); 6406621Sbt150084 } 6416621Sbt150084 6426621Sbt150084 /* 64311233SPaul.Guo@Sun.COM * remove the link check timer 64411233SPaul.Guo@Sun.COM */ 64511233SPaul.Guo@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) { 64611233SPaul.Guo@Sun.COM if (ixgbe->periodic_id != NULL) { 64711233SPaul.Guo@Sun.COM ddi_periodic_delete(ixgbe->periodic_id); 64811233SPaul.Guo@Sun.COM ixgbe->periodic_id = NULL; 64911233SPaul.Guo@Sun.COM } 65011233SPaul.Guo@Sun.COM } 65111233SPaul.Guo@Sun.COM 65211233SPaul.Guo@Sun.COM /* 6536621Sbt150084 * Unregister MAC 6546621Sbt150084 */ 6556621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) { 6566621Sbt150084 (void) mac_unregister(ixgbe->mac_hdl); 6576621Sbt150084 } 6586621Sbt150084 6596621Sbt150084 /* 6606621Sbt150084 * Free statistics 6616621Sbt150084 */ 6626621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) { 6636621Sbt150084 kstat_delete((kstat_t *)ixgbe->ixgbe_ks); 6646621Sbt150084 } 6656621Sbt150084 6666621Sbt150084 /* 6676621Sbt150084 * Remove interrupt handlers 6686621Sbt150084 */ 6696621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 6706621Sbt150084 ixgbe_rem_intr_handlers(ixgbe); 6716621Sbt150084 } 6726621Sbt150084 6736621Sbt150084 /* 67411233SPaul.Guo@Sun.COM * Remove taskq for sfp-status-change 6758490SPaul.Guo@Sun.COM */ 67611233SPaul.Guo@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) { 67711233SPaul.Guo@Sun.COM ddi_taskq_destroy(ixgbe->sfp_taskq); 6788490SPaul.Guo@Sun.COM } 6798490SPaul.Guo@Sun.COM 6808490SPaul.Guo@Sun.COM /* 6816621Sbt150084 * Remove interrupts 6826621Sbt150084 */ 6836621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) { 6846621Sbt150084 ixgbe_rem_intrs(ixgbe); 6856621Sbt150084 } 6866621Sbt150084 6876621Sbt150084 /* 68811878SVenu.Iyer@Sun.COM * Unregister interrupt callback handler 68911878SVenu.Iyer@Sun.COM */ 69011878SVenu.Iyer@Sun.COM (void) ddi_cb_unregister(ixgbe->cb_hdl); 69111878SVenu.Iyer@Sun.COM 69211878SVenu.Iyer@Sun.COM /* 6936621Sbt150084 * Remove driver properties 6946621Sbt150084 */ 6956621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) { 6966621Sbt150084 (void) ddi_prop_remove_all(devinfo); 6976621Sbt150084 } 6986621Sbt150084 6996621Sbt150084 /* 7006621Sbt150084 * Stop the chipset 7016621Sbt150084 */ 7026621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) { 7036621Sbt150084 mutex_enter(&ixgbe->gen_lock); 7046621Sbt150084 ixgbe_chip_stop(ixgbe); 7056621Sbt150084 mutex_exit(&ixgbe->gen_lock); 7066621Sbt150084 } 7076621Sbt150084 7086621Sbt150084 /* 7096621Sbt150084 * Free register handle 7106621Sbt150084 */ 7116621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) { 7126621Sbt150084 if (ixgbe->osdep.reg_handle != NULL) 7136621Sbt150084 ddi_regs_map_free(&ixgbe->osdep.reg_handle); 7146621Sbt150084 } 7156621Sbt150084 7166621Sbt150084 /* 7176621Sbt150084 * Free PCI config handle 7186621Sbt150084 */ 7196621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) { 7206621Sbt150084 if (ixgbe->osdep.cfg_handle != NULL) 7216621Sbt150084 pci_config_teardown(&ixgbe->osdep.cfg_handle); 7226621Sbt150084 } 7236621Sbt150084 7246621Sbt150084 /* 7256621Sbt150084 * Free locks 7266621Sbt150084 */ 7276621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) { 7286621Sbt150084 ixgbe_destroy_locks(ixgbe); 7296621Sbt150084 } 7306621Sbt150084 7316621Sbt150084 /* 7326621Sbt150084 * Free the rx/tx rings 7336621Sbt150084 */ 7346621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) { 7356621Sbt150084 ixgbe_free_rings(ixgbe); 7366621Sbt150084 } 7376621Sbt150084 7386621Sbt150084 /* 7396621Sbt150084 * Unregister FMA capabilities 7406621Sbt150084 */ 7416621Sbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) { 7426621Sbt150084 ixgbe_fm_fini(ixgbe); 7436621Sbt150084 } 7446621Sbt150084 7456621Sbt150084 /* 7466621Sbt150084 * Free the driver data structure 7476621Sbt150084 */ 7486621Sbt150084 kmem_free(ixgbe, sizeof (ixgbe_t)); 7496621Sbt150084 7506621Sbt150084 ddi_set_driver_private(devinfo, NULL); 7516621Sbt150084 } 7526621Sbt150084 7536621Sbt150084 /* 7546621Sbt150084 * ixgbe_register_mac - Register the driver and its function pointers with 7556621Sbt150084 * the GLD interface. 7566621Sbt150084 */ 7576621Sbt150084 static int 7586621Sbt150084 ixgbe_register_mac(ixgbe_t *ixgbe) 7596621Sbt150084 { 7606621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 7616621Sbt150084 mac_register_t *mac; 7626621Sbt150084 int status; 7636621Sbt150084 7646621Sbt150084 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 7656621Sbt150084 return (IXGBE_FAILURE); 7666621Sbt150084 7676621Sbt150084 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7686621Sbt150084 mac->m_driver = ixgbe; 7696621Sbt150084 mac->m_dip = ixgbe->dip; 7706621Sbt150084 mac->m_src_addr = hw->mac.addr; 7716621Sbt150084 mac->m_callbacks = &ixgbe_m_callbacks; 7726621Sbt150084 mac->m_min_sdu = 0; 7736621Sbt150084 mac->m_max_sdu = ixgbe->default_mtu; 7746621Sbt150084 mac->m_margin = VLAN_TAGSZ; 77510376SChenlu.Chen@Sun.COM mac->m_priv_props = ixgbe_priv_props; 7768275SEric Cheng mac->m_v12n = MAC_VIRT_LEVEL1; 7776621Sbt150084 7786621Sbt150084 status = mac_register(mac, &ixgbe->mac_hdl); 7796621Sbt150084 7806621Sbt150084 mac_free(mac); 7816621Sbt150084 7826621Sbt150084 return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE); 7836621Sbt150084 } 7846621Sbt150084 7856621Sbt150084 /* 7866621Sbt150084 * ixgbe_identify_hardware - Identify the type of the chipset. 7876621Sbt150084 */ 7886621Sbt150084 static int 7896621Sbt150084 ixgbe_identify_hardware(ixgbe_t *ixgbe) 7906621Sbt150084 { 7916621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 7926621Sbt150084 struct ixgbe_osdep *osdep = &ixgbe->osdep; 7936621Sbt150084 7946621Sbt150084 /* 7956621Sbt150084 * Get the device id 7966621Sbt150084 */ 7976621Sbt150084 hw->vendor_id = 7986621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID); 7996621Sbt150084 hw->device_id = 8006621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID); 8016621Sbt150084 hw->revision_id = 8026621Sbt150084 pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID); 8036621Sbt150084 hw->subsystem_device_id = 8046621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID); 8056621Sbt150084 hw->subsystem_vendor_id = 8066621Sbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID); 8076621Sbt150084 8088490SPaul.Guo@Sun.COM /* 8098490SPaul.Guo@Sun.COM * Set the mac type of the adapter based on the device id 8108490SPaul.Guo@Sun.COM */ 8118490SPaul.Guo@Sun.COM if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) { 8128490SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 8138490SPaul.Guo@Sun.COM } 8148490SPaul.Guo@Sun.COM 8158490SPaul.Guo@Sun.COM /* 8168490SPaul.Guo@Sun.COM * Install adapter capabilities 8178490SPaul.Guo@Sun.COM */ 8188490SPaul.Guo@Sun.COM switch (hw->mac.type) { 8198490SPaul.Guo@Sun.COM case ixgbe_mac_82598EB: 8209353SSamuel.Tu@Sun.COM ixgbe_log(ixgbe, "identify 82598 adapter\n"); 8218490SPaul.Guo@Sun.COM ixgbe->capab = &ixgbe_82598eb_cap; 8228490SPaul.Guo@Sun.COM 8238490SPaul.Guo@Sun.COM if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) { 8248490SPaul.Guo@Sun.COM ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; 8258490SPaul.Guo@Sun.COM ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1; 8268490SPaul.Guo@Sun.COM } 8279353SSamuel.Tu@Sun.COM ixgbe->capab->other_intr |= IXGBE_EICR_LSC; 8289353SSamuel.Tu@Sun.COM 8299353SSamuel.Tu@Sun.COM break; 8309353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 8319353SSamuel.Tu@Sun.COM ixgbe_log(ixgbe, "identify 82599 adapter\n"); 8329353SSamuel.Tu@Sun.COM ixgbe->capab = &ixgbe_82599eb_cap; 8339353SSamuel.Tu@Sun.COM 8349353SSamuel.Tu@Sun.COM ixgbe->capab->other_intr = (IXGBE_EICR_GPI_SDP1 | 8359353SSamuel.Tu@Sun.COM IXGBE_EICR_GPI_SDP2 | IXGBE_EICR_LSC); 8368490SPaul.Guo@Sun.COM 8378490SPaul.Guo@Sun.COM break; 8388490SPaul.Guo@Sun.COM default: 8398490SPaul.Guo@Sun.COM ixgbe_log(ixgbe, 8408490SPaul.Guo@Sun.COM "adapter not supported in ixgbe_identify_hardware(): %d\n", 8418490SPaul.Guo@Sun.COM hw->mac.type); 8428490SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 8438490SPaul.Guo@Sun.COM } 8448490SPaul.Guo@Sun.COM 8456621Sbt150084 return (IXGBE_SUCCESS); 8466621Sbt150084 } 8476621Sbt150084 8486621Sbt150084 /* 8496621Sbt150084 * ixgbe_regs_map - Map the device registers. 8506621Sbt150084 * 8516621Sbt150084 */ 8526621Sbt150084 static int 8536621Sbt150084 ixgbe_regs_map(ixgbe_t *ixgbe) 8546621Sbt150084 { 8556621Sbt150084 dev_info_t *devinfo = ixgbe->dip; 8566621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 8576621Sbt150084 struct ixgbe_osdep *osdep = &ixgbe->osdep; 8586621Sbt150084 off_t mem_size; 8596621Sbt150084 8606621Sbt150084 /* 8616621Sbt150084 * First get the size of device registers to be mapped. 8626621Sbt150084 */ 8639353SSamuel.Tu@Sun.COM if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size) 8649353SSamuel.Tu@Sun.COM != DDI_SUCCESS) { 8656621Sbt150084 return (IXGBE_FAILURE); 8666621Sbt150084 } 8676621Sbt150084 8686621Sbt150084 /* 8696621Sbt150084 * Call ddi_regs_map_setup() to map registers 8706621Sbt150084 */ 8719353SSamuel.Tu@Sun.COM if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET, 8726621Sbt150084 (caddr_t *)&hw->hw_addr, 0, 8736621Sbt150084 mem_size, &ixgbe_regs_acc_attr, 8746621Sbt150084 &osdep->reg_handle)) != DDI_SUCCESS) { 8756621Sbt150084 return (IXGBE_FAILURE); 8766621Sbt150084 } 8776621Sbt150084 8786621Sbt150084 return (IXGBE_SUCCESS); 8796621Sbt150084 } 8806621Sbt150084 8816621Sbt150084 /* 8826621Sbt150084 * ixgbe_init_properties - Initialize driver properties. 8836621Sbt150084 */ 8846621Sbt150084 static void 8856621Sbt150084 ixgbe_init_properties(ixgbe_t *ixgbe) 8866621Sbt150084 { 8876621Sbt150084 /* 8886621Sbt150084 * Get conf file properties, including link settings 8896621Sbt150084 * jumbo frames, ring number, descriptor number, etc. 8906621Sbt150084 */ 8916621Sbt150084 ixgbe_get_conf(ixgbe); 89210376SChenlu.Chen@Sun.COM 89310376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe); 8946621Sbt150084 } 8956621Sbt150084 8966621Sbt150084 /* 8976621Sbt150084 * ixgbe_init_driver_settings - Initialize driver settings. 8986621Sbt150084 * 8996621Sbt150084 * The settings include hardware function pointers, bus information, 9006621Sbt150084 * rx/tx rings settings, link state, and any other parameters that 9016621Sbt150084 * need to be setup during driver initialization. 9026621Sbt150084 */ 9036621Sbt150084 static int 9046621Sbt150084 ixgbe_init_driver_settings(ixgbe_t *ixgbe) 9056621Sbt150084 { 9066621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 9078275SEric Cheng dev_info_t *devinfo = ixgbe->dip; 9086621Sbt150084 ixgbe_rx_ring_t *rx_ring; 90911878SVenu.Iyer@Sun.COM ixgbe_rx_group_t *rx_group; 9106621Sbt150084 ixgbe_tx_ring_t *tx_ring; 9116621Sbt150084 uint32_t rx_size; 9126621Sbt150084 uint32_t tx_size; 91311878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 9146621Sbt150084 int i; 9156621Sbt150084 9166621Sbt150084 /* 9176621Sbt150084 * Initialize chipset specific hardware function pointers 9186621Sbt150084 */ 9196621Sbt150084 if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) { 9206621Sbt150084 return (IXGBE_FAILURE); 9216621Sbt150084 } 9226621Sbt150084 9236621Sbt150084 /* 9248275SEric Cheng * Get the system page size 9258275SEric Cheng */ 9268275SEric Cheng ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1); 9278275SEric Cheng 9288275SEric Cheng /* 9296621Sbt150084 * Set rx buffer size 9306621Sbt150084 * 9316621Sbt150084 * The IP header alignment room is counted in the calculation. 9326621Sbt150084 * The rx buffer size is in unit of 1K that is required by the 9336621Sbt150084 * chipset hardware. 9346621Sbt150084 */ 9356621Sbt150084 rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM; 9366621Sbt150084 ixgbe->rx_buf_size = ((rx_size >> 10) + 9376621Sbt150084 ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 9386621Sbt150084 9396621Sbt150084 /* 9406621Sbt150084 * Set tx buffer size 9416621Sbt150084 */ 9426621Sbt150084 tx_size = ixgbe->max_frame_size; 9436621Sbt150084 ixgbe->tx_buf_size = ((tx_size >> 10) + 9446621Sbt150084 ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 9456621Sbt150084 9466621Sbt150084 /* 94711878SVenu.Iyer@Sun.COM * Initialize rx/tx rings/groups parameters 94811878SVenu.Iyer@Sun.COM */ 94911878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 9506621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 9516621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 9526621Sbt150084 rx_ring->index = i; 9536621Sbt150084 rx_ring->ixgbe = ixgbe; 95411878SVenu.Iyer@Sun.COM rx_ring->group_index = i / ring_per_group; 95511878SVenu.Iyer@Sun.COM rx_ring->hw_index = ixgbe_get_hw_rx_index(ixgbe, i); 95611878SVenu.Iyer@Sun.COM } 95711878SVenu.Iyer@Sun.COM 95811878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_groups; i++) { 95911878SVenu.Iyer@Sun.COM rx_group = &ixgbe->rx_groups[i]; 96011878SVenu.Iyer@Sun.COM rx_group->index = i; 96111878SVenu.Iyer@Sun.COM rx_group->ixgbe = ixgbe; 9626621Sbt150084 } 9636621Sbt150084 9646621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 9656621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 9666621Sbt150084 tx_ring->index = i; 9676621Sbt150084 tx_ring->ixgbe = ixgbe; 9686621Sbt150084 if (ixgbe->tx_head_wb_enable) 9696621Sbt150084 tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb; 9706621Sbt150084 else 9716621Sbt150084 tx_ring->tx_recycle = ixgbe_tx_recycle_legacy; 9726621Sbt150084 9736621Sbt150084 tx_ring->ring_size = ixgbe->tx_ring_size; 9746621Sbt150084 tx_ring->free_list_size = ixgbe->tx_ring_size + 9756621Sbt150084 (ixgbe->tx_ring_size >> 1); 9766621Sbt150084 } 9776621Sbt150084 9786621Sbt150084 /* 9796621Sbt150084 * Initialize values of interrupt throttling rate 9806621Sbt150084 */ 9819353SSamuel.Tu@Sun.COM for (i = 1; i < MAX_INTR_VECTOR; i++) 9826621Sbt150084 ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0]; 9836621Sbt150084 9846621Sbt150084 /* 9856621Sbt150084 * The initial link state should be "unknown" 9866621Sbt150084 */ 9876621Sbt150084 ixgbe->link_state = LINK_STATE_UNKNOWN; 9889353SSamuel.Tu@Sun.COM 9896621Sbt150084 return (IXGBE_SUCCESS); 9906621Sbt150084 } 9916621Sbt150084 9926621Sbt150084 /* 9936621Sbt150084 * ixgbe_init_locks - Initialize locks. 9946621Sbt150084 */ 9956621Sbt150084 static void 9966621Sbt150084 ixgbe_init_locks(ixgbe_t *ixgbe) 9976621Sbt150084 { 9986621Sbt150084 ixgbe_rx_ring_t *rx_ring; 9996621Sbt150084 ixgbe_tx_ring_t *tx_ring; 10006621Sbt150084 int i; 10016621Sbt150084 10026621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 10036621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 10046621Sbt150084 mutex_init(&rx_ring->rx_lock, NULL, 10056621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10066621Sbt150084 } 10076621Sbt150084 10086621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 10096621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 10106621Sbt150084 mutex_init(&tx_ring->tx_lock, NULL, 10116621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10126621Sbt150084 mutex_init(&tx_ring->recycle_lock, NULL, 10136621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10146621Sbt150084 mutex_init(&tx_ring->tcb_head_lock, NULL, 10156621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10166621Sbt150084 mutex_init(&tx_ring->tcb_tail_lock, NULL, 10176621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10186621Sbt150084 } 10196621Sbt150084 10206621Sbt150084 mutex_init(&ixgbe->gen_lock, NULL, 10216621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10226621Sbt150084 10236621Sbt150084 mutex_init(&ixgbe->watchdog_lock, NULL, 10246621Sbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 10256621Sbt150084 } 10266621Sbt150084 10276621Sbt150084 /* 10286621Sbt150084 * ixgbe_destroy_locks - Destroy locks. 10296621Sbt150084 */ 10306621Sbt150084 static void 10316621Sbt150084 ixgbe_destroy_locks(ixgbe_t *ixgbe) 10326621Sbt150084 { 10336621Sbt150084 ixgbe_rx_ring_t *rx_ring; 10346621Sbt150084 ixgbe_tx_ring_t *tx_ring; 10356621Sbt150084 int i; 10366621Sbt150084 10376621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 10386621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 10396621Sbt150084 mutex_destroy(&rx_ring->rx_lock); 10406621Sbt150084 } 10416621Sbt150084 10426621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 10436621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 10446621Sbt150084 mutex_destroy(&tx_ring->tx_lock); 10456621Sbt150084 mutex_destroy(&tx_ring->recycle_lock); 10466621Sbt150084 mutex_destroy(&tx_ring->tcb_head_lock); 10476621Sbt150084 mutex_destroy(&tx_ring->tcb_tail_lock); 10486621Sbt150084 } 10496621Sbt150084 10506621Sbt150084 mutex_destroy(&ixgbe->gen_lock); 10516621Sbt150084 mutex_destroy(&ixgbe->watchdog_lock); 10526621Sbt150084 } 10536621Sbt150084 10546621Sbt150084 static int 10556621Sbt150084 ixgbe_resume(dev_info_t *devinfo) 10566621Sbt150084 { 10576621Sbt150084 ixgbe_t *ixgbe; 105811233SPaul.Guo@Sun.COM int i; 10596621Sbt150084 10606621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 10616621Sbt150084 if (ixgbe == NULL) 10626621Sbt150084 return (DDI_FAILURE); 10636621Sbt150084 10646621Sbt150084 mutex_enter(&ixgbe->gen_lock); 10656621Sbt150084 10666621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 106710376SChenlu.Chen@Sun.COM if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 10686621Sbt150084 mutex_exit(&ixgbe->gen_lock); 10696621Sbt150084 return (DDI_FAILURE); 10706621Sbt150084 } 10716621Sbt150084 10726621Sbt150084 /* 10736621Sbt150084 * Enable and start the watchdog timer 10746621Sbt150084 */ 10756621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe); 10766621Sbt150084 } 10776621Sbt150084 107811233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED); 107911233SPaul.Guo@Sun.COM 108011233SPaul.Guo@Sun.COM if (ixgbe->ixgbe_state & IXGBE_STARTED) { 108111233SPaul.Guo@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 108211233SPaul.Guo@Sun.COM mac_tx_ring_update(ixgbe->mac_hdl, 108311233SPaul.Guo@Sun.COM ixgbe->tx_rings[i].ring_handle); 108411233SPaul.Guo@Sun.COM } 108511233SPaul.Guo@Sun.COM } 10866621Sbt150084 10876621Sbt150084 mutex_exit(&ixgbe->gen_lock); 10886621Sbt150084 10896621Sbt150084 return (DDI_SUCCESS); 10906621Sbt150084 } 10916621Sbt150084 10926621Sbt150084 static int 10936621Sbt150084 ixgbe_suspend(dev_info_t *devinfo) 10946621Sbt150084 { 10956621Sbt150084 ixgbe_t *ixgbe; 10966621Sbt150084 10976621Sbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 10986621Sbt150084 if (ixgbe == NULL) 10996621Sbt150084 return (DDI_FAILURE); 11006621Sbt150084 11016621Sbt150084 mutex_enter(&ixgbe->gen_lock); 11026621Sbt150084 110311233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED); 110410376SChenlu.Chen@Sun.COM if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) { 110510376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->gen_lock); 110610376SChenlu.Chen@Sun.COM return (DDI_SUCCESS); 110710376SChenlu.Chen@Sun.COM } 110810376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_FALSE); 11096621Sbt150084 11106621Sbt150084 mutex_exit(&ixgbe->gen_lock); 11116621Sbt150084 11126621Sbt150084 /* 11136621Sbt150084 * Disable and stop the watchdog timer 11146621Sbt150084 */ 11156621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe); 11166621Sbt150084 11176621Sbt150084 return (DDI_SUCCESS); 11186621Sbt150084 } 11196621Sbt150084 11206621Sbt150084 /* 11216621Sbt150084 * ixgbe_init - Initialize the device. 11226621Sbt150084 */ 11236621Sbt150084 static int 11246621Sbt150084 ixgbe_init(ixgbe_t *ixgbe) 11256621Sbt150084 { 11266621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 11276621Sbt150084 11286621Sbt150084 mutex_enter(&ixgbe->gen_lock); 11296621Sbt150084 11306621Sbt150084 /* 11316621Sbt150084 * Reset chipset to put the hardware in a known state 11326621Sbt150084 * before we try to do anything with the eeprom. 11336621Sbt150084 */ 11346621Sbt150084 if (ixgbe_reset_hw(hw) != IXGBE_SUCCESS) { 11356621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11366621Sbt150084 goto init_fail; 11376621Sbt150084 } 11386621Sbt150084 11396621Sbt150084 /* 11406621Sbt150084 * Need to init eeprom before validating the checksum. 11416621Sbt150084 */ 11426621Sbt150084 if (ixgbe_init_eeprom_params(hw) < 0) { 11436621Sbt150084 ixgbe_error(ixgbe, 11446621Sbt150084 "Unable to intitialize the eeprom interface."); 11456621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11466621Sbt150084 goto init_fail; 11476621Sbt150084 } 11486621Sbt150084 11496621Sbt150084 /* 11506621Sbt150084 * NVM validation 11516621Sbt150084 */ 11526621Sbt150084 if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { 11536621Sbt150084 /* 11546621Sbt150084 * Some PCI-E parts fail the first check due to 11556621Sbt150084 * the link being in sleep state. Call it again, 11566621Sbt150084 * if it fails a second time it's a real issue. 11576621Sbt150084 */ 11586621Sbt150084 if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { 11596621Sbt150084 ixgbe_error(ixgbe, 11606621Sbt150084 "Invalid NVM checksum. Please contact " 11616621Sbt150084 "the vendor to update the NVM."); 11626621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11636621Sbt150084 goto init_fail; 11646621Sbt150084 } 11656621Sbt150084 } 11666621Sbt150084 11676621Sbt150084 /* 11686621Sbt150084 * Setup default flow control thresholds - enable/disable 11696621Sbt150084 * & flow control type is controlled by ixgbe.conf 11706621Sbt150084 */ 11716621Sbt150084 hw->fc.high_water = DEFAULT_FCRTH; 11726621Sbt150084 hw->fc.low_water = DEFAULT_FCRTL; 11736621Sbt150084 hw->fc.pause_time = DEFAULT_FCPAUSE; 11746621Sbt150084 hw->fc.send_xon = B_TRUE; 11756621Sbt150084 11766621Sbt150084 /* 11776621Sbt150084 * Initialize link settings 11786621Sbt150084 */ 11796621Sbt150084 (void) ixgbe_driver_setup_link(ixgbe, B_FALSE); 11806621Sbt150084 11816621Sbt150084 /* 11826621Sbt150084 * Initialize the chipset hardware 11836621Sbt150084 */ 11846621Sbt150084 if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { 11856621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 11866621Sbt150084 goto init_fail; 11876621Sbt150084 } 11886621Sbt150084 11896621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 11906621Sbt150084 goto init_fail; 11916621Sbt150084 } 11926621Sbt150084 11936621Sbt150084 mutex_exit(&ixgbe->gen_lock); 11946621Sbt150084 return (IXGBE_SUCCESS); 11956621Sbt150084 11966621Sbt150084 init_fail: 11976621Sbt150084 /* 11986621Sbt150084 * Reset PHY 11996621Sbt150084 */ 12006621Sbt150084 (void) ixgbe_reset_phy(hw); 12016621Sbt150084 12026621Sbt150084 mutex_exit(&ixgbe->gen_lock); 12036621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 12046621Sbt150084 return (IXGBE_FAILURE); 12056621Sbt150084 } 12066621Sbt150084 12076621Sbt150084 /* 12086621Sbt150084 * ixgbe_chip_start - Initialize and start the chipset hardware. 12096621Sbt150084 */ 12106621Sbt150084 static int 12116621Sbt150084 ixgbe_chip_start(ixgbe_t *ixgbe) 12126621Sbt150084 { 12136621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 121410305SPaul.Guo@Sun.COM int ret_val, i; 12156621Sbt150084 12166621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 12176621Sbt150084 12186621Sbt150084 /* 12196621Sbt150084 * Get the mac address 12206621Sbt150084 * This function should handle SPARC case correctly. 12216621Sbt150084 */ 12226621Sbt150084 if (!ixgbe_find_mac_address(ixgbe)) { 12236621Sbt150084 ixgbe_error(ixgbe, "Failed to get the mac address"); 12246621Sbt150084 return (IXGBE_FAILURE); 12256621Sbt150084 } 12266621Sbt150084 12276621Sbt150084 /* 12286621Sbt150084 * Validate the mac address 12296621Sbt150084 */ 12306621Sbt150084 (void) ixgbe_init_rx_addrs(hw); 12316621Sbt150084 if (!is_valid_mac_addr(hw->mac.addr)) { 12326621Sbt150084 ixgbe_error(ixgbe, "Invalid mac address"); 12336621Sbt150084 return (IXGBE_FAILURE); 12346621Sbt150084 } 12356621Sbt150084 12366621Sbt150084 /* 12376621Sbt150084 * Configure/Initialize hardware 12386621Sbt150084 */ 123910305SPaul.Guo@Sun.COM ret_val = ixgbe_init_hw(hw); 124010305SPaul.Guo@Sun.COM if (ret_val != IXGBE_SUCCESS) { 124110305SPaul.Guo@Sun.COM if (ret_val == IXGBE_ERR_EEPROM_VERSION) { 124210305SPaul.Guo@Sun.COM ixgbe_error(ixgbe, 124310305SPaul.Guo@Sun.COM "This 82599 device is pre-release and contains" 124410305SPaul.Guo@Sun.COM " outdated firmware, please contact your hardware" 124510305SPaul.Guo@Sun.COM " vendor for a replacement."); 124610305SPaul.Guo@Sun.COM } else { 124710305SPaul.Guo@Sun.COM ixgbe_error(ixgbe, "Failed to initialize hardware"); 124810305SPaul.Guo@Sun.COM return (IXGBE_FAILURE); 124910305SPaul.Guo@Sun.COM } 12506621Sbt150084 } 12516621Sbt150084 12526621Sbt150084 /* 12536621Sbt150084 * Setup adapter interrupt vectors 12546621Sbt150084 */ 12556621Sbt150084 ixgbe_setup_adapter_vector(ixgbe); 12566621Sbt150084 12576621Sbt150084 /* 12586621Sbt150084 * Initialize unicast addresses. 12596621Sbt150084 */ 12606621Sbt150084 ixgbe_init_unicst(ixgbe); 12616621Sbt150084 12626621Sbt150084 /* 12636621Sbt150084 * Setup and initialize the mctable structures. 12646621Sbt150084 */ 12656621Sbt150084 ixgbe_setup_multicst(ixgbe); 12666621Sbt150084 12676621Sbt150084 /* 12686621Sbt150084 * Set interrupt throttling rate 12696621Sbt150084 */ 12709353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->intr_cnt; i++) { 12716621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]); 12729353SSamuel.Tu@Sun.COM } 12736621Sbt150084 12746621Sbt150084 /* 12756621Sbt150084 * Save the state of the phy 12766621Sbt150084 */ 12776621Sbt150084 ixgbe_get_hw_state(ixgbe); 12786621Sbt150084 12796621Sbt150084 /* 12806621Sbt150084 * Make sure driver has control 12816621Sbt150084 */ 12826621Sbt150084 ixgbe_get_driver_control(hw); 12836621Sbt150084 12846621Sbt150084 return (IXGBE_SUCCESS); 12856621Sbt150084 } 12866621Sbt150084 12876621Sbt150084 /* 12886621Sbt150084 * ixgbe_chip_stop - Stop the chipset hardware 12896621Sbt150084 */ 12906621Sbt150084 static void 12916621Sbt150084 ixgbe_chip_stop(ixgbe_t *ixgbe) 12926621Sbt150084 { 12936621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 12946621Sbt150084 12956621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 12966621Sbt150084 12976621Sbt150084 /* 12986621Sbt150084 * Tell firmware driver is no longer in control 12996621Sbt150084 */ 13006621Sbt150084 ixgbe_release_driver_control(hw); 13016621Sbt150084 13026621Sbt150084 /* 13036621Sbt150084 * Reset the chipset 13046621Sbt150084 */ 13056621Sbt150084 (void) ixgbe_reset_hw(hw); 13066621Sbt150084 13076621Sbt150084 /* 13086621Sbt150084 * Reset PHY 13096621Sbt150084 */ 13106621Sbt150084 (void) ixgbe_reset_phy(hw); 13116621Sbt150084 } 13126621Sbt150084 13136621Sbt150084 /* 13146621Sbt150084 * ixgbe_reset - Reset the chipset and re-start the driver. 13156621Sbt150084 * 13166621Sbt150084 * It involves stopping and re-starting the chipset, 13176621Sbt150084 * and re-configuring the rx/tx rings. 13186621Sbt150084 */ 13196621Sbt150084 static int 13206621Sbt150084 ixgbe_reset(ixgbe_t *ixgbe) 13216621Sbt150084 { 132211233SPaul.Guo@Sun.COM int i; 132311233SPaul.Guo@Sun.COM 132410376SChenlu.Chen@Sun.COM /* 132510376SChenlu.Chen@Sun.COM * Disable and stop the watchdog timer 132610376SChenlu.Chen@Sun.COM */ 132710376SChenlu.Chen@Sun.COM ixgbe_disable_watchdog_timer(ixgbe); 13286621Sbt150084 13296621Sbt150084 mutex_enter(&ixgbe->gen_lock); 13306621Sbt150084 13316621Sbt150084 ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED); 133211233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 13336621Sbt150084 133410376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe, B_FALSE); 133510376SChenlu.Chen@Sun.COM 133610376SChenlu.Chen@Sun.COM if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 133710376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->gen_lock); 133810376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 13396621Sbt150084 } 13406621Sbt150084 134111233SPaul.Guo@Sun.COM /* 134211233SPaul.Guo@Sun.COM * After resetting, need to recheck the link status. 134311233SPaul.Guo@Sun.COM */ 134411233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 134511233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 134611233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 134711233SPaul.Guo@Sun.COM 134811233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED); 134911233SPaul.Guo@Sun.COM 135011233SPaul.Guo@Sun.COM if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) { 135111233SPaul.Guo@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 135211233SPaul.Guo@Sun.COM mac_tx_ring_update(ixgbe->mac_hdl, 135311233SPaul.Guo@Sun.COM ixgbe->tx_rings[i].ring_handle); 135411233SPaul.Guo@Sun.COM } 135511233SPaul.Guo@Sun.COM } 135611233SPaul.Guo@Sun.COM 13576621Sbt150084 mutex_exit(&ixgbe->gen_lock); 13586621Sbt150084 135910376SChenlu.Chen@Sun.COM /* 136010376SChenlu.Chen@Sun.COM * Enable and start the watchdog timer 136110376SChenlu.Chen@Sun.COM */ 136210376SChenlu.Chen@Sun.COM ixgbe_enable_watchdog_timer(ixgbe); 136310376SChenlu.Chen@Sun.COM 13646621Sbt150084 return (IXGBE_SUCCESS); 13656621Sbt150084 } 13666621Sbt150084 13676621Sbt150084 /* 13686621Sbt150084 * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources. 13696621Sbt150084 */ 13706621Sbt150084 static void 13716621Sbt150084 ixgbe_tx_clean(ixgbe_t *ixgbe) 13726621Sbt150084 { 13736621Sbt150084 ixgbe_tx_ring_t *tx_ring; 13746621Sbt150084 tx_control_block_t *tcb; 13756621Sbt150084 link_list_t pending_list; 13766621Sbt150084 uint32_t desc_num; 13776621Sbt150084 int i, j; 13786621Sbt150084 13796621Sbt150084 LINK_LIST_INIT(&pending_list); 13806621Sbt150084 13816621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 13826621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 13836621Sbt150084 13846621Sbt150084 mutex_enter(&tx_ring->recycle_lock); 13856621Sbt150084 13866621Sbt150084 /* 13876621Sbt150084 * Clean the pending tx data - the pending packets in the 13886621Sbt150084 * work_list that have no chances to be transmitted again. 13896621Sbt150084 * 13906621Sbt150084 * We must ensure the chipset is stopped or the link is down 13916621Sbt150084 * before cleaning the transmit packets. 13926621Sbt150084 */ 13936621Sbt150084 desc_num = 0; 13946621Sbt150084 for (j = 0; j < tx_ring->ring_size; j++) { 13956621Sbt150084 tcb = tx_ring->work_list[j]; 13966621Sbt150084 if (tcb != NULL) { 13976621Sbt150084 desc_num += tcb->desc_num; 13986621Sbt150084 13996621Sbt150084 tx_ring->work_list[j] = NULL; 14006621Sbt150084 14016621Sbt150084 ixgbe_free_tcb(tcb); 14026621Sbt150084 14036621Sbt150084 LIST_PUSH_TAIL(&pending_list, &tcb->link); 14046621Sbt150084 } 14056621Sbt150084 } 14066621Sbt150084 14076621Sbt150084 if (desc_num > 0) { 14086621Sbt150084 atomic_add_32(&tx_ring->tbd_free, desc_num); 14096621Sbt150084 ASSERT(tx_ring->tbd_free == tx_ring->ring_size); 14106621Sbt150084 14116621Sbt150084 /* 14126621Sbt150084 * Reset the head and tail pointers of the tbd ring; 14136621Sbt150084 * Reset the writeback head if it's enable. 14146621Sbt150084 */ 14156621Sbt150084 tx_ring->tbd_head = 0; 14166621Sbt150084 tx_ring->tbd_tail = 0; 14176621Sbt150084 if (ixgbe->tx_head_wb_enable) 14186621Sbt150084 *tx_ring->tbd_head_wb = 0; 14196621Sbt150084 14206621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, 14216621Sbt150084 IXGBE_TDH(tx_ring->index), 0); 14226621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, 14236621Sbt150084 IXGBE_TDT(tx_ring->index), 0); 14246621Sbt150084 } 14256621Sbt150084 14266621Sbt150084 mutex_exit(&tx_ring->recycle_lock); 14276621Sbt150084 14286621Sbt150084 /* 14296621Sbt150084 * Add the tx control blocks in the pending list to 14306621Sbt150084 * the free list. 14316621Sbt150084 */ 14326621Sbt150084 ixgbe_put_free_list(tx_ring, &pending_list); 14336621Sbt150084 } 14346621Sbt150084 } 14356621Sbt150084 14366621Sbt150084 /* 14376621Sbt150084 * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be 14386621Sbt150084 * transmitted. 14396621Sbt150084 */ 14406621Sbt150084 static boolean_t 14416621Sbt150084 ixgbe_tx_drain(ixgbe_t *ixgbe) 14426621Sbt150084 { 14436621Sbt150084 ixgbe_tx_ring_t *tx_ring; 14446621Sbt150084 boolean_t done; 14456621Sbt150084 int i, j; 14466621Sbt150084 14476621Sbt150084 /* 14486621Sbt150084 * Wait for a specific time to allow pending tx packets 14496621Sbt150084 * to be transmitted. 14506621Sbt150084 * 14516621Sbt150084 * Check the counter tbd_free to see if transmission is done. 14526621Sbt150084 * No lock protection is needed here. 14536621Sbt150084 * 14546621Sbt150084 * Return B_TRUE if all pending packets have been transmitted; 14556621Sbt150084 * Otherwise return B_FALSE; 14566621Sbt150084 */ 14576621Sbt150084 for (i = 0; i < TX_DRAIN_TIME; i++) { 14586621Sbt150084 14596621Sbt150084 done = B_TRUE; 14606621Sbt150084 for (j = 0; j < ixgbe->num_tx_rings; j++) { 14616621Sbt150084 tx_ring = &ixgbe->tx_rings[j]; 14626621Sbt150084 done = done && 14636621Sbt150084 (tx_ring->tbd_free == tx_ring->ring_size); 14646621Sbt150084 } 14656621Sbt150084 14666621Sbt150084 if (done) 14676621Sbt150084 break; 14686621Sbt150084 14696621Sbt150084 msec_delay(1); 14706621Sbt150084 } 14716621Sbt150084 14726621Sbt150084 return (done); 14736621Sbt150084 } 14746621Sbt150084 14756621Sbt150084 /* 14766621Sbt150084 * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer. 14776621Sbt150084 */ 14786621Sbt150084 static boolean_t 14796621Sbt150084 ixgbe_rx_drain(ixgbe_t *ixgbe) 14806621Sbt150084 { 148110376SChenlu.Chen@Sun.COM boolean_t done = B_TRUE; 148210376SChenlu.Chen@Sun.COM int i; 14836621Sbt150084 14846621Sbt150084 /* 14856621Sbt150084 * Polling the rx free list to check if those rx buffers held by 14866621Sbt150084 * the upper layer are released. 14876621Sbt150084 * 14886621Sbt150084 * Check the counter rcb_free to see if all pending buffers are 14896621Sbt150084 * released. No lock protection is needed here. 14906621Sbt150084 * 14916621Sbt150084 * Return B_TRUE if all pending buffers have been released; 14926621Sbt150084 * Otherwise return B_FALSE; 14936621Sbt150084 */ 14946621Sbt150084 for (i = 0; i < RX_DRAIN_TIME; i++) { 149510376SChenlu.Chen@Sun.COM done = (ixgbe->rcb_pending == 0); 14966621Sbt150084 14976621Sbt150084 if (done) 14986621Sbt150084 break; 14996621Sbt150084 15006621Sbt150084 msec_delay(1); 15016621Sbt150084 } 15026621Sbt150084 15036621Sbt150084 return (done); 15046621Sbt150084 } 15056621Sbt150084 15066621Sbt150084 /* 15076621Sbt150084 * ixgbe_start - Start the driver/chipset. 15086621Sbt150084 */ 15096621Sbt150084 int 151010376SChenlu.Chen@Sun.COM ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer) 15116621Sbt150084 { 15126621Sbt150084 int i; 15136621Sbt150084 15146621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 15156621Sbt150084 151610376SChenlu.Chen@Sun.COM if (alloc_buffer) { 151710376SChenlu.Chen@Sun.COM if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) { 151810376SChenlu.Chen@Sun.COM ixgbe_error(ixgbe, 151910376SChenlu.Chen@Sun.COM "Failed to allocate software receive rings"); 152010376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 152110376SChenlu.Chen@Sun.COM } 152210376SChenlu.Chen@Sun.COM 152310376SChenlu.Chen@Sun.COM /* Allocate buffers for all the rx/tx rings */ 152410376SChenlu.Chen@Sun.COM if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) { 152510376SChenlu.Chen@Sun.COM ixgbe_error(ixgbe, "Failed to allocate DMA resource"); 152610376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 152710376SChenlu.Chen@Sun.COM } 152810376SChenlu.Chen@Sun.COM 152910376SChenlu.Chen@Sun.COM ixgbe->tx_ring_init = B_TRUE; 153010376SChenlu.Chen@Sun.COM } else { 153110376SChenlu.Chen@Sun.COM ixgbe->tx_ring_init = B_FALSE; 153210376SChenlu.Chen@Sun.COM } 153310376SChenlu.Chen@Sun.COM 15346621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) 15356621Sbt150084 mutex_enter(&ixgbe->rx_rings[i].rx_lock); 15366621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) 15376621Sbt150084 mutex_enter(&ixgbe->tx_rings[i].tx_lock); 15386621Sbt150084 15396621Sbt150084 /* 15406621Sbt150084 * Start the chipset hardware 15416621Sbt150084 */ 15426621Sbt150084 if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { 15436621Sbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 15446621Sbt150084 goto start_failure; 15456621Sbt150084 } 15466621Sbt150084 15476621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 15486621Sbt150084 goto start_failure; 15496621Sbt150084 } 15506621Sbt150084 15516621Sbt150084 /* 15526621Sbt150084 * Setup the rx/tx rings 15536621Sbt150084 */ 15546621Sbt150084 ixgbe_setup_rings(ixgbe); 15556621Sbt150084 15566621Sbt150084 /* 155711233SPaul.Guo@Sun.COM * ixgbe_start() will be called when resetting, however if reset 155811233SPaul.Guo@Sun.COM * happens, we need to clear the ERROR and STALL flags before 155911233SPaul.Guo@Sun.COM * enabling the interrupts. 156011233SPaul.Guo@Sun.COM */ 156111233SPaul.Guo@Sun.COM atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR | IXGBE_STALL)); 156211233SPaul.Guo@Sun.COM 156311233SPaul.Guo@Sun.COM /* 15646621Sbt150084 * Enable adapter interrupts 15656621Sbt150084 * The interrupts must be enabled after the driver state is START 15666621Sbt150084 */ 15676621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe); 15686621Sbt150084 15696621Sbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 15706621Sbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 15716621Sbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 15726621Sbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 15736621Sbt150084 15746621Sbt150084 return (IXGBE_SUCCESS); 15756621Sbt150084 15766621Sbt150084 start_failure: 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 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 15836621Sbt150084 15846621Sbt150084 return (IXGBE_FAILURE); 15856621Sbt150084 } 15866621Sbt150084 15876621Sbt150084 /* 15886621Sbt150084 * ixgbe_stop - Stop the driver/chipset. 15896621Sbt150084 */ 15906621Sbt150084 void 159110376SChenlu.Chen@Sun.COM ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer) 15926621Sbt150084 { 15936621Sbt150084 int i; 15946621Sbt150084 15956621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 15966621Sbt150084 15976621Sbt150084 /* 15986621Sbt150084 * Disable the adapter interrupts 15996621Sbt150084 */ 16006621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe); 16016621Sbt150084 16026621Sbt150084 /* 16036621Sbt150084 * Drain the pending tx packets 16046621Sbt150084 */ 16056621Sbt150084 (void) ixgbe_tx_drain(ixgbe); 16066621Sbt150084 16076621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) 16086621Sbt150084 mutex_enter(&ixgbe->rx_rings[i].rx_lock); 16096621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) 16106621Sbt150084 mutex_enter(&ixgbe->tx_rings[i].tx_lock); 16116621Sbt150084 16126621Sbt150084 /* 16136621Sbt150084 * Stop the chipset hardware 16146621Sbt150084 */ 16156621Sbt150084 ixgbe_chip_stop(ixgbe); 16166621Sbt150084 16176621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 16186621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 16196621Sbt150084 } 16206621Sbt150084 16216621Sbt150084 /* 16226621Sbt150084 * Clean the pending tx data/resources 16236621Sbt150084 */ 16246621Sbt150084 ixgbe_tx_clean(ixgbe); 16256621Sbt150084 16266621Sbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 16276621Sbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 16286621Sbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 16296621Sbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 163010376SChenlu.Chen@Sun.COM 163110376SChenlu.Chen@Sun.COM if (ixgbe->link_state == LINK_STATE_UP) { 163210376SChenlu.Chen@Sun.COM ixgbe->link_state = LINK_STATE_UNKNOWN; 163310376SChenlu.Chen@Sun.COM mac_link_update(ixgbe->mac_hdl, ixgbe->link_state); 163410376SChenlu.Chen@Sun.COM } 163510376SChenlu.Chen@Sun.COM 163610376SChenlu.Chen@Sun.COM if (free_buffer) { 163710376SChenlu.Chen@Sun.COM /* 163810376SChenlu.Chen@Sun.COM * Release the DMA/memory resources of rx/tx rings 163910376SChenlu.Chen@Sun.COM */ 164010376SChenlu.Chen@Sun.COM ixgbe_free_dma(ixgbe); 164110376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe); 164210376SChenlu.Chen@Sun.COM } 16436621Sbt150084 } 16446621Sbt150084 16456621Sbt150084 /* 164611878SVenu.Iyer@Sun.COM * ixgbe_cbfunc - Driver interface for generic DDI callbacks 164711878SVenu.Iyer@Sun.COM */ 164811878SVenu.Iyer@Sun.COM /* ARGSUSED */ 164911878SVenu.Iyer@Sun.COM static int 165011878SVenu.Iyer@Sun.COM ixgbe_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg, 165111878SVenu.Iyer@Sun.COM void *arg1, void *arg2) 165211878SVenu.Iyer@Sun.COM { 165311878SVenu.Iyer@Sun.COM ixgbe_t *ixgbe = (ixgbe_t *)arg1; 165411878SVenu.Iyer@Sun.COM 165511878SVenu.Iyer@Sun.COM switch (cbaction) { 165611878SVenu.Iyer@Sun.COM /* IRM callback */ 165711878SVenu.Iyer@Sun.COM int count; 165811878SVenu.Iyer@Sun.COM case DDI_CB_INTR_ADD: 165911878SVenu.Iyer@Sun.COM case DDI_CB_INTR_REMOVE: 166011878SVenu.Iyer@Sun.COM count = (int)(uintptr_t)cbarg; 166111878SVenu.Iyer@Sun.COM ASSERT(ixgbe->intr_type == DDI_INTR_TYPE_MSIX); 166211878SVenu.Iyer@Sun.COM DTRACE_PROBE2(ixgbe__irm__callback, int, count, 166311878SVenu.Iyer@Sun.COM int, ixgbe->intr_cnt); 166411878SVenu.Iyer@Sun.COM if (ixgbe_intr_adjust(ixgbe, cbaction, count) != 166511878SVenu.Iyer@Sun.COM DDI_SUCCESS) { 166611878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, 166711878SVenu.Iyer@Sun.COM "IRM CB: Failed to adjust interrupts"); 166811878SVenu.Iyer@Sun.COM goto cb_fail; 166911878SVenu.Iyer@Sun.COM } 167011878SVenu.Iyer@Sun.COM break; 167111878SVenu.Iyer@Sun.COM default: 167211878SVenu.Iyer@Sun.COM IXGBE_DEBUGLOG_1(ixgbe, "DDI CB: action 0x%x NOT supported", 167311878SVenu.Iyer@Sun.COM cbaction); 167411878SVenu.Iyer@Sun.COM return (DDI_ENOTSUP); 167511878SVenu.Iyer@Sun.COM } 167611878SVenu.Iyer@Sun.COM return (DDI_SUCCESS); 167711878SVenu.Iyer@Sun.COM cb_fail: 167811878SVenu.Iyer@Sun.COM return (DDI_FAILURE); 167911878SVenu.Iyer@Sun.COM } 168011878SVenu.Iyer@Sun.COM 168111878SVenu.Iyer@Sun.COM /* 168211878SVenu.Iyer@Sun.COM * ixgbe_intr_adjust - Adjust interrupt to respond to IRM request. 168311878SVenu.Iyer@Sun.COM */ 168411878SVenu.Iyer@Sun.COM static int 168511878SVenu.Iyer@Sun.COM ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count) 168611878SVenu.Iyer@Sun.COM { 168711878SVenu.Iyer@Sun.COM int i, rc, actual; 168811878SVenu.Iyer@Sun.COM 168911878SVenu.Iyer@Sun.COM if (count == 0) 169011878SVenu.Iyer@Sun.COM return (DDI_SUCCESS); 169111878SVenu.Iyer@Sun.COM 169211878SVenu.Iyer@Sun.COM if ((cbaction == DDI_CB_INTR_ADD && 169311878SVenu.Iyer@Sun.COM ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) || 169411878SVenu.Iyer@Sun.COM (cbaction == DDI_CB_INTR_REMOVE && 169511878SVenu.Iyer@Sun.COM ixgbe->intr_cnt - count < ixgbe->intr_cnt_min)) 169611878SVenu.Iyer@Sun.COM return (DDI_FAILURE); 169711878SVenu.Iyer@Sun.COM 169811878SVenu.Iyer@Sun.COM if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) { 169911878SVenu.Iyer@Sun.COM return (DDI_FAILURE); 170011878SVenu.Iyer@Sun.COM } 170111878SVenu.Iyer@Sun.COM 170211878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) 170311878SVenu.Iyer@Sun.COM mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL); 170411878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) 170511878SVenu.Iyer@Sun.COM mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL); 170611878SVenu.Iyer@Sun.COM 170711878SVenu.Iyer@Sun.COM mutex_enter(&ixgbe->gen_lock); 170811878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state &= ~IXGBE_STARTED; 170911878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST; 171011878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state |= IXGBE_SUSPENDED; 171111878SVenu.Iyer@Sun.COM mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN); 171211878SVenu.Iyer@Sun.COM 171311878SVenu.Iyer@Sun.COM ixgbe_stop(ixgbe, B_FALSE); 171411878SVenu.Iyer@Sun.COM /* 171511878SVenu.Iyer@Sun.COM * Disable interrupts 171611878SVenu.Iyer@Sun.COM */ 171711878SVenu.Iyer@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 171811878SVenu.Iyer@Sun.COM rc = ixgbe_disable_intrs(ixgbe); 171911878SVenu.Iyer@Sun.COM ASSERT(rc == IXGBE_SUCCESS); 172011878SVenu.Iyer@Sun.COM } 172111878SVenu.Iyer@Sun.COM ixgbe->attach_progress &= ~ATTACH_PROGRESS_ENABLE_INTR; 172211878SVenu.Iyer@Sun.COM 172311878SVenu.Iyer@Sun.COM /* 172411878SVenu.Iyer@Sun.COM * Remove interrupt handlers 172511878SVenu.Iyer@Sun.COM */ 172611878SVenu.Iyer@Sun.COM if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 172711878SVenu.Iyer@Sun.COM ixgbe_rem_intr_handlers(ixgbe); 172811878SVenu.Iyer@Sun.COM } 172911878SVenu.Iyer@Sun.COM ixgbe->attach_progress &= ~ATTACH_PROGRESS_ADD_INTR; 173011878SVenu.Iyer@Sun.COM 173111878SVenu.Iyer@Sun.COM /* 173211878SVenu.Iyer@Sun.COM * Clear vect_map 173311878SVenu.Iyer@Sun.COM */ 173411878SVenu.Iyer@Sun.COM bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map)); 173511878SVenu.Iyer@Sun.COM switch (cbaction) { 173611878SVenu.Iyer@Sun.COM case DDI_CB_INTR_ADD: 173711878SVenu.Iyer@Sun.COM rc = ddi_intr_alloc(ixgbe->dip, ixgbe->htable, 173811878SVenu.Iyer@Sun.COM DDI_INTR_TYPE_MSIX, ixgbe->intr_cnt, count, &actual, 173911878SVenu.Iyer@Sun.COM DDI_INTR_ALLOC_NORMAL); 174011878SVenu.Iyer@Sun.COM if (rc != DDI_SUCCESS || actual != count) { 174111878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, "Adjust interrupts failed." 174211878SVenu.Iyer@Sun.COM "return: %d, irm cb size: %d, actual: %d", 174311878SVenu.Iyer@Sun.COM rc, count, actual); 174411878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 174511878SVenu.Iyer@Sun.COM } 174611878SVenu.Iyer@Sun.COM ixgbe->intr_cnt += count; 174711878SVenu.Iyer@Sun.COM break; 174811878SVenu.Iyer@Sun.COM 174911878SVenu.Iyer@Sun.COM case DDI_CB_INTR_REMOVE: 175011878SVenu.Iyer@Sun.COM for (i = ixgbe->intr_cnt - count; 175111878SVenu.Iyer@Sun.COM i < ixgbe->intr_cnt; i ++) { 175211878SVenu.Iyer@Sun.COM rc = ddi_intr_free(ixgbe->htable[i]); 175311878SVenu.Iyer@Sun.COM ixgbe->htable[i] = NULL; 175411878SVenu.Iyer@Sun.COM if (rc != DDI_SUCCESS) { 175511878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, "Adjust interrupts failed." 175611878SVenu.Iyer@Sun.COM "return: %d, irm cb size: %d, actual: %d", 175711878SVenu.Iyer@Sun.COM rc, count, actual); 175811878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 175911878SVenu.Iyer@Sun.COM } 176011878SVenu.Iyer@Sun.COM } 176111878SVenu.Iyer@Sun.COM ixgbe->intr_cnt -= count; 176211878SVenu.Iyer@Sun.COM break; 176311878SVenu.Iyer@Sun.COM } 176411878SVenu.Iyer@Sun.COM 176511878SVenu.Iyer@Sun.COM /* 176611878SVenu.Iyer@Sun.COM * Get priority for first vector, assume remaining are all the same 176711878SVenu.Iyer@Sun.COM */ 176811878SVenu.Iyer@Sun.COM rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri); 176911878SVenu.Iyer@Sun.COM if (rc != DDI_SUCCESS) { 177011878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, 177111878SVenu.Iyer@Sun.COM "Get interrupt priority failed: %d", rc); 177211878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 177311878SVenu.Iyer@Sun.COM } 177411878SVenu.Iyer@Sun.COM rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap); 177511878SVenu.Iyer@Sun.COM if (rc != DDI_SUCCESS) { 177611878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, "Get interrupt cap failed: %d", rc); 177711878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 177811878SVenu.Iyer@Sun.COM } 177911878SVenu.Iyer@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR; 178011878SVenu.Iyer@Sun.COM 178111878SVenu.Iyer@Sun.COM /* 178211878SVenu.Iyer@Sun.COM * Map rings to interrupt vectors 178311878SVenu.Iyer@Sun.COM */ 178411878SVenu.Iyer@Sun.COM if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) { 178511878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, 178611878SVenu.Iyer@Sun.COM "IRM CB: Failed to map interrupts to vectors"); 178711878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 178811878SVenu.Iyer@Sun.COM } 178911878SVenu.Iyer@Sun.COM 179011878SVenu.Iyer@Sun.COM /* 179111878SVenu.Iyer@Sun.COM * Add interrupt handlers 179211878SVenu.Iyer@Sun.COM */ 179311878SVenu.Iyer@Sun.COM if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) { 179411878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, "IRM CB: Failed to add interrupt handlers"); 179511878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 179611878SVenu.Iyer@Sun.COM } 179711878SVenu.Iyer@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 179811878SVenu.Iyer@Sun.COM 179911878SVenu.Iyer@Sun.COM /* 180011878SVenu.Iyer@Sun.COM * Now that mutex locks are initialized, and the chip is also 180111878SVenu.Iyer@Sun.COM * initialized, enable interrupts. 180211878SVenu.Iyer@Sun.COM */ 180311878SVenu.Iyer@Sun.COM if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) { 180411878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts"); 180511878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 180611878SVenu.Iyer@Sun.COM } 180711878SVenu.Iyer@Sun.COM ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 180811878SVenu.Iyer@Sun.COM if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 180911878SVenu.Iyer@Sun.COM ixgbe_error(ixgbe, "IRM CB: Failed to start"); 181011878SVenu.Iyer@Sun.COM goto intr_adjust_fail; 181111878SVenu.Iyer@Sun.COM } 181211878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST; 181311878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED; 181411878SVenu.Iyer@Sun.COM ixgbe->ixgbe_state |= IXGBE_STARTED; 181511878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 181611878SVenu.Iyer@Sun.COM 181711878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 181811878SVenu.Iyer@Sun.COM mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, 181911878SVenu.Iyer@Sun.COM ixgbe->htable[ixgbe->rx_rings[i].intr_vector]); 182011878SVenu.Iyer@Sun.COM } 182111878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 182211878SVenu.Iyer@Sun.COM mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, 182311878SVenu.Iyer@Sun.COM ixgbe->htable[ixgbe->tx_rings[i].intr_vector]); 182411878SVenu.Iyer@Sun.COM } 182511878SVenu.Iyer@Sun.COM 182611878SVenu.Iyer@Sun.COM /* Wakeup all Tx rings */ 182711878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 182811878SVenu.Iyer@Sun.COM mac_tx_ring_update(ixgbe->mac_hdl, 182911878SVenu.Iyer@Sun.COM ixgbe->tx_rings[i].ring_handle); 183011878SVenu.Iyer@Sun.COM } 183111878SVenu.Iyer@Sun.COM 183211878SVenu.Iyer@Sun.COM IXGBE_DEBUGLOG_3(ixgbe, 183311878SVenu.Iyer@Sun.COM "IRM CB: interrupts new value: 0x%x(0x%x:0x%x).", 183411878SVenu.Iyer@Sun.COM ixgbe->intr_cnt, ixgbe->intr_cnt_min, ixgbe->intr_cnt_max); 183511878SVenu.Iyer@Sun.COM return (DDI_SUCCESS); 183611878SVenu.Iyer@Sun.COM 183711878SVenu.Iyer@Sun.COM intr_adjust_fail: 183811878SVenu.Iyer@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 183911878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 184011878SVenu.Iyer@Sun.COM return (DDI_FAILURE); 184111878SVenu.Iyer@Sun.COM } 184211878SVenu.Iyer@Sun.COM 184311878SVenu.Iyer@Sun.COM /* 184411878SVenu.Iyer@Sun.COM * ixgbe_intr_cb_register - Register interrupt callback function. 184511878SVenu.Iyer@Sun.COM */ 184611878SVenu.Iyer@Sun.COM static int 184711878SVenu.Iyer@Sun.COM ixgbe_intr_cb_register(ixgbe_t *ixgbe) 184811878SVenu.Iyer@Sun.COM { 184911878SVenu.Iyer@Sun.COM if (ddi_cb_register(ixgbe->dip, DDI_CB_FLAG_INTR, ixgbe_cbfunc, 185011878SVenu.Iyer@Sun.COM ixgbe, NULL, &ixgbe->cb_hdl) != DDI_SUCCESS) { 185111878SVenu.Iyer@Sun.COM return (IXGBE_FAILURE); 185211878SVenu.Iyer@Sun.COM } 185311878SVenu.Iyer@Sun.COM IXGBE_DEBUGLOG_0(ixgbe, "Interrupt callback function registered."); 185411878SVenu.Iyer@Sun.COM return (IXGBE_SUCCESS); 185511878SVenu.Iyer@Sun.COM } 185611878SVenu.Iyer@Sun.COM 185711878SVenu.Iyer@Sun.COM /* 18586621Sbt150084 * ixgbe_alloc_rings - Allocate memory space for rx/tx rings. 18596621Sbt150084 */ 18606621Sbt150084 static int 18616621Sbt150084 ixgbe_alloc_rings(ixgbe_t *ixgbe) 18626621Sbt150084 { 18636621Sbt150084 /* 18646621Sbt150084 * Allocate memory space for rx rings 18656621Sbt150084 */ 18666621Sbt150084 ixgbe->rx_rings = kmem_zalloc( 18676621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings, 18686621Sbt150084 KM_NOSLEEP); 18696621Sbt150084 18706621Sbt150084 if (ixgbe->rx_rings == NULL) { 18716621Sbt150084 return (IXGBE_FAILURE); 18726621Sbt150084 } 18736621Sbt150084 18746621Sbt150084 /* 18756621Sbt150084 * Allocate memory space for tx rings 18766621Sbt150084 */ 18776621Sbt150084 ixgbe->tx_rings = kmem_zalloc( 18786621Sbt150084 sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings, 18796621Sbt150084 KM_NOSLEEP); 18806621Sbt150084 18816621Sbt150084 if (ixgbe->tx_rings == NULL) { 18826621Sbt150084 kmem_free(ixgbe->rx_rings, 18836621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 18846621Sbt150084 ixgbe->rx_rings = NULL; 18856621Sbt150084 return (IXGBE_FAILURE); 18866621Sbt150084 } 18876621Sbt150084 18888275SEric Cheng /* 18898275SEric Cheng * Allocate memory space for rx ring groups 18908275SEric Cheng */ 18918275SEric Cheng ixgbe->rx_groups = kmem_zalloc( 18928275SEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups, 18938275SEric Cheng KM_NOSLEEP); 18948275SEric Cheng 18958275SEric Cheng if (ixgbe->rx_groups == NULL) { 18968275SEric Cheng kmem_free(ixgbe->rx_rings, 18978275SEric Cheng sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 18988275SEric Cheng kmem_free(ixgbe->tx_rings, 18998275SEric Cheng sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings); 19008275SEric Cheng ixgbe->rx_rings = NULL; 19018275SEric Cheng ixgbe->tx_rings = NULL; 19028275SEric Cheng return (IXGBE_FAILURE); 19038275SEric Cheng } 19048275SEric Cheng 19056621Sbt150084 return (IXGBE_SUCCESS); 19066621Sbt150084 } 19076621Sbt150084 19086621Sbt150084 /* 19096621Sbt150084 * ixgbe_free_rings - Free the memory space of rx/tx rings. 19106621Sbt150084 */ 19116621Sbt150084 static void 19126621Sbt150084 ixgbe_free_rings(ixgbe_t *ixgbe) 19136621Sbt150084 { 19146621Sbt150084 if (ixgbe->rx_rings != NULL) { 19156621Sbt150084 kmem_free(ixgbe->rx_rings, 19166621Sbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 19176621Sbt150084 ixgbe->rx_rings = NULL; 19186621Sbt150084 } 19196621Sbt150084 19206621Sbt150084 if (ixgbe->tx_rings != NULL) { 19216621Sbt150084 kmem_free(ixgbe->tx_rings, 19226621Sbt150084 sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings); 19236621Sbt150084 ixgbe->tx_rings = NULL; 19246621Sbt150084 } 19258275SEric Cheng 19268275SEric Cheng if (ixgbe->rx_groups != NULL) { 19278275SEric Cheng kmem_free(ixgbe->rx_groups, 19288275SEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups); 19298275SEric Cheng ixgbe->rx_groups = NULL; 19308275SEric Cheng } 19316621Sbt150084 } 19326621Sbt150084 193310376SChenlu.Chen@Sun.COM static int 193410376SChenlu.Chen@Sun.COM ixgbe_alloc_rx_data(ixgbe_t *ixgbe) 193510376SChenlu.Chen@Sun.COM { 193610376SChenlu.Chen@Sun.COM ixgbe_rx_ring_t *rx_ring; 193710376SChenlu.Chen@Sun.COM int i; 193810376SChenlu.Chen@Sun.COM 193910376SChenlu.Chen@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 194010376SChenlu.Chen@Sun.COM rx_ring = &ixgbe->rx_rings[i]; 194110376SChenlu.Chen@Sun.COM if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS) 194210376SChenlu.Chen@Sun.COM goto alloc_rx_rings_failure; 194310376SChenlu.Chen@Sun.COM } 194410376SChenlu.Chen@Sun.COM return (IXGBE_SUCCESS); 194510376SChenlu.Chen@Sun.COM 194610376SChenlu.Chen@Sun.COM alloc_rx_rings_failure: 194710376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe); 194810376SChenlu.Chen@Sun.COM return (IXGBE_FAILURE); 194910376SChenlu.Chen@Sun.COM } 195010376SChenlu.Chen@Sun.COM 195110376SChenlu.Chen@Sun.COM static void 195210376SChenlu.Chen@Sun.COM ixgbe_free_rx_data(ixgbe_t *ixgbe) 195310376SChenlu.Chen@Sun.COM { 195410376SChenlu.Chen@Sun.COM ixgbe_rx_ring_t *rx_ring; 195510376SChenlu.Chen@Sun.COM ixgbe_rx_data_t *rx_data; 195610376SChenlu.Chen@Sun.COM int i; 195710376SChenlu.Chen@Sun.COM 195810376SChenlu.Chen@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 195910376SChenlu.Chen@Sun.COM rx_ring = &ixgbe->rx_rings[i]; 196010376SChenlu.Chen@Sun.COM 196110376SChenlu.Chen@Sun.COM mutex_enter(&ixgbe->rx_pending_lock); 196210376SChenlu.Chen@Sun.COM rx_data = rx_ring->rx_data; 196310376SChenlu.Chen@Sun.COM 196410376SChenlu.Chen@Sun.COM if (rx_data != NULL) { 196510376SChenlu.Chen@Sun.COM rx_data->flag |= IXGBE_RX_STOPPED; 196610376SChenlu.Chen@Sun.COM 196710376SChenlu.Chen@Sun.COM if (rx_data->rcb_pending == 0) { 196810376SChenlu.Chen@Sun.COM ixgbe_free_rx_ring_data(rx_data); 196910376SChenlu.Chen@Sun.COM rx_ring->rx_data = NULL; 197010376SChenlu.Chen@Sun.COM } 197110376SChenlu.Chen@Sun.COM } 197210376SChenlu.Chen@Sun.COM 197310376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->rx_pending_lock); 197410376SChenlu.Chen@Sun.COM } 197510376SChenlu.Chen@Sun.COM } 197610376SChenlu.Chen@Sun.COM 19776621Sbt150084 /* 19786621Sbt150084 * ixgbe_setup_rings - Setup rx/tx rings. 19796621Sbt150084 */ 19806621Sbt150084 static void 19816621Sbt150084 ixgbe_setup_rings(ixgbe_t *ixgbe) 19826621Sbt150084 { 19836621Sbt150084 /* 19846621Sbt150084 * Setup the rx/tx rings, including the following: 19856621Sbt150084 * 19866621Sbt150084 * 1. Setup the descriptor ring and the control block buffers; 19876621Sbt150084 * 2. Initialize necessary registers for receive/transmit; 19886621Sbt150084 * 3. Initialize software pointers/parameters for receive/transmit; 19896621Sbt150084 */ 19906621Sbt150084 ixgbe_setup_rx(ixgbe); 19916621Sbt150084 19926621Sbt150084 ixgbe_setup_tx(ixgbe); 19936621Sbt150084 } 19946621Sbt150084 19956621Sbt150084 static void 19966621Sbt150084 ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring) 19976621Sbt150084 { 19986621Sbt150084 ixgbe_t *ixgbe = rx_ring->ixgbe; 199910376SChenlu.Chen@Sun.COM ixgbe_rx_data_t *rx_data = rx_ring->rx_data; 20006621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 20016621Sbt150084 rx_control_block_t *rcb; 20026621Sbt150084 union ixgbe_adv_rx_desc *rbd; 20036621Sbt150084 uint32_t size; 20046621Sbt150084 uint32_t buf_low; 20056621Sbt150084 uint32_t buf_high; 20066621Sbt150084 uint32_t reg_val; 20076621Sbt150084 int i; 20086621Sbt150084 20096621Sbt150084 ASSERT(mutex_owned(&rx_ring->rx_lock)); 20106621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 20116621Sbt150084 20126621Sbt150084 for (i = 0; i < ixgbe->rx_ring_size; i++) { 201310376SChenlu.Chen@Sun.COM rcb = rx_data->work_list[i]; 201410376SChenlu.Chen@Sun.COM rbd = &rx_data->rbd_ring[i]; 20156621Sbt150084 20166621Sbt150084 rbd->read.pkt_addr = rcb->rx_buf.dma_address; 20176621Sbt150084 rbd->read.hdr_addr = NULL; 20186621Sbt150084 } 20196621Sbt150084 20206621Sbt150084 /* 20216621Sbt150084 * Initialize the length register 20226621Sbt150084 */ 202310376SChenlu.Chen@Sun.COM size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc); 202411878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->hw_index), size); 20256621Sbt150084 20266621Sbt150084 /* 20276621Sbt150084 * Initialize the base address registers 20286621Sbt150084 */ 202910376SChenlu.Chen@Sun.COM buf_low = (uint32_t)rx_data->rbd_area.dma_address; 203010376SChenlu.Chen@Sun.COM buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32); 203111878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->hw_index), buf_high); 203211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->hw_index), buf_low); 20336621Sbt150084 20346621Sbt150084 /* 20356621Sbt150084 * Setup head & tail pointers 20366621Sbt150084 */ 203711878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->hw_index), 203811878SVenu.Iyer@Sun.COM rx_data->ring_size - 1); 203911878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->hw_index), 0); 20406621Sbt150084 204110376SChenlu.Chen@Sun.COM rx_data->rbd_next = 0; 204211486SZhen.W@Sun.COM rx_data->lro_first = 0; 20436621Sbt150084 20446621Sbt150084 /* 20456621Sbt150084 * Setup the Receive Descriptor Control Register (RXDCTL) 20466621Sbt150084 * PTHRESH=32 descriptors (half the internal cache) 20476621Sbt150084 * HTHRESH=0 descriptors (to minimize latency on fetch) 20486621Sbt150084 * WTHRESH defaults to 1 (writeback each descriptor) 20496621Sbt150084 */ 205011878SVenu.Iyer@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index)); 20516621Sbt150084 reg_val |= IXGBE_RXDCTL_ENABLE; /* enable queue */ 20529353SSamuel.Tu@Sun.COM 20539353SSamuel.Tu@Sun.COM /* Not a valid value for 82599 */ 20549353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 20559353SSamuel.Tu@Sun.COM reg_val |= 0x0020; /* pthresh */ 20569353SSamuel.Tu@Sun.COM } 205711878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val); 20586621Sbt150084 20599353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 20609353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 20619353SSamuel.Tu@Sun.COM reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS); 20629353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); 20639353SSamuel.Tu@Sun.COM } 20649353SSamuel.Tu@Sun.COM 20656621Sbt150084 /* 20666621Sbt150084 * Setup the Split and Replication Receive Control Register. 20676621Sbt150084 * Set the rx buffer size and the advanced descriptor type. 20686621Sbt150084 */ 20696621Sbt150084 reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) | 20706621Sbt150084 IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 20719353SSamuel.Tu@Sun.COM reg_val |= IXGBE_SRRCTL_DROP_EN; 207211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->hw_index), reg_val); 20736621Sbt150084 } 20746621Sbt150084 20756621Sbt150084 static void 20766621Sbt150084 ixgbe_setup_rx(ixgbe_t *ixgbe) 20776621Sbt150084 { 20786621Sbt150084 ixgbe_rx_ring_t *rx_ring; 20796621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 20806621Sbt150084 uint32_t reg_val; 20818275SEric Cheng uint32_t ring_mapping; 208211878SVenu.Iyer@Sun.COM uint32_t i, index; 208311878SVenu.Iyer@Sun.COM uint32_t psrtype_rss_bit; 20846621Sbt150084 20859353SSamuel.Tu@Sun.COM /* PSRTYPE must be configured for 82599 */ 208611878SVenu.Iyer@Sun.COM if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ && 208711878SVenu.Iyer@Sun.COM ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) { 208811878SVenu.Iyer@Sun.COM reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | 208911878SVenu.Iyer@Sun.COM IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR; 209011878SVenu.Iyer@Sun.COM reg_val |= IXGBE_PSRTYPE_L2HDR; 209111878SVenu.Iyer@Sun.COM reg_val |= 0x80000000; 209211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val); 209311878SVenu.Iyer@Sun.COM } else { 209411878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups > 32) { 209511878SVenu.Iyer@Sun.COM psrtype_rss_bit = 0x20000000; 209611878SVenu.Iyer@Sun.COM } else { 209711878SVenu.Iyer@Sun.COM psrtype_rss_bit = 0x40000000; 209811878SVenu.Iyer@Sun.COM } 209911878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->capab->max_rx_grp_num; i++) { 210011878SVenu.Iyer@Sun.COM reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | 210111878SVenu.Iyer@Sun.COM IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR; 210211878SVenu.Iyer@Sun.COM reg_val |= IXGBE_PSRTYPE_L2HDR; 210311878SVenu.Iyer@Sun.COM reg_val |= psrtype_rss_bit; 210411878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val); 210511878SVenu.Iyer@Sun.COM } 210611878SVenu.Iyer@Sun.COM } 21079353SSamuel.Tu@Sun.COM 21086621Sbt150084 /* 21096621Sbt150084 * Set filter control in FCTRL to accept broadcast packets and do 21106621Sbt150084 * not pass pause frames to host. Flow control settings are already 21116621Sbt150084 * in this register, so preserve them. 21126621Sbt150084 */ 21136621Sbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL); 21146621Sbt150084 reg_val |= IXGBE_FCTRL_BAM; /* broadcast accept mode */ 21156621Sbt150084 reg_val |= IXGBE_FCTRL_DPF; /* discard pause frames */ 21166621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val); 21176621Sbt150084 21186621Sbt150084 /* 211911878SVenu.Iyer@Sun.COM * Hardware checksum settings 212011878SVenu.Iyer@Sun.COM */ 212111878SVenu.Iyer@Sun.COM if (ixgbe->rx_hcksum_enable) { 212211878SVenu.Iyer@Sun.COM reg_val = IXGBE_RXCSUM_IPPCSE; /* IP checksum */ 212311878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val); 212411878SVenu.Iyer@Sun.COM } 212511878SVenu.Iyer@Sun.COM 212611878SVenu.Iyer@Sun.COM /* 212711878SVenu.Iyer@Sun.COM * Setup VMDq and RSS for multiple receive queues 212811878SVenu.Iyer@Sun.COM */ 212911878SVenu.Iyer@Sun.COM switch (ixgbe->classify_mode) { 213011878SVenu.Iyer@Sun.COM case IXGBE_CLASSIFY_RSS: 213111878SVenu.Iyer@Sun.COM /* 213211878SVenu.Iyer@Sun.COM * One group, only RSS is needed when more than 213311878SVenu.Iyer@Sun.COM * one ring enabled. 213411878SVenu.Iyer@Sun.COM */ 213511878SVenu.Iyer@Sun.COM ixgbe_setup_rss(ixgbe); 213611878SVenu.Iyer@Sun.COM break; 213711878SVenu.Iyer@Sun.COM 213811878SVenu.Iyer@Sun.COM case IXGBE_CLASSIFY_VMDQ: 213911878SVenu.Iyer@Sun.COM /* 214011878SVenu.Iyer@Sun.COM * Multiple groups, each group has one ring, 214111878SVenu.Iyer@Sun.COM * only VMDq is needed. 214211878SVenu.Iyer@Sun.COM */ 214311878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq(ixgbe); 214411878SVenu.Iyer@Sun.COM break; 214511878SVenu.Iyer@Sun.COM 214611878SVenu.Iyer@Sun.COM case IXGBE_CLASSIFY_VMDQ_RSS: 214711878SVenu.Iyer@Sun.COM /* 214811878SVenu.Iyer@Sun.COM * Multiple groups and multiple rings, both 214911878SVenu.Iyer@Sun.COM * VMDq and RSS are needed. 215011878SVenu.Iyer@Sun.COM */ 215111878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss(ixgbe); 215211878SVenu.Iyer@Sun.COM break; 215311878SVenu.Iyer@Sun.COM 215411878SVenu.Iyer@Sun.COM default: 215511878SVenu.Iyer@Sun.COM break; 215611878SVenu.Iyer@Sun.COM } 215711878SVenu.Iyer@Sun.COM 215811878SVenu.Iyer@Sun.COM /* 21596621Sbt150084 * Enable the receive unit. This must be done after filter 21606621Sbt150084 * control is set in FCTRL. 21616621Sbt150084 */ 21626621Sbt150084 reg_val = (IXGBE_RXCTRL_RXEN /* Enable Receive Unit */ 21636621Sbt150084 | IXGBE_RXCTRL_DMBYPS); /* descriptor monitor bypass */ 21646621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); 21656621Sbt150084 21666621Sbt150084 /* 21676621Sbt150084 * ixgbe_setup_rx_ring must be called after configuring RXCTRL 21686621Sbt150084 */ 21696621Sbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 21706621Sbt150084 rx_ring = &ixgbe->rx_rings[i]; 21716621Sbt150084 ixgbe_setup_rx_ring(rx_ring); 21726621Sbt150084 } 21736621Sbt150084 21746621Sbt150084 /* 21758275SEric Cheng * Setup the per-ring statistics mapping. 21768275SEric Cheng */ 21778275SEric Cheng ring_mapping = 0; 21788275SEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) { 217911878SVenu.Iyer@Sun.COM index = ixgbe->rx_rings[i].hw_index; 218011878SVenu.Iyer@Sun.COM ring_mapping = IXGBE_READ_REG(hw, IXGBE_RQSMR(index >> 2)); 218111878SVenu.Iyer@Sun.COM ring_mapping |= (i & 0xF) << (8 * (index & 0x3)); 218211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RQSMR(index >> 2), ring_mapping); 218311878SVenu.Iyer@Sun.COM } 21848275SEric Cheng 21858275SEric Cheng /* 21869353SSamuel.Tu@Sun.COM * The Max Frame Size in MHADD/MAXFRS will be internally increased 21879353SSamuel.Tu@Sun.COM * by four bytes if the packet has a VLAN field, so includes MTU, 21889353SSamuel.Tu@Sun.COM * ethernet header and frame check sequence. 21899353SSamuel.Tu@Sun.COM * Register is MAXFRS in 82599. 21906621Sbt150084 */ 21916621Sbt150084 reg_val = (ixgbe->default_mtu + sizeof (struct ether_header) 21926621Sbt150084 + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT; 21936621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val); 21946621Sbt150084 21956621Sbt150084 /* 21966621Sbt150084 * Setup Jumbo Frame enable bit 21976621Sbt150084 */ 21986621Sbt150084 if (ixgbe->default_mtu > ETHERMTU) { 21996621Sbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); 22006621Sbt150084 reg_val |= IXGBE_HLREG0_JUMBOEN; 22016621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); 22026621Sbt150084 } 2203*11891SVenu.Iyer@Sun.COM 2204*11891SVenu.Iyer@Sun.COM /* 2205*11891SVenu.Iyer@Sun.COM * Setup RSC for multiple receive queues. 2206*11891SVenu.Iyer@Sun.COM */ 2207*11891SVenu.Iyer@Sun.COM if (ixgbe->lro_enable) { 2208*11891SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 2209*11891SVenu.Iyer@Sun.COM /* 2210*11891SVenu.Iyer@Sun.COM * Make sure rx_buf_size * MAXDESC not greater 2211*11891SVenu.Iyer@Sun.COM * than 65535. 2212*11891SVenu.Iyer@Sun.COM * Intel recommends 4 for MAXDESC field value. 2213*11891SVenu.Iyer@Sun.COM */ 2214*11891SVenu.Iyer@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RSCCTL(i)); 2215*11891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RSCCTL_RSCEN; 2216*11891SVenu.Iyer@Sun.COM if (ixgbe->rx_buf_size == IXGBE_PKG_BUF_16k) 2217*11891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RSCCTL_MAXDESC_1; 2218*11891SVenu.Iyer@Sun.COM else 2219*11891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RSCCTL_MAXDESC_4; 2220*11891SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(i), reg_val); 2221*11891SVenu.Iyer@Sun.COM } 2222*11891SVenu.Iyer@Sun.COM 2223*11891SVenu.Iyer@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RSCDBU); 2224*11891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RSCDBU_RSCACKDIS; 2225*11891SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, reg_val); 2226*11891SVenu.Iyer@Sun.COM 2227*11891SVenu.Iyer@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 2228*11891SVenu.Iyer@Sun.COM reg_val |= IXGBE_RDRXCTL_RSCACKC; 2229*11891SVenu.Iyer@Sun.COM reg_val &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; 2230*11891SVenu.Iyer@Sun.COM 2231*11891SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); 2232*11891SVenu.Iyer@Sun.COM } 22336621Sbt150084 } 22346621Sbt150084 22356621Sbt150084 static void 22366621Sbt150084 ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring) 22376621Sbt150084 { 22386621Sbt150084 ixgbe_t *ixgbe = tx_ring->ixgbe; 22396621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 22406621Sbt150084 uint32_t size; 22416621Sbt150084 uint32_t buf_low; 22426621Sbt150084 uint32_t buf_high; 22436621Sbt150084 uint32_t reg_val; 22446621Sbt150084 22456621Sbt150084 ASSERT(mutex_owned(&tx_ring->tx_lock)); 22466621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 22476621Sbt150084 22486621Sbt150084 /* 22496621Sbt150084 * Initialize the length register 22506621Sbt150084 */ 22516621Sbt150084 size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc); 22526621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size); 22536621Sbt150084 22546621Sbt150084 /* 22556621Sbt150084 * Initialize the base address registers 22566621Sbt150084 */ 22576621Sbt150084 buf_low = (uint32_t)tx_ring->tbd_area.dma_address; 22586621Sbt150084 buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32); 22596621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low); 22606621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high); 22616621Sbt150084 22626621Sbt150084 /* 22636621Sbt150084 * Setup head & tail pointers 22646621Sbt150084 */ 22656621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0); 22666621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0); 22676621Sbt150084 22686621Sbt150084 /* 22696621Sbt150084 * Setup head write-back 22706621Sbt150084 */ 22716621Sbt150084 if (ixgbe->tx_head_wb_enable) { 22726621Sbt150084 /* 22736621Sbt150084 * The memory of the head write-back is allocated using 22746621Sbt150084 * the extra tbd beyond the tail of the tbd ring. 22756621Sbt150084 */ 22766621Sbt150084 tx_ring->tbd_head_wb = (uint32_t *) 22776621Sbt150084 ((uintptr_t)tx_ring->tbd_area.address + size); 22786621Sbt150084 *tx_ring->tbd_head_wb = 0; 22796621Sbt150084 22806621Sbt150084 buf_low = (uint32_t) 22816621Sbt150084 (tx_ring->tbd_area.dma_address + size); 22826621Sbt150084 buf_high = (uint32_t) 22836621Sbt150084 ((tx_ring->tbd_area.dma_address + size) >> 32); 22846621Sbt150084 22856621Sbt150084 /* Set the head write-back enable bit */ 22866621Sbt150084 buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE; 22876621Sbt150084 22886621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low); 22896621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high); 22906621Sbt150084 22916621Sbt150084 /* 22926621Sbt150084 * Turn off relaxed ordering for head write back or it will 22936621Sbt150084 * cause problems with the tx recycling 22946621Sbt150084 */ 22956621Sbt150084 reg_val = IXGBE_READ_REG(hw, 22966621Sbt150084 IXGBE_DCA_TXCTRL(tx_ring->index)); 22976621Sbt150084 reg_val &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; 22986621Sbt150084 IXGBE_WRITE_REG(hw, 22996621Sbt150084 IXGBE_DCA_TXCTRL(tx_ring->index), reg_val); 23006621Sbt150084 } else { 23016621Sbt150084 tx_ring->tbd_head_wb = NULL; 23026621Sbt150084 } 23036621Sbt150084 23046621Sbt150084 tx_ring->tbd_head = 0; 23056621Sbt150084 tx_ring->tbd_tail = 0; 23066621Sbt150084 tx_ring->tbd_free = tx_ring->ring_size; 23076621Sbt150084 230810376SChenlu.Chen@Sun.COM if (ixgbe->tx_ring_init == B_TRUE) { 23096621Sbt150084 tx_ring->tcb_head = 0; 23106621Sbt150084 tx_ring->tcb_tail = 0; 23116621Sbt150084 tx_ring->tcb_free = tx_ring->free_list_size; 23126621Sbt150084 } 23136621Sbt150084 23146621Sbt150084 /* 23157245Sgg161487 * Initialize the s/w context structure 23166621Sbt150084 */ 23177245Sgg161487 bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t)); 23186621Sbt150084 } 23196621Sbt150084 23206621Sbt150084 static void 23216621Sbt150084 ixgbe_setup_tx(ixgbe_t *ixgbe) 23226621Sbt150084 { 23237167Sgg161487 struct ixgbe_hw *hw = &ixgbe->hw; 23246621Sbt150084 ixgbe_tx_ring_t *tx_ring; 23257167Sgg161487 uint32_t reg_val; 23268275SEric Cheng uint32_t ring_mapping; 23276621Sbt150084 int i; 23286621Sbt150084 23296621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 23306621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 23316621Sbt150084 ixgbe_setup_tx_ring(tx_ring); 23326621Sbt150084 } 23337167Sgg161487 23347167Sgg161487 /* 23358275SEric Cheng * Setup the per-ring statistics mapping. 23368275SEric Cheng */ 23378275SEric Cheng ring_mapping = 0; 23388275SEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) { 23398275SEric Cheng ring_mapping |= (i & 0xF) << (8 * (i & 0x3)); 23408275SEric Cheng if ((i & 0x3) == 0x3) { 23419353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 23429353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), 23439353SSamuel.Tu@Sun.COM ring_mapping); 23449353SSamuel.Tu@Sun.COM } else { 23459353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), 23469353SSamuel.Tu@Sun.COM ring_mapping); 23479353SSamuel.Tu@Sun.COM } 23488275SEric Cheng ring_mapping = 0; 23498275SEric Cheng } 23508275SEric Cheng } 23518275SEric Cheng if ((i & 0x3) != 0x3) 23529353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 23539353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping); 23549353SSamuel.Tu@Sun.COM } else { 23559353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping); 23569353SSamuel.Tu@Sun.COM } 23578275SEric Cheng 23588275SEric Cheng /* 23597167Sgg161487 * Enable CRC appending and TX padding (for short tx frames) 23607167Sgg161487 */ 23617167Sgg161487 reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); 23627167Sgg161487 reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN; 23637167Sgg161487 IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); 23649353SSamuel.Tu@Sun.COM 23659353SSamuel.Tu@Sun.COM /* 23669353SSamuel.Tu@Sun.COM * enable DMA for 82599 parts 23679353SSamuel.Tu@Sun.COM */ 23689353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 23699353SSamuel.Tu@Sun.COM /* DMATXCTL.TE must be set after all Tx config is complete */ 23709353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 23719353SSamuel.Tu@Sun.COM reg_val |= IXGBE_DMATXCTL_TE; 23729353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val); 23739353SSamuel.Tu@Sun.COM } 23749353SSamuel.Tu@Sun.COM 23759353SSamuel.Tu@Sun.COM /* 23769353SSamuel.Tu@Sun.COM * Enabling tx queues .. 23779353SSamuel.Tu@Sun.COM * For 82599 must be done after DMATXCTL.TE is set 23789353SSamuel.Tu@Sun.COM */ 23799353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->num_tx_rings; i++) { 23809353SSamuel.Tu@Sun.COM tx_ring = &ixgbe->tx_rings[i]; 23819353SSamuel.Tu@Sun.COM reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index)); 23829353SSamuel.Tu@Sun.COM reg_val |= IXGBE_TXDCTL_ENABLE; 23839353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val); 23849353SSamuel.Tu@Sun.COM } 23856621Sbt150084 } 23866621Sbt150084 23876621Sbt150084 /* 23886621Sbt150084 * ixgbe_setup_rss - Setup receive-side scaling feature. 23896621Sbt150084 */ 23906621Sbt150084 static void 23916621Sbt150084 ixgbe_setup_rss(ixgbe_t *ixgbe) 23926621Sbt150084 { 23936621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 23947167Sgg161487 uint32_t i, mrqc, rxcsum; 23956621Sbt150084 uint32_t random; 23966621Sbt150084 uint32_t reta; 239711878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 23986621Sbt150084 23996621Sbt150084 /* 24006621Sbt150084 * Fill out redirection table 24016621Sbt150084 */ 24026621Sbt150084 reta = 0; 240311878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 240411878SVenu.Iyer@Sun.COM 24056621Sbt150084 for (i = 0; i < 128; i++) { 240611878SVenu.Iyer@Sun.COM reta = (reta << 8) | (i % ring_per_group) | 240711878SVenu.Iyer@Sun.COM ((i % ring_per_group) << 4); 24087167Sgg161487 if ((i & 3) == 3) 24096621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 24106621Sbt150084 } 24116621Sbt150084 24126621Sbt150084 /* 24136621Sbt150084 * Fill out hash function seeds with a random constant 24146621Sbt150084 */ 24156621Sbt150084 for (i = 0; i < 10; i++) { 24166621Sbt150084 (void) random_get_pseudo_bytes((uint8_t *)&random, 24176621Sbt150084 sizeof (uint32_t)); 24186621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); 24196621Sbt150084 } 24206621Sbt150084 24216621Sbt150084 /* 24227167Sgg161487 * Enable RSS & perform hash on these packet types 24236621Sbt150084 */ 24246621Sbt150084 mrqc = IXGBE_MRQC_RSSEN | 24256621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4 | 24266621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 24276621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 24286621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 24296621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX | 24306621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6 | 24316621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 24326621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 24336621Sbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 24346621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 24356621Sbt150084 24366621Sbt150084 /* 24376621Sbt150084 * Disable Packet Checksum to enable RSS for multiple receive queues. 24386621Sbt150084 * It is an adapter hardware limitation that Packet Checksum is 24396621Sbt150084 * mutually exclusive with RSS. 24406621Sbt150084 */ 24416621Sbt150084 rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 24426621Sbt150084 rxcsum |= IXGBE_RXCSUM_PCSD; 24436621Sbt150084 rxcsum &= ~IXGBE_RXCSUM_IPPCSE; 24446621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 24456621Sbt150084 } 24466621Sbt150084 24476621Sbt150084 /* 244811878SVenu.Iyer@Sun.COM * ixgbe_setup_vmdq - Setup MAC classification feature 244911878SVenu.Iyer@Sun.COM */ 245011878SVenu.Iyer@Sun.COM static void 245111878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq(ixgbe_t *ixgbe) 245211878SVenu.Iyer@Sun.COM { 245311878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 245411878SVenu.Iyer@Sun.COM uint32_t vmdctl, i, vtctl; 245511878SVenu.Iyer@Sun.COM 245611878SVenu.Iyer@Sun.COM /* 245711878SVenu.Iyer@Sun.COM * Setup the VMDq Control register, enable VMDq based on 245811878SVenu.Iyer@Sun.COM * packet destination MAC address: 245911878SVenu.Iyer@Sun.COM */ 246011878SVenu.Iyer@Sun.COM switch (hw->mac.type) { 246111878SVenu.Iyer@Sun.COM case ixgbe_mac_82598EB: 246211878SVenu.Iyer@Sun.COM /* 246311878SVenu.Iyer@Sun.COM * VMDq Enable = 1; 246411878SVenu.Iyer@Sun.COM * VMDq Filter = 0; MAC filtering 246511878SVenu.Iyer@Sun.COM * Default VMDq output index = 0; 246611878SVenu.Iyer@Sun.COM */ 246711878SVenu.Iyer@Sun.COM vmdctl = IXGBE_VMD_CTL_VMDQ_EN; 246811878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl); 246911878SVenu.Iyer@Sun.COM break; 247011878SVenu.Iyer@Sun.COM 247111878SVenu.Iyer@Sun.COM case ixgbe_mac_82599EB: 247211878SVenu.Iyer@Sun.COM /* 247311878SVenu.Iyer@Sun.COM * Enable VMDq-only. 247411878SVenu.Iyer@Sun.COM */ 247511878SVenu.Iyer@Sun.COM vmdctl = IXGBE_MRQC_VMDQEN; 247611878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl); 247711878SVenu.Iyer@Sun.COM 247811878SVenu.Iyer@Sun.COM for (i = 0; i < hw->mac.num_rar_entries; i++) { 247911878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0); 248011878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0); 248111878SVenu.Iyer@Sun.COM } 248211878SVenu.Iyer@Sun.COM 248311878SVenu.Iyer@Sun.COM /* 248411878SVenu.Iyer@Sun.COM * Enable Virtualization and Replication. 248511878SVenu.Iyer@Sun.COM */ 248611878SVenu.Iyer@Sun.COM vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 248711878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl); 248811878SVenu.Iyer@Sun.COM 248911878SVenu.Iyer@Sun.COM /* 249011878SVenu.Iyer@Sun.COM * Enable receiving packets to all VFs 249111878SVenu.Iyer@Sun.COM */ 249211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL); 249311878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL); 249411878SVenu.Iyer@Sun.COM 249511878SVenu.Iyer@Sun.COM break; 249611878SVenu.Iyer@Sun.COM 249711878SVenu.Iyer@Sun.COM default: 249811878SVenu.Iyer@Sun.COM break; 249911878SVenu.Iyer@Sun.COM } 250011878SVenu.Iyer@Sun.COM } 250111878SVenu.Iyer@Sun.COM 250211878SVenu.Iyer@Sun.COM /* 250311878SVenu.Iyer@Sun.COM * ixgbe_setup_vmdq_rss - Setup both vmdq feature and rss feature. 250411878SVenu.Iyer@Sun.COM */ 250511878SVenu.Iyer@Sun.COM static void 250611878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe) 250711878SVenu.Iyer@Sun.COM { 250811878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 250911878SVenu.Iyer@Sun.COM uint32_t i, mrqc, rxcsum; 251011878SVenu.Iyer@Sun.COM uint32_t random; 251111878SVenu.Iyer@Sun.COM uint32_t reta; 251211878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 251311878SVenu.Iyer@Sun.COM uint32_t vmdctl, vtctl; 251411878SVenu.Iyer@Sun.COM 251511878SVenu.Iyer@Sun.COM /* 251611878SVenu.Iyer@Sun.COM * Fill out redirection table 251711878SVenu.Iyer@Sun.COM */ 251811878SVenu.Iyer@Sun.COM reta = 0; 251911878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 252011878SVenu.Iyer@Sun.COM for (i = 0; i < 128; i++) { 252111878SVenu.Iyer@Sun.COM reta = (reta << 8) | (i % ring_per_group) | 252211878SVenu.Iyer@Sun.COM ((i % ring_per_group) << 4); 252311878SVenu.Iyer@Sun.COM if ((i & 3) == 3) 252411878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 252511878SVenu.Iyer@Sun.COM } 252611878SVenu.Iyer@Sun.COM 252711878SVenu.Iyer@Sun.COM /* 252811878SVenu.Iyer@Sun.COM * Fill out hash function seeds with a random constant 252911878SVenu.Iyer@Sun.COM */ 253011878SVenu.Iyer@Sun.COM for (i = 0; i < 10; i++) { 253111878SVenu.Iyer@Sun.COM (void) random_get_pseudo_bytes((uint8_t *)&random, 253211878SVenu.Iyer@Sun.COM sizeof (uint32_t)); 253311878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); 253411878SVenu.Iyer@Sun.COM } 253511878SVenu.Iyer@Sun.COM 253611878SVenu.Iyer@Sun.COM /* 253711878SVenu.Iyer@Sun.COM * Enable and setup RSS and VMDq 253811878SVenu.Iyer@Sun.COM */ 253911878SVenu.Iyer@Sun.COM switch (hw->mac.type) { 254011878SVenu.Iyer@Sun.COM case ixgbe_mac_82598EB: 254111878SVenu.Iyer@Sun.COM /* 254211878SVenu.Iyer@Sun.COM * Enable RSS & Setup RSS Hash functions 254311878SVenu.Iyer@Sun.COM */ 254411878SVenu.Iyer@Sun.COM mrqc = IXGBE_MRQC_RSSEN | 254511878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4 | 254611878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 254711878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 254811878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 254911878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX | 255011878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6 | 255111878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 255211878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 255311878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 255411878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 255511878SVenu.Iyer@Sun.COM 255611878SVenu.Iyer@Sun.COM /* 255711878SVenu.Iyer@Sun.COM * Enable and Setup VMDq 255811878SVenu.Iyer@Sun.COM * VMDq Filter = 0; MAC filtering 255911878SVenu.Iyer@Sun.COM * Default VMDq output index = 0; 256011878SVenu.Iyer@Sun.COM */ 256111878SVenu.Iyer@Sun.COM vmdctl = IXGBE_VMD_CTL_VMDQ_EN; 256211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl); 256311878SVenu.Iyer@Sun.COM break; 256411878SVenu.Iyer@Sun.COM 256511878SVenu.Iyer@Sun.COM case ixgbe_mac_82599EB: 256611878SVenu.Iyer@Sun.COM /* 256711878SVenu.Iyer@Sun.COM * Enable RSS & Setup RSS Hash functions 256811878SVenu.Iyer@Sun.COM */ 256911878SVenu.Iyer@Sun.COM mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 | 257011878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 257111878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 257211878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 257311878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX | 257411878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6 | 257511878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 257611878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 257711878SVenu.Iyer@Sun.COM IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 257811878SVenu.Iyer@Sun.COM 257911878SVenu.Iyer@Sun.COM /* 258011878SVenu.Iyer@Sun.COM * Enable VMDq+RSS. 258111878SVenu.Iyer@Sun.COM */ 258211878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups > 32) { 258311878SVenu.Iyer@Sun.COM mrqc = mrqc | IXGBE_MRQC_VMDQRSS64EN; 258411878SVenu.Iyer@Sun.COM } else { 258511878SVenu.Iyer@Sun.COM mrqc = mrqc | IXGBE_MRQC_VMDQRSS32EN; 258611878SVenu.Iyer@Sun.COM } 258711878SVenu.Iyer@Sun.COM 258811878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 258911878SVenu.Iyer@Sun.COM 259011878SVenu.Iyer@Sun.COM for (i = 0; i < hw->mac.num_rar_entries; i++) { 259111878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0); 259211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0); 259311878SVenu.Iyer@Sun.COM } 259411878SVenu.Iyer@Sun.COM break; 259511878SVenu.Iyer@Sun.COM 259611878SVenu.Iyer@Sun.COM default: 259711878SVenu.Iyer@Sun.COM break; 259811878SVenu.Iyer@Sun.COM 259911878SVenu.Iyer@Sun.COM } 260011878SVenu.Iyer@Sun.COM 260111878SVenu.Iyer@Sun.COM /* 260211878SVenu.Iyer@Sun.COM * Disable Packet Checksum to enable RSS for multiple receive queues. 260311878SVenu.Iyer@Sun.COM * It is an adapter hardware limitation that Packet Checksum is 260411878SVenu.Iyer@Sun.COM * mutually exclusive with RSS. 260511878SVenu.Iyer@Sun.COM */ 260611878SVenu.Iyer@Sun.COM rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 260711878SVenu.Iyer@Sun.COM rxcsum |= IXGBE_RXCSUM_PCSD; 260811878SVenu.Iyer@Sun.COM rxcsum &= ~IXGBE_RXCSUM_IPPCSE; 260911878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 261011878SVenu.Iyer@Sun.COM 261111878SVenu.Iyer@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 261211878SVenu.Iyer@Sun.COM /* 261311878SVenu.Iyer@Sun.COM * Enable Virtualization and Replication. 261411878SVenu.Iyer@Sun.COM */ 261511878SVenu.Iyer@Sun.COM vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 261611878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl); 261711878SVenu.Iyer@Sun.COM 261811878SVenu.Iyer@Sun.COM /* 261911878SVenu.Iyer@Sun.COM * Enable receiving packets to all VFs 262011878SVenu.Iyer@Sun.COM */ 262111878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL); 262211878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL); 262311878SVenu.Iyer@Sun.COM } 262411878SVenu.Iyer@Sun.COM } 262511878SVenu.Iyer@Sun.COM 262611878SVenu.Iyer@Sun.COM /* 26276621Sbt150084 * ixgbe_init_unicst - Initialize the unicast addresses. 26286621Sbt150084 */ 26296621Sbt150084 static void 26306621Sbt150084 ixgbe_init_unicst(ixgbe_t *ixgbe) 26316621Sbt150084 { 26326621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 26338275SEric Cheng uint8_t *mac_addr; 26346621Sbt150084 int slot; 26356621Sbt150084 /* 26366621Sbt150084 * Here we should consider two situations: 26376621Sbt150084 * 26388275SEric Cheng * 1. Chipset is initialized at the first time, 26398275SEric Cheng * Clear all the multiple unicast addresses. 26406621Sbt150084 * 26416621Sbt150084 * 2. Chipset is reset 26426621Sbt150084 * Recover the multiple unicast addresses from the 26436621Sbt150084 * software data structure to the RAR registers. 26446621Sbt150084 */ 26456621Sbt150084 if (!ixgbe->unicst_init) { 26466621Sbt150084 /* 26476621Sbt150084 * Initialize the multiple unicast addresses 26486621Sbt150084 */ 264911878SVenu.Iyer@Sun.COM ixgbe->unicst_total = hw->mac.num_rar_entries; 26508275SEric Cheng ixgbe->unicst_avail = ixgbe->unicst_total; 26518275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 26528275SEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr; 26538275SEric Cheng bzero(mac_addr, ETHERADDRL); 26548275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, NULL, NULL); 26556621Sbt150084 ixgbe->unicst_addr[slot].mac.set = 0; 26568275SEric Cheng } 26576621Sbt150084 ixgbe->unicst_init = B_TRUE; 26586621Sbt150084 } else { 26596621Sbt150084 /* Re-configure the RAR registers */ 26608275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 26618275SEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr; 26628275SEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 1) { 26638275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, 266411878SVenu.Iyer@Sun.COM ixgbe->unicst_addr[slot].mac.group_index, 266511878SVenu.Iyer@Sun.COM IXGBE_RAH_AV); 26668275SEric Cheng } else { 26678275SEric Cheng bzero(mac_addr, ETHERADDRL); 26688275SEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, 26698275SEric Cheng NULL, NULL); 26708275SEric Cheng } 26718275SEric Cheng } 26726621Sbt150084 } 26736621Sbt150084 } 26748275SEric Cheng 26756621Sbt150084 /* 26768275SEric Cheng * ixgbe_unicst_find - Find the slot for the specified unicast address 26778275SEric Cheng */ 26788275SEric Cheng int 26798275SEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr) 26808275SEric Cheng { 26818275SEric Cheng int slot; 26828275SEric Cheng 26838275SEric Cheng ASSERT(mutex_owned(&ixgbe->gen_lock)); 26848275SEric Cheng 26858275SEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 26868275SEric Cheng if (bcmp(ixgbe->unicst_addr[slot].mac.addr, 26878275SEric Cheng mac_addr, ETHERADDRL) == 0) 26888275SEric Cheng return (slot); 26898275SEric Cheng } 26908275SEric Cheng 26918275SEric Cheng return (-1); 26928275SEric Cheng } 26938275SEric Cheng 26948275SEric Cheng /* 26956621Sbt150084 * ixgbe_multicst_add - Add a multicst address. 26966621Sbt150084 */ 26976621Sbt150084 int 26986621Sbt150084 ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr) 26996621Sbt150084 { 27006621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 27016621Sbt150084 27026621Sbt150084 if ((multiaddr[0] & 01) == 0) { 27036621Sbt150084 return (EINVAL); 27046621Sbt150084 } 27056621Sbt150084 27066621Sbt150084 if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) { 27076621Sbt150084 return (ENOENT); 27086621Sbt150084 } 27096621Sbt150084 27106621Sbt150084 bcopy(multiaddr, 27116621Sbt150084 &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL); 27126621Sbt150084 ixgbe->mcast_count++; 27136621Sbt150084 27146621Sbt150084 /* 27156621Sbt150084 * Update the multicast table in the hardware 27166621Sbt150084 */ 27176621Sbt150084 ixgbe_setup_multicst(ixgbe); 27186621Sbt150084 27196621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 27206621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 27216621Sbt150084 return (EIO); 27226621Sbt150084 } 27236621Sbt150084 27246621Sbt150084 return (0); 27256621Sbt150084 } 27266621Sbt150084 27276621Sbt150084 /* 27286621Sbt150084 * ixgbe_multicst_remove - Remove a multicst address. 27296621Sbt150084 */ 27306621Sbt150084 int 27316621Sbt150084 ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr) 27326621Sbt150084 { 27336621Sbt150084 int i; 27346621Sbt150084 27356621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 27366621Sbt150084 27376621Sbt150084 for (i = 0; i < ixgbe->mcast_count; i++) { 27386621Sbt150084 if (bcmp(multiaddr, &ixgbe->mcast_table[i], 27396621Sbt150084 ETHERADDRL) == 0) { 27406621Sbt150084 for (i++; i < ixgbe->mcast_count; i++) { 27416621Sbt150084 ixgbe->mcast_table[i - 1] = 27426621Sbt150084 ixgbe->mcast_table[i]; 27436621Sbt150084 } 27446621Sbt150084 ixgbe->mcast_count--; 27456621Sbt150084 break; 27466621Sbt150084 } 27476621Sbt150084 } 27486621Sbt150084 27496621Sbt150084 /* 27506621Sbt150084 * Update the multicast table in the hardware 27516621Sbt150084 */ 27526621Sbt150084 ixgbe_setup_multicst(ixgbe); 27536621Sbt150084 27546621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 27556621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 27566621Sbt150084 return (EIO); 27576621Sbt150084 } 27586621Sbt150084 27596621Sbt150084 return (0); 27606621Sbt150084 } 27616621Sbt150084 27626621Sbt150084 /* 27636621Sbt150084 * ixgbe_setup_multicast - Setup multicast data structures. 27646621Sbt150084 * 27656621Sbt150084 * This routine initializes all of the multicast related structures 27666621Sbt150084 * and save them in the hardware registers. 27676621Sbt150084 */ 27686621Sbt150084 static void 27696621Sbt150084 ixgbe_setup_multicst(ixgbe_t *ixgbe) 27706621Sbt150084 { 27716621Sbt150084 uint8_t *mc_addr_list; 27726621Sbt150084 uint32_t mc_addr_count; 27736621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 27746621Sbt150084 27756621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 27766621Sbt150084 27776621Sbt150084 ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES); 27786621Sbt150084 27796621Sbt150084 mc_addr_list = (uint8_t *)ixgbe->mcast_table; 27806621Sbt150084 mc_addr_count = ixgbe->mcast_count; 27816621Sbt150084 27826621Sbt150084 /* 27836621Sbt150084 * Update the multicast addresses to the MTA registers 27846621Sbt150084 */ 27856621Sbt150084 (void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count, 27866621Sbt150084 ixgbe_mc_table_itr); 27876621Sbt150084 } 27886621Sbt150084 27896621Sbt150084 /* 279011878SVenu.Iyer@Sun.COM * ixgbe_setup_vmdq_rss_conf - Configure vmdq and rss (number and mode). 279111878SVenu.Iyer@Sun.COM * 279211878SVenu.Iyer@Sun.COM * Configure the rx classification mode (vmdq & rss) and vmdq & rss numbers. 279311878SVenu.Iyer@Sun.COM * Different chipsets may have different allowed configuration of vmdq and rss. 279411878SVenu.Iyer@Sun.COM */ 279511878SVenu.Iyer@Sun.COM static void 279611878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe) 279711878SVenu.Iyer@Sun.COM { 279811878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 279911878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 280011878SVenu.Iyer@Sun.COM 280111878SVenu.Iyer@Sun.COM switch (hw->mac.type) { 280211878SVenu.Iyer@Sun.COM case ixgbe_mac_82598EB: 280311878SVenu.Iyer@Sun.COM /* 280411878SVenu.Iyer@Sun.COM * 82598 supports the following combination: 280511878SVenu.Iyer@Sun.COM * vmdq no. x rss no. 280611878SVenu.Iyer@Sun.COM * [5..16] x 1 280711878SVenu.Iyer@Sun.COM * [1..4] x [1..16] 280811878SVenu.Iyer@Sun.COM * However 8 rss queue per pool (vmdq) is sufficient for 280911878SVenu.Iyer@Sun.COM * most cases. 281011878SVenu.Iyer@Sun.COM */ 281111878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 281211878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups > 4) { 281311878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups; 281411878SVenu.Iyer@Sun.COM } else { 281511878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 281611878SVenu.Iyer@Sun.COM min(8, ring_per_group); 281711878SVenu.Iyer@Sun.COM } 281811878SVenu.Iyer@Sun.COM 281911878SVenu.Iyer@Sun.COM break; 282011878SVenu.Iyer@Sun.COM 282111878SVenu.Iyer@Sun.COM case ixgbe_mac_82599EB: 282211878SVenu.Iyer@Sun.COM /* 282311878SVenu.Iyer@Sun.COM * 82599 supports the following combination: 282411878SVenu.Iyer@Sun.COM * vmdq no. x rss no. 282511878SVenu.Iyer@Sun.COM * [33..64] x [1..2] 282611878SVenu.Iyer@Sun.COM * [2..32] x [1..4] 282711878SVenu.Iyer@Sun.COM * 1 x [1..16] 282811878SVenu.Iyer@Sun.COM * However 8 rss queue per pool (vmdq) is sufficient for 282911878SVenu.Iyer@Sun.COM * most cases. 283011878SVenu.Iyer@Sun.COM */ 283111878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 283211878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups == 1) { 283311878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = min(8, ring_per_group); 283411878SVenu.Iyer@Sun.COM } else if (ixgbe->num_rx_groups <= 32) { 283511878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 283611878SVenu.Iyer@Sun.COM min(4, ring_per_group); 283711878SVenu.Iyer@Sun.COM } else if (ixgbe->num_rx_groups <= 64) { 283811878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 283911878SVenu.Iyer@Sun.COM min(2, ring_per_group); 284011878SVenu.Iyer@Sun.COM } 284111878SVenu.Iyer@Sun.COM 284211878SVenu.Iyer@Sun.COM break; 284311878SVenu.Iyer@Sun.COM 284411878SVenu.Iyer@Sun.COM default: 284511878SVenu.Iyer@Sun.COM break; 284611878SVenu.Iyer@Sun.COM } 284711878SVenu.Iyer@Sun.COM 284811878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 284911878SVenu.Iyer@Sun.COM 285011878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups == 1 && ring_per_group == 1) { 285111878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 285211878SVenu.Iyer@Sun.COM } else if (ixgbe->num_rx_groups != 1 && ring_per_group == 1) { 285311878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ; 285411878SVenu.Iyer@Sun.COM } else if (ixgbe->num_rx_groups != 1 && ring_per_group != 1) { 285511878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ_RSS; 285611878SVenu.Iyer@Sun.COM } else { 285711878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_RSS; 285811878SVenu.Iyer@Sun.COM } 285911878SVenu.Iyer@Sun.COM 286011878SVenu.Iyer@Sun.COM ixgbe_log(ixgbe, "rx group number:%d, rx ring number:%d", 286111878SVenu.Iyer@Sun.COM ixgbe->num_rx_groups, ixgbe->num_rx_rings); 286211878SVenu.Iyer@Sun.COM } 286311878SVenu.Iyer@Sun.COM 286411878SVenu.Iyer@Sun.COM /* 28656621Sbt150084 * ixgbe_get_conf - Get driver configurations set in driver.conf. 28666621Sbt150084 * 28676621Sbt150084 * This routine gets user-configured values out of the configuration 28686621Sbt150084 * file ixgbe.conf. 28696621Sbt150084 * 28706621Sbt150084 * For each configurable value, there is a minimum, a maximum, and a 28716621Sbt150084 * default. 28726621Sbt150084 * If user does not configure a value, use the default. 28736621Sbt150084 * If user configures below the minimum, use the minumum. 28746621Sbt150084 * If user configures above the maximum, use the maxumum. 28756621Sbt150084 */ 28766621Sbt150084 static void 28776621Sbt150084 ixgbe_get_conf(ixgbe_t *ixgbe) 28786621Sbt150084 { 28796621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 28806621Sbt150084 uint32_t flow_control; 28816621Sbt150084 28826621Sbt150084 /* 28836621Sbt150084 * ixgbe driver supports the following user configurations: 28846621Sbt150084 * 28856621Sbt150084 * Jumbo frame configuration: 28866621Sbt150084 * default_mtu 28876621Sbt150084 * 28886621Sbt150084 * Ethernet flow control configuration: 28896621Sbt150084 * flow_control 28906621Sbt150084 * 28916621Sbt150084 * Multiple rings configurations: 28926621Sbt150084 * tx_queue_number 28936621Sbt150084 * tx_ring_size 28946621Sbt150084 * rx_queue_number 28956621Sbt150084 * rx_ring_size 28966621Sbt150084 * 28976621Sbt150084 * Call ixgbe_get_prop() to get the value for a specific 28986621Sbt150084 * configuration parameter. 28996621Sbt150084 */ 29006621Sbt150084 29016621Sbt150084 /* 29026621Sbt150084 * Jumbo frame configuration - max_frame_size controls host buffer 29036621Sbt150084 * allocation, so includes MTU, ethernet header, vlan tag and 29046621Sbt150084 * frame check sequence. 29056621Sbt150084 */ 29066621Sbt150084 ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU, 290711150SZhen.W@Sun.COM MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU); 29086621Sbt150084 29096621Sbt150084 ixgbe->max_frame_size = ixgbe->default_mtu + 29106621Sbt150084 sizeof (struct ether_vlan_header) + ETHERFCSL; 29116621Sbt150084 29126621Sbt150084 /* 29136621Sbt150084 * Ethernet flow control configuration 29146621Sbt150084 */ 29156621Sbt150084 flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL, 29168275SEric Cheng ixgbe_fc_none, 3, ixgbe_fc_none); 29176621Sbt150084 if (flow_control == 3) 29186621Sbt150084 flow_control = ixgbe_fc_default; 29196621Sbt150084 29209353SSamuel.Tu@Sun.COM /* 29219353SSamuel.Tu@Sun.COM * fc.requested mode is what the user requests. After autoneg, 29229353SSamuel.Tu@Sun.COM * fc.current_mode will be the flow_control mode that was negotiated. 29239353SSamuel.Tu@Sun.COM */ 29249353SSamuel.Tu@Sun.COM hw->fc.requested_mode = flow_control; 29256621Sbt150084 29266621Sbt150084 /* 29276621Sbt150084 * Multiple rings configurations 29286621Sbt150084 */ 29296621Sbt150084 ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM, 29308490SPaul.Guo@Sun.COM ixgbe->capab->min_tx_que_num, 29318490SPaul.Guo@Sun.COM ixgbe->capab->max_tx_que_num, 29328490SPaul.Guo@Sun.COM ixgbe->capab->def_tx_que_num); 29336621Sbt150084 ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE, 29346621Sbt150084 MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE); 29356621Sbt150084 29366621Sbt150084 ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM, 29378490SPaul.Guo@Sun.COM ixgbe->capab->min_rx_que_num, 29388490SPaul.Guo@Sun.COM ixgbe->capab->max_rx_que_num, 29398490SPaul.Guo@Sun.COM ixgbe->capab->def_rx_que_num); 29406621Sbt150084 ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE, 29416621Sbt150084 MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE); 29426621Sbt150084 29436621Sbt150084 /* 29448275SEric Cheng * Multiple groups configuration 29458275SEric Cheng */ 29468275SEric Cheng ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM, 294711878SVenu.Iyer@Sun.COM ixgbe->capab->min_rx_grp_num, ixgbe->capab->max_rx_grp_num, 294811878SVenu.Iyer@Sun.COM ixgbe->capab->def_rx_grp_num); 29498275SEric Cheng 29508275SEric Cheng ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE, 29518275SEric Cheng 0, 1, DEFAULT_MR_ENABLE); 29528275SEric Cheng 29538275SEric Cheng if (ixgbe->mr_enable == B_FALSE) { 29548275SEric Cheng ixgbe->num_tx_rings = 1; 29558275SEric Cheng ixgbe->num_rx_rings = 1; 29568275SEric Cheng ixgbe->num_rx_groups = 1; 295711878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 295811878SVenu.Iyer@Sun.COM } else { 295911878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 296011878SVenu.Iyer@Sun.COM max(ixgbe->num_rx_rings / ixgbe->num_rx_groups, 1); 296111878SVenu.Iyer@Sun.COM /* 296211878SVenu.Iyer@Sun.COM * The combination of num_rx_rings and num_rx_groups 296311878SVenu.Iyer@Sun.COM * may be not supported by h/w. We need to adjust 296411878SVenu.Iyer@Sun.COM * them to appropriate values. 296511878SVenu.Iyer@Sun.COM */ 296611878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss_conf(ixgbe); 29678275SEric Cheng } 29688275SEric Cheng 29698275SEric Cheng /* 29706621Sbt150084 * Tunable used to force an interrupt type. The only use is 29716621Sbt150084 * for testing of the lesser interrupt types. 29726621Sbt150084 * 0 = don't force interrupt type 29738275SEric Cheng * 1 = force interrupt type MSI-X 29746621Sbt150084 * 2 = force interrupt type MSI 29756621Sbt150084 * 3 = force interrupt type Legacy 29766621Sbt150084 */ 29776621Sbt150084 ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE, 29786621Sbt150084 IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE); 29796621Sbt150084 29806621Sbt150084 ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE, 29817167Sgg161487 0, 1, DEFAULT_TX_HCKSUM_ENABLE); 29826621Sbt150084 ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE, 29837167Sgg161487 0, 1, DEFAULT_RX_HCKSUM_ENABLE); 29846621Sbt150084 ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE, 29857167Sgg161487 0, 1, DEFAULT_LSO_ENABLE); 298611486SZhen.W@Sun.COM ixgbe->lro_enable = ixgbe_get_prop(ixgbe, PROP_LRO_ENABLE, 298711486SZhen.W@Sun.COM 0, 1, DEFAULT_LRO_ENABLE); 29886621Sbt150084 ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE, 29897167Sgg161487 0, 1, DEFAULT_TX_HEAD_WB_ENABLE); 29907167Sgg161487 29919353SSamuel.Tu@Sun.COM /* Head Write Back not recommended for 82599 */ 29929353SSamuel.Tu@Sun.COM if (hw->mac.type >= ixgbe_mac_82599EB) { 29939353SSamuel.Tu@Sun.COM ixgbe->tx_head_wb_enable = B_FALSE; 29949353SSamuel.Tu@Sun.COM } 29959353SSamuel.Tu@Sun.COM 29967167Sgg161487 /* 29977167Sgg161487 * ixgbe LSO needs the tx h/w checksum support. 29987167Sgg161487 * LSO will be disabled if tx h/w checksum is not 29997167Sgg161487 * enabled. 30007167Sgg161487 */ 30017167Sgg161487 if (ixgbe->tx_hcksum_enable == B_FALSE) { 30027167Sgg161487 ixgbe->lso_enable = B_FALSE; 30037167Sgg161487 } 30046621Sbt150084 300511486SZhen.W@Sun.COM /* 300611486SZhen.W@Sun.COM * ixgbe LRO needs the rx h/w checksum support. 300711486SZhen.W@Sun.COM * LRO will be disabled if rx h/w checksum is not 300811486SZhen.W@Sun.COM * enabled. 300911486SZhen.W@Sun.COM */ 301011486SZhen.W@Sun.COM if (ixgbe->rx_hcksum_enable == B_FALSE) { 301111486SZhen.W@Sun.COM ixgbe->lro_enable = B_FALSE; 301211486SZhen.W@Sun.COM } 301311486SZhen.W@Sun.COM 301411486SZhen.W@Sun.COM /* 301511486SZhen.W@Sun.COM * ixgbe LRO only been supported by 82599 now 301611486SZhen.W@Sun.COM */ 301711486SZhen.W@Sun.COM if (hw->mac.type != ixgbe_mac_82599EB) { 301811486SZhen.W@Sun.COM ixgbe->lro_enable = B_FALSE; 301911486SZhen.W@Sun.COM } 30206621Sbt150084 ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD, 30216621Sbt150084 MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD, 30226621Sbt150084 DEFAULT_TX_COPY_THRESHOLD); 30236621Sbt150084 ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe, 30246621Sbt150084 PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD, 30256621Sbt150084 MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD); 30266621Sbt150084 ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe, 30276621Sbt150084 PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD, 30286621Sbt150084 MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD); 30296621Sbt150084 ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe, 30306621Sbt150084 PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD, 30316621Sbt150084 MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD); 30326621Sbt150084 30336621Sbt150084 ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD, 30346621Sbt150084 MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD, 30356621Sbt150084 DEFAULT_RX_COPY_THRESHOLD); 30366621Sbt150084 ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR, 30376621Sbt150084 MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR, 30386621Sbt150084 DEFAULT_RX_LIMIT_PER_INTR); 30396621Sbt150084 304010376SChenlu.Chen@Sun.COM ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING, 304110376SChenlu.Chen@Sun.COM ixgbe->capab->min_intr_throttle, 304210376SChenlu.Chen@Sun.COM ixgbe->capab->max_intr_throttle, 304310376SChenlu.Chen@Sun.COM ixgbe->capab->def_intr_throttle); 30449353SSamuel.Tu@Sun.COM /* 304510376SChenlu.Chen@Sun.COM * 82599 requires the interupt throttling rate is 304610376SChenlu.Chen@Sun.COM * a multiple of 8. This is enforced by the register 304710376SChenlu.Chen@Sun.COM * definiton. 30489353SSamuel.Tu@Sun.COM */ 304910376SChenlu.Chen@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) 305010376SChenlu.Chen@Sun.COM ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8; 305110376SChenlu.Chen@Sun.COM } 305210376SChenlu.Chen@Sun.COM 305310376SChenlu.Chen@Sun.COM static void 305410376SChenlu.Chen@Sun.COM ixgbe_init_params(ixgbe_t *ixgbe) 305510376SChenlu.Chen@Sun.COM { 305610376SChenlu.Chen@Sun.COM ixgbe->param_en_10000fdx_cap = 1; 305710376SChenlu.Chen@Sun.COM ixgbe->param_en_1000fdx_cap = 1; 305810376SChenlu.Chen@Sun.COM ixgbe->param_en_100fdx_cap = 1; 305910376SChenlu.Chen@Sun.COM ixgbe->param_adv_10000fdx_cap = 1; 306010376SChenlu.Chen@Sun.COM ixgbe->param_adv_1000fdx_cap = 1; 306110376SChenlu.Chen@Sun.COM ixgbe->param_adv_100fdx_cap = 1; 306210376SChenlu.Chen@Sun.COM 306310376SChenlu.Chen@Sun.COM ixgbe->param_pause_cap = 1; 306410376SChenlu.Chen@Sun.COM ixgbe->param_asym_pause_cap = 1; 306510376SChenlu.Chen@Sun.COM ixgbe->param_rem_fault = 0; 306610376SChenlu.Chen@Sun.COM 306710376SChenlu.Chen@Sun.COM ixgbe->param_adv_autoneg_cap = 1; 306810376SChenlu.Chen@Sun.COM ixgbe->param_adv_pause_cap = 1; 306910376SChenlu.Chen@Sun.COM ixgbe->param_adv_asym_pause_cap = 1; 307010376SChenlu.Chen@Sun.COM ixgbe->param_adv_rem_fault = 0; 307110376SChenlu.Chen@Sun.COM 307210376SChenlu.Chen@Sun.COM ixgbe->param_lp_10000fdx_cap = 0; 307310376SChenlu.Chen@Sun.COM ixgbe->param_lp_1000fdx_cap = 0; 307410376SChenlu.Chen@Sun.COM ixgbe->param_lp_100fdx_cap = 0; 307510376SChenlu.Chen@Sun.COM ixgbe->param_lp_autoneg_cap = 0; 307610376SChenlu.Chen@Sun.COM ixgbe->param_lp_pause_cap = 0; 307710376SChenlu.Chen@Sun.COM ixgbe->param_lp_asym_pause_cap = 0; 307810376SChenlu.Chen@Sun.COM ixgbe->param_lp_rem_fault = 0; 30796621Sbt150084 } 30806621Sbt150084 30816621Sbt150084 /* 30826621Sbt150084 * ixgbe_get_prop - Get a property value out of the configuration file 30836621Sbt150084 * ixgbe.conf. 30846621Sbt150084 * 30856621Sbt150084 * Caller provides the name of the property, a default value, a minimum 30866621Sbt150084 * value, and a maximum value. 30876621Sbt150084 * 30886621Sbt150084 * Return configured value of the property, with default, minimum and 30896621Sbt150084 * maximum properly applied. 30906621Sbt150084 */ 30916621Sbt150084 static int 30926621Sbt150084 ixgbe_get_prop(ixgbe_t *ixgbe, 30936621Sbt150084 char *propname, /* name of the property */ 30946621Sbt150084 int minval, /* minimum acceptable value */ 30956621Sbt150084 int maxval, /* maximim acceptable value */ 30966621Sbt150084 int defval) /* default value */ 30976621Sbt150084 { 30986621Sbt150084 int value; 30996621Sbt150084 31006621Sbt150084 /* 31016621Sbt150084 * Call ddi_prop_get_int() to read the conf settings 31026621Sbt150084 */ 31036621Sbt150084 value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip, 31046621Sbt150084 DDI_PROP_DONTPASS, propname, defval); 31056621Sbt150084 if (value > maxval) 31066621Sbt150084 value = maxval; 31076621Sbt150084 31086621Sbt150084 if (value < minval) 31096621Sbt150084 value = minval; 31106621Sbt150084 31116621Sbt150084 return (value); 31126621Sbt150084 } 31136621Sbt150084 31146621Sbt150084 /* 31156621Sbt150084 * ixgbe_driver_setup_link - Using the link properties to setup the link. 31166621Sbt150084 */ 31176621Sbt150084 int 31186621Sbt150084 ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw) 31196621Sbt150084 { 312010998SChenlu.Chen@Sun.COM u32 autoneg_advertised = 0; 312110998SChenlu.Chen@Sun.COM 312210998SChenlu.Chen@Sun.COM /* 312310998SChenlu.Chen@Sun.COM * No half duplex support with 10Gb parts 312410998SChenlu.Chen@Sun.COM */ 312510998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_10000fdx_cap == 1) 312610998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; 312710998SChenlu.Chen@Sun.COM 312810998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_1000fdx_cap == 1) 312910998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; 313010998SChenlu.Chen@Sun.COM 313110998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_100fdx_cap == 1) 313210998SChenlu.Chen@Sun.COM autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; 313310998SChenlu.Chen@Sun.COM 313410998SChenlu.Chen@Sun.COM if (ixgbe->param_adv_autoneg_cap == 1 && autoneg_advertised == 0) { 313510998SChenlu.Chen@Sun.COM ixgbe_notice(ixgbe, "Invalid link settings. Setup link " 313610998SChenlu.Chen@Sun.COM "to autonegotiation with full link capabilities."); 313710998SChenlu.Chen@Sun.COM 313810998SChenlu.Chen@Sun.COM autoneg_advertised = IXGBE_LINK_SPEED_10GB_FULL | 313910998SChenlu.Chen@Sun.COM IXGBE_LINK_SPEED_1GB_FULL | 314010998SChenlu.Chen@Sun.COM IXGBE_LINK_SPEED_100_FULL; 31416621Sbt150084 } 31426621Sbt150084 31436621Sbt150084 if (setup_hw) { 314410998SChenlu.Chen@Sun.COM if (ixgbe_setup_link(&ixgbe->hw, autoneg_advertised, 314510998SChenlu.Chen@Sun.COM ixgbe->param_adv_autoneg_cap, B_TRUE) != IXGBE_SUCCESS) { 31469353SSamuel.Tu@Sun.COM ixgbe_notice(ixgbe, "Setup link failed on this " 31479353SSamuel.Tu@Sun.COM "device."); 31486621Sbt150084 return (IXGBE_FAILURE); 31499353SSamuel.Tu@Sun.COM } 31506621Sbt150084 } 31516621Sbt150084 31526621Sbt150084 return (IXGBE_SUCCESS); 31536621Sbt150084 } 31546621Sbt150084 31556621Sbt150084 /* 315611233SPaul.Guo@Sun.COM * ixgbe_driver_link_check - Link status processing. 315711233SPaul.Guo@Sun.COM * 315811233SPaul.Guo@Sun.COM * This function can be called in both kernel context and interrupt context 31596621Sbt150084 */ 31608490SPaul.Guo@Sun.COM static void 316111233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe_t *ixgbe) 31626621Sbt150084 { 31636621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 31646621Sbt150084 ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN; 31656621Sbt150084 boolean_t link_up = B_FALSE; 31666621Sbt150084 boolean_t link_changed = B_FALSE; 31676621Sbt150084 316811233SPaul.Guo@Sun.COM ASSERT(mutex_owned(&ixgbe->gen_lock)); 316911233SPaul.Guo@Sun.COM 317011233SPaul.Guo@Sun.COM (void) ixgbe_check_link(hw, &speed, &link_up, false); 31716621Sbt150084 if (link_up) { 317211233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_TRUE; 317311233SPaul.Guo@Sun.COM 31749353SSamuel.Tu@Sun.COM /* Link is up, enable flow control settings */ 31759353SSamuel.Tu@Sun.COM (void) ixgbe_fc_enable(hw, 0); 31769353SSamuel.Tu@Sun.COM 31776621Sbt150084 /* 31786621Sbt150084 * The Link is up, check whether it was marked as down earlier 31796621Sbt150084 */ 31806621Sbt150084 if (ixgbe->link_state != LINK_STATE_UP) { 31816621Sbt150084 switch (speed) { 31829353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_10GB_FULL: 31839353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_10GB; 31849353SSamuel.Tu@Sun.COM break; 31859353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_1GB_FULL: 31869353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_1GB; 31879353SSamuel.Tu@Sun.COM break; 31889353SSamuel.Tu@Sun.COM case IXGBE_LINK_SPEED_100_FULL: 31899353SSamuel.Tu@Sun.COM ixgbe->link_speed = SPEED_100; 31906621Sbt150084 } 31916621Sbt150084 ixgbe->link_duplex = LINK_DUPLEX_FULL; 31926621Sbt150084 ixgbe->link_state = LINK_STATE_UP; 31936621Sbt150084 link_changed = B_TRUE; 31946621Sbt150084 } 31956621Sbt150084 } else { 319611233SPaul.Guo@Sun.COM if (ixgbe->link_check_complete == B_TRUE || 319711233SPaul.Guo@Sun.COM (ixgbe->link_check_complete == B_FALSE && 319811233SPaul.Guo@Sun.COM gethrtime() >= ixgbe->link_check_hrtime)) { 319911233SPaul.Guo@Sun.COM /* 320011233SPaul.Guo@Sun.COM * The link is really down 320111233SPaul.Guo@Sun.COM */ 320211233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_TRUE; 320311233SPaul.Guo@Sun.COM 320411233SPaul.Guo@Sun.COM if (ixgbe->link_state != LINK_STATE_DOWN) { 320511233SPaul.Guo@Sun.COM ixgbe->link_speed = 0; 320611233SPaul.Guo@Sun.COM ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN; 320711233SPaul.Guo@Sun.COM ixgbe->link_state = LINK_STATE_DOWN; 320811233SPaul.Guo@Sun.COM link_changed = B_TRUE; 320911233SPaul.Guo@Sun.COM } 32106621Sbt150084 } 32116621Sbt150084 } 32126621Sbt150084 32138490SPaul.Guo@Sun.COM /* 32148490SPaul.Guo@Sun.COM * this is only reached after a link-status-change interrupt 32158490SPaul.Guo@Sun.COM * so always get new phy state 32168490SPaul.Guo@Sun.COM */ 32178490SPaul.Guo@Sun.COM ixgbe_get_hw_state(ixgbe); 32188490SPaul.Guo@Sun.COM 321911233SPaul.Guo@Sun.COM /* 322011233SPaul.Guo@Sun.COM * If we are in an interrupt context, need to re-enable the 322111233SPaul.Guo@Sun.COM * interrupt, which was automasked 322211233SPaul.Guo@Sun.COM */ 322311233SPaul.Guo@Sun.COM if (servicing_interrupt() != 0) { 322411233SPaul.Guo@Sun.COM ixgbe->eims |= IXGBE_EICR_LSC; 322511233SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 322611233SPaul.Guo@Sun.COM } 322711233SPaul.Guo@Sun.COM 32288490SPaul.Guo@Sun.COM if (link_changed) { 32298490SPaul.Guo@Sun.COM mac_link_update(ixgbe->mac_hdl, ixgbe->link_state); 32308490SPaul.Guo@Sun.COM } 32316621Sbt150084 } 32326621Sbt150084 32336621Sbt150084 /* 32349353SSamuel.Tu@Sun.COM * ixgbe_sfp_check - sfp module processing done in taskq only for 82599. 32359353SSamuel.Tu@Sun.COM */ 32369353SSamuel.Tu@Sun.COM static void 32379353SSamuel.Tu@Sun.COM ixgbe_sfp_check(void *arg) 32389353SSamuel.Tu@Sun.COM { 32399353SSamuel.Tu@Sun.COM ixgbe_t *ixgbe = (ixgbe_t *)arg; 32409353SSamuel.Tu@Sun.COM uint32_t eicr = ixgbe->eicr; 32419353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 32429353SSamuel.Tu@Sun.COM 324311233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 32449353SSamuel.Tu@Sun.COM if (eicr & IXGBE_EICR_GPI_SDP1) { 32459353SSamuel.Tu@Sun.COM /* clear the interrupt */ 32469353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); 32479353SSamuel.Tu@Sun.COM 32489353SSamuel.Tu@Sun.COM /* if link up, do multispeed fiber setup */ 324910998SChenlu.Chen@Sun.COM (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, 325010998SChenlu.Chen@Sun.COM B_TRUE, B_TRUE); 32519353SSamuel.Tu@Sun.COM ixgbe_driver_link_check(ixgbe); 32529353SSamuel.Tu@Sun.COM } else if (eicr & IXGBE_EICR_GPI_SDP2) { 32539353SSamuel.Tu@Sun.COM /* clear the interrupt */ 32549353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); 32559353SSamuel.Tu@Sun.COM 32569353SSamuel.Tu@Sun.COM /* if link up, do sfp module setup */ 32579353SSamuel.Tu@Sun.COM (void) hw->mac.ops.setup_sfp(hw); 32589353SSamuel.Tu@Sun.COM 32599353SSamuel.Tu@Sun.COM /* do multispeed fiber setup */ 326010998SChenlu.Chen@Sun.COM (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, 326110998SChenlu.Chen@Sun.COM B_TRUE, B_TRUE); 32629353SSamuel.Tu@Sun.COM ixgbe_driver_link_check(ixgbe); 32639353SSamuel.Tu@Sun.COM } 326411233SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 326511233SPaul.Guo@Sun.COM } 326611233SPaul.Guo@Sun.COM 326711233SPaul.Guo@Sun.COM /* 326811233SPaul.Guo@Sun.COM * ixgbe_link_timer - timer for link status detection 326911233SPaul.Guo@Sun.COM */ 327011233SPaul.Guo@Sun.COM static void 327111233SPaul.Guo@Sun.COM ixgbe_link_timer(void *arg) 327211233SPaul.Guo@Sun.COM { 327311233SPaul.Guo@Sun.COM ixgbe_t *ixgbe = (ixgbe_t *)arg; 327411233SPaul.Guo@Sun.COM 327511233SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 327611233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe); 327711233SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 32789353SSamuel.Tu@Sun.COM } 32799353SSamuel.Tu@Sun.COM 32809353SSamuel.Tu@Sun.COM /* 32816621Sbt150084 * ixgbe_local_timer - Driver watchdog function. 32826621Sbt150084 * 328311233SPaul.Guo@Sun.COM * This function will handle the transmit stall check and other routines. 32846621Sbt150084 */ 32856621Sbt150084 static void 32866621Sbt150084 ixgbe_local_timer(void *arg) 32876621Sbt150084 { 32886621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg; 32896621Sbt150084 329011233SPaul.Guo@Sun.COM if (ixgbe->ixgbe_state & IXGBE_ERROR) { 32916621Sbt150084 ixgbe->reset_count++; 32926621Sbt150084 if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS) 32936621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED); 329411233SPaul.Guo@Sun.COM ixgbe_restart_watchdog_timer(ixgbe); 329511233SPaul.Guo@Sun.COM return; 32966621Sbt150084 } 32976621Sbt150084 329811233SPaul.Guo@Sun.COM if (ixgbe_stall_check(ixgbe)) { 329911233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL); 330011233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 330111233SPaul.Guo@Sun.COM 330211233SPaul.Guo@Sun.COM ixgbe->reset_count++; 330311233SPaul.Guo@Sun.COM if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS) 330411233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED); 330511233SPaul.Guo@Sun.COM } 330611486SZhen.W@Sun.COM 330711486SZhen.W@Sun.COM ixgbe_restart_watchdog_timer(ixgbe); 33086621Sbt150084 } 33096621Sbt150084 33106621Sbt150084 /* 33116621Sbt150084 * ixgbe_stall_check - Check for transmit stall. 33126621Sbt150084 * 33136621Sbt150084 * This function checks if the adapter is stalled (in transmit). 33146621Sbt150084 * 33156621Sbt150084 * It is called each time the watchdog timeout is invoked. 33166621Sbt150084 * If the transmit descriptor reclaim continuously fails, 33176621Sbt150084 * the watchdog value will increment by 1. If the watchdog 33186621Sbt150084 * value exceeds the threshold, the ixgbe is assumed to 33196621Sbt150084 * have stalled and need to be reset. 33206621Sbt150084 */ 33216621Sbt150084 static boolean_t 33226621Sbt150084 ixgbe_stall_check(ixgbe_t *ixgbe) 33236621Sbt150084 { 33246621Sbt150084 ixgbe_tx_ring_t *tx_ring; 33256621Sbt150084 boolean_t result; 33266621Sbt150084 int i; 33276621Sbt150084 33286621Sbt150084 if (ixgbe->link_state != LINK_STATE_UP) 33296621Sbt150084 return (B_FALSE); 33306621Sbt150084 33316621Sbt150084 /* 33326621Sbt150084 * If any tx ring is stalled, we'll reset the chipset 33336621Sbt150084 */ 33346621Sbt150084 result = B_FALSE; 33356621Sbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 33366621Sbt150084 tx_ring = &ixgbe->tx_rings[i]; 333710376SChenlu.Chen@Sun.COM if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) { 333810305SPaul.Guo@Sun.COM tx_ring->tx_recycle(tx_ring); 333910305SPaul.Guo@Sun.COM } 33406621Sbt150084 33416621Sbt150084 if (tx_ring->recycle_fail > 0) 33426621Sbt150084 tx_ring->stall_watchdog++; 33436621Sbt150084 else 33446621Sbt150084 tx_ring->stall_watchdog = 0; 33456621Sbt150084 33466621Sbt150084 if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) { 33476621Sbt150084 result = B_TRUE; 33486621Sbt150084 break; 33496621Sbt150084 } 33506621Sbt150084 } 33516621Sbt150084 33526621Sbt150084 if (result) { 33536621Sbt150084 tx_ring->stall_watchdog = 0; 33546621Sbt150084 tx_ring->recycle_fail = 0; 33556621Sbt150084 } 33566621Sbt150084 33576621Sbt150084 return (result); 33586621Sbt150084 } 33596621Sbt150084 33606621Sbt150084 33616621Sbt150084 /* 33626621Sbt150084 * is_valid_mac_addr - Check if the mac address is valid. 33636621Sbt150084 */ 33646621Sbt150084 static boolean_t 33656621Sbt150084 is_valid_mac_addr(uint8_t *mac_addr) 33666621Sbt150084 { 33676621Sbt150084 const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 }; 33686621Sbt150084 const uint8_t addr_test2[6] = 33696621Sbt150084 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 33706621Sbt150084 33716621Sbt150084 if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) || 33726621Sbt150084 !(bcmp(addr_test2, mac_addr, ETHERADDRL))) 33736621Sbt150084 return (B_FALSE); 33746621Sbt150084 33756621Sbt150084 return (B_TRUE); 33766621Sbt150084 } 33776621Sbt150084 33786621Sbt150084 static boolean_t 33796621Sbt150084 ixgbe_find_mac_address(ixgbe_t *ixgbe) 33806621Sbt150084 { 33816621Sbt150084 #ifdef __sparc 33826621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 33836621Sbt150084 uchar_t *bytes; 33846621Sbt150084 struct ether_addr sysaddr; 33856621Sbt150084 uint_t nelts; 33866621Sbt150084 int err; 33876621Sbt150084 boolean_t found = B_FALSE; 33886621Sbt150084 33896621Sbt150084 /* 33906621Sbt150084 * The "vendor's factory-set address" may already have 33916621Sbt150084 * been extracted from the chip, but if the property 33926621Sbt150084 * "local-mac-address" is set we use that instead. 33936621Sbt150084 * 33946621Sbt150084 * We check whether it looks like an array of 6 33956621Sbt150084 * bytes (which it should, if OBP set it). If we can't 33966621Sbt150084 * make sense of it this way, we'll ignore it. 33976621Sbt150084 */ 33986621Sbt150084 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 33996621Sbt150084 DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts); 34006621Sbt150084 if (err == DDI_PROP_SUCCESS) { 34016621Sbt150084 if (nelts == ETHERADDRL) { 34026621Sbt150084 while (nelts--) 34036621Sbt150084 hw->mac.addr[nelts] = bytes[nelts]; 34046621Sbt150084 found = B_TRUE; 34056621Sbt150084 } 34066621Sbt150084 ddi_prop_free(bytes); 34076621Sbt150084 } 34086621Sbt150084 34096621Sbt150084 /* 34106621Sbt150084 * Look up the OBP property "local-mac-address?". If the user has set 34116621Sbt150084 * 'local-mac-address? = false', use "the system address" instead. 34126621Sbt150084 */ 34136621Sbt150084 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0, 34146621Sbt150084 "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) { 34156621Sbt150084 if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) { 34166621Sbt150084 if (localetheraddr(NULL, &sysaddr) != 0) { 34176621Sbt150084 bcopy(&sysaddr, hw->mac.addr, ETHERADDRL); 34186621Sbt150084 found = B_TRUE; 34196621Sbt150084 } 34206621Sbt150084 } 34216621Sbt150084 ddi_prop_free(bytes); 34226621Sbt150084 } 34236621Sbt150084 34246621Sbt150084 /* 34256621Sbt150084 * Finally(!), if there's a valid "mac-address" property (created 34266621Sbt150084 * if we netbooted from this interface), we must use this instead 34276621Sbt150084 * of any of the above to ensure that the NFS/install server doesn't 34286621Sbt150084 * get confused by the address changing as Solaris takes over! 34296621Sbt150084 */ 34306621Sbt150084 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 34316621Sbt150084 DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts); 34326621Sbt150084 if (err == DDI_PROP_SUCCESS) { 34336621Sbt150084 if (nelts == ETHERADDRL) { 34346621Sbt150084 while (nelts--) 34356621Sbt150084 hw->mac.addr[nelts] = bytes[nelts]; 34366621Sbt150084 found = B_TRUE; 34376621Sbt150084 } 34386621Sbt150084 ddi_prop_free(bytes); 34396621Sbt150084 } 34406621Sbt150084 34416621Sbt150084 if (found) { 34426621Sbt150084 bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL); 34436621Sbt150084 return (B_TRUE); 34446621Sbt150084 } 34456621Sbt150084 #else 34466621Sbt150084 _NOTE(ARGUNUSED(ixgbe)); 34476621Sbt150084 #endif 34486621Sbt150084 34496621Sbt150084 return (B_TRUE); 34506621Sbt150084 } 34516621Sbt150084 34526621Sbt150084 #pragma inline(ixgbe_arm_watchdog_timer) 34536621Sbt150084 static void 34546621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe) 34556621Sbt150084 { 34566621Sbt150084 /* 34576621Sbt150084 * Fire a watchdog timer 34586621Sbt150084 */ 34596621Sbt150084 ixgbe->watchdog_tid = 34606621Sbt150084 timeout(ixgbe_local_timer, 34616621Sbt150084 (void *)ixgbe, 1 * drv_usectohz(1000000)); 34626621Sbt150084 34636621Sbt150084 } 34646621Sbt150084 34656621Sbt150084 /* 34666621Sbt150084 * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer. 34676621Sbt150084 */ 34686621Sbt150084 void 34696621Sbt150084 ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe) 34706621Sbt150084 { 34716621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 34726621Sbt150084 34736621Sbt150084 if (!ixgbe->watchdog_enable) { 34746621Sbt150084 ixgbe->watchdog_enable = B_TRUE; 34756621Sbt150084 ixgbe->watchdog_start = B_TRUE; 34766621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 34776621Sbt150084 } 34786621Sbt150084 34796621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 34806621Sbt150084 } 34816621Sbt150084 34826621Sbt150084 /* 34836621Sbt150084 * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer. 34846621Sbt150084 */ 34856621Sbt150084 void 34866621Sbt150084 ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe) 34876621Sbt150084 { 34886621Sbt150084 timeout_id_t tid; 34896621Sbt150084 34906621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 34916621Sbt150084 34926621Sbt150084 ixgbe->watchdog_enable = B_FALSE; 34936621Sbt150084 ixgbe->watchdog_start = B_FALSE; 34946621Sbt150084 tid = ixgbe->watchdog_tid; 34956621Sbt150084 ixgbe->watchdog_tid = 0; 34966621Sbt150084 34976621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 34986621Sbt150084 34996621Sbt150084 if (tid != 0) 35006621Sbt150084 (void) untimeout(tid); 35016621Sbt150084 } 35026621Sbt150084 35036621Sbt150084 /* 35046621Sbt150084 * ixgbe_start_watchdog_timer - Start the driver watchdog timer. 35056621Sbt150084 */ 35068490SPaul.Guo@Sun.COM void 35076621Sbt150084 ixgbe_start_watchdog_timer(ixgbe_t *ixgbe) 35086621Sbt150084 { 35096621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 35106621Sbt150084 35116621Sbt150084 if (ixgbe->watchdog_enable) { 35126621Sbt150084 if (!ixgbe->watchdog_start) { 35136621Sbt150084 ixgbe->watchdog_start = B_TRUE; 35146621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 35156621Sbt150084 } 35166621Sbt150084 } 35176621Sbt150084 35186621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 35196621Sbt150084 } 35206621Sbt150084 35216621Sbt150084 /* 35226621Sbt150084 * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer. 35236621Sbt150084 */ 35246621Sbt150084 static void 35256621Sbt150084 ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe) 35266621Sbt150084 { 35276621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 35286621Sbt150084 35296621Sbt150084 if (ixgbe->watchdog_start) 35306621Sbt150084 ixgbe_arm_watchdog_timer(ixgbe); 35316621Sbt150084 35326621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 35336621Sbt150084 } 35346621Sbt150084 35356621Sbt150084 /* 35366621Sbt150084 * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer. 35376621Sbt150084 */ 35388490SPaul.Guo@Sun.COM void 35396621Sbt150084 ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe) 35406621Sbt150084 { 35416621Sbt150084 timeout_id_t tid; 35426621Sbt150084 35436621Sbt150084 mutex_enter(&ixgbe->watchdog_lock); 35446621Sbt150084 35456621Sbt150084 ixgbe->watchdog_start = B_FALSE; 35466621Sbt150084 tid = ixgbe->watchdog_tid; 35476621Sbt150084 ixgbe->watchdog_tid = 0; 35486621Sbt150084 35496621Sbt150084 mutex_exit(&ixgbe->watchdog_lock); 35506621Sbt150084 35516621Sbt150084 if (tid != 0) 35526621Sbt150084 (void) untimeout(tid); 35536621Sbt150084 } 35546621Sbt150084 35556621Sbt150084 /* 35566621Sbt150084 * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts. 35576621Sbt150084 */ 35586621Sbt150084 static void 35596621Sbt150084 ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe) 35606621Sbt150084 { 35616621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 35626621Sbt150084 35636621Sbt150084 /* 35646621Sbt150084 * mask all interrupts off 35656621Sbt150084 */ 35666621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff); 35676621Sbt150084 35686621Sbt150084 /* 35696621Sbt150084 * for MSI-X, also disable autoclear 35706621Sbt150084 */ 35716621Sbt150084 if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) { 35726621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0); 35736621Sbt150084 } 35746621Sbt150084 35756621Sbt150084 IXGBE_WRITE_FLUSH(hw); 35766621Sbt150084 } 35776621Sbt150084 35786621Sbt150084 /* 35796621Sbt150084 * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts. 35806621Sbt150084 */ 35816621Sbt150084 static void 35826621Sbt150084 ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe) 35836621Sbt150084 { 35846621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 35858490SPaul.Guo@Sun.COM uint32_t eiac, eiam; 35868490SPaul.Guo@Sun.COM uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 35878490SPaul.Guo@Sun.COM 35888490SPaul.Guo@Sun.COM /* interrupt types to enable */ 35898490SPaul.Guo@Sun.COM ixgbe->eims = IXGBE_EIMS_ENABLE_MASK; /* shared code default */ 35908490SPaul.Guo@Sun.COM ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER; /* minus tcp timer */ 35918490SPaul.Guo@Sun.COM ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */ 35928490SPaul.Guo@Sun.COM 35938490SPaul.Guo@Sun.COM /* enable automask on "other" causes that this adapter can generate */ 35948490SPaul.Guo@Sun.COM eiam = ixgbe->capab->other_intr; 35956621Sbt150084 35966621Sbt150084 /* 35976621Sbt150084 * msi-x mode 35986621Sbt150084 */ 35996621Sbt150084 if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) { 36006621Sbt150084 /* enable autoclear but not on bits 29:20 */ 36018490SPaul.Guo@Sun.COM eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR); 36026621Sbt150084 36036621Sbt150084 /* general purpose interrupt enable */ 36048490SPaul.Guo@Sun.COM gpie |= (IXGBE_GPIE_MSIX_MODE 36058490SPaul.Guo@Sun.COM | IXGBE_GPIE_PBA_SUPPORT 36068490SPaul.Guo@Sun.COM | IXGBE_GPIE_OCD 36078490SPaul.Guo@Sun.COM | IXGBE_GPIE_EIAME); 36086621Sbt150084 /* 36096621Sbt150084 * non-msi-x mode 36106621Sbt150084 */ 36116621Sbt150084 } else { 36126621Sbt150084 36136621Sbt150084 /* disable autoclear, leave gpie at default */ 36146621Sbt150084 eiac = 0; 36158490SPaul.Guo@Sun.COM 36169353SSamuel.Tu@Sun.COM /* 36179353SSamuel.Tu@Sun.COM * General purpose interrupt enable. 36189353SSamuel.Tu@Sun.COM * For 82599, extended interrupt automask enable 36199353SSamuel.Tu@Sun.COM * only in MSI or MSI-X mode 36209353SSamuel.Tu@Sun.COM */ 36219353SSamuel.Tu@Sun.COM if ((hw->mac.type < ixgbe_mac_82599EB) || 36229353SSamuel.Tu@Sun.COM (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) { 36239353SSamuel.Tu@Sun.COM gpie |= IXGBE_GPIE_EIAME; 36249353SSamuel.Tu@Sun.COM } 36259353SSamuel.Tu@Sun.COM } 36269353SSamuel.Tu@Sun.COM /* Enable specific interrupts for 82599 */ 36279353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 36289353SSamuel.Tu@Sun.COM gpie |= IXGBE_SDP2_GPIEN; /* pluggable optics intr */ 36299353SSamuel.Tu@Sun.COM gpie |= IXGBE_SDP1_GPIEN; /* LSC interrupt */ 36306621Sbt150084 } 363111486SZhen.W@Sun.COM /* Enable RSC Dealy 8us for 82599 */ 363211486SZhen.W@Sun.COM if (ixgbe->lro_enable) { 363311486SZhen.W@Sun.COM gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT); 363411486SZhen.W@Sun.COM } 36358490SPaul.Guo@Sun.COM /* write to interrupt control registers */ 36368490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 36376621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac); 36388490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam); 36396621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 36406621Sbt150084 IXGBE_WRITE_FLUSH(hw); 36416621Sbt150084 } 36426621Sbt150084 36436621Sbt150084 /* 36446621Sbt150084 * ixgbe_loopback_ioctl - Loopback support. 36456621Sbt150084 */ 36466621Sbt150084 enum ioc_reply 36476621Sbt150084 ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp) 36486621Sbt150084 { 36496621Sbt150084 lb_info_sz_t *lbsp; 36506621Sbt150084 lb_property_t *lbpp; 36516621Sbt150084 uint32_t *lbmp; 36526621Sbt150084 uint32_t size; 36536621Sbt150084 uint32_t value; 36546621Sbt150084 36556621Sbt150084 if (mp->b_cont == NULL) 36566621Sbt150084 return (IOC_INVAL); 36576621Sbt150084 36586621Sbt150084 switch (iocp->ioc_cmd) { 36596621Sbt150084 default: 36606621Sbt150084 return (IOC_INVAL); 36616621Sbt150084 36626621Sbt150084 case LB_GET_INFO_SIZE: 36636621Sbt150084 size = sizeof (lb_info_sz_t); 36646621Sbt150084 if (iocp->ioc_count != size) 36656621Sbt150084 return (IOC_INVAL); 36666621Sbt150084 36676621Sbt150084 value = sizeof (lb_normal); 36686621Sbt150084 value += sizeof (lb_mac); 366911150SZhen.W@Sun.COM value += sizeof (lb_external); 36706621Sbt150084 36716621Sbt150084 lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr; 36726621Sbt150084 *lbsp = value; 36736621Sbt150084 break; 36746621Sbt150084 36756621Sbt150084 case LB_GET_INFO: 36766621Sbt150084 value = sizeof (lb_normal); 36776621Sbt150084 value += sizeof (lb_mac); 367811150SZhen.W@Sun.COM value += sizeof (lb_external); 36796621Sbt150084 36806621Sbt150084 size = value; 36816621Sbt150084 if (iocp->ioc_count != size) 36826621Sbt150084 return (IOC_INVAL); 36836621Sbt150084 36846621Sbt150084 value = 0; 36856621Sbt150084 lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr; 36866621Sbt150084 36876621Sbt150084 lbpp[value++] = lb_normal; 36886621Sbt150084 lbpp[value++] = lb_mac; 368911150SZhen.W@Sun.COM lbpp[value++] = lb_external; 36906621Sbt150084 break; 36916621Sbt150084 36926621Sbt150084 case LB_GET_MODE: 36936621Sbt150084 size = sizeof (uint32_t); 36946621Sbt150084 if (iocp->ioc_count != size) 36956621Sbt150084 return (IOC_INVAL); 36966621Sbt150084 36976621Sbt150084 lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 36986621Sbt150084 *lbmp = ixgbe->loopback_mode; 36996621Sbt150084 break; 37006621Sbt150084 37016621Sbt150084 case LB_SET_MODE: 37026621Sbt150084 size = 0; 37036621Sbt150084 if (iocp->ioc_count != sizeof (uint32_t)) 37046621Sbt150084 return (IOC_INVAL); 37056621Sbt150084 37066621Sbt150084 lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 37076621Sbt150084 if (!ixgbe_set_loopback_mode(ixgbe, *lbmp)) 37086621Sbt150084 return (IOC_INVAL); 37096621Sbt150084 break; 37106621Sbt150084 } 37116621Sbt150084 37126621Sbt150084 iocp->ioc_count = size; 37136621Sbt150084 iocp->ioc_error = 0; 37146621Sbt150084 37156621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 37166621Sbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 37176621Sbt150084 return (IOC_INVAL); 37186621Sbt150084 } 37196621Sbt150084 37206621Sbt150084 return (IOC_REPLY); 37216621Sbt150084 } 37226621Sbt150084 37236621Sbt150084 /* 37246621Sbt150084 * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode. 37256621Sbt150084 */ 37266621Sbt150084 static boolean_t 37276621Sbt150084 ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode) 37286621Sbt150084 { 37296621Sbt150084 if (mode == ixgbe->loopback_mode) 37306621Sbt150084 return (B_TRUE); 37316621Sbt150084 37326621Sbt150084 ixgbe->loopback_mode = mode; 37336621Sbt150084 37346621Sbt150084 if (mode == IXGBE_LB_NONE) { 37356621Sbt150084 /* 37366621Sbt150084 * Reset the chip 37376621Sbt150084 */ 37386621Sbt150084 (void) ixgbe_reset(ixgbe); 37396621Sbt150084 return (B_TRUE); 37406621Sbt150084 } 37416621Sbt150084 37426621Sbt150084 mutex_enter(&ixgbe->gen_lock); 37436621Sbt150084 37446621Sbt150084 switch (mode) { 37456621Sbt150084 default: 37466621Sbt150084 mutex_exit(&ixgbe->gen_lock); 37476621Sbt150084 return (B_FALSE); 37486621Sbt150084 374911150SZhen.W@Sun.COM case IXGBE_LB_EXTERNAL: 375011150SZhen.W@Sun.COM break; 375111150SZhen.W@Sun.COM 37526621Sbt150084 case IXGBE_LB_INTERNAL_MAC: 37536621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe); 37546621Sbt150084 break; 37556621Sbt150084 } 37566621Sbt150084 37576621Sbt150084 mutex_exit(&ixgbe->gen_lock); 37586621Sbt150084 37596621Sbt150084 return (B_TRUE); 37606621Sbt150084 } 37616621Sbt150084 37626621Sbt150084 /* 37636621Sbt150084 * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode. 37646621Sbt150084 */ 37656621Sbt150084 static void 37666621Sbt150084 ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe) 37676621Sbt150084 { 37686621Sbt150084 struct ixgbe_hw *hw; 37696621Sbt150084 uint32_t reg; 37706621Sbt150084 uint8_t atlas; 37716621Sbt150084 37726621Sbt150084 hw = &ixgbe->hw; 37736621Sbt150084 37746621Sbt150084 /* 37756621Sbt150084 * Setup MAC loopback 37766621Sbt150084 */ 37776621Sbt150084 reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0); 37786621Sbt150084 reg |= IXGBE_HLREG0_LPBK; 37796621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg); 37806621Sbt150084 37816621Sbt150084 reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC); 37826621Sbt150084 reg &= ~IXGBE_AUTOC_LMS_MASK; 37836621Sbt150084 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg); 37846621Sbt150084 37856621Sbt150084 /* 37866621Sbt150084 * Disable Atlas Tx lanes to keep packets in loopback and not on wire 37876621Sbt150084 */ 37886621Sbt150084 if (hw->mac.type == ixgbe_mac_82598EB) { 37896621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK, 37906621Sbt150084 &atlas); 37916621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_REG_EN; 37926621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK, 37936621Sbt150084 atlas); 37946621Sbt150084 37956621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G, 37966621Sbt150084 &atlas); 37976621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL; 37986621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G, 37996621Sbt150084 atlas); 38006621Sbt150084 38016621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G, 38026621Sbt150084 &atlas); 38036621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL; 38046621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G, 38056621Sbt150084 atlas); 38066621Sbt150084 38076621Sbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN, 38086621Sbt150084 &atlas); 38096621Sbt150084 atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL; 38106621Sbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN, 38116621Sbt150084 atlas); 38126621Sbt150084 } 38136621Sbt150084 } 38146621Sbt150084 38156621Sbt150084 #pragma inline(ixgbe_intr_rx_work) 38166621Sbt150084 /* 38176621Sbt150084 * ixgbe_intr_rx_work - RX processing of ISR. 38186621Sbt150084 */ 38196621Sbt150084 static void 38206621Sbt150084 ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring) 38216621Sbt150084 { 38226621Sbt150084 mblk_t *mp; 38236621Sbt150084 38246621Sbt150084 mutex_enter(&rx_ring->rx_lock); 38256621Sbt150084 38268275SEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL); 38276621Sbt150084 mutex_exit(&rx_ring->rx_lock); 38286621Sbt150084 38296621Sbt150084 if (mp != NULL) 38308275SEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp, 38318275SEric Cheng rx_ring->ring_gen_num); 38326621Sbt150084 } 38336621Sbt150084 38346621Sbt150084 #pragma inline(ixgbe_intr_tx_work) 38356621Sbt150084 /* 38366621Sbt150084 * ixgbe_intr_tx_work - TX processing of ISR. 38376621Sbt150084 */ 38386621Sbt150084 static void 38396621Sbt150084 ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring) 38406621Sbt150084 { 384110376SChenlu.Chen@Sun.COM ixgbe_t *ixgbe = tx_ring->ixgbe; 384210376SChenlu.Chen@Sun.COM 38436621Sbt150084 /* 38446621Sbt150084 * Recycle the tx descriptors 38456621Sbt150084 */ 38466621Sbt150084 tx_ring->tx_recycle(tx_ring); 38476621Sbt150084 38486621Sbt150084 /* 38496621Sbt150084 * Schedule the re-transmit 38506621Sbt150084 */ 38516621Sbt150084 if (tx_ring->reschedule && 385210376SChenlu.Chen@Sun.COM (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) { 38536621Sbt150084 tx_ring->reschedule = B_FALSE; 38548275SEric Cheng mac_tx_ring_update(tx_ring->ixgbe->mac_hdl, 38558275SEric Cheng tx_ring->ring_handle); 38566621Sbt150084 IXGBE_DEBUG_STAT(tx_ring->stat_reschedule); 38576621Sbt150084 } 38586621Sbt150084 } 38596621Sbt150084 38606621Sbt150084 #pragma inline(ixgbe_intr_other_work) 38616621Sbt150084 /* 38628490SPaul.Guo@Sun.COM * ixgbe_intr_other_work - Process interrupt types other than tx/rx 38636621Sbt150084 */ 38646621Sbt150084 static void 38658490SPaul.Guo@Sun.COM ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr) 38666621Sbt150084 { 38679353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 386811233SPaul.Guo@Sun.COM 386911233SPaul.Guo@Sun.COM ASSERT(mutex_owned(&ixgbe->gen_lock)); 387011233SPaul.Guo@Sun.COM 38718490SPaul.Guo@Sun.COM /* 387211233SPaul.Guo@Sun.COM * handle link status change 38738490SPaul.Guo@Sun.COM */ 38748490SPaul.Guo@Sun.COM if (eicr & IXGBE_EICR_LSC) { 387511233SPaul.Guo@Sun.COM ixgbe_driver_link_check(ixgbe); 38768490SPaul.Guo@Sun.COM } 38776621Sbt150084 38786621Sbt150084 /* 38798490SPaul.Guo@Sun.COM * check for fan failure on adapters with fans 38806621Sbt150084 */ 38818490SPaul.Guo@Sun.COM if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) && 38828490SPaul.Guo@Sun.COM (eicr & IXGBE_EICR_GPI_SDP1)) { 38839353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 38849353SSamuel.Tu@Sun.COM ixgbe_log(ixgbe, 38859353SSamuel.Tu@Sun.COM "Fan has stopped, replace the adapter\n"); 38869353SSamuel.Tu@Sun.COM 38879353SSamuel.Tu@Sun.COM /* re-enable the interrupt, which was automasked */ 38889353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_GPI_SDP1; 38899353SSamuel.Tu@Sun.COM } 38909353SSamuel.Tu@Sun.COM } 38919353SSamuel.Tu@Sun.COM 38929353SSamuel.Tu@Sun.COM /* 38939353SSamuel.Tu@Sun.COM * Do SFP check for 82599 38949353SSamuel.Tu@Sun.COM */ 38959353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 389611233SPaul.Guo@Sun.COM if ((ddi_taskq_dispatch(ixgbe->sfp_taskq, 38979353SSamuel.Tu@Sun.COM ixgbe_sfp_check, (void *)ixgbe, 38989353SSamuel.Tu@Sun.COM DDI_NOSLEEP)) != DDI_SUCCESS) { 389910305SPaul.Guo@Sun.COM ixgbe_log(ixgbe, "No memory available to dispatch " 390010305SPaul.Guo@Sun.COM "taskq for SFP check"); 39019353SSamuel.Tu@Sun.COM } 390211233SPaul.Guo@Sun.COM 390311233SPaul.Guo@Sun.COM /* 390411233SPaul.Guo@Sun.COM * We need to fully re-check the link later. 390511233SPaul.Guo@Sun.COM */ 390611233SPaul.Guo@Sun.COM ixgbe->link_check_complete = B_FALSE; 390711233SPaul.Guo@Sun.COM ixgbe->link_check_hrtime = gethrtime() + 390811233SPaul.Guo@Sun.COM (IXGBE_LINK_UP_TIME * 100000000ULL); 39098490SPaul.Guo@Sun.COM } 39106621Sbt150084 } 39116621Sbt150084 39126621Sbt150084 /* 39136621Sbt150084 * ixgbe_intr_legacy - Interrupt handler for legacy interrupts. 39146621Sbt150084 */ 39156621Sbt150084 static uint_t 39166621Sbt150084 ixgbe_intr_legacy(void *arg1, void *arg2) 39176621Sbt150084 { 39186621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg1; 39196621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 39206621Sbt150084 ixgbe_tx_ring_t *tx_ring; 39218275SEric Cheng ixgbe_rx_ring_t *rx_ring; 39226621Sbt150084 uint32_t eicr; 39236621Sbt150084 mblk_t *mp; 39246621Sbt150084 boolean_t tx_reschedule; 39256621Sbt150084 uint_t result; 39266621Sbt150084 39278490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 39286621Sbt150084 39296621Sbt150084 mutex_enter(&ixgbe->gen_lock); 39306621Sbt150084 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 39316621Sbt150084 mutex_exit(&ixgbe->gen_lock); 39326621Sbt150084 return (DDI_INTR_UNCLAIMED); 39336621Sbt150084 } 39346621Sbt150084 39356621Sbt150084 mp = NULL; 39366621Sbt150084 tx_reschedule = B_FALSE; 39376621Sbt150084 39386621Sbt150084 /* 39396621Sbt150084 * Any bit set in eicr: claim this interrupt 39406621Sbt150084 */ 39416621Sbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 394211233SPaul.Guo@Sun.COM 394311233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 394411233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 394511233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 394611233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 394711233SPaul.Guo@Sun.COM } 394811233SPaul.Guo@Sun.COM 39496621Sbt150084 if (eicr) { 39506621Sbt150084 /* 39516621Sbt150084 * For legacy interrupt, we have only one interrupt, 39526621Sbt150084 * so we have only one rx ring and one tx ring enabled. 39536621Sbt150084 */ 39546621Sbt150084 ASSERT(ixgbe->num_rx_rings == 1); 39556621Sbt150084 ASSERT(ixgbe->num_tx_rings == 1); 39566621Sbt150084 39576621Sbt150084 /* 39588275SEric Cheng * For legacy interrupt, rx rings[0] will use RTxQ[0]. 39596621Sbt150084 */ 39608275SEric Cheng if (eicr & 0x1) { 39619353SSamuel.Tu@Sun.COM ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE; 39629353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 39639353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; 39646621Sbt150084 /* 39656621Sbt150084 * Clean the rx descriptors 39666621Sbt150084 */ 39678275SEric Cheng rx_ring = &ixgbe->rx_rings[0]; 39688275SEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL); 39698275SEric Cheng } 39708275SEric Cheng 39718275SEric Cheng /* 39728275SEric Cheng * For legacy interrupt, tx rings[0] will use RTxQ[1]. 39738275SEric Cheng */ 39748275SEric Cheng if (eicr & 0x2) { 39756621Sbt150084 /* 39766621Sbt150084 * Recycle the tx descriptors 39776621Sbt150084 */ 39786621Sbt150084 tx_ring = &ixgbe->tx_rings[0]; 39796621Sbt150084 tx_ring->tx_recycle(tx_ring); 39806621Sbt150084 39816621Sbt150084 /* 39826621Sbt150084 * Schedule the re-transmit 39836621Sbt150084 */ 39846621Sbt150084 tx_reschedule = (tx_ring->reschedule && 398510376SChenlu.Chen@Sun.COM (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)); 39866621Sbt150084 } 39876621Sbt150084 39888490SPaul.Guo@Sun.COM /* any interrupt type other than tx/rx */ 39898490SPaul.Guo@Sun.COM if (eicr & ixgbe->capab->other_intr) { 39909353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 39919353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 39929353SSamuel.Tu@Sun.COM } 39939353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 39949353SSamuel.Tu@Sun.COM ixgbe->eimc = IXGBE_82599_OTHER_INTR; 39959353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 39969353SSamuel.Tu@Sun.COM } 39979353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 39988490SPaul.Guo@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 39996621Sbt150084 } 40006621Sbt150084 40018490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 40028490SPaul.Guo@Sun.COM 40036621Sbt150084 result = DDI_INTR_CLAIMED; 40046621Sbt150084 } else { 40058490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 40068490SPaul.Guo@Sun.COM 40076621Sbt150084 /* 40086621Sbt150084 * No interrupt cause bits set: don't claim this interrupt. 40096621Sbt150084 */ 40106621Sbt150084 result = DDI_INTR_UNCLAIMED; 40116621Sbt150084 } 40126621Sbt150084 40138490SPaul.Guo@Sun.COM /* re-enable the interrupts which were automasked */ 40148490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 40156621Sbt150084 40166621Sbt150084 /* 40176621Sbt150084 * Do the following work outside of the gen_lock 40186621Sbt150084 */ 40199353SSamuel.Tu@Sun.COM if (mp != NULL) { 40208275SEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp, 40218275SEric Cheng rx_ring->ring_gen_num); 40229353SSamuel.Tu@Sun.COM } 40236621Sbt150084 40246621Sbt150084 if (tx_reschedule) { 40256621Sbt150084 tx_ring->reschedule = B_FALSE; 40268275SEric Cheng mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle); 40276621Sbt150084 IXGBE_DEBUG_STAT(tx_ring->stat_reschedule); 40286621Sbt150084 } 40296621Sbt150084 40306621Sbt150084 return (result); 40316621Sbt150084 } 40326621Sbt150084 40336621Sbt150084 /* 40346621Sbt150084 * ixgbe_intr_msi - Interrupt handler for MSI. 40356621Sbt150084 */ 40366621Sbt150084 static uint_t 40376621Sbt150084 ixgbe_intr_msi(void *arg1, void *arg2) 40386621Sbt150084 { 40396621Sbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg1; 40406621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 40416621Sbt150084 uint32_t eicr; 40426621Sbt150084 40438490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 40448490SPaul.Guo@Sun.COM 40456621Sbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 40466621Sbt150084 404711233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 404811233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 404911233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 405011233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 405111233SPaul.Guo@Sun.COM } 405211233SPaul.Guo@Sun.COM 40536621Sbt150084 /* 40546621Sbt150084 * For MSI interrupt, we have only one vector, 40556621Sbt150084 * so we have only one rx ring and one tx ring enabled. 40566621Sbt150084 */ 40576621Sbt150084 ASSERT(ixgbe->num_rx_rings == 1); 40586621Sbt150084 ASSERT(ixgbe->num_tx_rings == 1); 40596621Sbt150084 40606621Sbt150084 /* 40618275SEric Cheng * For MSI interrupt, rx rings[0] will use RTxQ[0]. 40626621Sbt150084 */ 40638275SEric Cheng if (eicr & 0x1) { 40646621Sbt150084 ixgbe_intr_rx_work(&ixgbe->rx_rings[0]); 40658275SEric Cheng } 40668275SEric Cheng 40678275SEric Cheng /* 40688275SEric Cheng * For MSI interrupt, tx rings[0] will use RTxQ[1]. 40698275SEric Cheng */ 40708275SEric Cheng if (eicr & 0x2) { 40716621Sbt150084 ixgbe_intr_tx_work(&ixgbe->tx_rings[0]); 40726621Sbt150084 } 40736621Sbt150084 40748490SPaul.Guo@Sun.COM /* any interrupt type other than tx/rx */ 40758490SPaul.Guo@Sun.COM if (eicr & ixgbe->capab->other_intr) { 40768490SPaul.Guo@Sun.COM mutex_enter(&ixgbe->gen_lock); 40779353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 40789353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 40799353SSamuel.Tu@Sun.COM } 40809353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 40819353SSamuel.Tu@Sun.COM ixgbe->eimc = IXGBE_82599_OTHER_INTR; 40829353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 40839353SSamuel.Tu@Sun.COM } 40849353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 40858490SPaul.Guo@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 40868490SPaul.Guo@Sun.COM mutex_exit(&ixgbe->gen_lock); 40876621Sbt150084 } 40886621Sbt150084 40898490SPaul.Guo@Sun.COM /* re-enable the interrupts which were automasked */ 40908490SPaul.Guo@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 40918490SPaul.Guo@Sun.COM 40926621Sbt150084 return (DDI_INTR_CLAIMED); 40936621Sbt150084 } 40946621Sbt150084 40956621Sbt150084 /* 40969353SSamuel.Tu@Sun.COM * ixgbe_intr_msix - Interrupt handler for MSI-X. 40976621Sbt150084 */ 40986621Sbt150084 static uint_t 40999353SSamuel.Tu@Sun.COM ixgbe_intr_msix(void *arg1, void *arg2) 41006621Sbt150084 { 41019353SSamuel.Tu@Sun.COM ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1; 41028275SEric Cheng ixgbe_t *ixgbe = vect->ixgbe; 41039353SSamuel.Tu@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 41049353SSamuel.Tu@Sun.COM uint32_t eicr; 41058275SEric Cheng int r_idx = 0; 41066621Sbt150084 41078490SPaul.Guo@Sun.COM _NOTE(ARGUNUSED(arg2)); 41088490SPaul.Guo@Sun.COM 41096621Sbt150084 /* 41108275SEric Cheng * Clean each rx ring that has its bit set in the map 41116621Sbt150084 */ 41126621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1)); 41136621Sbt150084 while (r_idx >= 0) { 41146621Sbt150084 ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]); 41156621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1), 41166621Sbt150084 (ixgbe->num_rx_rings - 1)); 41176621Sbt150084 } 41186621Sbt150084 41198275SEric Cheng /* 41208275SEric Cheng * Clean each tx ring that has its bit set in the map 41218275SEric Cheng */ 41228275SEric Cheng r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1)); 41238275SEric Cheng while (r_idx >= 0) { 41248275SEric Cheng ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]); 41258275SEric Cheng r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1), 41268275SEric Cheng (ixgbe->num_tx_rings - 1)); 41278275SEric Cheng } 41288275SEric Cheng 41296621Sbt150084 41306621Sbt150084 /* 41319353SSamuel.Tu@Sun.COM * Clean other interrupt (link change) that has its bit set in the map 41326621Sbt150084 */ 41339353SSamuel.Tu@Sun.COM if (BT_TEST(vect->other_map, 0) == 1) { 41349353SSamuel.Tu@Sun.COM eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 41359353SSamuel.Tu@Sun.COM 413611233SPaul.Guo@Sun.COM if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != 413711233SPaul.Guo@Sun.COM DDI_FM_OK) { 413811233SPaul.Guo@Sun.COM ddi_fm_service_impact(ixgbe->dip, 413911233SPaul.Guo@Sun.COM DDI_SERVICE_DEGRADED); 414011233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 414111233SPaul.Guo@Sun.COM return (DDI_INTR_CLAIMED); 414211233SPaul.Guo@Sun.COM } 414311233SPaul.Guo@Sun.COM 41449353SSamuel.Tu@Sun.COM /* 41459353SSamuel.Tu@Sun.COM * Need check cause bits and only other causes will 41469353SSamuel.Tu@Sun.COM * be processed 41479353SSamuel.Tu@Sun.COM */ 41489353SSamuel.Tu@Sun.COM /* any interrupt type other than tx/rx */ 41499353SSamuel.Tu@Sun.COM if (eicr & ixgbe->capab->other_intr) { 41509353SSamuel.Tu@Sun.COM if (hw->mac.type < ixgbe_mac_82599EB) { 41519353SSamuel.Tu@Sun.COM mutex_enter(&ixgbe->gen_lock); 41529353SSamuel.Tu@Sun.COM ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 41539353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 41549353SSamuel.Tu@Sun.COM mutex_exit(&ixgbe->gen_lock); 41559353SSamuel.Tu@Sun.COM } else { 41569353SSamuel.Tu@Sun.COM if (hw->mac.type == ixgbe_mac_82599EB) { 41579353SSamuel.Tu@Sun.COM mutex_enter(&ixgbe->gen_lock); 41589353SSamuel.Tu@Sun.COM ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; 41599353SSamuel.Tu@Sun.COM ixgbe_intr_other_work(ixgbe, eicr); 41609353SSamuel.Tu@Sun.COM mutex_exit(&ixgbe->gen_lock); 41619353SSamuel.Tu@Sun.COM } 41629353SSamuel.Tu@Sun.COM } 41639353SSamuel.Tu@Sun.COM } 41649353SSamuel.Tu@Sun.COM 41659353SSamuel.Tu@Sun.COM /* re-enable the interrupts which were automasked */ 41669353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 41676621Sbt150084 } 41686621Sbt150084 41696621Sbt150084 return (DDI_INTR_CLAIMED); 41706621Sbt150084 } 41716621Sbt150084 41726621Sbt150084 /* 41736621Sbt150084 * ixgbe_alloc_intrs - Allocate interrupts for the driver. 41746621Sbt150084 * 41756621Sbt150084 * Normal sequence is to try MSI-X; if not sucessful, try MSI; 41766621Sbt150084 * if not successful, try Legacy. 41776621Sbt150084 * ixgbe->intr_force can be used to force sequence to start with 41786621Sbt150084 * any of the 3 types. 41796621Sbt150084 * If MSI-X is not used, number of tx/rx rings is forced to 1. 41806621Sbt150084 */ 41816621Sbt150084 static int 41826621Sbt150084 ixgbe_alloc_intrs(ixgbe_t *ixgbe) 41836621Sbt150084 { 41846621Sbt150084 dev_info_t *devinfo; 41856621Sbt150084 int intr_types; 41866621Sbt150084 int rc; 41876621Sbt150084 41886621Sbt150084 devinfo = ixgbe->dip; 41896621Sbt150084 41906621Sbt150084 /* 41916621Sbt150084 * Get supported interrupt types 41926621Sbt150084 */ 41936621Sbt150084 rc = ddi_intr_get_supported_types(devinfo, &intr_types); 41946621Sbt150084 41956621Sbt150084 if (rc != DDI_SUCCESS) { 41966621Sbt150084 ixgbe_log(ixgbe, 41976621Sbt150084 "Get supported interrupt types failed: %d", rc); 41986621Sbt150084 return (IXGBE_FAILURE); 41996621Sbt150084 } 42006621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types); 42016621Sbt150084 42026621Sbt150084 ixgbe->intr_type = 0; 42036621Sbt150084 42046621Sbt150084 /* 42056621Sbt150084 * Install MSI-X interrupts 42066621Sbt150084 */ 42076621Sbt150084 if ((intr_types & DDI_INTR_TYPE_MSIX) && 42086621Sbt150084 (ixgbe->intr_force <= IXGBE_INTR_MSIX)) { 42096621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX); 42106621Sbt150084 if (rc == IXGBE_SUCCESS) 42116621Sbt150084 return (IXGBE_SUCCESS); 42126621Sbt150084 42136621Sbt150084 ixgbe_log(ixgbe, 42146621Sbt150084 "Allocate MSI-X failed, trying MSI interrupts..."); 42156621Sbt150084 } 42166621Sbt150084 42176621Sbt150084 /* 42188275SEric Cheng * MSI-X not used, force rings and groups to 1 42196621Sbt150084 */ 42206621Sbt150084 ixgbe->num_rx_rings = 1; 42218275SEric Cheng ixgbe->num_rx_groups = 1; 42226621Sbt150084 ixgbe->num_tx_rings = 1; 422311878SVenu.Iyer@Sun.COM ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 42246621Sbt150084 ixgbe_log(ixgbe, 42258275SEric Cheng "MSI-X not used, force rings and groups number to 1"); 42266621Sbt150084 42276621Sbt150084 /* 42286621Sbt150084 * Install MSI interrupts 42296621Sbt150084 */ 42306621Sbt150084 if ((intr_types & DDI_INTR_TYPE_MSI) && 42316621Sbt150084 (ixgbe->intr_force <= IXGBE_INTR_MSI)) { 42326621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI); 42336621Sbt150084 if (rc == IXGBE_SUCCESS) 42346621Sbt150084 return (IXGBE_SUCCESS); 42356621Sbt150084 42366621Sbt150084 ixgbe_log(ixgbe, 42376621Sbt150084 "Allocate MSI failed, trying Legacy interrupts..."); 42386621Sbt150084 } 42396621Sbt150084 42406621Sbt150084 /* 42416621Sbt150084 * Install legacy interrupts 42426621Sbt150084 */ 42436621Sbt150084 if (intr_types & DDI_INTR_TYPE_FIXED) { 42446621Sbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED); 42456621Sbt150084 if (rc == IXGBE_SUCCESS) 42466621Sbt150084 return (IXGBE_SUCCESS); 42476621Sbt150084 42486621Sbt150084 ixgbe_log(ixgbe, 42496621Sbt150084 "Allocate Legacy interrupts failed"); 42506621Sbt150084 } 42516621Sbt150084 42526621Sbt150084 /* 42536621Sbt150084 * If none of the 3 types succeeded, return failure 42546621Sbt150084 */ 42556621Sbt150084 return (IXGBE_FAILURE); 42566621Sbt150084 } 42576621Sbt150084 42586621Sbt150084 /* 42596621Sbt150084 * ixgbe_alloc_intr_handles - Allocate interrupt handles. 42606621Sbt150084 * 42616621Sbt150084 * For legacy and MSI, only 1 handle is needed. For MSI-X, 42626621Sbt150084 * if fewer than 2 handles are available, return failure. 42638275SEric Cheng * Upon success, this maps the vectors to rx and tx rings for 42648275SEric Cheng * interrupts. 42656621Sbt150084 */ 42666621Sbt150084 static int 42676621Sbt150084 ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type) 42686621Sbt150084 { 42696621Sbt150084 dev_info_t *devinfo; 427011878SVenu.Iyer@Sun.COM int request, count, actual; 42718275SEric Cheng int minimum; 42726621Sbt150084 int rc; 427311878SVenu.Iyer@Sun.COM uint32_t ring_per_group; 42746621Sbt150084 42756621Sbt150084 devinfo = ixgbe->dip; 42766621Sbt150084 42776621Sbt150084 switch (intr_type) { 42786621Sbt150084 case DDI_INTR_TYPE_FIXED: 42796621Sbt150084 request = 1; /* Request 1 legacy interrupt handle */ 42806621Sbt150084 minimum = 1; 42816621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy"); 42826621Sbt150084 break; 42836621Sbt150084 42846621Sbt150084 case DDI_INTR_TYPE_MSI: 42856621Sbt150084 request = 1; /* Request 1 MSI interrupt handle */ 42866621Sbt150084 minimum = 1; 42876621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI"); 42886621Sbt150084 break; 42896621Sbt150084 42906621Sbt150084 case DDI_INTR_TYPE_MSIX: 42916621Sbt150084 /* 42926621Sbt150084 * Best number of vectors for the adapter is 429311878SVenu.Iyer@Sun.COM * (# rx rings + # tx rings), however we will 429411878SVenu.Iyer@Sun.COM * limit the request number. 42956621Sbt150084 */ 429611878SVenu.Iyer@Sun.COM request = min(16, ixgbe->num_rx_rings + ixgbe->num_tx_rings); 42979353SSamuel.Tu@Sun.COM if (request > ixgbe->capab->max_ring_vect) 42989353SSamuel.Tu@Sun.COM request = ixgbe->capab->max_ring_vect; 429911878SVenu.Iyer@Sun.COM minimum = 1; 43006621Sbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X"); 43016621Sbt150084 break; 43026621Sbt150084 43036621Sbt150084 default: 43046621Sbt150084 ixgbe_log(ixgbe, 43056621Sbt150084 "invalid call to ixgbe_alloc_intr_handles(): %d\n", 43066621Sbt150084 intr_type); 43076621Sbt150084 return (IXGBE_FAILURE); 43086621Sbt150084 } 43096621Sbt150084 IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d minimum: %d", 43106621Sbt150084 request, minimum); 43116621Sbt150084 43126621Sbt150084 /* 43136621Sbt150084 * Get number of supported interrupts 43146621Sbt150084 */ 43156621Sbt150084 rc = ddi_intr_get_nintrs(devinfo, intr_type, &count); 43166621Sbt150084 if ((rc != DDI_SUCCESS) || (count < minimum)) { 43176621Sbt150084 ixgbe_log(ixgbe, 43186621Sbt150084 "Get interrupt number failed. Return: %d, count: %d", 43196621Sbt150084 rc, count); 43206621Sbt150084 return (IXGBE_FAILURE); 43216621Sbt150084 } 43226621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count); 43236621Sbt150084 43246621Sbt150084 actual = 0; 43256621Sbt150084 ixgbe->intr_cnt = 0; 432611878SVenu.Iyer@Sun.COM ixgbe->intr_cnt_max = 0; 432711878SVenu.Iyer@Sun.COM ixgbe->intr_cnt_min = 0; 43286621Sbt150084 43296621Sbt150084 /* 43306621Sbt150084 * Allocate an array of interrupt handles 43316621Sbt150084 */ 43326621Sbt150084 ixgbe->intr_size = request * sizeof (ddi_intr_handle_t); 43336621Sbt150084 ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP); 43346621Sbt150084 43356621Sbt150084 rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0, 43366621Sbt150084 request, &actual, DDI_INTR_ALLOC_NORMAL); 43376621Sbt150084 if (rc != DDI_SUCCESS) { 43386621Sbt150084 ixgbe_log(ixgbe, "Allocate interrupts failed. " 43396621Sbt150084 "return: %d, request: %d, actual: %d", 43406621Sbt150084 rc, request, actual); 43416621Sbt150084 goto alloc_handle_fail; 43426621Sbt150084 } 43436621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual); 43446621Sbt150084 434511878SVenu.Iyer@Sun.COM /* 434611878SVenu.Iyer@Sun.COM * upper/lower limit of interrupts 434711878SVenu.Iyer@Sun.COM */ 43486621Sbt150084 ixgbe->intr_cnt = actual; 434911878SVenu.Iyer@Sun.COM ixgbe->intr_cnt_max = request; 435011878SVenu.Iyer@Sun.COM ixgbe->intr_cnt_min = minimum; 435111878SVenu.Iyer@Sun.COM 435211878SVenu.Iyer@Sun.COM /* 435311878SVenu.Iyer@Sun.COM * rss number per group should not exceed the rx interrupt number, 435411878SVenu.Iyer@Sun.COM * else need to adjust rx ring number. 435511878SVenu.Iyer@Sun.COM */ 435611878SVenu.Iyer@Sun.COM ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 435711878SVenu.Iyer@Sun.COM ASSERT((ixgbe->num_rx_rings % ixgbe->num_rx_groups) == 0); 435811878SVenu.Iyer@Sun.COM if (min(actual, ixgbe->num_rx_rings) < ring_per_group) { 435911878SVenu.Iyer@Sun.COM ixgbe->num_rx_rings = ixgbe->num_rx_groups * 436011878SVenu.Iyer@Sun.COM min(actual, ixgbe->num_rx_rings); 436111878SVenu.Iyer@Sun.COM ixgbe_setup_vmdq_rss_conf(ixgbe); 436211878SVenu.Iyer@Sun.COM } 43636621Sbt150084 43646621Sbt150084 /* 43658275SEric Cheng * Now we know the actual number of vectors. Here we map the vector 43668275SEric Cheng * to other, rx rings and tx ring. 43676621Sbt150084 */ 43686621Sbt150084 if (actual < minimum) { 43696621Sbt150084 ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d", 43706621Sbt150084 actual); 43716621Sbt150084 goto alloc_handle_fail; 43726621Sbt150084 } 43736621Sbt150084 43746621Sbt150084 /* 43756621Sbt150084 * Get priority for first vector, assume remaining are all the same 43766621Sbt150084 */ 43776621Sbt150084 rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri); 43786621Sbt150084 if (rc != DDI_SUCCESS) { 43796621Sbt150084 ixgbe_log(ixgbe, 43806621Sbt150084 "Get interrupt priority failed: %d", rc); 43816621Sbt150084 goto alloc_handle_fail; 43826621Sbt150084 } 43836621Sbt150084 43846621Sbt150084 rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap); 43856621Sbt150084 if (rc != DDI_SUCCESS) { 43866621Sbt150084 ixgbe_log(ixgbe, 43876621Sbt150084 "Get interrupt cap failed: %d", rc); 43886621Sbt150084 goto alloc_handle_fail; 43896621Sbt150084 } 43906621Sbt150084 43916621Sbt150084 ixgbe->intr_type = intr_type; 43926621Sbt150084 43936621Sbt150084 return (IXGBE_SUCCESS); 43946621Sbt150084 43956621Sbt150084 alloc_handle_fail: 43966621Sbt150084 ixgbe_rem_intrs(ixgbe); 43976621Sbt150084 43986621Sbt150084 return (IXGBE_FAILURE); 43996621Sbt150084 } 44006621Sbt150084 44016621Sbt150084 /* 44026621Sbt150084 * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type. 44036621Sbt150084 * 44046621Sbt150084 * Before adding the interrupt handlers, the interrupt vectors have 44056621Sbt150084 * been allocated, and the rx/tx rings have also been allocated. 44066621Sbt150084 */ 44076621Sbt150084 static int 44086621Sbt150084 ixgbe_add_intr_handlers(ixgbe_t *ixgbe) 44096621Sbt150084 { 44108275SEric Cheng int vector = 0; 44116621Sbt150084 int rc; 44126621Sbt150084 44136621Sbt150084 switch (ixgbe->intr_type) { 44146621Sbt150084 case DDI_INTR_TYPE_MSIX: 44156621Sbt150084 /* 44169353SSamuel.Tu@Sun.COM * Add interrupt handler for all vectors 44176621Sbt150084 */ 44189353SSamuel.Tu@Sun.COM for (vector = 0; vector < ixgbe->intr_cnt; vector++) { 44196621Sbt150084 /* 44206621Sbt150084 * install pointer to vect_map[vector] 44216621Sbt150084 */ 44226621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 44239353SSamuel.Tu@Sun.COM (ddi_intr_handler_t *)ixgbe_intr_msix, 44246621Sbt150084 (void *)&ixgbe->vect_map[vector], NULL); 44256621Sbt150084 44266621Sbt150084 if (rc != DDI_SUCCESS) { 44276621Sbt150084 ixgbe_log(ixgbe, 44286621Sbt150084 "Add rx interrupt handler failed. " 44298275SEric Cheng "return: %d, vector: %d", rc, vector); 44306621Sbt150084 for (vector--; vector >= 0; vector--) { 44316621Sbt150084 (void) ddi_intr_remove_handler( 44326621Sbt150084 ixgbe->htable[vector]); 44336621Sbt150084 } 44346621Sbt150084 return (IXGBE_FAILURE); 44356621Sbt150084 } 44366621Sbt150084 } 44378275SEric Cheng 44386621Sbt150084 break; 44396621Sbt150084 44406621Sbt150084 case DDI_INTR_TYPE_MSI: 44416621Sbt150084 /* 44426621Sbt150084 * Add interrupt handlers for the only vector 44436621Sbt150084 */ 44446621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 44456621Sbt150084 (ddi_intr_handler_t *)ixgbe_intr_msi, 44466621Sbt150084 (void *)ixgbe, NULL); 44476621Sbt150084 44486621Sbt150084 if (rc != DDI_SUCCESS) { 44496621Sbt150084 ixgbe_log(ixgbe, 44506621Sbt150084 "Add MSI interrupt handler failed: %d", rc); 44516621Sbt150084 return (IXGBE_FAILURE); 44526621Sbt150084 } 44536621Sbt150084 44546621Sbt150084 break; 44556621Sbt150084 44566621Sbt150084 case DDI_INTR_TYPE_FIXED: 44576621Sbt150084 /* 44586621Sbt150084 * Add interrupt handlers for the only vector 44596621Sbt150084 */ 44606621Sbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 44616621Sbt150084 (ddi_intr_handler_t *)ixgbe_intr_legacy, 44626621Sbt150084 (void *)ixgbe, NULL); 44636621Sbt150084 44646621Sbt150084 if (rc != DDI_SUCCESS) { 44656621Sbt150084 ixgbe_log(ixgbe, 44666621Sbt150084 "Add legacy interrupt handler failed: %d", rc); 44676621Sbt150084 return (IXGBE_FAILURE); 44686621Sbt150084 } 44696621Sbt150084 44706621Sbt150084 break; 44716621Sbt150084 44726621Sbt150084 default: 44736621Sbt150084 return (IXGBE_FAILURE); 44746621Sbt150084 } 44756621Sbt150084 44766621Sbt150084 return (IXGBE_SUCCESS); 44776621Sbt150084 } 44786621Sbt150084 44796621Sbt150084 #pragma inline(ixgbe_map_rxring_to_vector) 44806621Sbt150084 /* 44816621Sbt150084 * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector. 44826621Sbt150084 */ 44836621Sbt150084 static void 44846621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx) 44856621Sbt150084 { 44866621Sbt150084 /* 44876621Sbt150084 * Set bit in map 44886621Sbt150084 */ 44896621Sbt150084 BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx); 44906621Sbt150084 44916621Sbt150084 /* 44926621Sbt150084 * Count bits set 44936621Sbt150084 */ 44946621Sbt150084 ixgbe->vect_map[v_idx].rxr_cnt++; 44956621Sbt150084 44966621Sbt150084 /* 44976621Sbt150084 * Remember bit position 44986621Sbt150084 */ 44998275SEric Cheng ixgbe->rx_rings[r_idx].intr_vector = v_idx; 45006621Sbt150084 ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx; 45016621Sbt150084 } 45026621Sbt150084 45036621Sbt150084 #pragma inline(ixgbe_map_txring_to_vector) 45046621Sbt150084 /* 45056621Sbt150084 * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector. 45066621Sbt150084 */ 45076621Sbt150084 static void 45086621Sbt150084 ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx) 45096621Sbt150084 { 45106621Sbt150084 /* 45116621Sbt150084 * Set bit in map 45126621Sbt150084 */ 45136621Sbt150084 BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx); 45146621Sbt150084 45156621Sbt150084 /* 45166621Sbt150084 * Count bits set 45176621Sbt150084 */ 45186621Sbt150084 ixgbe->vect_map[v_idx].txr_cnt++; 45196621Sbt150084 45206621Sbt150084 /* 45216621Sbt150084 * Remember bit position 45226621Sbt150084 */ 45238275SEric Cheng ixgbe->tx_rings[t_idx].intr_vector = v_idx; 45246621Sbt150084 ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx; 45256621Sbt150084 } 45266621Sbt150084 45276621Sbt150084 /* 45288275SEric Cheng * ixgbe_setup_ivar - Set the given entry in the given interrupt vector 45296621Sbt150084 * allocation register (IVAR). 45309353SSamuel.Tu@Sun.COM * cause: 45319353SSamuel.Tu@Sun.COM * -1 : other cause 45329353SSamuel.Tu@Sun.COM * 0 : rx 45339353SSamuel.Tu@Sun.COM * 1 : tx 45346621Sbt150084 */ 45356621Sbt150084 static void 45369353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector, 45379353SSamuel.Tu@Sun.COM int8_t cause) 45386621Sbt150084 { 45396621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 45406621Sbt150084 u32 ivar, index; 45416621Sbt150084 45429353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 45439353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 45449353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 45459353SSamuel.Tu@Sun.COM if (cause == -1) { 45469353SSamuel.Tu@Sun.COM cause = 0; 45479353SSamuel.Tu@Sun.COM } 45489353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 45499353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 45509353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3))); 45519353SSamuel.Tu@Sun.COM ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3))); 45529353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 45539353SSamuel.Tu@Sun.COM break; 45549353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 45559353SSamuel.Tu@Sun.COM if (cause == -1) { 45569353SSamuel.Tu@Sun.COM /* other causes */ 45579353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 45589353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 45599353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 45609353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << index); 45619353SSamuel.Tu@Sun.COM ivar |= (msix_vector << index); 45629353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 45639353SSamuel.Tu@Sun.COM } else { 45649353SSamuel.Tu@Sun.COM /* tx or rx causes */ 45659353SSamuel.Tu@Sun.COM msix_vector |= IXGBE_IVAR_ALLOC_VAL; 45669353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 45679353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 45689353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 45699353SSamuel.Tu@Sun.COM ivar &= ~(0xFF << index); 45709353SSamuel.Tu@Sun.COM ivar |= (msix_vector << index); 45719353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 45729353SSamuel.Tu@Sun.COM ivar); 45739353SSamuel.Tu@Sun.COM } 45749353SSamuel.Tu@Sun.COM break; 45759353SSamuel.Tu@Sun.COM default: 45769353SSamuel.Tu@Sun.COM break; 45779353SSamuel.Tu@Sun.COM } 45788275SEric Cheng } 45798275SEric Cheng 45808275SEric Cheng /* 45818275SEric Cheng * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of 45828275SEric Cheng * given interrupt vector allocation register (IVAR). 45839353SSamuel.Tu@Sun.COM * cause: 45849353SSamuel.Tu@Sun.COM * -1 : other cause 45859353SSamuel.Tu@Sun.COM * 0 : rx 45869353SSamuel.Tu@Sun.COM * 1 : tx 45878275SEric Cheng */ 45888275SEric Cheng static void 45899353SSamuel.Tu@Sun.COM ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause) 45908275SEric Cheng { 45918275SEric Cheng struct ixgbe_hw *hw = &ixgbe->hw; 45928275SEric Cheng u32 ivar, index; 45938275SEric Cheng 45949353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 45959353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 45969353SSamuel.Tu@Sun.COM if (cause == -1) { 45979353SSamuel.Tu@Sun.COM cause = 0; 45989353SSamuel.Tu@Sun.COM } 45999353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 46009353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 46019353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 * 46029353SSamuel.Tu@Sun.COM (intr_alloc_entry & 0x3))); 46039353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 46049353SSamuel.Tu@Sun.COM break; 46059353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 46069353SSamuel.Tu@Sun.COM if (cause == -1) { 46079353SSamuel.Tu@Sun.COM /* other causes */ 46089353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 46099353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 46109353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << index); 46119353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 46129353SSamuel.Tu@Sun.COM } else { 46139353SSamuel.Tu@Sun.COM /* tx or rx causes */ 46149353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 46159353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 46169353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 46179353SSamuel.Tu@Sun.COM ivar |= (IXGBE_IVAR_ALLOC_VAL << index); 46189353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 46199353SSamuel.Tu@Sun.COM ivar); 46209353SSamuel.Tu@Sun.COM } 46219353SSamuel.Tu@Sun.COM break; 46229353SSamuel.Tu@Sun.COM default: 46239353SSamuel.Tu@Sun.COM break; 46249353SSamuel.Tu@Sun.COM } 46258275SEric Cheng } 46268275SEric Cheng 46278275SEric Cheng /* 46289353SSamuel.Tu@Sun.COM * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of 46298275SEric Cheng * given interrupt vector allocation register (IVAR). 46309353SSamuel.Tu@Sun.COM * cause: 46319353SSamuel.Tu@Sun.COM * -1 : other cause 46329353SSamuel.Tu@Sun.COM * 0 : rx 46339353SSamuel.Tu@Sun.COM * 1 : tx 46348275SEric Cheng */ 46358275SEric Cheng static void 46369353SSamuel.Tu@Sun.COM ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause) 46378275SEric Cheng { 46388275SEric Cheng struct ixgbe_hw *hw = &ixgbe->hw; 46398275SEric Cheng u32 ivar, index; 46408275SEric Cheng 46419353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 46429353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 46439353SSamuel.Tu@Sun.COM if (cause == -1) { 46449353SSamuel.Tu@Sun.COM cause = 0; 46459353SSamuel.Tu@Sun.COM } 46469353SSamuel.Tu@Sun.COM index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 46479353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 46489353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 * 46499353SSamuel.Tu@Sun.COM (intr_alloc_entry & 0x3))); 46509353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 46519353SSamuel.Tu@Sun.COM break; 46529353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 46539353SSamuel.Tu@Sun.COM if (cause == -1) { 46549353SSamuel.Tu@Sun.COM /* other causes */ 46559353SSamuel.Tu@Sun.COM index = (intr_alloc_entry & 1) * 8; 46569353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 46579353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index); 46589353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 46599353SSamuel.Tu@Sun.COM } else { 46609353SSamuel.Tu@Sun.COM /* tx or rx causes */ 46619353SSamuel.Tu@Sun.COM index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 46629353SSamuel.Tu@Sun.COM ivar = IXGBE_READ_REG(hw, 46639353SSamuel.Tu@Sun.COM IXGBE_IVAR(intr_alloc_entry >> 1)); 46649353SSamuel.Tu@Sun.COM ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index); 46659353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 46669353SSamuel.Tu@Sun.COM ivar); 46679353SSamuel.Tu@Sun.COM } 46689353SSamuel.Tu@Sun.COM break; 46699353SSamuel.Tu@Sun.COM default: 46709353SSamuel.Tu@Sun.COM break; 46719353SSamuel.Tu@Sun.COM } 46726621Sbt150084 } 46736621Sbt150084 46746621Sbt150084 /* 467511878SVenu.Iyer@Sun.COM * Convert the rx ring index driver maintained to the rx ring index 467611878SVenu.Iyer@Sun.COM * in h/w. 467711878SVenu.Iyer@Sun.COM */ 467811878SVenu.Iyer@Sun.COM static uint32_t 467911878SVenu.Iyer@Sun.COM ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index) 468011878SVenu.Iyer@Sun.COM { 468111878SVenu.Iyer@Sun.COM 468211878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 468311878SVenu.Iyer@Sun.COM uint32_t rx_ring_per_group, hw_rx_index; 468411878SVenu.Iyer@Sun.COM 468511878SVenu.Iyer@Sun.COM if (ixgbe->classify_mode == IXGBE_CLASSIFY_RSS || 468611878SVenu.Iyer@Sun.COM ixgbe->classify_mode == IXGBE_CLASSIFY_NONE) { 468711878SVenu.Iyer@Sun.COM return (sw_rx_index); 468811878SVenu.Iyer@Sun.COM } else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ) { 468911878SVenu.Iyer@Sun.COM if (hw->mac.type == ixgbe_mac_82598EB) { 469011878SVenu.Iyer@Sun.COM return (sw_rx_index); 469111878SVenu.Iyer@Sun.COM } else if (hw->mac.type == ixgbe_mac_82599EB) { 469211878SVenu.Iyer@Sun.COM return (sw_rx_index * 2); 469311878SVenu.Iyer@Sun.COM } 469411878SVenu.Iyer@Sun.COM } else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) { 469511878SVenu.Iyer@Sun.COM rx_ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 469611878SVenu.Iyer@Sun.COM 469711878SVenu.Iyer@Sun.COM if (hw->mac.type == ixgbe_mac_82598EB) { 469811878SVenu.Iyer@Sun.COM hw_rx_index = (sw_rx_index / rx_ring_per_group) * 469911878SVenu.Iyer@Sun.COM 16 + (sw_rx_index % rx_ring_per_group); 470011878SVenu.Iyer@Sun.COM return (hw_rx_index); 470111878SVenu.Iyer@Sun.COM } else if (hw->mac.type == ixgbe_mac_82599EB) { 470211878SVenu.Iyer@Sun.COM if (ixgbe->num_rx_groups > 32) { 470311878SVenu.Iyer@Sun.COM hw_rx_index = (sw_rx_index / 470411878SVenu.Iyer@Sun.COM rx_ring_per_group) * 2 + 470511878SVenu.Iyer@Sun.COM (sw_rx_index % rx_ring_per_group); 470611878SVenu.Iyer@Sun.COM } else { 470711878SVenu.Iyer@Sun.COM hw_rx_index = (sw_rx_index / 470811878SVenu.Iyer@Sun.COM rx_ring_per_group) * 4 + 470911878SVenu.Iyer@Sun.COM (sw_rx_index % rx_ring_per_group); 471011878SVenu.Iyer@Sun.COM } 471111878SVenu.Iyer@Sun.COM return (hw_rx_index); 471211878SVenu.Iyer@Sun.COM } 471311878SVenu.Iyer@Sun.COM } 471411878SVenu.Iyer@Sun.COM 471511878SVenu.Iyer@Sun.COM /* 471611878SVenu.Iyer@Sun.COM * Should never reach. Just to make compiler happy. 471711878SVenu.Iyer@Sun.COM */ 471811878SVenu.Iyer@Sun.COM return (sw_rx_index); 471911878SVenu.Iyer@Sun.COM } 472011878SVenu.Iyer@Sun.COM 472111878SVenu.Iyer@Sun.COM /* 47229353SSamuel.Tu@Sun.COM * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors. 47236621Sbt150084 * 47249353SSamuel.Tu@Sun.COM * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt 47259353SSamuel.Tu@Sun.COM * to vector[0 - (intr_cnt -1)]. 47266621Sbt150084 */ 47276621Sbt150084 static int 47289353SSamuel.Tu@Sun.COM ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe) 47296621Sbt150084 { 47306621Sbt150084 int i, vector = 0; 47316621Sbt150084 47326621Sbt150084 /* initialize vector map */ 47336621Sbt150084 bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map)); 47349353SSamuel.Tu@Sun.COM for (i = 0; i < ixgbe->intr_cnt; i++) { 47359353SSamuel.Tu@Sun.COM ixgbe->vect_map[i].ixgbe = ixgbe; 47369353SSamuel.Tu@Sun.COM } 47376621Sbt150084 47386621Sbt150084 /* 47398275SEric Cheng * non-MSI-X case is very simple: rx rings[0] on RTxQ[0], 47408275SEric Cheng * tx rings[0] on RTxQ[1]. 47416621Sbt150084 */ 47426621Sbt150084 if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) { 47436621Sbt150084 ixgbe_map_rxring_to_vector(ixgbe, 0, 0); 47448275SEric Cheng ixgbe_map_txring_to_vector(ixgbe, 0, 1); 47456621Sbt150084 return (IXGBE_SUCCESS); 47466621Sbt150084 } 47476621Sbt150084 47486621Sbt150084 /* 47499353SSamuel.Tu@Sun.COM * Interrupts/vectors mapping for MSI-X 47506621Sbt150084 */ 47516621Sbt150084 47526621Sbt150084 /* 47539353SSamuel.Tu@Sun.COM * Map other interrupt to vector 0, 47549353SSamuel.Tu@Sun.COM * Set bit in map and count the bits set. 47559353SSamuel.Tu@Sun.COM */ 47569353SSamuel.Tu@Sun.COM BT_SET(ixgbe->vect_map[vector].other_map, 0); 47579353SSamuel.Tu@Sun.COM ixgbe->vect_map[vector].other_cnt++; 47589353SSamuel.Tu@Sun.COM 47599353SSamuel.Tu@Sun.COM /* 47609353SSamuel.Tu@Sun.COM * Map rx ring interrupts to vectors 47616621Sbt150084 */ 47628275SEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) { 47638275SEric Cheng ixgbe_map_rxring_to_vector(ixgbe, i, vector); 47649353SSamuel.Tu@Sun.COM vector = (vector +1) % ixgbe->intr_cnt; 47658275SEric Cheng } 47666621Sbt150084 47676621Sbt150084 /* 47689353SSamuel.Tu@Sun.COM * Map tx ring interrupts to vectors 47696621Sbt150084 */ 47708275SEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) { 47718275SEric Cheng ixgbe_map_txring_to_vector(ixgbe, i, vector); 47729353SSamuel.Tu@Sun.COM vector = (vector +1) % ixgbe->intr_cnt; 47736621Sbt150084 } 47746621Sbt150084 47756621Sbt150084 return (IXGBE_SUCCESS); 47766621Sbt150084 } 47776621Sbt150084 47786621Sbt150084 /* 47796621Sbt150084 * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s). 47806621Sbt150084 * 47818275SEric Cheng * This relies on ring/vector mapping already set up in the 47826621Sbt150084 * vect_map[] structures 47836621Sbt150084 */ 47846621Sbt150084 static void 47856621Sbt150084 ixgbe_setup_adapter_vector(ixgbe_t *ixgbe) 47866621Sbt150084 { 47876621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 47889353SSamuel.Tu@Sun.COM ixgbe_intr_vector_t *vect; /* vector bitmap */ 47898275SEric Cheng int r_idx; /* ring index */ 47908275SEric Cheng int v_idx; /* vector index */ 479111878SVenu.Iyer@Sun.COM uint32_t hw_index; 47926621Sbt150084 47936621Sbt150084 /* 47946621Sbt150084 * Clear any previous entries 47956621Sbt150084 */ 47969353SSamuel.Tu@Sun.COM switch (hw->mac.type) { 47979353SSamuel.Tu@Sun.COM case ixgbe_mac_82598EB: 47989353SSamuel.Tu@Sun.COM for (v_idx = 0; v_idx < 25; v_idx++) 47999353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); 48009353SSamuel.Tu@Sun.COM 48019353SSamuel.Tu@Sun.COM break; 48029353SSamuel.Tu@Sun.COM case ixgbe_mac_82599EB: 48039353SSamuel.Tu@Sun.COM for (v_idx = 0; v_idx < 64; v_idx++) 48049353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); 48059353SSamuel.Tu@Sun.COM IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0); 48069353SSamuel.Tu@Sun.COM 48079353SSamuel.Tu@Sun.COM break; 48089353SSamuel.Tu@Sun.COM default: 48099353SSamuel.Tu@Sun.COM break; 48109353SSamuel.Tu@Sun.COM } 48116621Sbt150084 48126621Sbt150084 /* 48138275SEric Cheng * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and 48148275SEric Cheng * tx rings[0] will use RTxQ[1]. 48156621Sbt150084 */ 48168275SEric Cheng if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) { 48179353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, 0, 0, 0); 48189353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, 0, 1, 1); 48198275SEric Cheng return; 48208275SEric Cheng } 48218275SEric Cheng 48228275SEric Cheng /* 48239353SSamuel.Tu@Sun.COM * For MSI-X interrupt, "Other" is always on vector[0]. 48248275SEric Cheng */ 48259353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1); 48266621Sbt150084 48276621Sbt150084 /* 48286621Sbt150084 * For each interrupt vector, populate the IVAR table 48296621Sbt150084 */ 48306621Sbt150084 for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) { 48316621Sbt150084 vect = &ixgbe->vect_map[v_idx]; 48326621Sbt150084 48336621Sbt150084 /* 48346621Sbt150084 * For each rx ring bit set 48356621Sbt150084 */ 48366621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, 0, 48376621Sbt150084 (ixgbe->num_rx_rings - 1)); 48386621Sbt150084 48396621Sbt150084 while (r_idx >= 0) { 484011878SVenu.Iyer@Sun.COM hw_index = ixgbe->rx_rings[r_idx].hw_index; 484111878SVenu.Iyer@Sun.COM ixgbe_setup_ivar(ixgbe, hw_index, v_idx, 0); 48426621Sbt150084 r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1), 48436621Sbt150084 (ixgbe->num_rx_rings - 1)); 48446621Sbt150084 } 48456621Sbt150084 48466621Sbt150084 /* 48476621Sbt150084 * For each tx ring bit set 48486621Sbt150084 */ 48496621Sbt150084 r_idx = bt_getlowbit(vect->tx_map, 0, 48506621Sbt150084 (ixgbe->num_tx_rings - 1)); 48516621Sbt150084 48526621Sbt150084 while (r_idx >= 0) { 48539353SSamuel.Tu@Sun.COM ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1); 48546621Sbt150084 r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1), 48556621Sbt150084 (ixgbe->num_tx_rings - 1)); 48566621Sbt150084 } 48576621Sbt150084 } 48586621Sbt150084 } 48596621Sbt150084 48606621Sbt150084 /* 48616621Sbt150084 * ixgbe_rem_intr_handlers - Remove the interrupt handlers. 48626621Sbt150084 */ 48636621Sbt150084 static void 48646621Sbt150084 ixgbe_rem_intr_handlers(ixgbe_t *ixgbe) 48656621Sbt150084 { 48666621Sbt150084 int i; 48676621Sbt150084 int rc; 48686621Sbt150084 48696621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 48706621Sbt150084 rc = ddi_intr_remove_handler(ixgbe->htable[i]); 48716621Sbt150084 if (rc != DDI_SUCCESS) { 48726621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, 48736621Sbt150084 "Remove intr handler failed: %d", rc); 48746621Sbt150084 } 48756621Sbt150084 } 48766621Sbt150084 } 48776621Sbt150084 48786621Sbt150084 /* 48796621Sbt150084 * ixgbe_rem_intrs - Remove the allocated interrupts. 48806621Sbt150084 */ 48816621Sbt150084 static void 48826621Sbt150084 ixgbe_rem_intrs(ixgbe_t *ixgbe) 48836621Sbt150084 { 48846621Sbt150084 int i; 48856621Sbt150084 int rc; 48866621Sbt150084 48876621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 48886621Sbt150084 rc = ddi_intr_free(ixgbe->htable[i]); 48896621Sbt150084 if (rc != DDI_SUCCESS) { 48906621Sbt150084 IXGBE_DEBUGLOG_1(ixgbe, 48916621Sbt150084 "Free intr failed: %d", rc); 48926621Sbt150084 } 48936621Sbt150084 } 48946621Sbt150084 48956621Sbt150084 kmem_free(ixgbe->htable, ixgbe->intr_size); 48966621Sbt150084 ixgbe->htable = NULL; 48976621Sbt150084 } 48986621Sbt150084 48996621Sbt150084 /* 49006621Sbt150084 * ixgbe_enable_intrs - Enable all the ddi interrupts. 49016621Sbt150084 */ 49026621Sbt150084 static int 49036621Sbt150084 ixgbe_enable_intrs(ixgbe_t *ixgbe) 49046621Sbt150084 { 49056621Sbt150084 int i; 49066621Sbt150084 int rc; 49076621Sbt150084 49086621Sbt150084 /* 49096621Sbt150084 * Enable interrupts 49106621Sbt150084 */ 49116621Sbt150084 if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) { 49126621Sbt150084 /* 49136621Sbt150084 * Call ddi_intr_block_enable() for MSI 49146621Sbt150084 */ 49156621Sbt150084 rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt); 49166621Sbt150084 if (rc != DDI_SUCCESS) { 49176621Sbt150084 ixgbe_log(ixgbe, 49186621Sbt150084 "Enable block intr failed: %d", rc); 49196621Sbt150084 return (IXGBE_FAILURE); 49206621Sbt150084 } 49216621Sbt150084 } else { 49226621Sbt150084 /* 49236621Sbt150084 * Call ddi_intr_enable() for Legacy/MSI non block enable 49246621Sbt150084 */ 49256621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 49266621Sbt150084 rc = ddi_intr_enable(ixgbe->htable[i]); 49276621Sbt150084 if (rc != DDI_SUCCESS) { 49286621Sbt150084 ixgbe_log(ixgbe, 49296621Sbt150084 "Enable intr failed: %d", rc); 49306621Sbt150084 return (IXGBE_FAILURE); 49316621Sbt150084 } 49326621Sbt150084 } 49336621Sbt150084 } 49346621Sbt150084 49356621Sbt150084 return (IXGBE_SUCCESS); 49366621Sbt150084 } 49376621Sbt150084 49386621Sbt150084 /* 49396621Sbt150084 * ixgbe_disable_intrs - Disable all the interrupts. 49406621Sbt150084 */ 49416621Sbt150084 static int 49426621Sbt150084 ixgbe_disable_intrs(ixgbe_t *ixgbe) 49436621Sbt150084 { 49446621Sbt150084 int i; 49456621Sbt150084 int rc; 49466621Sbt150084 49476621Sbt150084 /* 49486621Sbt150084 * Disable all interrupts 49496621Sbt150084 */ 49506621Sbt150084 if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) { 49516621Sbt150084 rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt); 49526621Sbt150084 if (rc != DDI_SUCCESS) { 49536621Sbt150084 ixgbe_log(ixgbe, 49546621Sbt150084 "Disable block intr failed: %d", rc); 49556621Sbt150084 return (IXGBE_FAILURE); 49566621Sbt150084 } 49576621Sbt150084 } else { 49586621Sbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 49596621Sbt150084 rc = ddi_intr_disable(ixgbe->htable[i]); 49606621Sbt150084 if (rc != DDI_SUCCESS) { 49616621Sbt150084 ixgbe_log(ixgbe, 49626621Sbt150084 "Disable intr failed: %d", rc); 49636621Sbt150084 return (IXGBE_FAILURE); 49646621Sbt150084 } 49656621Sbt150084 } 49666621Sbt150084 } 49676621Sbt150084 49686621Sbt150084 return (IXGBE_SUCCESS); 49696621Sbt150084 } 49706621Sbt150084 49716621Sbt150084 /* 49726621Sbt150084 * ixgbe_get_hw_state - Get and save parameters related to adapter hardware. 49736621Sbt150084 */ 49746621Sbt150084 static void 49756621Sbt150084 ixgbe_get_hw_state(ixgbe_t *ixgbe) 49766621Sbt150084 { 49776621Sbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 49788490SPaul.Guo@Sun.COM ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN; 49798490SPaul.Guo@Sun.COM boolean_t link_up = B_FALSE; 49806621Sbt150084 uint32_t pcs1g_anlp = 0; 49816621Sbt150084 uint32_t pcs1g_ana = 0; 49826621Sbt150084 49836621Sbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 49846621Sbt150084 ixgbe->param_lp_1000fdx_cap = 0; 49856621Sbt150084 ixgbe->param_lp_100fdx_cap = 0; 49866621Sbt150084 49878490SPaul.Guo@Sun.COM /* check for link, don't wait */ 49888490SPaul.Guo@Sun.COM (void) ixgbe_check_link(hw, &speed, &link_up, false); 49898490SPaul.Guo@Sun.COM if (link_up) { 49906621Sbt150084 pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); 49916621Sbt150084 pcs1g_ana = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); 49926621Sbt150084 49936621Sbt150084 ixgbe->param_lp_1000fdx_cap = 49946621Sbt150084 (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; 49956621Sbt150084 ixgbe->param_lp_100fdx_cap = 49966621Sbt150084 (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; 49976621Sbt150084 } 49986621Sbt150084 499910376SChenlu.Chen@Sun.COM ixgbe->param_adv_1000fdx_cap = 500010376SChenlu.Chen@Sun.COM (pcs1g_ana & IXGBE_PCS1GANA_FDC) ? 1 : 0; 500110376SChenlu.Chen@Sun.COM ixgbe->param_adv_100fdx_cap = (pcs1g_ana & IXGBE_PCS1GANA_FDC) ? 1 : 0; 50026621Sbt150084 } 50036621Sbt150084 50046621Sbt150084 /* 50056621Sbt150084 * ixgbe_get_driver_control - Notify that driver is in control of device. 50066621Sbt150084 */ 50076621Sbt150084 static void 50086621Sbt150084 ixgbe_get_driver_control(struct ixgbe_hw *hw) 50096621Sbt150084 { 50106621Sbt150084 uint32_t ctrl_ext; 50116621Sbt150084 50126621Sbt150084 /* 50136621Sbt150084 * Notify firmware that driver is in control of device 50146621Sbt150084 */ 50156621Sbt150084 ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 50166621Sbt150084 ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 50176621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 50186621Sbt150084 } 50196621Sbt150084 50206621Sbt150084 /* 50216621Sbt150084 * ixgbe_release_driver_control - Notify that driver is no longer in control 50226621Sbt150084 * of device. 50236621Sbt150084 */ 50246621Sbt150084 static void 50256621Sbt150084 ixgbe_release_driver_control(struct ixgbe_hw *hw) 50266621Sbt150084 { 50276621Sbt150084 uint32_t ctrl_ext; 50286621Sbt150084 50296621Sbt150084 /* 50306621Sbt150084 * Notify firmware that driver is no longer in control of device 50316621Sbt150084 */ 50326621Sbt150084 ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 50336621Sbt150084 ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 50346621Sbt150084 IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 50356621Sbt150084 } 50366621Sbt150084 50376621Sbt150084 /* 50386621Sbt150084 * ixgbe_atomic_reserve - Atomic decrease operation. 50396621Sbt150084 */ 50406621Sbt150084 int 50416621Sbt150084 ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n) 50426621Sbt150084 { 50436621Sbt150084 uint32_t oldval; 50446621Sbt150084 uint32_t newval; 50456621Sbt150084 50466621Sbt150084 /* 50476621Sbt150084 * ATOMICALLY 50486621Sbt150084 */ 50496621Sbt150084 do { 50506621Sbt150084 oldval = *count_p; 50516621Sbt150084 if (oldval < n) 50526621Sbt150084 return (-1); 50536621Sbt150084 newval = oldval - n; 50546621Sbt150084 } while (atomic_cas_32(count_p, oldval, newval) != oldval); 50556621Sbt150084 50566621Sbt150084 return (newval); 50576621Sbt150084 } 50586621Sbt150084 50596621Sbt150084 /* 50606621Sbt150084 * ixgbe_mc_table_itr - Traverse the entries in the multicast table. 50616621Sbt150084 */ 50626621Sbt150084 static uint8_t * 50636621Sbt150084 ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq) 50646621Sbt150084 { 50658490SPaul.Guo@Sun.COM uint8_t *addr = *upd_ptr; 50668490SPaul.Guo@Sun.COM uint8_t *new_ptr; 50678490SPaul.Guo@Sun.COM 50686621Sbt150084 _NOTE(ARGUNUSED(hw)); 50696621Sbt150084 _NOTE(ARGUNUSED(vmdq)); 50706621Sbt150084 50716621Sbt150084 new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; 50726621Sbt150084 *upd_ptr = new_ptr; 50736621Sbt150084 return (addr); 50746621Sbt150084 } 50756621Sbt150084 50766621Sbt150084 /* 50776621Sbt150084 * FMA support 50786621Sbt150084 */ 50796621Sbt150084 int 50806621Sbt150084 ixgbe_check_acc_handle(ddi_acc_handle_t handle) 50816621Sbt150084 { 50826621Sbt150084 ddi_fm_error_t de; 50836621Sbt150084 50846621Sbt150084 ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 50856621Sbt150084 ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 50866621Sbt150084 return (de.fme_status); 50876621Sbt150084 } 50886621Sbt150084 50896621Sbt150084 int 50906621Sbt150084 ixgbe_check_dma_handle(ddi_dma_handle_t handle) 50916621Sbt150084 { 50926621Sbt150084 ddi_fm_error_t de; 50936621Sbt150084 50946621Sbt150084 ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 50956621Sbt150084 return (de.fme_status); 50966621Sbt150084 } 50976621Sbt150084 50986621Sbt150084 /* 50996621Sbt150084 * ixgbe_fm_error_cb - The IO fault service error handling callback function. 51006621Sbt150084 */ 51016621Sbt150084 static int 51026621Sbt150084 ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 51036621Sbt150084 { 51046621Sbt150084 _NOTE(ARGUNUSED(impl_data)); 51056621Sbt150084 /* 51066621Sbt150084 * as the driver can always deal with an error in any dma or 51076621Sbt150084 * access handle, we can just return the fme_status value. 51086621Sbt150084 */ 51096621Sbt150084 pci_ereport_post(dip, err, NULL); 51106621Sbt150084 return (err->fme_status); 51116621Sbt150084 } 51126621Sbt150084 51136621Sbt150084 static void 51146621Sbt150084 ixgbe_fm_init(ixgbe_t *ixgbe) 51156621Sbt150084 { 51166621Sbt150084 ddi_iblock_cookie_t iblk; 511711236SStephen.Hanson@Sun.COM int fma_dma_flag; 51186621Sbt150084 51196621Sbt150084 /* 51206621Sbt150084 * Only register with IO Fault Services if we have some capability 51216621Sbt150084 */ 51226621Sbt150084 if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) { 51236621Sbt150084 ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; 51246621Sbt150084 } else { 51256621Sbt150084 ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; 51266621Sbt150084 } 51276621Sbt150084 51286621Sbt150084 if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) { 51296621Sbt150084 fma_dma_flag = 1; 51306621Sbt150084 } else { 51316621Sbt150084 fma_dma_flag = 0; 51326621Sbt150084 } 51336621Sbt150084 513411236SStephen.Hanson@Sun.COM ixgbe_set_fma_flags(fma_dma_flag); 51356621Sbt150084 51366621Sbt150084 if (ixgbe->fm_capabilities) { 51376621Sbt150084 51386621Sbt150084 /* 51396621Sbt150084 * Register capabilities with IO Fault Services 51406621Sbt150084 */ 51416621Sbt150084 ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk); 51426621Sbt150084 51436621Sbt150084 /* 51446621Sbt150084 * Initialize pci ereport capabilities if ereport capable 51456621Sbt150084 */ 51466621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) || 51476621Sbt150084 DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 51486621Sbt150084 pci_ereport_setup(ixgbe->dip); 51496621Sbt150084 51506621Sbt150084 /* 51516621Sbt150084 * Register error callback if error callback capable 51526621Sbt150084 */ 51536621Sbt150084 if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 51546621Sbt150084 ddi_fm_handler_register(ixgbe->dip, 51556621Sbt150084 ixgbe_fm_error_cb, (void*) ixgbe); 51566621Sbt150084 } 51576621Sbt150084 } 51586621Sbt150084 51596621Sbt150084 static void 51606621Sbt150084 ixgbe_fm_fini(ixgbe_t *ixgbe) 51616621Sbt150084 { 51626621Sbt150084 /* 51636621Sbt150084 * Only unregister FMA capabilities if they are registered 51646621Sbt150084 */ 51656621Sbt150084 if (ixgbe->fm_capabilities) { 51666621Sbt150084 51676621Sbt150084 /* 51686621Sbt150084 * Release any resources allocated by pci_ereport_setup() 51696621Sbt150084 */ 51706621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) || 51716621Sbt150084 DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 51726621Sbt150084 pci_ereport_teardown(ixgbe->dip); 51736621Sbt150084 51746621Sbt150084 /* 51756621Sbt150084 * Un-register error callback if error callback capable 51766621Sbt150084 */ 51776621Sbt150084 if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 51786621Sbt150084 ddi_fm_handler_unregister(ixgbe->dip); 51796621Sbt150084 51806621Sbt150084 /* 51816621Sbt150084 * Unregister from IO Fault Service 51826621Sbt150084 */ 51836621Sbt150084 ddi_fm_fini(ixgbe->dip); 51846621Sbt150084 } 51856621Sbt150084 } 51866621Sbt150084 51876621Sbt150084 void 51886621Sbt150084 ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail) 51896621Sbt150084 { 51906621Sbt150084 uint64_t ena; 51916621Sbt150084 char buf[FM_MAX_CLASS]; 51926621Sbt150084 51936621Sbt150084 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 51946621Sbt150084 ena = fm_ena_generate(0, FM_ENA_FMT1); 51956621Sbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) { 51966621Sbt150084 ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP, 51976621Sbt150084 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 51986621Sbt150084 } 51996621Sbt150084 } 52008275SEric Cheng 52018275SEric Cheng static int 52028275SEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 52038275SEric Cheng { 52048275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh; 52058275SEric Cheng 52068275SEric Cheng mutex_enter(&rx_ring->rx_lock); 52078275SEric Cheng rx_ring->ring_gen_num = mr_gen_num; 52088275SEric Cheng mutex_exit(&rx_ring->rx_lock); 52098275SEric Cheng return (0); 52108275SEric Cheng } 52118275SEric Cheng 52128275SEric Cheng /* 521311878SVenu.Iyer@Sun.COM * Get the global ring index by a ring index within a group. 521411878SVenu.Iyer@Sun.COM */ 521511878SVenu.Iyer@Sun.COM static int 521611878SVenu.Iyer@Sun.COM ixgbe_get_rx_ring_index(ixgbe_t *ixgbe, int gindex, int rindex) 521711878SVenu.Iyer@Sun.COM { 521811878SVenu.Iyer@Sun.COM ixgbe_rx_ring_t *rx_ring; 521911878SVenu.Iyer@Sun.COM int i; 522011878SVenu.Iyer@Sun.COM 522111878SVenu.Iyer@Sun.COM for (i = 0; i < ixgbe->num_rx_rings; i++) { 522211878SVenu.Iyer@Sun.COM rx_ring = &ixgbe->rx_rings[i]; 522311878SVenu.Iyer@Sun.COM if (rx_ring->group_index == gindex) 522411878SVenu.Iyer@Sun.COM rindex--; 522511878SVenu.Iyer@Sun.COM if (rindex < 0) 522611878SVenu.Iyer@Sun.COM return (i); 522711878SVenu.Iyer@Sun.COM } 522811878SVenu.Iyer@Sun.COM 522911878SVenu.Iyer@Sun.COM return (-1); 523011878SVenu.Iyer@Sun.COM } 523111878SVenu.Iyer@Sun.COM 523211878SVenu.Iyer@Sun.COM /* 52338275SEric Cheng * Callback funtion for MAC layer to register all rings. 52348275SEric Cheng */ 52358275SEric Cheng /* ARGSUSED */ 52368275SEric Cheng void 523711878SVenu.Iyer@Sun.COM ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index, 52388275SEric Cheng const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 52398275SEric Cheng { 52408275SEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg; 52418275SEric Cheng mac_intr_t *mintr = &infop->mri_intr; 52428275SEric Cheng 52438275SEric Cheng switch (rtype) { 52448275SEric Cheng case MAC_RING_TYPE_RX: { 524511878SVenu.Iyer@Sun.COM /* 524611878SVenu.Iyer@Sun.COM * 'index' is the ring index within the group. 524711878SVenu.Iyer@Sun.COM * Need to get the global ring index by searching in groups. 524811878SVenu.Iyer@Sun.COM */ 524911878SVenu.Iyer@Sun.COM int global_ring_index = ixgbe_get_rx_ring_index( 525011878SVenu.Iyer@Sun.COM ixgbe, group_index, ring_index); 525111878SVenu.Iyer@Sun.COM 525211878SVenu.Iyer@Sun.COM ASSERT(global_ring_index >= 0); 525311878SVenu.Iyer@Sun.COM 525411878SVenu.Iyer@Sun.COM ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[global_ring_index]; 52558275SEric Cheng rx_ring->ring_handle = rh; 52568275SEric Cheng 52578275SEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 52588275SEric Cheng infop->mri_start = ixgbe_ring_start; 52598275SEric Cheng infop->mri_stop = NULL; 52608275SEric Cheng infop->mri_poll = ixgbe_ring_rx_poll; 526111878SVenu.Iyer@Sun.COM infop->mri_stat = ixgbe_rx_ring_stat; 52628275SEric Cheng 52638275SEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring; 52648275SEric Cheng mintr->mi_enable = ixgbe_rx_ring_intr_enable; 52658275SEric Cheng mintr->mi_disable = ixgbe_rx_ring_intr_disable; 526611878SVenu.Iyer@Sun.COM if (ixgbe->intr_type & 526711878SVenu.Iyer@Sun.COM (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) { 526811878SVenu.Iyer@Sun.COM mintr->mi_ddi_handle = 526911878SVenu.Iyer@Sun.COM ixgbe->htable[rx_ring->intr_vector]; 527011878SVenu.Iyer@Sun.COM } 52718275SEric Cheng 52728275SEric Cheng break; 52738275SEric Cheng } 52748275SEric Cheng case MAC_RING_TYPE_TX: { 527511878SVenu.Iyer@Sun.COM ASSERT(group_index == -1); 52768275SEric Cheng ASSERT(ring_index < ixgbe->num_tx_rings); 52778275SEric Cheng 52788275SEric Cheng ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index]; 52798275SEric Cheng tx_ring->ring_handle = rh; 52808275SEric Cheng 52818275SEric Cheng infop->mri_driver = (mac_ring_driver_t)tx_ring; 52828275SEric Cheng infop->mri_start = NULL; 52838275SEric Cheng infop->mri_stop = NULL; 52848275SEric Cheng infop->mri_tx = ixgbe_ring_tx; 528511878SVenu.Iyer@Sun.COM infop->mri_stat = ixgbe_tx_ring_stat; 528611878SVenu.Iyer@Sun.COM if (ixgbe->intr_type & 528711878SVenu.Iyer@Sun.COM (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) { 528811878SVenu.Iyer@Sun.COM mintr->mi_ddi_handle = 528911878SVenu.Iyer@Sun.COM ixgbe->htable[tx_ring->intr_vector]; 529011878SVenu.Iyer@Sun.COM } 52918275SEric Cheng break; 52928275SEric Cheng } 52938275SEric Cheng default: 52948275SEric Cheng break; 52958275SEric Cheng } 52968275SEric Cheng } 52978275SEric Cheng 52988275SEric Cheng /* 52998275SEric Cheng * Callback funtion for MAC layer to register all groups. 53008275SEric Cheng */ 53018275SEric Cheng void 53028275SEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index, 53038275SEric Cheng mac_group_info_t *infop, mac_group_handle_t gh) 53048275SEric Cheng { 53058275SEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg; 53068275SEric Cheng 53078275SEric Cheng switch (rtype) { 53088275SEric Cheng case MAC_RING_TYPE_RX: { 53098275SEric Cheng ixgbe_rx_group_t *rx_group; 53108275SEric Cheng 53118275SEric Cheng rx_group = &ixgbe->rx_groups[index]; 53128275SEric Cheng rx_group->group_handle = gh; 53138275SEric Cheng 53148275SEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_group; 53158275SEric Cheng infop->mgi_start = NULL; 53168275SEric Cheng infop->mgi_stop = NULL; 53178275SEric Cheng infop->mgi_addmac = ixgbe_addmac; 53188275SEric Cheng infop->mgi_remmac = ixgbe_remmac; 53198275SEric Cheng infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups); 53208275SEric Cheng 53218275SEric Cheng break; 53228275SEric Cheng } 53238275SEric Cheng case MAC_RING_TYPE_TX: 53248275SEric Cheng break; 53258275SEric Cheng default: 53268275SEric Cheng break; 53278275SEric Cheng } 53288275SEric Cheng } 53298275SEric Cheng 53308275SEric Cheng /* 53318275SEric Cheng * Enable interrupt on the specificed rx ring. 53328275SEric Cheng */ 53338275SEric Cheng int 53348275SEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh) 53358275SEric Cheng { 53368275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh; 53378275SEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe; 53388275SEric Cheng int r_idx = rx_ring->index; 533911878SVenu.Iyer@Sun.COM int hw_r_idx = rx_ring->hw_index; 53408275SEric Cheng int v_idx = rx_ring->intr_vector; 53418275SEric Cheng 53428275SEric Cheng mutex_enter(&ixgbe->gen_lock); 534311878SVenu.Iyer@Sun.COM if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) { 534411878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 534511878SVenu.Iyer@Sun.COM /* 534611878SVenu.Iyer@Sun.COM * Simply return 0. 534711878SVenu.Iyer@Sun.COM * Interrupts are being adjusted. ixgbe_intr_adjust() 534811878SVenu.Iyer@Sun.COM * will eventually re-enable the interrupt when it's 534911878SVenu.Iyer@Sun.COM * done with the adjustment. 535011878SVenu.Iyer@Sun.COM */ 535111878SVenu.Iyer@Sun.COM return (0); 535211878SVenu.Iyer@Sun.COM } 53538275SEric Cheng 53548275SEric Cheng /* 53558275SEric Cheng * To enable interrupt by setting the VAL bit of given interrupt 53568275SEric Cheng * vector allocation register (IVAR). 53578275SEric Cheng */ 535811878SVenu.Iyer@Sun.COM ixgbe_enable_ivar(ixgbe, hw_r_idx, 0); 53598275SEric Cheng 53608275SEric Cheng BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx); 536110305SPaul.Guo@Sun.COM 536210305SPaul.Guo@Sun.COM /* 536310305SPaul.Guo@Sun.COM * To trigger a Rx interrupt to on this ring 536410305SPaul.Guo@Sun.COM */ 536510305SPaul.Guo@Sun.COM IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx)); 536610305SPaul.Guo@Sun.COM IXGBE_WRITE_FLUSH(&ixgbe->hw); 536710305SPaul.Guo@Sun.COM 53688275SEric Cheng mutex_exit(&ixgbe->gen_lock); 53698275SEric Cheng 53708275SEric Cheng return (0); 53718275SEric Cheng } 53728275SEric Cheng 53738275SEric Cheng /* 53748275SEric Cheng * Disable interrupt on the specificed rx ring. 53758275SEric Cheng */ 53768275SEric Cheng int 53778275SEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh) 53788275SEric Cheng { 53798275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh; 53808275SEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe; 53818275SEric Cheng int r_idx = rx_ring->index; 538211878SVenu.Iyer@Sun.COM int hw_r_idx = rx_ring->hw_index; 53838275SEric Cheng int v_idx = rx_ring->intr_vector; 53848275SEric Cheng 53858275SEric Cheng mutex_enter(&ixgbe->gen_lock); 538611878SVenu.Iyer@Sun.COM if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) { 538711878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 538811878SVenu.Iyer@Sun.COM /* 538911878SVenu.Iyer@Sun.COM * Simply return 0. 539011878SVenu.Iyer@Sun.COM * In the rare case where an interrupt is being 539111878SVenu.Iyer@Sun.COM * disabled while interrupts are being adjusted, 539211878SVenu.Iyer@Sun.COM * we don't fail the operation. No interrupts will 539311878SVenu.Iyer@Sun.COM * be generated while they are adjusted, and 539411878SVenu.Iyer@Sun.COM * ixgbe_intr_adjust() will cause the interrupts 539511878SVenu.Iyer@Sun.COM * to be re-enabled once it completes. Note that 539611878SVenu.Iyer@Sun.COM * in this case, packets may be delivered to the 539711878SVenu.Iyer@Sun.COM * stack via interrupts before xgbe_rx_ring_intr_enable() 539811878SVenu.Iyer@Sun.COM * is called again. This is acceptable since interrupt 539911878SVenu.Iyer@Sun.COM * adjustment is infrequent, and the stack will be 540011878SVenu.Iyer@Sun.COM * able to handle these packets. 540111878SVenu.Iyer@Sun.COM */ 540211878SVenu.Iyer@Sun.COM return (0); 540311878SVenu.Iyer@Sun.COM } 54048275SEric Cheng 54058275SEric Cheng /* 54068275SEric Cheng * To disable interrupt by clearing the VAL bit of given interrupt 54078275SEric Cheng * vector allocation register (IVAR). 54088275SEric Cheng */ 540911878SVenu.Iyer@Sun.COM ixgbe_disable_ivar(ixgbe, hw_r_idx, 0); 54108275SEric Cheng 54118275SEric Cheng BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx); 54128275SEric Cheng 54138275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54148275SEric Cheng 54158275SEric Cheng return (0); 54168275SEric Cheng } 54178275SEric Cheng 54188275SEric Cheng /* 54198275SEric Cheng * Add a mac address. 54208275SEric Cheng */ 54218275SEric Cheng static int 54228275SEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr) 54238275SEric Cheng { 54248275SEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg; 54258275SEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe; 542611878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 542711878SVenu.Iyer@Sun.COM int slot, i; 54288275SEric Cheng 54298275SEric Cheng mutex_enter(&ixgbe->gen_lock); 54308275SEric Cheng 54318275SEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 54328275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54338275SEric Cheng return (ECANCELED); 54348275SEric Cheng } 54358275SEric Cheng 54368275SEric Cheng if (ixgbe->unicst_avail == 0) { 54378275SEric Cheng /* no slots available */ 54388275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54398275SEric Cheng return (ENOSPC); 54408275SEric Cheng } 54418275SEric Cheng 544211878SVenu.Iyer@Sun.COM /* 544311878SVenu.Iyer@Sun.COM * The first ixgbe->num_rx_groups slots are reserved for each respective 544411878SVenu.Iyer@Sun.COM * group. The rest slots are shared by all groups. While adding a 544511878SVenu.Iyer@Sun.COM * MAC address, reserved slots are firstly checked then the shared 544611878SVenu.Iyer@Sun.COM * slots are searched. 544711878SVenu.Iyer@Sun.COM */ 544811878SVenu.Iyer@Sun.COM slot = -1; 544911878SVenu.Iyer@Sun.COM if (ixgbe->unicst_addr[rx_group->index].mac.set == 1) { 545011878SVenu.Iyer@Sun.COM for (i = ixgbe->num_rx_groups; i < ixgbe->unicst_total; i++) { 545111878SVenu.Iyer@Sun.COM if (ixgbe->unicst_addr[i].mac.set == 0) { 545211878SVenu.Iyer@Sun.COM slot = i; 545311878SVenu.Iyer@Sun.COM break; 545411878SVenu.Iyer@Sun.COM } 545511878SVenu.Iyer@Sun.COM } 545611878SVenu.Iyer@Sun.COM } else { 545711878SVenu.Iyer@Sun.COM slot = rx_group->index; 545811878SVenu.Iyer@Sun.COM } 545911878SVenu.Iyer@Sun.COM 546011878SVenu.Iyer@Sun.COM if (slot == -1) { 546111878SVenu.Iyer@Sun.COM /* no slots available */ 546211878SVenu.Iyer@Sun.COM mutex_exit(&ixgbe->gen_lock); 546311878SVenu.Iyer@Sun.COM return (ENOSPC); 546411878SVenu.Iyer@Sun.COM } 546511878SVenu.Iyer@Sun.COM 546611878SVenu.Iyer@Sun.COM bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL); 546711878SVenu.Iyer@Sun.COM (void) ixgbe_set_rar(hw, slot, ixgbe->unicst_addr[slot].mac.addr, 546811878SVenu.Iyer@Sun.COM rx_group->index, IXGBE_RAH_AV); 546911878SVenu.Iyer@Sun.COM ixgbe->unicst_addr[slot].mac.set = 1; 547011878SVenu.Iyer@Sun.COM ixgbe->unicst_addr[slot].mac.group_index = rx_group->index; 547111878SVenu.Iyer@Sun.COM ixgbe->unicst_avail--; 54728275SEric Cheng 54738275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54748275SEric Cheng 547511878SVenu.Iyer@Sun.COM return (0); 54768275SEric Cheng } 54778275SEric Cheng 54788275SEric Cheng /* 54798275SEric Cheng * Remove a mac address. 54808275SEric Cheng */ 54818275SEric Cheng static int 54828275SEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr) 54838275SEric Cheng { 54848275SEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg; 54858275SEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe; 548611878SVenu.Iyer@Sun.COM struct ixgbe_hw *hw = &ixgbe->hw; 54878275SEric Cheng int slot; 54888275SEric Cheng 54898275SEric Cheng mutex_enter(&ixgbe->gen_lock); 54908275SEric Cheng 54918275SEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 54928275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54938275SEric Cheng return (ECANCELED); 54948275SEric Cheng } 54958275SEric Cheng 54968275SEric Cheng slot = ixgbe_unicst_find(ixgbe, mac_addr); 54978275SEric Cheng if (slot == -1) { 54988275SEric Cheng mutex_exit(&ixgbe->gen_lock); 54998275SEric Cheng return (EINVAL); 55008275SEric Cheng } 55018275SEric Cheng 55028275SEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 0) { 55038275SEric Cheng mutex_exit(&ixgbe->gen_lock); 55048275SEric Cheng return (EINVAL); 55058275SEric Cheng } 55068275SEric Cheng 55078275SEric Cheng bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL); 550811878SVenu.Iyer@Sun.COM (void) ixgbe_clear_rar(hw, slot); 550911878SVenu.Iyer@Sun.COM ixgbe->unicst_addr[slot].mac.set = 0; 551011878SVenu.Iyer@Sun.COM ixgbe->unicst_avail++; 55118275SEric Cheng 55128275SEric Cheng mutex_exit(&ixgbe->gen_lock); 55138275SEric Cheng 551411878SVenu.Iyer@Sun.COM return (0); 55158275SEric Cheng } 5516