19da57d7bSbt150084 /* 29da57d7bSbt150084 * CDDL HEADER START 39da57d7bSbt150084 * 49da57d7bSbt150084 * The contents of this file are subject to the terms of the 59da57d7bSbt150084 * Common Development and Distribution License (the "License"). 69da57d7bSbt150084 * You may not use this file except in compliance with the License. 79da57d7bSbt150084 * 819397407SSherry Moore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 919397407SSherry Moore * or http://www.opensolaris.org/os/licensing. 109da57d7bSbt150084 * See the License for the specific language governing permissions 119da57d7bSbt150084 * and limitations under the License. 129da57d7bSbt150084 * 1319397407SSherry Moore * When distributing Covered Code, include this CDDL HEADER in each 1419397407SSherry Moore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159da57d7bSbt150084 * If applicable, add the following below this CDDL HEADER, with the 169da57d7bSbt150084 * fields enclosed by brackets "[]" replaced with your own identifying 179da57d7bSbt150084 * information: Portions Copyright [yyyy] [name of copyright owner] 189da57d7bSbt150084 * 199da57d7bSbt150084 * CDDL HEADER END 209da57d7bSbt150084 */ 219da57d7bSbt150084 229da57d7bSbt150084 /* 2300f1c25aSchenlu chen - Sun Microsystems - Beijing China * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. 2400f1c25aSchenlu chen - Sun Microsystems - Beijing China */ 2500f1c25aSchenlu chen - Sun Microsystems - Beijing China 2600f1c25aSchenlu chen - Sun Microsystems - Beijing China /* 2700f1c25aSchenlu chen - Sun Microsystems - Beijing China * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 28*59596c01SRobert Mustacchi * Copyright (c) 2017, Joyent, Inc. 2969b5a878SDan McDonald * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 3043fab1a9SSaso Kiselkov * Copyright (c) 2013 Saso Kiselkov. All rights reserved. 318c430e59SSaso Kiselkov * Copyright (c) 2013 OSN Online Service Nuernberg GmbH. All rights reserved. 327e579c30SDale Ghent * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved. 3319397407SSherry Moore */ 3419397407SSherry Moore 359da57d7bSbt150084 #include "ixgbe_sw.h" 369da57d7bSbt150084 37ffd8e883SWinson Wang - Sun Microsystems - Beijing China static char ixgbe_ident[] = "Intel 10Gb Ethernet"; 389da57d7bSbt150084 399da57d7bSbt150084 /* 409da57d7bSbt150084 * Local function protoypes 419da57d7bSbt150084 */ 429da57d7bSbt150084 static int ixgbe_register_mac(ixgbe_t *); 439da57d7bSbt150084 static int ixgbe_identify_hardware(ixgbe_t *); 449da57d7bSbt150084 static int ixgbe_regs_map(ixgbe_t *); 459da57d7bSbt150084 static void ixgbe_init_properties(ixgbe_t *); 469da57d7bSbt150084 static int ixgbe_init_driver_settings(ixgbe_t *); 479da57d7bSbt150084 static void ixgbe_init_locks(ixgbe_t *); 489da57d7bSbt150084 static void ixgbe_destroy_locks(ixgbe_t *); 499da57d7bSbt150084 static int ixgbe_init(ixgbe_t *); 509da57d7bSbt150084 static int ixgbe_chip_start(ixgbe_t *); 519da57d7bSbt150084 static void ixgbe_chip_stop(ixgbe_t *); 529da57d7bSbt150084 static int ixgbe_reset(ixgbe_t *); 539da57d7bSbt150084 static void ixgbe_tx_clean(ixgbe_t *); 549da57d7bSbt150084 static boolean_t ixgbe_tx_drain(ixgbe_t *); 559da57d7bSbt150084 static boolean_t ixgbe_rx_drain(ixgbe_t *); 569da57d7bSbt150084 static int ixgbe_alloc_rings(ixgbe_t *); 579da57d7bSbt150084 static void ixgbe_free_rings(ixgbe_t *); 58ea65739eSchenlu chen - Sun Microsystems - Beijing China static int ixgbe_alloc_rx_data(ixgbe_t *); 59ea65739eSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_free_rx_data(ixgbe_t *); 609da57d7bSbt150084 static void ixgbe_setup_rings(ixgbe_t *); 619da57d7bSbt150084 static void ixgbe_setup_rx(ixgbe_t *); 629da57d7bSbt150084 static void ixgbe_setup_tx(ixgbe_t *); 639da57d7bSbt150084 static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *); 649da57d7bSbt150084 static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *); 659da57d7bSbt150084 static void ixgbe_setup_rss(ixgbe_t *); 660dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq(ixgbe_t *); 670dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq_rss(ixgbe_t *); 687e579c30SDale Ghent static void ixgbe_setup_rss_table(ixgbe_t *); 699da57d7bSbt150084 static void ixgbe_init_unicst(ixgbe_t *); 70da14cebeSEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *); 719da57d7bSbt150084 static void ixgbe_setup_multicst(ixgbe_t *); 729da57d7bSbt150084 static void ixgbe_get_hw_state(ixgbe_t *); 730dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe); 749da57d7bSbt150084 static void ixgbe_get_conf(ixgbe_t *); 75ea65739eSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_init_params(ixgbe_t *); 769da57d7bSbt150084 static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int); 7762e6e1adSPaul Guo static void ixgbe_driver_link_check(ixgbe_t *); 7873cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_sfp_check(void *); 795b6dd21fSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_overtemp_check(void *); 807e579c30SDale Ghent static void ixgbe_phy_check(void *); 8162e6e1adSPaul Guo static void ixgbe_link_timer(void *); 829da57d7bSbt150084 static void ixgbe_local_timer(void *); 839da57d7bSbt150084 static void ixgbe_arm_watchdog_timer(ixgbe_t *); 849da57d7bSbt150084 static void ixgbe_restart_watchdog_timer(ixgbe_t *); 859da57d7bSbt150084 static void ixgbe_disable_adapter_interrupts(ixgbe_t *); 869da57d7bSbt150084 static void ixgbe_enable_adapter_interrupts(ixgbe_t *); 879da57d7bSbt150084 static boolean_t is_valid_mac_addr(uint8_t *); 889da57d7bSbt150084 static boolean_t ixgbe_stall_check(ixgbe_t *); 899da57d7bSbt150084 static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t); 909da57d7bSbt150084 static void ixgbe_set_internal_mac_loopback(ixgbe_t *); 919da57d7bSbt150084 static boolean_t ixgbe_find_mac_address(ixgbe_t *); 929da57d7bSbt150084 static int ixgbe_alloc_intrs(ixgbe_t *); 939da57d7bSbt150084 static int ixgbe_alloc_intr_handles(ixgbe_t *, int); 949da57d7bSbt150084 static int ixgbe_add_intr_handlers(ixgbe_t *); 959da57d7bSbt150084 static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int); 969da57d7bSbt150084 static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int); 9773cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t); 9873cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t); 9973cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t); 1000dc2366fSVenugopal Iyer static uint32_t ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index); 10173cd555cSBin Tu - Sun Microsystems - Beijing China static int ixgbe_map_intrs_to_vectors(ixgbe_t *); 1029da57d7bSbt150084 static void ixgbe_setup_adapter_vector(ixgbe_t *); 1039da57d7bSbt150084 static void ixgbe_rem_intr_handlers(ixgbe_t *); 1049da57d7bSbt150084 static void ixgbe_rem_intrs(ixgbe_t *); 1059da57d7bSbt150084 static int ixgbe_enable_intrs(ixgbe_t *); 1069da57d7bSbt150084 static int ixgbe_disable_intrs(ixgbe_t *); 1079da57d7bSbt150084 static uint_t ixgbe_intr_legacy(void *, void *); 1089da57d7bSbt150084 static uint_t ixgbe_intr_msi(void *, void *); 10973cd555cSBin Tu - Sun Microsystems - Beijing China static uint_t ixgbe_intr_msix(void *, void *); 1109da57d7bSbt150084 static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *); 1119da57d7bSbt150084 static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *); 11213740cb2SPaul Guo static void ixgbe_intr_other_work(ixgbe_t *, uint32_t); 1139da57d7bSbt150084 static void ixgbe_get_driver_control(struct ixgbe_hw *); 114da14cebeSEric Cheng static int ixgbe_addmac(void *, const uint8_t *); 115da14cebeSEric Cheng static int ixgbe_remmac(void *, const uint8_t *); 1169da57d7bSbt150084 static void ixgbe_release_driver_control(struct ixgbe_hw *); 1179da57d7bSbt150084 1189da57d7bSbt150084 static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t); 1199da57d7bSbt150084 static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t); 1209da57d7bSbt150084 static int ixgbe_resume(dev_info_t *); 1219da57d7bSbt150084 static int ixgbe_suspend(dev_info_t *); 1228c430e59SSaso Kiselkov static int ixgbe_quiesce(dev_info_t *); 1239da57d7bSbt150084 static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *); 1249da57d7bSbt150084 static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *); 1250dc2366fSVenugopal Iyer static int ixgbe_cbfunc(dev_info_t *, ddi_cb_action_t, void *, void *, void *); 1260dc2366fSVenugopal Iyer static int ixgbe_intr_cb_register(ixgbe_t *); 1270dc2366fSVenugopal Iyer static int ixgbe_intr_adjust(ixgbe_t *, ddi_cb_action_t, int); 1289da57d7bSbt150084 1299da57d7bSbt150084 static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, 1309da57d7bSbt150084 const void *impl_data); 1319da57d7bSbt150084 static void ixgbe_fm_init(ixgbe_t *); 1329da57d7bSbt150084 static void ixgbe_fm_fini(ixgbe_t *); 1339da57d7bSbt150084 1340dc2366fSVenugopal Iyer char *ixgbe_priv_props[] = { 1350dc2366fSVenugopal Iyer "_tx_copy_thresh", 1360dc2366fSVenugopal Iyer "_tx_recycle_thresh", 1370dc2366fSVenugopal Iyer "_tx_overload_thresh", 1380dc2366fSVenugopal Iyer "_tx_resched_thresh", 1390dc2366fSVenugopal Iyer "_rx_copy_thresh", 1400dc2366fSVenugopal Iyer "_rx_limit_per_intr", 1410dc2366fSVenugopal Iyer "_intr_throttling", 1420dc2366fSVenugopal Iyer "_adv_pause_cap", 1430dc2366fSVenugopal Iyer "_adv_asym_pause_cap", 1440dc2366fSVenugopal Iyer NULL 145ea65739eSchenlu chen - Sun Microsystems - Beijing China }; 146ea65739eSchenlu chen - Sun Microsystems - Beijing China 147ea65739eSchenlu chen - Sun Microsystems - Beijing China #define IXGBE_MAX_PRIV_PROPS \ 148ea65739eSchenlu chen - Sun Microsystems - Beijing China (sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t)) 149ea65739eSchenlu chen - Sun Microsystems - Beijing China 1509da57d7bSbt150084 static struct cb_ops ixgbe_cb_ops = { 1519da57d7bSbt150084 nulldev, /* cb_open */ 1529da57d7bSbt150084 nulldev, /* cb_close */ 1539da57d7bSbt150084 nodev, /* cb_strategy */ 1549da57d7bSbt150084 nodev, /* cb_print */ 1559da57d7bSbt150084 nodev, /* cb_dump */ 1569da57d7bSbt150084 nodev, /* cb_read */ 1579da57d7bSbt150084 nodev, /* cb_write */ 1589da57d7bSbt150084 nodev, /* cb_ioctl */ 1599da57d7bSbt150084 nodev, /* cb_devmap */ 1609da57d7bSbt150084 nodev, /* cb_mmap */ 1619da57d7bSbt150084 nodev, /* cb_segmap */ 1629da57d7bSbt150084 nochpoll, /* cb_chpoll */ 1639da57d7bSbt150084 ddi_prop_op, /* cb_prop_op */ 1649da57d7bSbt150084 NULL, /* cb_stream */ 1659da57d7bSbt150084 D_MP | D_HOTPLUG, /* cb_flag */ 1669da57d7bSbt150084 CB_REV, /* cb_rev */ 1679da57d7bSbt150084 nodev, /* cb_aread */ 1689da57d7bSbt150084 nodev /* cb_awrite */ 1699da57d7bSbt150084 }; 1709da57d7bSbt150084 1719da57d7bSbt150084 static struct dev_ops ixgbe_dev_ops = { 1729da57d7bSbt150084 DEVO_REV, /* devo_rev */ 1739da57d7bSbt150084 0, /* devo_refcnt */ 1749da57d7bSbt150084 NULL, /* devo_getinfo */ 1759da57d7bSbt150084 nulldev, /* devo_identify */ 1769da57d7bSbt150084 nulldev, /* devo_probe */ 1779da57d7bSbt150084 ixgbe_attach, /* devo_attach */ 1789da57d7bSbt150084 ixgbe_detach, /* devo_detach */ 1799da57d7bSbt150084 nodev, /* devo_reset */ 1809da57d7bSbt150084 &ixgbe_cb_ops, /* devo_cb_ops */ 1819da57d7bSbt150084 NULL, /* devo_bus_ops */ 18219397407SSherry Moore ddi_power, /* devo_power */ 1838c430e59SSaso Kiselkov ixgbe_quiesce, /* devo_quiesce */ 1849da57d7bSbt150084 }; 1859da57d7bSbt150084 1869da57d7bSbt150084 static struct modldrv ixgbe_modldrv = { 1879da57d7bSbt150084 &mod_driverops, /* Type of module. This one is a driver */ 188ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe_ident, /* Discription string */ 1899da57d7bSbt150084 &ixgbe_dev_ops /* driver ops */ 1909da57d7bSbt150084 }; 1919da57d7bSbt150084 1929da57d7bSbt150084 static struct modlinkage ixgbe_modlinkage = { 1939da57d7bSbt150084 MODREV_1, &ixgbe_modldrv, NULL 1949da57d7bSbt150084 }; 1959da57d7bSbt150084 1969da57d7bSbt150084 /* 1979da57d7bSbt150084 * Access attributes for register mapping 1989da57d7bSbt150084 */ 1999da57d7bSbt150084 ddi_device_acc_attr_t ixgbe_regs_acc_attr = { 200837c1ac4SStephen Hanson DDI_DEVICE_ATTR_V1, 2019da57d7bSbt150084 DDI_STRUCTURE_LE_ACC, 2029da57d7bSbt150084 DDI_STRICTORDER_ACC, 2039da57d7bSbt150084 DDI_FLAGERR_ACC 2049da57d7bSbt150084 }; 2059da57d7bSbt150084 2069da57d7bSbt150084 /* 2079da57d7bSbt150084 * Loopback property 2089da57d7bSbt150084 */ 2099da57d7bSbt150084 static lb_property_t lb_normal = { 2109da57d7bSbt150084 normal, "normal", IXGBE_LB_NONE 2119da57d7bSbt150084 }; 2129da57d7bSbt150084 2139da57d7bSbt150084 static lb_property_t lb_mac = { 2149da57d7bSbt150084 internal, "MAC", IXGBE_LB_INTERNAL_MAC 2159da57d7bSbt150084 }; 2169da57d7bSbt150084 2171fedc51fSWinson Wang - Sun Microsystems - Beijing China static lb_property_t lb_external = { 2181fedc51fSWinson Wang - Sun Microsystems - Beijing China external, "External", IXGBE_LB_EXTERNAL 2191fedc51fSWinson Wang - Sun Microsystems - Beijing China }; 2201fedc51fSWinson Wang - Sun Microsystems - Beijing China 221ea65739eSchenlu chen - Sun Microsystems - Beijing China #define IXGBE_M_CALLBACK_FLAGS \ 2220dc2366fSVenugopal Iyer (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 2239da57d7bSbt150084 2249da57d7bSbt150084 static mac_callbacks_t ixgbe_m_callbacks = { 2259da57d7bSbt150084 IXGBE_M_CALLBACK_FLAGS, 2269da57d7bSbt150084 ixgbe_m_stat, 2279da57d7bSbt150084 ixgbe_m_start, 2289da57d7bSbt150084 ixgbe_m_stop, 2299da57d7bSbt150084 ixgbe_m_promisc, 2309da57d7bSbt150084 ixgbe_m_multicst, 231da14cebeSEric Cheng NULL, 2329da57d7bSbt150084 NULL, 2330dc2366fSVenugopal Iyer NULL, 2349da57d7bSbt150084 ixgbe_m_ioctl, 235ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_m_getcapab, 236ea65739eSchenlu chen - Sun Microsystems - Beijing China NULL, 237ea65739eSchenlu chen - Sun Microsystems - Beijing China NULL, 238ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_m_setprop, 2390dc2366fSVenugopal Iyer ixgbe_m_getprop, 2400dc2366fSVenugopal Iyer ixgbe_m_propinfo 2419da57d7bSbt150084 }; 2429da57d7bSbt150084 2439da57d7bSbt150084 /* 24413740cb2SPaul Guo * Initialize capabilities of each supported adapter type 24513740cb2SPaul Guo */ 24613740cb2SPaul Guo static adapter_info_t ixgbe_82598eb_cap = { 24713740cb2SPaul Guo 64, /* maximum number of rx queues */ 24813740cb2SPaul Guo 1, /* minimum number of rx queues */ 2490dc2366fSVenugopal Iyer 64, /* default number of rx queues */ 2500dc2366fSVenugopal Iyer 16, /* maximum number of rx groups */ 2510dc2366fSVenugopal Iyer 1, /* minimum number of rx groups */ 2520dc2366fSVenugopal Iyer 1, /* default number of rx groups */ 25313740cb2SPaul Guo 32, /* maximum number of tx queues */ 25413740cb2SPaul Guo 1, /* minimum number of tx queues */ 25513740cb2SPaul Guo 8, /* default number of tx queues */ 2561fedc51fSWinson Wang - Sun Microsystems - Beijing China 16366, /* maximum MTU size */ 257ea65739eSchenlu chen - Sun Microsystems - Beijing China 0xFFFF, /* maximum interrupt throttle rate */ 258ea65739eSchenlu chen - Sun Microsystems - Beijing China 0, /* minimum interrupt throttle rate */ 259ea65739eSchenlu chen - Sun Microsystems - Beijing China 200, /* default interrupt throttle rate */ 26013740cb2SPaul Guo 18, /* maximum total msix vectors */ 26113740cb2SPaul Guo 16, /* maximum number of ring vectors */ 26213740cb2SPaul Guo 2, /* maximum number of other vectors */ 26313740cb2SPaul Guo IXGBE_EICR_LSC, /* "other" interrupt types handled */ 2645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 0, /* "other" interrupt types enable mask */ 26513740cb2SPaul Guo (IXGBE_FLAG_DCA_CAPABLE /* capability flags */ 26613740cb2SPaul Guo | IXGBE_FLAG_RSS_CAPABLE 26713740cb2SPaul Guo | IXGBE_FLAG_VMDQ_CAPABLE) 26813740cb2SPaul Guo }; 26913740cb2SPaul Guo 27073cd555cSBin Tu - Sun Microsystems - Beijing China static adapter_info_t ixgbe_82599eb_cap = { 27173cd555cSBin Tu - Sun Microsystems - Beijing China 128, /* maximum number of rx queues */ 27273cd555cSBin Tu - Sun Microsystems - Beijing China 1, /* minimum number of rx queues */ 2730dc2366fSVenugopal Iyer 128, /* default number of rx queues */ 2740dc2366fSVenugopal Iyer 64, /* maximum number of rx groups */ 2750dc2366fSVenugopal Iyer 1, /* minimum number of rx groups */ 2760dc2366fSVenugopal Iyer 1, /* default number of rx groups */ 27773cd555cSBin Tu - Sun Microsystems - Beijing China 128, /* maximum number of tx queues */ 27873cd555cSBin Tu - Sun Microsystems - Beijing China 1, /* minimum number of tx queues */ 27973cd555cSBin Tu - Sun Microsystems - Beijing China 8, /* default number of tx queues */ 2801fedc51fSWinson Wang - Sun Microsystems - Beijing China 15500, /* maximum MTU size */ 281ea65739eSchenlu chen - Sun Microsystems - Beijing China 0xFF8, /* maximum interrupt throttle rate */ 282ea65739eSchenlu chen - Sun Microsystems - Beijing China 0, /* minimum interrupt throttle rate */ 283ea65739eSchenlu chen - Sun Microsystems - Beijing China 200, /* default interrupt throttle rate */ 28473cd555cSBin Tu - Sun Microsystems - Beijing China 64, /* maximum total msix vectors */ 28573cd555cSBin Tu - Sun Microsystems - Beijing China 16, /* maximum number of ring vectors */ 28673cd555cSBin Tu - Sun Microsystems - Beijing China 2, /* maximum number of other vectors */ 2875b6dd21fSchenlu chen - Sun Microsystems - Beijing China (IXGBE_EICR_LSC 2885b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_EICR_GPI_SDP1 2895b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_EICR_GPI_SDP2), /* "other" interrupt types handled */ 2905b6dd21fSchenlu chen - Sun Microsystems - Beijing China 2915b6dd21fSchenlu chen - Sun Microsystems - Beijing China (IXGBE_SDP1_GPIEN 2925b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_SDP2_GPIEN), /* "other" interrupt types enable mask */ 2935b6dd21fSchenlu chen - Sun Microsystems - Beijing China 2945b6dd21fSchenlu chen - Sun Microsystems - Beijing China (IXGBE_FLAG_DCA_CAPABLE 29573cd555cSBin Tu - Sun Microsystems - Beijing China | IXGBE_FLAG_RSS_CAPABLE 296ffd8e883SWinson Wang - Sun Microsystems - Beijing China | IXGBE_FLAG_VMDQ_CAPABLE 2975b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_FLAG_RSC_CAPABLE 2985b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_FLAG_SFP_PLUG_CAPABLE) /* capability flags */ 29973cd555cSBin Tu - Sun Microsystems - Beijing China }; 30073cd555cSBin Tu - Sun Microsystems - Beijing China 30169b5a878SDan McDonald static adapter_info_t ixgbe_X540_cap = { 30269b5a878SDan McDonald 128, /* maximum number of rx queues */ 30369b5a878SDan McDonald 1, /* minimum number of rx queues */ 30469b5a878SDan McDonald 128, /* default number of rx queues */ 30569b5a878SDan McDonald 64, /* maximum number of rx groups */ 30669b5a878SDan McDonald 1, /* minimum number of rx groups */ 30769b5a878SDan McDonald 1, /* default number of rx groups */ 30869b5a878SDan McDonald 128, /* maximum number of tx queues */ 30969b5a878SDan McDonald 1, /* minimum number of tx queues */ 31069b5a878SDan McDonald 8, /* default number of tx queues */ 31169b5a878SDan McDonald 15500, /* maximum MTU size */ 31269b5a878SDan McDonald 0xFF8, /* maximum interrupt throttle rate */ 31369b5a878SDan McDonald 0, /* minimum interrupt throttle rate */ 31469b5a878SDan McDonald 200, /* default interrupt throttle rate */ 31569b5a878SDan McDonald 64, /* maximum total msix vectors */ 31669b5a878SDan McDonald 16, /* maximum number of ring vectors */ 31769b5a878SDan McDonald 2, /* maximum number of other vectors */ 31869b5a878SDan McDonald (IXGBE_EICR_LSC 3197e579c30SDale Ghent | IXGBE_EICR_GPI_SDP1_X540 3207e579c30SDale Ghent | IXGBE_EICR_GPI_SDP2_X540), /* "other" interrupt types handled */ 32169b5a878SDan McDonald 3227e579c30SDale Ghent (IXGBE_SDP1_GPIEN_X540 3237e579c30SDale Ghent | IXGBE_SDP2_GPIEN_X540), /* "other" interrupt types enable mask */ 32469b5a878SDan McDonald 32569b5a878SDan McDonald (IXGBE_FLAG_DCA_CAPABLE 32669b5a878SDan McDonald | IXGBE_FLAG_RSS_CAPABLE 32769b5a878SDan McDonald | IXGBE_FLAG_VMDQ_CAPABLE 32869b5a878SDan McDonald | IXGBE_FLAG_RSC_CAPABLE) /* capability flags */ 32969b5a878SDan McDonald }; 33069b5a878SDan McDonald 3317e579c30SDale Ghent static adapter_info_t ixgbe_X550_cap = { 3327e579c30SDale Ghent 128, /* maximum number of rx queues */ 3337e579c30SDale Ghent 1, /* minimum number of rx queues */ 3347e579c30SDale Ghent 128, /* default number of rx queues */ 3357e579c30SDale Ghent 64, /* maximum number of rx groups */ 3367e579c30SDale Ghent 1, /* minimum number of rx groups */ 3377e579c30SDale Ghent 1, /* default number of rx groups */ 3387e579c30SDale Ghent 128, /* maximum number of tx queues */ 3397e579c30SDale Ghent 1, /* minimum number of tx queues */ 3407e579c30SDale Ghent 8, /* default number of tx queues */ 3417e579c30SDale Ghent 15500, /* maximum MTU size */ 3427e579c30SDale Ghent 0xFF8, /* maximum interrupt throttle rate */ 3437e579c30SDale Ghent 0, /* minimum interrupt throttle rate */ 3447e579c30SDale Ghent 0x200, /* default interrupt throttle rate */ 3457e579c30SDale Ghent 64, /* maximum total msix vectors */ 3467e579c30SDale Ghent 16, /* maximum number of ring vectors */ 3477e579c30SDale Ghent 2, /* maximum number of other vectors */ 3487e579c30SDale Ghent IXGBE_EICR_LSC, /* "other" interrupt types handled */ 3497e579c30SDale Ghent 0, /* "other" interrupt types enable mask */ 3507e579c30SDale Ghent (IXGBE_FLAG_RSS_CAPABLE 3517e579c30SDale Ghent | IXGBE_FLAG_VMDQ_CAPABLE 3527e579c30SDale Ghent | IXGBE_FLAG_RSC_CAPABLE) /* capability flags */ 3537e579c30SDale Ghent }; 3547e579c30SDale Ghent 35513740cb2SPaul Guo /* 3569da57d7bSbt150084 * Module Initialization Functions. 3579da57d7bSbt150084 */ 3589da57d7bSbt150084 3599da57d7bSbt150084 int 3609da57d7bSbt150084 _init(void) 3619da57d7bSbt150084 { 3629da57d7bSbt150084 int status; 3639da57d7bSbt150084 3649da57d7bSbt150084 mac_init_ops(&ixgbe_dev_ops, MODULE_NAME); 3659da57d7bSbt150084 3669da57d7bSbt150084 status = mod_install(&ixgbe_modlinkage); 3679da57d7bSbt150084 3689da57d7bSbt150084 if (status != DDI_SUCCESS) { 3699da57d7bSbt150084 mac_fini_ops(&ixgbe_dev_ops); 3709da57d7bSbt150084 } 3719da57d7bSbt150084 3729da57d7bSbt150084 return (status); 3739da57d7bSbt150084 } 3749da57d7bSbt150084 3759da57d7bSbt150084 int 3769da57d7bSbt150084 _fini(void) 3779da57d7bSbt150084 { 3789da57d7bSbt150084 int status; 3799da57d7bSbt150084 3809da57d7bSbt150084 status = mod_remove(&ixgbe_modlinkage); 3819da57d7bSbt150084 3829da57d7bSbt150084 if (status == DDI_SUCCESS) { 3839da57d7bSbt150084 mac_fini_ops(&ixgbe_dev_ops); 3849da57d7bSbt150084 } 3859da57d7bSbt150084 3869da57d7bSbt150084 return (status); 3879da57d7bSbt150084 } 3889da57d7bSbt150084 3899da57d7bSbt150084 int 3909da57d7bSbt150084 _info(struct modinfo *modinfop) 3919da57d7bSbt150084 { 3929da57d7bSbt150084 int status; 3939da57d7bSbt150084 3949da57d7bSbt150084 status = mod_info(&ixgbe_modlinkage, modinfop); 3959da57d7bSbt150084 3969da57d7bSbt150084 return (status); 3979da57d7bSbt150084 } 3989da57d7bSbt150084 3999da57d7bSbt150084 /* 4009da57d7bSbt150084 * ixgbe_attach - Driver attach. 4019da57d7bSbt150084 * 4029da57d7bSbt150084 * This function is the device specific initialization entry 4039da57d7bSbt150084 * point. This entry point is required and must be written. 4049da57d7bSbt150084 * The DDI_ATTACH command must be provided in the attach entry 4059da57d7bSbt150084 * point. When attach() is called with cmd set to DDI_ATTACH, 4069da57d7bSbt150084 * all normal kernel services (such as kmem_alloc(9F)) are 4079da57d7bSbt150084 * available for use by the driver. 4089da57d7bSbt150084 * 4099da57d7bSbt150084 * The attach() function will be called once for each instance 4109da57d7bSbt150084 * of the device on the system with cmd set to DDI_ATTACH. 4119da57d7bSbt150084 * Until attach() succeeds, the only driver entry points which 4129da57d7bSbt150084 * may be called are open(9E) and getinfo(9E). 4139da57d7bSbt150084 */ 4149da57d7bSbt150084 static int 4159da57d7bSbt150084 ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 4169da57d7bSbt150084 { 4179da57d7bSbt150084 ixgbe_t *ixgbe; 4189da57d7bSbt150084 struct ixgbe_osdep *osdep; 4199da57d7bSbt150084 struct ixgbe_hw *hw; 4209da57d7bSbt150084 int instance; 42113740cb2SPaul Guo char taskqname[32]; 4229da57d7bSbt150084 4239da57d7bSbt150084 /* 4249da57d7bSbt150084 * Check the command and perform corresponding operations 4259da57d7bSbt150084 */ 4269da57d7bSbt150084 switch (cmd) { 4279da57d7bSbt150084 default: 4289da57d7bSbt150084 return (DDI_FAILURE); 4299da57d7bSbt150084 4309da57d7bSbt150084 case DDI_RESUME: 4319da57d7bSbt150084 return (ixgbe_resume(devinfo)); 4329da57d7bSbt150084 4339da57d7bSbt150084 case DDI_ATTACH: 4349da57d7bSbt150084 break; 4359da57d7bSbt150084 } 4369da57d7bSbt150084 4379da57d7bSbt150084 /* Get the device instance */ 4389da57d7bSbt150084 instance = ddi_get_instance(devinfo); 4399da57d7bSbt150084 4409da57d7bSbt150084 /* Allocate memory for the instance data structure */ 4419da57d7bSbt150084 ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP); 4429da57d7bSbt150084 4439da57d7bSbt150084 ixgbe->dip = devinfo; 4449da57d7bSbt150084 ixgbe->instance = instance; 4459da57d7bSbt150084 4469da57d7bSbt150084 hw = &ixgbe->hw; 4479da57d7bSbt150084 osdep = &ixgbe->osdep; 4489da57d7bSbt150084 hw->back = osdep; 4499da57d7bSbt150084 osdep->ixgbe = ixgbe; 4509da57d7bSbt150084 4519da57d7bSbt150084 /* Attach the instance pointer to the dev_info data structure */ 4529da57d7bSbt150084 ddi_set_driver_private(devinfo, ixgbe); 4539da57d7bSbt150084 4549da57d7bSbt150084 /* 4557e579c30SDale Ghent * Initialize for FMA support 4569da57d7bSbt150084 */ 457c971fb7eSgg161487 ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE, 4589da57d7bSbt150084 0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 4599da57d7bSbt150084 DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 4609da57d7bSbt150084 ixgbe_fm_init(ixgbe); 4619da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT; 4629da57d7bSbt150084 4639da57d7bSbt150084 /* 4649da57d7bSbt150084 * Map PCI config space registers 4659da57d7bSbt150084 */ 4669da57d7bSbt150084 if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) { 4679da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to map PCI configurations"); 4689da57d7bSbt150084 goto attach_fail; 4699da57d7bSbt150084 } 4709da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG; 4719da57d7bSbt150084 4729da57d7bSbt150084 /* 4739da57d7bSbt150084 * Identify the chipset family 4749da57d7bSbt150084 */ 4759da57d7bSbt150084 if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) { 4769da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to identify hardware"); 4779da57d7bSbt150084 goto attach_fail; 4789da57d7bSbt150084 } 4799da57d7bSbt150084 4809da57d7bSbt150084 /* 4819da57d7bSbt150084 * Map device registers 4829da57d7bSbt150084 */ 4839da57d7bSbt150084 if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) { 4849da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to map device registers"); 4859da57d7bSbt150084 goto attach_fail; 4869da57d7bSbt150084 } 4879da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP; 4889da57d7bSbt150084 4899da57d7bSbt150084 /* 4909da57d7bSbt150084 * Initialize driver parameters 4919da57d7bSbt150084 */ 4929da57d7bSbt150084 ixgbe_init_properties(ixgbe); 4939da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS; 4949da57d7bSbt150084 4959da57d7bSbt150084 /* 4960dc2366fSVenugopal Iyer * Register interrupt callback 4970dc2366fSVenugopal Iyer */ 4980dc2366fSVenugopal Iyer if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) { 4990dc2366fSVenugopal Iyer ixgbe_error(ixgbe, "Failed to register interrupt callback"); 5000dc2366fSVenugopal Iyer goto attach_fail; 5010dc2366fSVenugopal Iyer } 5020dc2366fSVenugopal Iyer 5030dc2366fSVenugopal Iyer /* 5049da57d7bSbt150084 * Allocate interrupts 5059da57d7bSbt150084 */ 5069da57d7bSbt150084 if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) { 5079da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to allocate interrupts"); 5089da57d7bSbt150084 goto attach_fail; 5099da57d7bSbt150084 } 5109da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR; 5119da57d7bSbt150084 5129da57d7bSbt150084 /* 5139da57d7bSbt150084 * Allocate rx/tx rings based on the ring numbers. 5149da57d7bSbt150084 * The actual numbers of rx/tx rings are decided by the number of 5159da57d7bSbt150084 * allocated interrupt vectors, so we should allocate the rings after 5169da57d7bSbt150084 * interrupts are allocated. 5179da57d7bSbt150084 */ 5189da57d7bSbt150084 if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) { 5199da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to allocate rx and tx rings"); 5209da57d7bSbt150084 goto attach_fail; 5219da57d7bSbt150084 } 5229da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS; 5239da57d7bSbt150084 5249da57d7bSbt150084 /* 5259da57d7bSbt150084 * Map rings to interrupt vectors 5269da57d7bSbt150084 */ 52773cd555cSBin Tu - Sun Microsystems - Beijing China if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) { 52873cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_error(ixgbe, "Failed to map interrupts to vectors"); 5299da57d7bSbt150084 goto attach_fail; 5309da57d7bSbt150084 } 5319da57d7bSbt150084 5329da57d7bSbt150084 /* 5339da57d7bSbt150084 * Add interrupt handlers 5349da57d7bSbt150084 */ 5359da57d7bSbt150084 if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) { 5369da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to add interrupt handlers"); 5379da57d7bSbt150084 goto attach_fail; 5389da57d7bSbt150084 } 5399da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 5409da57d7bSbt150084 5419da57d7bSbt150084 /* 54262e6e1adSPaul Guo * Create a taskq for sfp-change 54313740cb2SPaul Guo */ 5445b6dd21fSchenlu chen - Sun Microsystems - Beijing China (void) sprintf(taskqname, "ixgbe%d_sfp_taskq", instance); 54562e6e1adSPaul Guo if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname, 54613740cb2SPaul Guo 1, TASKQ_DEFAULTPRI, 0)) == NULL) { 5475b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, "sfp_taskq create failed"); 54813740cb2SPaul Guo goto attach_fail; 54913740cb2SPaul Guo } 55062e6e1adSPaul Guo ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ; 55113740cb2SPaul Guo 55213740cb2SPaul Guo /* 5535b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Create a taskq for over-temp 5545b6dd21fSchenlu chen - Sun Microsystems - Beijing China */ 5555b6dd21fSchenlu chen - Sun Microsystems - Beijing China (void) sprintf(taskqname, "ixgbe%d_overtemp_taskq", instance); 5565b6dd21fSchenlu chen - Sun Microsystems - Beijing China if ((ixgbe->overtemp_taskq = ddi_taskq_create(devinfo, taskqname, 5575b6dd21fSchenlu chen - Sun Microsystems - Beijing China 1, TASKQ_DEFAULTPRI, 0)) == NULL) { 5585b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, "overtemp_taskq create failed"); 5595b6dd21fSchenlu chen - Sun Microsystems - Beijing China goto attach_fail; 5605b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 5615b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->attach_progress |= ATTACH_PROGRESS_OVERTEMP_TASKQ; 5625b6dd21fSchenlu chen - Sun Microsystems - Beijing China 5635b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* 5647e579c30SDale Ghent * Create a taskq for processing external PHY interrupts 5657e579c30SDale Ghent */ 5667e579c30SDale Ghent (void) sprintf(taskqname, "ixgbe%d_phy_taskq", instance); 5677e579c30SDale Ghent if ((ixgbe->phy_taskq = ddi_taskq_create(devinfo, taskqname, 5687e579c30SDale Ghent 1, TASKQ_DEFAULTPRI, 0)) == NULL) { 5697e579c30SDale Ghent ixgbe_error(ixgbe, "phy_taskq create failed"); 5707e579c30SDale Ghent goto attach_fail; 5717e579c30SDale Ghent } 5727e579c30SDale Ghent ixgbe->attach_progress |= ATTACH_PROGRESS_PHY_TASKQ; 5737e579c30SDale Ghent 5747e579c30SDale Ghent /* 5759da57d7bSbt150084 * Initialize driver parameters 5769da57d7bSbt150084 */ 5779da57d7bSbt150084 if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) { 5789da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to initialize driver settings"); 5799da57d7bSbt150084 goto attach_fail; 5809da57d7bSbt150084 } 5819da57d7bSbt150084 5829da57d7bSbt150084 /* 5839da57d7bSbt150084 * Initialize mutexes for this device. 5849da57d7bSbt150084 * Do this before enabling the interrupt handler and 5859da57d7bSbt150084 * register the softint to avoid the condition where 5869da57d7bSbt150084 * interrupt handler can try using uninitialized mutex. 5879da57d7bSbt150084 */ 5889da57d7bSbt150084 ixgbe_init_locks(ixgbe); 5899da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS; 5909da57d7bSbt150084 5919da57d7bSbt150084 /* 5929da57d7bSbt150084 * Initialize chipset hardware 5939da57d7bSbt150084 */ 5949da57d7bSbt150084 if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) { 5959da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to initialize adapter"); 5969da57d7bSbt150084 goto attach_fail; 5979da57d7bSbt150084 } 59862e6e1adSPaul Guo ixgbe->link_check_complete = B_FALSE; 59962e6e1adSPaul Guo ixgbe->link_check_hrtime = gethrtime() + 60062e6e1adSPaul Guo (IXGBE_LINK_UP_TIME * 100000000ULL); 6019da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_INIT; 6029da57d7bSbt150084 6039da57d7bSbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) { 6049da57d7bSbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 6059da57d7bSbt150084 goto attach_fail; 6069da57d7bSbt150084 } 6079da57d7bSbt150084 6089da57d7bSbt150084 /* 6097e579c30SDale Ghent * Initialize adapter capabilities 6107e579c30SDale Ghent */ 6117e579c30SDale Ghent ixgbe_init_params(ixgbe); 6127e579c30SDale Ghent 6137e579c30SDale Ghent /* 6149da57d7bSbt150084 * Initialize statistics 6159da57d7bSbt150084 */ 6169da57d7bSbt150084 if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) { 6179da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to initialize statistics"); 6189da57d7bSbt150084 goto attach_fail; 6199da57d7bSbt150084 } 6209da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_STATS; 6219da57d7bSbt150084 6229da57d7bSbt150084 /* 6239da57d7bSbt150084 * Register the driver to the MAC 6249da57d7bSbt150084 */ 6259da57d7bSbt150084 if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) { 6269da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to register MAC"); 6279da57d7bSbt150084 goto attach_fail; 6289da57d7bSbt150084 } 62913740cb2SPaul Guo mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN); 6309da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_MAC; 6319da57d7bSbt150084 63262e6e1adSPaul Guo ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe, 63362e6e1adSPaul Guo IXGBE_CYCLIC_PERIOD, DDI_IPL_0); 63462e6e1adSPaul Guo if (ixgbe->periodic_id == 0) { 63562e6e1adSPaul Guo ixgbe_error(ixgbe, "Failed to add the link check timer"); 63662e6e1adSPaul Guo goto attach_fail; 63762e6e1adSPaul Guo } 63862e6e1adSPaul Guo ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER; 63962e6e1adSPaul Guo 6409da57d7bSbt150084 /* 6419da57d7bSbt150084 * Now that mutex locks are initialized, and the chip is also 6429da57d7bSbt150084 * initialized, enable interrupts. 6439da57d7bSbt150084 */ 6449da57d7bSbt150084 if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) { 6459da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to enable DDI interrupts"); 6469da57d7bSbt150084 goto attach_fail; 6479da57d7bSbt150084 } 6489da57d7bSbt150084 ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 6499da57d7bSbt150084 6507e579c30SDale Ghent ixgbe_log(ixgbe, "%s", ixgbe_ident); 65162e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED); 6529da57d7bSbt150084 6539da57d7bSbt150084 return (DDI_SUCCESS); 6549da57d7bSbt150084 6559da57d7bSbt150084 attach_fail: 6569da57d7bSbt150084 ixgbe_unconfigure(devinfo, ixgbe); 6579da57d7bSbt150084 return (DDI_FAILURE); 6589da57d7bSbt150084 } 6599da57d7bSbt150084 6609da57d7bSbt150084 /* 6619da57d7bSbt150084 * ixgbe_detach - Driver detach. 6629da57d7bSbt150084 * 6639da57d7bSbt150084 * The detach() function is the complement of the attach routine. 6649da57d7bSbt150084 * If cmd is set to DDI_DETACH, detach() is used to remove the 6659da57d7bSbt150084 * state associated with a given instance of a device node 6669da57d7bSbt150084 * prior to the removal of that instance from the system. 6679da57d7bSbt150084 * 6689da57d7bSbt150084 * The detach() function will be called once for each instance 6699da57d7bSbt150084 * of the device for which there has been a successful attach() 6709da57d7bSbt150084 * once there are no longer any opens on the device. 6719da57d7bSbt150084 * 6729da57d7bSbt150084 * Interrupts routine are disabled, All memory allocated by this 6739da57d7bSbt150084 * driver are freed. 6749da57d7bSbt150084 */ 6759da57d7bSbt150084 static int 6769da57d7bSbt150084 ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 6779da57d7bSbt150084 { 6789da57d7bSbt150084 ixgbe_t *ixgbe; 6799da57d7bSbt150084 6809da57d7bSbt150084 /* 6819da57d7bSbt150084 * Check detach command 6829da57d7bSbt150084 */ 6839da57d7bSbt150084 switch (cmd) { 6849da57d7bSbt150084 default: 6859da57d7bSbt150084 return (DDI_FAILURE); 6869da57d7bSbt150084 6879da57d7bSbt150084 case DDI_SUSPEND: 6889da57d7bSbt150084 return (ixgbe_suspend(devinfo)); 6899da57d7bSbt150084 6909da57d7bSbt150084 case DDI_DETACH: 6919da57d7bSbt150084 break; 6929da57d7bSbt150084 } 6939da57d7bSbt150084 6949da57d7bSbt150084 /* 6959da57d7bSbt150084 * Get the pointer to the driver private data structure 6969da57d7bSbt150084 */ 6979da57d7bSbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 6989da57d7bSbt150084 if (ixgbe == NULL) 6999da57d7bSbt150084 return (DDI_FAILURE); 7009da57d7bSbt150084 7019da57d7bSbt150084 /* 7029da57d7bSbt150084 * If the device is still running, it needs to be stopped first. 7039da57d7bSbt150084 * This check is necessary because under some specific circumstances, 7049da57d7bSbt150084 * the detach routine can be called without stopping the interface 7059da57d7bSbt150084 * first. 7069da57d7bSbt150084 */ 7079da57d7bSbt150084 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 70862e6e1adSPaul Guo atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 70962e6e1adSPaul Guo mutex_enter(&ixgbe->gen_lock); 710ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe, B_TRUE); 7119da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 7129da57d7bSbt150084 /* Disable and stop the watchdog timer */ 7139da57d7bSbt150084 ixgbe_disable_watchdog_timer(ixgbe); 71462e6e1adSPaul Guo } 7159da57d7bSbt150084 7169da57d7bSbt150084 /* 7179da57d7bSbt150084 * Check if there are still rx buffers held by the upper layer. 7189da57d7bSbt150084 * If so, fail the detach. 7199da57d7bSbt150084 */ 7209da57d7bSbt150084 if (!ixgbe_rx_drain(ixgbe)) 7219da57d7bSbt150084 return (DDI_FAILURE); 7229da57d7bSbt150084 7239da57d7bSbt150084 /* 7249da57d7bSbt150084 * Do the remaining unconfigure routines 7259da57d7bSbt150084 */ 7269da57d7bSbt150084 ixgbe_unconfigure(devinfo, ixgbe); 7279da57d7bSbt150084 7289da57d7bSbt150084 return (DDI_SUCCESS); 7299da57d7bSbt150084 } 7309da57d7bSbt150084 7318c430e59SSaso Kiselkov /* 7328c430e59SSaso Kiselkov * quiesce(9E) entry point. 7338c430e59SSaso Kiselkov * 7348c430e59SSaso Kiselkov * This function is called when the system is single-threaded at high 7358c430e59SSaso Kiselkov * PIL with preemption disabled. Therefore, this function must not be 7368c430e59SSaso Kiselkov * blocked. 7378c430e59SSaso Kiselkov * 7388c430e59SSaso Kiselkov * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 7398c430e59SSaso Kiselkov * DDI_FAILURE indicates an error condition and should almost never happen. 7408c430e59SSaso Kiselkov */ 7418c430e59SSaso Kiselkov static int 7428c430e59SSaso Kiselkov ixgbe_quiesce(dev_info_t *devinfo) 7438c430e59SSaso Kiselkov { 7448c430e59SSaso Kiselkov ixgbe_t *ixgbe; 7458c430e59SSaso Kiselkov struct ixgbe_hw *hw; 7468c430e59SSaso Kiselkov 7478c430e59SSaso Kiselkov ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 7488c430e59SSaso Kiselkov 7498c430e59SSaso Kiselkov if (ixgbe == NULL) 7508c430e59SSaso Kiselkov return (DDI_FAILURE); 7518c430e59SSaso Kiselkov 7528c430e59SSaso Kiselkov hw = &ixgbe->hw; 7538c430e59SSaso Kiselkov 7548c430e59SSaso Kiselkov /* 7558c430e59SSaso Kiselkov * Disable the adapter interrupts 7568c430e59SSaso Kiselkov */ 7578c430e59SSaso Kiselkov ixgbe_disable_adapter_interrupts(ixgbe); 7588c430e59SSaso Kiselkov 7598c430e59SSaso Kiselkov /* 7608c430e59SSaso Kiselkov * Tell firmware driver is no longer in control 7618c430e59SSaso Kiselkov */ 7628c430e59SSaso Kiselkov ixgbe_release_driver_control(hw); 7638c430e59SSaso Kiselkov 7648c430e59SSaso Kiselkov /* 7658c430e59SSaso Kiselkov * Reset the chipset 7668c430e59SSaso Kiselkov */ 7678c430e59SSaso Kiselkov (void) ixgbe_reset_hw(hw); 7688c430e59SSaso Kiselkov 7698c430e59SSaso Kiselkov /* 7708c430e59SSaso Kiselkov * Reset PHY 7718c430e59SSaso Kiselkov */ 7728c430e59SSaso Kiselkov (void) ixgbe_reset_phy(hw); 7738c430e59SSaso Kiselkov 7748c430e59SSaso Kiselkov return (DDI_SUCCESS); 7758c430e59SSaso Kiselkov } 7768c430e59SSaso Kiselkov 7779da57d7bSbt150084 static void 7789da57d7bSbt150084 ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe) 7799da57d7bSbt150084 { 7809da57d7bSbt150084 /* 7819da57d7bSbt150084 * Disable interrupt 7829da57d7bSbt150084 */ 7839da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 7849da57d7bSbt150084 (void) ixgbe_disable_intrs(ixgbe); 7859da57d7bSbt150084 } 7869da57d7bSbt150084 7879da57d7bSbt150084 /* 78862e6e1adSPaul Guo * remove the link check timer 78962e6e1adSPaul Guo */ 79062e6e1adSPaul Guo if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) { 79162e6e1adSPaul Guo if (ixgbe->periodic_id != NULL) { 79262e6e1adSPaul Guo ddi_periodic_delete(ixgbe->periodic_id); 79362e6e1adSPaul Guo ixgbe->periodic_id = NULL; 79462e6e1adSPaul Guo } 79562e6e1adSPaul Guo } 79662e6e1adSPaul Guo 79762e6e1adSPaul Guo /* 7989da57d7bSbt150084 * Unregister MAC 7999da57d7bSbt150084 */ 8009da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) { 8019da57d7bSbt150084 (void) mac_unregister(ixgbe->mac_hdl); 8029da57d7bSbt150084 } 8039da57d7bSbt150084 8049da57d7bSbt150084 /* 8059da57d7bSbt150084 * Free statistics 8069da57d7bSbt150084 */ 8079da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) { 8089da57d7bSbt150084 kstat_delete((kstat_t *)ixgbe->ixgbe_ks); 8099da57d7bSbt150084 } 8109da57d7bSbt150084 8119da57d7bSbt150084 /* 8129da57d7bSbt150084 * Remove interrupt handlers 8139da57d7bSbt150084 */ 8149da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 8159da57d7bSbt150084 ixgbe_rem_intr_handlers(ixgbe); 8169da57d7bSbt150084 } 8179da57d7bSbt150084 8189da57d7bSbt150084 /* 81962e6e1adSPaul Guo * Remove taskq for sfp-status-change 82013740cb2SPaul Guo */ 82162e6e1adSPaul Guo if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) { 82262e6e1adSPaul Guo ddi_taskq_destroy(ixgbe->sfp_taskq); 82313740cb2SPaul Guo } 82413740cb2SPaul Guo 82513740cb2SPaul Guo /* 8265b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Remove taskq for over-temp 8275b6dd21fSchenlu chen - Sun Microsystems - Beijing China */ 8285b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->attach_progress & ATTACH_PROGRESS_OVERTEMP_TASKQ) { 8295b6dd21fSchenlu chen - Sun Microsystems - Beijing China ddi_taskq_destroy(ixgbe->overtemp_taskq); 8305b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 8315b6dd21fSchenlu chen - Sun Microsystems - Beijing China 8325b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* 8337e579c30SDale Ghent * Remove taskq for external PHYs 8347e579c30SDale Ghent */ 8357e579c30SDale Ghent if (ixgbe->attach_progress & ATTACH_PROGRESS_PHY_TASKQ) { 8367e579c30SDale Ghent ddi_taskq_destroy(ixgbe->phy_taskq); 8377e579c30SDale Ghent } 8387e579c30SDale Ghent 8397e579c30SDale Ghent /* 8409da57d7bSbt150084 * Remove interrupts 8419da57d7bSbt150084 */ 8429da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) { 8439da57d7bSbt150084 ixgbe_rem_intrs(ixgbe); 8449da57d7bSbt150084 } 8459da57d7bSbt150084 8469da57d7bSbt150084 /* 8470dc2366fSVenugopal Iyer * Unregister interrupt callback handler 8480dc2366fSVenugopal Iyer */ 84965e6526dSRobert Mustacchi if (ixgbe->cb_hdl != NULL) { 8500dc2366fSVenugopal Iyer (void) ddi_cb_unregister(ixgbe->cb_hdl); 85165e6526dSRobert Mustacchi } 8520dc2366fSVenugopal Iyer 8530dc2366fSVenugopal Iyer /* 8549da57d7bSbt150084 * Remove driver properties 8559da57d7bSbt150084 */ 8569da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) { 8579da57d7bSbt150084 (void) ddi_prop_remove_all(devinfo); 8589da57d7bSbt150084 } 8599da57d7bSbt150084 8609da57d7bSbt150084 /* 8619da57d7bSbt150084 * Stop the chipset 8629da57d7bSbt150084 */ 8639da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) { 8649da57d7bSbt150084 mutex_enter(&ixgbe->gen_lock); 8659da57d7bSbt150084 ixgbe_chip_stop(ixgbe); 8669da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 8679da57d7bSbt150084 } 8689da57d7bSbt150084 8699da57d7bSbt150084 /* 8709da57d7bSbt150084 * Free register handle 8719da57d7bSbt150084 */ 8729da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) { 8739da57d7bSbt150084 if (ixgbe->osdep.reg_handle != NULL) 8749da57d7bSbt150084 ddi_regs_map_free(&ixgbe->osdep.reg_handle); 8759da57d7bSbt150084 } 8769da57d7bSbt150084 8779da57d7bSbt150084 /* 8789da57d7bSbt150084 * Free PCI config handle 8799da57d7bSbt150084 */ 8809da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) { 8819da57d7bSbt150084 if (ixgbe->osdep.cfg_handle != NULL) 8829da57d7bSbt150084 pci_config_teardown(&ixgbe->osdep.cfg_handle); 8839da57d7bSbt150084 } 8849da57d7bSbt150084 8859da57d7bSbt150084 /* 8869da57d7bSbt150084 * Free locks 8879da57d7bSbt150084 */ 8889da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) { 8899da57d7bSbt150084 ixgbe_destroy_locks(ixgbe); 8909da57d7bSbt150084 } 8919da57d7bSbt150084 8929da57d7bSbt150084 /* 8939da57d7bSbt150084 * Free the rx/tx rings 8949da57d7bSbt150084 */ 8959da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) { 8969da57d7bSbt150084 ixgbe_free_rings(ixgbe); 8979da57d7bSbt150084 } 8989da57d7bSbt150084 8999da57d7bSbt150084 /* 9009da57d7bSbt150084 * Unregister FMA capabilities 9019da57d7bSbt150084 */ 9029da57d7bSbt150084 if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) { 9039da57d7bSbt150084 ixgbe_fm_fini(ixgbe); 9049da57d7bSbt150084 } 9059da57d7bSbt150084 9069da57d7bSbt150084 /* 9079da57d7bSbt150084 * Free the driver data structure 9089da57d7bSbt150084 */ 9099da57d7bSbt150084 kmem_free(ixgbe, sizeof (ixgbe_t)); 9109da57d7bSbt150084 9119da57d7bSbt150084 ddi_set_driver_private(devinfo, NULL); 9129da57d7bSbt150084 } 9139da57d7bSbt150084 9149da57d7bSbt150084 /* 9159da57d7bSbt150084 * ixgbe_register_mac - Register the driver and its function pointers with 9169da57d7bSbt150084 * the GLD interface. 9179da57d7bSbt150084 */ 9189da57d7bSbt150084 static int 9199da57d7bSbt150084 ixgbe_register_mac(ixgbe_t *ixgbe) 9209da57d7bSbt150084 { 9219da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 9229da57d7bSbt150084 mac_register_t *mac; 9239da57d7bSbt150084 int status; 9249da57d7bSbt150084 9259da57d7bSbt150084 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 9269da57d7bSbt150084 return (IXGBE_FAILURE); 9279da57d7bSbt150084 9289da57d7bSbt150084 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 9299da57d7bSbt150084 mac->m_driver = ixgbe; 9309da57d7bSbt150084 mac->m_dip = ixgbe->dip; 9319da57d7bSbt150084 mac->m_src_addr = hw->mac.addr; 9329da57d7bSbt150084 mac->m_callbacks = &ixgbe_m_callbacks; 9339da57d7bSbt150084 mac->m_min_sdu = 0; 9349da57d7bSbt150084 mac->m_max_sdu = ixgbe->default_mtu; 9359da57d7bSbt150084 mac->m_margin = VLAN_TAGSZ; 936ea65739eSchenlu chen - Sun Microsystems - Beijing China mac->m_priv_props = ixgbe_priv_props; 937da14cebeSEric Cheng mac->m_v12n = MAC_VIRT_LEVEL1; 9389da57d7bSbt150084 9399da57d7bSbt150084 status = mac_register(mac, &ixgbe->mac_hdl); 9409da57d7bSbt150084 9419da57d7bSbt150084 mac_free(mac); 9429da57d7bSbt150084 9439da57d7bSbt150084 return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE); 9449da57d7bSbt150084 } 9459da57d7bSbt150084 9469da57d7bSbt150084 /* 9479da57d7bSbt150084 * ixgbe_identify_hardware - Identify the type of the chipset. 9489da57d7bSbt150084 */ 9499da57d7bSbt150084 static int 9509da57d7bSbt150084 ixgbe_identify_hardware(ixgbe_t *ixgbe) 9519da57d7bSbt150084 { 9529da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 9539da57d7bSbt150084 struct ixgbe_osdep *osdep = &ixgbe->osdep; 9549da57d7bSbt150084 9559da57d7bSbt150084 /* 9569da57d7bSbt150084 * Get the device id 9579da57d7bSbt150084 */ 9589da57d7bSbt150084 hw->vendor_id = 9599da57d7bSbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID); 9609da57d7bSbt150084 hw->device_id = 9619da57d7bSbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID); 9629da57d7bSbt150084 hw->revision_id = 9639da57d7bSbt150084 pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID); 9649da57d7bSbt150084 hw->subsystem_device_id = 9659da57d7bSbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID); 9669da57d7bSbt150084 hw->subsystem_vendor_id = 9679da57d7bSbt150084 pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID); 9689da57d7bSbt150084 96913740cb2SPaul Guo /* 97013740cb2SPaul Guo * Set the mac type of the adapter based on the device id 97113740cb2SPaul Guo */ 97213740cb2SPaul Guo if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) { 97313740cb2SPaul Guo return (IXGBE_FAILURE); 97413740cb2SPaul Guo } 97513740cb2SPaul Guo 97613740cb2SPaul Guo /* 97713740cb2SPaul Guo * Install adapter capabilities 97813740cb2SPaul Guo */ 97913740cb2SPaul Guo switch (hw->mac.type) { 98013740cb2SPaul Guo case ixgbe_mac_82598EB: 98119843f01SPaul Guo IXGBE_DEBUGLOG_0(ixgbe, "identify 82598 adapter\n"); 98213740cb2SPaul Guo ixgbe->capab = &ixgbe_82598eb_cap; 98313740cb2SPaul Guo 98413740cb2SPaul Guo if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) { 98513740cb2SPaul Guo ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; 98613740cb2SPaul Guo ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1; 9875b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->other_gpie |= IXGBE_SDP1_GPIEN; 98813740cb2SPaul Guo } 98973cd555cSBin Tu - Sun Microsystems - Beijing China break; 9905b6dd21fSchenlu chen - Sun Microsystems - Beijing China 99173cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 99219843f01SPaul Guo IXGBE_DEBUGLOG_0(ixgbe, "identify 82599 adapter\n"); 99373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->capab = &ixgbe_82599eb_cap; 99473cd555cSBin Tu - Sun Microsystems - Beijing China 9955b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM) { 9965b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->flags |= IXGBE_FLAG_TEMP_SENSOR_CAPABLE; 9975b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP0; 9985b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN; 9995b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 100013740cb2SPaul Guo break; 10015b6dd21fSchenlu chen - Sun Microsystems - Beijing China 100269b5a878SDan McDonald case ixgbe_mac_X540: 100369b5a878SDan McDonald IXGBE_DEBUGLOG_0(ixgbe, "identify X540 adapter\n"); 100469b5a878SDan McDonald ixgbe->capab = &ixgbe_X540_cap; 100569b5a878SDan McDonald /* 100669b5a878SDan McDonald * For now, X540 is all set in its capab structure. 100769b5a878SDan McDonald * As other X540 variants show up, things can change here. 100869b5a878SDan McDonald */ 100969b5a878SDan McDonald break; 101069b5a878SDan McDonald 10117e579c30SDale Ghent case ixgbe_mac_X550: 10127e579c30SDale Ghent case ixgbe_mac_X550EM_x: 10137e579c30SDale Ghent IXGBE_DEBUGLOG_0(ixgbe, "identify X550 adapter\n"); 10147e579c30SDale Ghent ixgbe->capab = &ixgbe_X550_cap; 10157e579c30SDale Ghent 10167e579c30SDale Ghent if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) 10177e579c30SDale Ghent ixgbe->capab->flags |= IXGBE_FLAG_SFP_PLUG_CAPABLE; 10187e579c30SDale Ghent 10197e579c30SDale Ghent /* 10207e579c30SDale Ghent * Link detection on X552 SFP+ and X552/X557-AT 10217e579c30SDale Ghent */ 10227e579c30SDale Ghent if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || 10237e579c30SDale Ghent hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { 10247e579c30SDale Ghent ixgbe->capab->other_intr |= 10257e579c30SDale Ghent IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); 10267e579c30SDale Ghent ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN_X540; 10277e579c30SDale Ghent } 10287e579c30SDale Ghent break; 10297e579c30SDale Ghent 103013740cb2SPaul Guo default: 103119843f01SPaul Guo IXGBE_DEBUGLOG_1(ixgbe, 103213740cb2SPaul Guo "adapter not supported in ixgbe_identify_hardware(): %d\n", 103313740cb2SPaul Guo hw->mac.type); 103413740cb2SPaul Guo return (IXGBE_FAILURE); 103513740cb2SPaul Guo } 103613740cb2SPaul Guo 10379da57d7bSbt150084 return (IXGBE_SUCCESS); 10389da57d7bSbt150084 } 10399da57d7bSbt150084 10409da57d7bSbt150084 /* 10419da57d7bSbt150084 * ixgbe_regs_map - Map the device registers. 10429da57d7bSbt150084 * 10439da57d7bSbt150084 */ 10449da57d7bSbt150084 static int 10459da57d7bSbt150084 ixgbe_regs_map(ixgbe_t *ixgbe) 10469da57d7bSbt150084 { 10479da57d7bSbt150084 dev_info_t *devinfo = ixgbe->dip; 10489da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 10499da57d7bSbt150084 struct ixgbe_osdep *osdep = &ixgbe->osdep; 10509da57d7bSbt150084 off_t mem_size; 10519da57d7bSbt150084 10529da57d7bSbt150084 /* 10539da57d7bSbt150084 * First get the size of device registers to be mapped. 10549da57d7bSbt150084 */ 105573cd555cSBin Tu - Sun Microsystems - Beijing China if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size) 105673cd555cSBin Tu - Sun Microsystems - Beijing China != DDI_SUCCESS) { 10579da57d7bSbt150084 return (IXGBE_FAILURE); 10589da57d7bSbt150084 } 10599da57d7bSbt150084 10609da57d7bSbt150084 /* 10619da57d7bSbt150084 * Call ddi_regs_map_setup() to map registers 10629da57d7bSbt150084 */ 106373cd555cSBin Tu - Sun Microsystems - Beijing China if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET, 10649da57d7bSbt150084 (caddr_t *)&hw->hw_addr, 0, 10659da57d7bSbt150084 mem_size, &ixgbe_regs_acc_attr, 10669da57d7bSbt150084 &osdep->reg_handle)) != DDI_SUCCESS) { 10679da57d7bSbt150084 return (IXGBE_FAILURE); 10689da57d7bSbt150084 } 10699da57d7bSbt150084 10709da57d7bSbt150084 return (IXGBE_SUCCESS); 10719da57d7bSbt150084 } 10729da57d7bSbt150084 10739da57d7bSbt150084 /* 10749da57d7bSbt150084 * ixgbe_init_properties - Initialize driver properties. 10759da57d7bSbt150084 */ 10769da57d7bSbt150084 static void 10779da57d7bSbt150084 ixgbe_init_properties(ixgbe_t *ixgbe) 10789da57d7bSbt150084 { 10799da57d7bSbt150084 /* 10809da57d7bSbt150084 * Get conf file properties, including link settings 10819da57d7bSbt150084 * jumbo frames, ring number, descriptor number, etc. 10829da57d7bSbt150084 */ 10839da57d7bSbt150084 ixgbe_get_conf(ixgbe); 10849da57d7bSbt150084 } 10859da57d7bSbt150084 10869da57d7bSbt150084 /* 10879da57d7bSbt150084 * ixgbe_init_driver_settings - Initialize driver settings. 10889da57d7bSbt150084 * 10899da57d7bSbt150084 * The settings include hardware function pointers, bus information, 10909da57d7bSbt150084 * rx/tx rings settings, link state, and any other parameters that 10919da57d7bSbt150084 * need to be setup during driver initialization. 10929da57d7bSbt150084 */ 10939da57d7bSbt150084 static int 10949da57d7bSbt150084 ixgbe_init_driver_settings(ixgbe_t *ixgbe) 10959da57d7bSbt150084 { 10969da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 1097da14cebeSEric Cheng dev_info_t *devinfo = ixgbe->dip; 10989da57d7bSbt150084 ixgbe_rx_ring_t *rx_ring; 10990dc2366fSVenugopal Iyer ixgbe_rx_group_t *rx_group; 11009da57d7bSbt150084 ixgbe_tx_ring_t *tx_ring; 11019da57d7bSbt150084 uint32_t rx_size; 11029da57d7bSbt150084 uint32_t tx_size; 11030dc2366fSVenugopal Iyer uint32_t ring_per_group; 11049da57d7bSbt150084 int i; 11059da57d7bSbt150084 11069da57d7bSbt150084 /* 11079da57d7bSbt150084 * Initialize chipset specific hardware function pointers 11089da57d7bSbt150084 */ 11099da57d7bSbt150084 if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) { 11109da57d7bSbt150084 return (IXGBE_FAILURE); 11119da57d7bSbt150084 } 11129da57d7bSbt150084 11139da57d7bSbt150084 /* 1114da14cebeSEric Cheng * Get the system page size 1115da14cebeSEric Cheng */ 1116da14cebeSEric Cheng ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1); 1117da14cebeSEric Cheng 1118da14cebeSEric Cheng /* 11199da57d7bSbt150084 * Set rx buffer size 11209da57d7bSbt150084 * 11219da57d7bSbt150084 * The IP header alignment room is counted in the calculation. 11229da57d7bSbt150084 * The rx buffer size is in unit of 1K that is required by the 11239da57d7bSbt150084 * chipset hardware. 11249da57d7bSbt150084 */ 11259da57d7bSbt150084 rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM; 11269da57d7bSbt150084 ixgbe->rx_buf_size = ((rx_size >> 10) + 11279da57d7bSbt150084 ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 11289da57d7bSbt150084 11299da57d7bSbt150084 /* 11309da57d7bSbt150084 * Set tx buffer size 11319da57d7bSbt150084 */ 11329da57d7bSbt150084 tx_size = ixgbe->max_frame_size; 11339da57d7bSbt150084 ixgbe->tx_buf_size = ((tx_size >> 10) + 11349da57d7bSbt150084 ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 11359da57d7bSbt150084 11369da57d7bSbt150084 /* 11370dc2366fSVenugopal Iyer * Initialize rx/tx rings/groups parameters 11389da57d7bSbt150084 */ 11390dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 11409da57d7bSbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 11419da57d7bSbt150084 rx_ring = &ixgbe->rx_rings[i]; 11429da57d7bSbt150084 rx_ring->index = i; 11439da57d7bSbt150084 rx_ring->ixgbe = ixgbe; 11440dc2366fSVenugopal Iyer rx_ring->group_index = i / ring_per_group; 11450dc2366fSVenugopal Iyer rx_ring->hw_index = ixgbe_get_hw_rx_index(ixgbe, i); 11460dc2366fSVenugopal Iyer } 11470dc2366fSVenugopal Iyer 11480dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_rx_groups; i++) { 11490dc2366fSVenugopal Iyer rx_group = &ixgbe->rx_groups[i]; 11500dc2366fSVenugopal Iyer rx_group->index = i; 11510dc2366fSVenugopal Iyer rx_group->ixgbe = ixgbe; 11529da57d7bSbt150084 } 11539da57d7bSbt150084 11549da57d7bSbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 11559da57d7bSbt150084 tx_ring = &ixgbe->tx_rings[i]; 11569da57d7bSbt150084 tx_ring->index = i; 11579da57d7bSbt150084 tx_ring->ixgbe = ixgbe; 11589da57d7bSbt150084 if (ixgbe->tx_head_wb_enable) 11599da57d7bSbt150084 tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb; 11609da57d7bSbt150084 else 11619da57d7bSbt150084 tx_ring->tx_recycle = ixgbe_tx_recycle_legacy; 11629da57d7bSbt150084 11639da57d7bSbt150084 tx_ring->ring_size = ixgbe->tx_ring_size; 11649da57d7bSbt150084 tx_ring->free_list_size = ixgbe->tx_ring_size + 11659da57d7bSbt150084 (ixgbe->tx_ring_size >> 1); 11669da57d7bSbt150084 } 11679da57d7bSbt150084 11689da57d7bSbt150084 /* 11699da57d7bSbt150084 * Initialize values of interrupt throttling rate 11709da57d7bSbt150084 */ 117173cd555cSBin Tu - Sun Microsystems - Beijing China for (i = 1; i < MAX_INTR_VECTOR; i++) 11729da57d7bSbt150084 ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0]; 11739da57d7bSbt150084 11749da57d7bSbt150084 /* 11759da57d7bSbt150084 * The initial link state should be "unknown" 11769da57d7bSbt150084 */ 11779da57d7bSbt150084 ixgbe->link_state = LINK_STATE_UNKNOWN; 117873cd555cSBin Tu - Sun Microsystems - Beijing China 11799da57d7bSbt150084 return (IXGBE_SUCCESS); 11809da57d7bSbt150084 } 11819da57d7bSbt150084 11829da57d7bSbt150084 /* 11839da57d7bSbt150084 * ixgbe_init_locks - Initialize locks. 11849da57d7bSbt150084 */ 11859da57d7bSbt150084 static void 11869da57d7bSbt150084 ixgbe_init_locks(ixgbe_t *ixgbe) 11879da57d7bSbt150084 { 11889da57d7bSbt150084 ixgbe_rx_ring_t *rx_ring; 11899da57d7bSbt150084 ixgbe_tx_ring_t *tx_ring; 11909da57d7bSbt150084 int i; 11919da57d7bSbt150084 11929da57d7bSbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 11939da57d7bSbt150084 rx_ring = &ixgbe->rx_rings[i]; 11949da57d7bSbt150084 mutex_init(&rx_ring->rx_lock, NULL, 11959da57d7bSbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 11969da57d7bSbt150084 } 11979da57d7bSbt150084 11989da57d7bSbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 11999da57d7bSbt150084 tx_ring = &ixgbe->tx_rings[i]; 12009da57d7bSbt150084 mutex_init(&tx_ring->tx_lock, NULL, 12019da57d7bSbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 12029da57d7bSbt150084 mutex_init(&tx_ring->recycle_lock, NULL, 12039da57d7bSbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 12049da57d7bSbt150084 mutex_init(&tx_ring->tcb_head_lock, NULL, 12059da57d7bSbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 12069da57d7bSbt150084 mutex_init(&tx_ring->tcb_tail_lock, NULL, 12079da57d7bSbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 12089da57d7bSbt150084 } 12099da57d7bSbt150084 12109da57d7bSbt150084 mutex_init(&ixgbe->gen_lock, NULL, 12119da57d7bSbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 12129da57d7bSbt150084 12139da57d7bSbt150084 mutex_init(&ixgbe->watchdog_lock, NULL, 12149da57d7bSbt150084 MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri)); 12159da57d7bSbt150084 } 12169da57d7bSbt150084 12179da57d7bSbt150084 /* 12189da57d7bSbt150084 * ixgbe_destroy_locks - Destroy locks. 12199da57d7bSbt150084 */ 12209da57d7bSbt150084 static void 12219da57d7bSbt150084 ixgbe_destroy_locks(ixgbe_t *ixgbe) 12229da57d7bSbt150084 { 12239da57d7bSbt150084 ixgbe_rx_ring_t *rx_ring; 12249da57d7bSbt150084 ixgbe_tx_ring_t *tx_ring; 12259da57d7bSbt150084 int i; 12269da57d7bSbt150084 12279da57d7bSbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 12289da57d7bSbt150084 rx_ring = &ixgbe->rx_rings[i]; 12299da57d7bSbt150084 mutex_destroy(&rx_ring->rx_lock); 12309da57d7bSbt150084 } 12319da57d7bSbt150084 12329da57d7bSbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 12339da57d7bSbt150084 tx_ring = &ixgbe->tx_rings[i]; 12349da57d7bSbt150084 mutex_destroy(&tx_ring->tx_lock); 12359da57d7bSbt150084 mutex_destroy(&tx_ring->recycle_lock); 12369da57d7bSbt150084 mutex_destroy(&tx_ring->tcb_head_lock); 12379da57d7bSbt150084 mutex_destroy(&tx_ring->tcb_tail_lock); 12389da57d7bSbt150084 } 12399da57d7bSbt150084 12409da57d7bSbt150084 mutex_destroy(&ixgbe->gen_lock); 12419da57d7bSbt150084 mutex_destroy(&ixgbe->watchdog_lock); 12429da57d7bSbt150084 } 12439da57d7bSbt150084 12449da57d7bSbt150084 static int 12459da57d7bSbt150084 ixgbe_resume(dev_info_t *devinfo) 12469da57d7bSbt150084 { 12479da57d7bSbt150084 ixgbe_t *ixgbe; 124862e6e1adSPaul Guo int i; 12499da57d7bSbt150084 12509da57d7bSbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 12519da57d7bSbt150084 if (ixgbe == NULL) 12529da57d7bSbt150084 return (DDI_FAILURE); 12539da57d7bSbt150084 12549da57d7bSbt150084 mutex_enter(&ixgbe->gen_lock); 12559da57d7bSbt150084 12569da57d7bSbt150084 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 1257ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 12589da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 12599da57d7bSbt150084 return (DDI_FAILURE); 12609da57d7bSbt150084 } 12619da57d7bSbt150084 12629da57d7bSbt150084 /* 12639da57d7bSbt150084 * Enable and start the watchdog timer 12649da57d7bSbt150084 */ 12659da57d7bSbt150084 ixgbe_enable_watchdog_timer(ixgbe); 12669da57d7bSbt150084 } 12679da57d7bSbt150084 126862e6e1adSPaul Guo atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED); 126962e6e1adSPaul Guo 127062e6e1adSPaul Guo if (ixgbe->ixgbe_state & IXGBE_STARTED) { 127162e6e1adSPaul Guo for (i = 0; i < ixgbe->num_tx_rings; i++) { 127262e6e1adSPaul Guo mac_tx_ring_update(ixgbe->mac_hdl, 127362e6e1adSPaul Guo ixgbe->tx_rings[i].ring_handle); 127462e6e1adSPaul Guo } 127562e6e1adSPaul Guo } 12769da57d7bSbt150084 12779da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 12789da57d7bSbt150084 12799da57d7bSbt150084 return (DDI_SUCCESS); 12809da57d7bSbt150084 } 12819da57d7bSbt150084 12829da57d7bSbt150084 static int 12839da57d7bSbt150084 ixgbe_suspend(dev_info_t *devinfo) 12849da57d7bSbt150084 { 12859da57d7bSbt150084 ixgbe_t *ixgbe; 12869da57d7bSbt150084 12879da57d7bSbt150084 ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo); 12889da57d7bSbt150084 if (ixgbe == NULL) 12899da57d7bSbt150084 return (DDI_FAILURE); 12909da57d7bSbt150084 12919da57d7bSbt150084 mutex_enter(&ixgbe->gen_lock); 12929da57d7bSbt150084 129362e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED); 1294ea65739eSchenlu chen - Sun Microsystems - Beijing China if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) { 1295ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock); 1296ea65739eSchenlu chen - Sun Microsystems - Beijing China return (DDI_SUCCESS); 1297ea65739eSchenlu chen - Sun Microsystems - Beijing China } 1298ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe, B_FALSE); 12999da57d7bSbt150084 13009da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 13019da57d7bSbt150084 13029da57d7bSbt150084 /* 13039da57d7bSbt150084 * Disable and stop the watchdog timer 13049da57d7bSbt150084 */ 13059da57d7bSbt150084 ixgbe_disable_watchdog_timer(ixgbe); 13069da57d7bSbt150084 13079da57d7bSbt150084 return (DDI_SUCCESS); 13089da57d7bSbt150084 } 13099da57d7bSbt150084 13109da57d7bSbt150084 /* 13119da57d7bSbt150084 * ixgbe_init - Initialize the device. 13129da57d7bSbt150084 */ 13139da57d7bSbt150084 static int 13149da57d7bSbt150084 ixgbe_init(ixgbe_t *ixgbe) 13159da57d7bSbt150084 { 13169da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 131769c76190SKeith M Wesolowski u8 pbanum[IXGBE_PBANUM_LENGTH]; 13187e579c30SDale Ghent int rv; 13199da57d7bSbt150084 13209da57d7bSbt150084 mutex_enter(&ixgbe->gen_lock); 13219da57d7bSbt150084 13229da57d7bSbt150084 /* 13237e579c30SDale Ghent * Configure/Initialize hardware 13249da57d7bSbt150084 */ 13257e579c30SDale Ghent rv = ixgbe_init_hw(hw); 13267e579c30SDale Ghent if (rv != IXGBE_SUCCESS) { 13277e579c30SDale Ghent switch (rv) { 13287e579c30SDale Ghent 13297e579c30SDale Ghent /* 13307e579c30SDale Ghent * The first three errors are not prohibitive to us progressing 13317e579c30SDale Ghent * further, and are maily advisory in nature. In the case of a 13327e579c30SDale Ghent * SFP module not being present or not deemed supported by the 13337e579c30SDale Ghent * common code, we adivse the operator of this fact but carry on 13347e579c30SDale Ghent * instead of failing hard, as SFPs can be inserted or replaced 13357e579c30SDale Ghent * while the driver is running. In the case of a unknown error, 13367e579c30SDale Ghent * we fail-hard, logging the reason and emitting a FMA event. 13377e579c30SDale Ghent */ 13387e579c30SDale Ghent case IXGBE_ERR_EEPROM_VERSION: 13397e579c30SDale Ghent ixgbe_error(ixgbe, 13407e579c30SDale Ghent "This Intel 10Gb Ethernet device is pre-release and" 13417e579c30SDale Ghent " contains outdated firmware. Please contact your" 13427e579c30SDale Ghent " hardware vendor for a replacement."); 13437e579c30SDale Ghent break; 13447e579c30SDale Ghent case IXGBE_ERR_SFP_NOT_PRESENT: 13457e579c30SDale Ghent ixgbe_error(ixgbe, 13467e579c30SDale Ghent "No SFP+ module detected on this interface. Please " 13477e579c30SDale Ghent "install a supported SFP+ module for this " 13487e579c30SDale Ghent "interface to become operational."); 13497e579c30SDale Ghent break; 13507e579c30SDale Ghent case IXGBE_ERR_SFP_NOT_SUPPORTED: 13517e579c30SDale Ghent ixgbe_error(ixgbe, 13527e579c30SDale Ghent "Unsupported SFP+ module detected. Please replace " 13537e579c30SDale Ghent "it with a supported SFP+ module per Intel " 13547e579c30SDale Ghent "documentation, or bypass this check with " 13557e579c30SDale Ghent "allow_unsupported_sfp=1 in ixgbe.conf."); 13567e579c30SDale Ghent break; 13577e579c30SDale Ghent default: 13587e579c30SDale Ghent ixgbe_error(ixgbe, 13597e579c30SDale Ghent "Failed to initialize hardware. ixgbe_init_hw " 13607e579c30SDale Ghent "returned %d", rv); 13619da57d7bSbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 13629da57d7bSbt150084 goto init_fail; 13639da57d7bSbt150084 } 13647e579c30SDale Ghent } 13659da57d7bSbt150084 13669da57d7bSbt150084 /* 13679da57d7bSbt150084 * Need to init eeprom before validating the checksum. 13689da57d7bSbt150084 */ 13699da57d7bSbt150084 if (ixgbe_init_eeprom_params(hw) < 0) { 13709da57d7bSbt150084 ixgbe_error(ixgbe, 13719da57d7bSbt150084 "Unable to intitialize the eeprom interface."); 13729da57d7bSbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 13739da57d7bSbt150084 goto init_fail; 13749da57d7bSbt150084 } 13759da57d7bSbt150084 13769da57d7bSbt150084 /* 13779da57d7bSbt150084 * NVM validation 13789da57d7bSbt150084 */ 13799da57d7bSbt150084 if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { 13809da57d7bSbt150084 /* 13819da57d7bSbt150084 * Some PCI-E parts fail the first check due to 13829da57d7bSbt150084 * the link being in sleep state. Call it again, 13839da57d7bSbt150084 * if it fails a second time it's a real issue. 13849da57d7bSbt150084 */ 13859da57d7bSbt150084 if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { 13869da57d7bSbt150084 ixgbe_error(ixgbe, 13879da57d7bSbt150084 "Invalid NVM checksum. Please contact " 13889da57d7bSbt150084 "the vendor to update the NVM."); 13899da57d7bSbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 13909da57d7bSbt150084 goto init_fail; 13919da57d7bSbt150084 } 13929da57d7bSbt150084 } 13939da57d7bSbt150084 13949da57d7bSbt150084 /* 13959da57d7bSbt150084 * Setup default flow control thresholds - enable/disable 13969da57d7bSbt150084 * & flow control type is controlled by ixgbe.conf 13979da57d7bSbt150084 */ 139869b5a878SDan McDonald hw->fc.high_water[0] = DEFAULT_FCRTH; 139969b5a878SDan McDonald hw->fc.low_water[0] = DEFAULT_FCRTL; 14009da57d7bSbt150084 hw->fc.pause_time = DEFAULT_FCPAUSE; 14019da57d7bSbt150084 hw->fc.send_xon = B_TRUE; 14029da57d7bSbt150084 14039da57d7bSbt150084 /* 14047e579c30SDale Ghent * Initialize flow control 14057e579c30SDale Ghent */ 14067e579c30SDale Ghent (void) ixgbe_start_hw(hw); 14077e579c30SDale Ghent 14087e579c30SDale Ghent /* 14099da57d7bSbt150084 * Initialize link settings 14109da57d7bSbt150084 */ 14119da57d7bSbt150084 (void) ixgbe_driver_setup_link(ixgbe, B_FALSE); 14129da57d7bSbt150084 14139da57d7bSbt150084 /* 14149da57d7bSbt150084 * Initialize the chipset hardware 14159da57d7bSbt150084 */ 14169da57d7bSbt150084 if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { 14179da57d7bSbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 14189da57d7bSbt150084 goto init_fail; 14199da57d7bSbt150084 } 14209da57d7bSbt150084 142169c76190SKeith M Wesolowski /* 142269c76190SKeith M Wesolowski * Read identifying information and place in devinfo. 142369c76190SKeith M Wesolowski */ 142469c76190SKeith M Wesolowski pbanum[0] = '\0'; 142569c76190SKeith M Wesolowski (void) ixgbe_read_pba_string(hw, pbanum, sizeof (pbanum)); 142669c76190SKeith M Wesolowski if (*pbanum != '\0') { 142769c76190SKeith M Wesolowski (void) ddi_prop_update_string(DDI_DEV_T_NONE, ixgbe->dip, 142869c76190SKeith M Wesolowski "printed-board-assembly", (char *)pbanum); 142969c76190SKeith M Wesolowski } 143069c76190SKeith M Wesolowski 14319da57d7bSbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 14329da57d7bSbt150084 goto init_fail; 14339da57d7bSbt150084 } 14349da57d7bSbt150084 14359da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 14369da57d7bSbt150084 return (IXGBE_SUCCESS); 14379da57d7bSbt150084 14389da57d7bSbt150084 init_fail: 14399da57d7bSbt150084 /* 14409da57d7bSbt150084 * Reset PHY 14419da57d7bSbt150084 */ 14429da57d7bSbt150084 (void) ixgbe_reset_phy(hw); 14439da57d7bSbt150084 14449da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 14459da57d7bSbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 14469da57d7bSbt150084 return (IXGBE_FAILURE); 14479da57d7bSbt150084 } 14489da57d7bSbt150084 14499da57d7bSbt150084 /* 14509da57d7bSbt150084 * ixgbe_chip_start - Initialize and start the chipset hardware. 14519da57d7bSbt150084 */ 14529da57d7bSbt150084 static int 14539da57d7bSbt150084 ixgbe_chip_start(ixgbe_t *ixgbe) 14549da57d7bSbt150084 { 14559da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 14567e579c30SDale Ghent int i; 14579da57d7bSbt150084 14589da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 14599da57d7bSbt150084 14609da57d7bSbt150084 /* 14619da57d7bSbt150084 * Get the mac address 14629da57d7bSbt150084 * This function should handle SPARC case correctly. 14639da57d7bSbt150084 */ 14649da57d7bSbt150084 if (!ixgbe_find_mac_address(ixgbe)) { 14659da57d7bSbt150084 ixgbe_error(ixgbe, "Failed to get the mac address"); 14669da57d7bSbt150084 return (IXGBE_FAILURE); 14679da57d7bSbt150084 } 14689da57d7bSbt150084 14699da57d7bSbt150084 /* 14709da57d7bSbt150084 * Validate the mac address 14719da57d7bSbt150084 */ 14729da57d7bSbt150084 (void) ixgbe_init_rx_addrs(hw); 14739da57d7bSbt150084 if (!is_valid_mac_addr(hw->mac.addr)) { 14749da57d7bSbt150084 ixgbe_error(ixgbe, "Invalid mac address"); 14759da57d7bSbt150084 return (IXGBE_FAILURE); 14769da57d7bSbt150084 } 14779da57d7bSbt150084 14789da57d7bSbt150084 /* 147919843f01SPaul Guo * Re-enable relaxed ordering for performance. It is disabled 148019843f01SPaul Guo * by default in the hardware init. 148119843f01SPaul Guo */ 14825b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->relax_order_enable == B_TRUE) 148319843f01SPaul Guo ixgbe_enable_relaxed_ordering(hw); 148419843f01SPaul Guo 148519843f01SPaul Guo /* 14869da57d7bSbt150084 * Setup adapter interrupt vectors 14879da57d7bSbt150084 */ 14889da57d7bSbt150084 ixgbe_setup_adapter_vector(ixgbe); 14899da57d7bSbt150084 14909da57d7bSbt150084 /* 14919da57d7bSbt150084 * Initialize unicast addresses. 14929da57d7bSbt150084 */ 14939da57d7bSbt150084 ixgbe_init_unicst(ixgbe); 14949da57d7bSbt150084 14959da57d7bSbt150084 /* 14969da57d7bSbt150084 * Setup and initialize the mctable structures. 14979da57d7bSbt150084 */ 14989da57d7bSbt150084 ixgbe_setup_multicst(ixgbe); 14999da57d7bSbt150084 15009da57d7bSbt150084 /* 15019da57d7bSbt150084 * Set interrupt throttling rate 15029da57d7bSbt150084 */ 150373cd555cSBin Tu - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->intr_cnt; i++) { 15049da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]); 150573cd555cSBin Tu - Sun Microsystems - Beijing China } 15069da57d7bSbt150084 15079da57d7bSbt150084 /* 15087e579c30SDale Ghent * Disable Wake-on-LAN 15097e579c30SDale Ghent */ 15107e579c30SDale Ghent IXGBE_WRITE_REG(hw, IXGBE_WUC, 0); 15117e579c30SDale Ghent 15127e579c30SDale Ghent /* 15137e579c30SDale Ghent * Some adapters offer Energy Efficient Ethernet (EEE) support. 15147e579c30SDale Ghent * Due to issues with EEE in e1000g/igb, we disable this by default 15157e579c30SDale Ghent * as a precautionary measure. 15167e579c30SDale Ghent * 15177e579c30SDale Ghent * Currently, the only known adapter which supports EEE in the ixgbe 15187e579c30SDale Ghent * line is 8086,15AB (IXGBE_DEV_ID_X550EM_X_KR), and only after the 15197e579c30SDale Ghent * first revision of it, as well as any X550 with MAC type 6 (non-EM) 15207e579c30SDale Ghent */ 15217e579c30SDale Ghent (void) ixgbe_setup_eee(hw, B_FALSE); 15227e579c30SDale Ghent 15237e579c30SDale Ghent /* 15247e579c30SDale Ghent * Turn on any present SFP Tx laser 15257e579c30SDale Ghent */ 15267e579c30SDale Ghent ixgbe_enable_tx_laser(hw); 15277e579c30SDale Ghent 15287e579c30SDale Ghent /* 15297e579c30SDale Ghent * Power on the PHY 15307e579c30SDale Ghent */ 15317e579c30SDale Ghent (void) ixgbe_set_phy_power(hw, B_TRUE); 15327e579c30SDale Ghent 15337e579c30SDale Ghent /* 15347e579c30SDale Ghent * Save the state of the PHY 15359da57d7bSbt150084 */ 15369da57d7bSbt150084 ixgbe_get_hw_state(ixgbe); 15379da57d7bSbt150084 15389da57d7bSbt150084 /* 15399da57d7bSbt150084 * Make sure driver has control 15409da57d7bSbt150084 */ 15419da57d7bSbt150084 ixgbe_get_driver_control(hw); 15429da57d7bSbt150084 15439da57d7bSbt150084 return (IXGBE_SUCCESS); 15449da57d7bSbt150084 } 15459da57d7bSbt150084 15469da57d7bSbt150084 /* 15479da57d7bSbt150084 * ixgbe_chip_stop - Stop the chipset hardware 15489da57d7bSbt150084 */ 15499da57d7bSbt150084 static void 15509da57d7bSbt150084 ixgbe_chip_stop(ixgbe_t *ixgbe) 15519da57d7bSbt150084 { 15529da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 15537e579c30SDale Ghent int rv; 15549da57d7bSbt150084 15559da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 15569da57d7bSbt150084 15579da57d7bSbt150084 /* 15587e579c30SDale Ghent * Stop interupt generation and disable Tx unit 15599da57d7bSbt150084 */ 15607e579c30SDale Ghent hw->adapter_stopped = B_FALSE; 15617e579c30SDale Ghent (void) ixgbe_stop_adapter(hw); 15629da57d7bSbt150084 15639da57d7bSbt150084 /* 15649da57d7bSbt150084 * Reset the chipset 15659da57d7bSbt150084 */ 15669da57d7bSbt150084 (void) ixgbe_reset_hw(hw); 15679da57d7bSbt150084 15689da57d7bSbt150084 /* 15699da57d7bSbt150084 * Reset PHY 15709da57d7bSbt150084 */ 15719da57d7bSbt150084 (void) ixgbe_reset_phy(hw); 15727e579c30SDale Ghent 15737e579c30SDale Ghent /* 15747e579c30SDale Ghent * Enter LPLU (Low Power, Link Up) mode, if available. Avoid resetting 15757e579c30SDale Ghent * the PHY while doing so. Else, just power down the PHY. 15767e579c30SDale Ghent */ 15777e579c30SDale Ghent if (hw->phy.ops.enter_lplu != NULL) { 15787e579c30SDale Ghent hw->phy.reset_disable = B_TRUE; 15797e579c30SDale Ghent rv = hw->phy.ops.enter_lplu(hw); 15807e579c30SDale Ghent if (rv != IXGBE_SUCCESS) 15817e579c30SDale Ghent ixgbe_error(ixgbe, "Error while entering LPLU: %d", rv); 15827e579c30SDale Ghent hw->phy.reset_disable = B_FALSE; 15837e579c30SDale Ghent } else { 15847e579c30SDale Ghent (void) ixgbe_set_phy_power(hw, B_FALSE); 15857e579c30SDale Ghent } 15867e579c30SDale Ghent 15877e579c30SDale Ghent /* 15887e579c30SDale Ghent * Turn off any present SFP Tx laser 15897e579c30SDale Ghent * Expected for health and safety reasons 15907e579c30SDale Ghent */ 15917e579c30SDale Ghent ixgbe_disable_tx_laser(hw); 15927e579c30SDale Ghent 15937e579c30SDale Ghent /* 15947e579c30SDale Ghent * Tell firmware driver is no longer in control 15957e579c30SDale Ghent */ 15967e579c30SDale Ghent ixgbe_release_driver_control(hw); 15977e579c30SDale Ghent 15989da57d7bSbt150084 } 15999da57d7bSbt150084 16009da57d7bSbt150084 /* 16019da57d7bSbt150084 * ixgbe_reset - Reset the chipset and re-start the driver. 16029da57d7bSbt150084 * 16039da57d7bSbt150084 * It involves stopping and re-starting the chipset, 16049da57d7bSbt150084 * and re-configuring the rx/tx rings. 16059da57d7bSbt150084 */ 16069da57d7bSbt150084 static int 16079da57d7bSbt150084 ixgbe_reset(ixgbe_t *ixgbe) 16089da57d7bSbt150084 { 160962e6e1adSPaul Guo int i; 161062e6e1adSPaul Guo 1611ea65739eSchenlu chen - Sun Microsystems - Beijing China /* 1612ea65739eSchenlu chen - Sun Microsystems - Beijing China * Disable and stop the watchdog timer 1613ea65739eSchenlu chen - Sun Microsystems - Beijing China */ 1614ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_disable_watchdog_timer(ixgbe); 16159da57d7bSbt150084 16169da57d7bSbt150084 mutex_enter(&ixgbe->gen_lock); 16179da57d7bSbt150084 16189da57d7bSbt150084 ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED); 161962e6e1adSPaul Guo atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 16209da57d7bSbt150084 1621ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe, B_FALSE); 16229da57d7bSbt150084 1623ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 1624ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock); 1625ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_FAILURE); 16269da57d7bSbt150084 } 16279da57d7bSbt150084 162862e6e1adSPaul Guo /* 162962e6e1adSPaul Guo * After resetting, need to recheck the link status. 163062e6e1adSPaul Guo */ 163162e6e1adSPaul Guo ixgbe->link_check_complete = B_FALSE; 163262e6e1adSPaul Guo ixgbe->link_check_hrtime = gethrtime() + 163362e6e1adSPaul Guo (IXGBE_LINK_UP_TIME * 100000000ULL); 163462e6e1adSPaul Guo 163562e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED); 163662e6e1adSPaul Guo 163762e6e1adSPaul Guo if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) { 163862e6e1adSPaul Guo for (i = 0; i < ixgbe->num_tx_rings; i++) { 163962e6e1adSPaul Guo mac_tx_ring_update(ixgbe->mac_hdl, 164062e6e1adSPaul Guo ixgbe->tx_rings[i].ring_handle); 164162e6e1adSPaul Guo } 164262e6e1adSPaul Guo } 164362e6e1adSPaul Guo 16449da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 16459da57d7bSbt150084 1646ea65739eSchenlu chen - Sun Microsystems - Beijing China /* 1647ea65739eSchenlu chen - Sun Microsystems - Beijing China * Enable and start the watchdog timer 1648ea65739eSchenlu chen - Sun Microsystems - Beijing China */ 1649ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_enable_watchdog_timer(ixgbe); 1650ea65739eSchenlu chen - Sun Microsystems - Beijing China 16519da57d7bSbt150084 return (IXGBE_SUCCESS); 16529da57d7bSbt150084 } 16539da57d7bSbt150084 16549da57d7bSbt150084 /* 16559da57d7bSbt150084 * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources. 16569da57d7bSbt150084 */ 16579da57d7bSbt150084 static void 16589da57d7bSbt150084 ixgbe_tx_clean(ixgbe_t *ixgbe) 16599da57d7bSbt150084 { 16609da57d7bSbt150084 ixgbe_tx_ring_t *tx_ring; 16619da57d7bSbt150084 tx_control_block_t *tcb; 16629da57d7bSbt150084 link_list_t pending_list; 16639da57d7bSbt150084 uint32_t desc_num; 16649da57d7bSbt150084 int i, j; 16659da57d7bSbt150084 16669da57d7bSbt150084 LINK_LIST_INIT(&pending_list); 16679da57d7bSbt150084 16689da57d7bSbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 16699da57d7bSbt150084 tx_ring = &ixgbe->tx_rings[i]; 16709da57d7bSbt150084 16719da57d7bSbt150084 mutex_enter(&tx_ring->recycle_lock); 16729da57d7bSbt150084 16739da57d7bSbt150084 /* 16749da57d7bSbt150084 * Clean the pending tx data - the pending packets in the 16759da57d7bSbt150084 * work_list that have no chances to be transmitted again. 16769da57d7bSbt150084 * 16779da57d7bSbt150084 * We must ensure the chipset is stopped or the link is down 16789da57d7bSbt150084 * before cleaning the transmit packets. 16799da57d7bSbt150084 */ 16809da57d7bSbt150084 desc_num = 0; 16819da57d7bSbt150084 for (j = 0; j < tx_ring->ring_size; j++) { 16829da57d7bSbt150084 tcb = tx_ring->work_list[j]; 16839da57d7bSbt150084 if (tcb != NULL) { 16849da57d7bSbt150084 desc_num += tcb->desc_num; 16859da57d7bSbt150084 16869da57d7bSbt150084 tx_ring->work_list[j] = NULL; 16879da57d7bSbt150084 16889da57d7bSbt150084 ixgbe_free_tcb(tcb); 16899da57d7bSbt150084 16909da57d7bSbt150084 LIST_PUSH_TAIL(&pending_list, &tcb->link); 16919da57d7bSbt150084 } 16929da57d7bSbt150084 } 16939da57d7bSbt150084 16949da57d7bSbt150084 if (desc_num > 0) { 16959da57d7bSbt150084 atomic_add_32(&tx_ring->tbd_free, desc_num); 16969da57d7bSbt150084 ASSERT(tx_ring->tbd_free == tx_ring->ring_size); 16979da57d7bSbt150084 16989da57d7bSbt150084 /* 16999da57d7bSbt150084 * Reset the head and tail pointers of the tbd ring; 17009da57d7bSbt150084 * Reset the writeback head if it's enable. 17019da57d7bSbt150084 */ 17029da57d7bSbt150084 tx_ring->tbd_head = 0; 17039da57d7bSbt150084 tx_ring->tbd_tail = 0; 17049da57d7bSbt150084 if (ixgbe->tx_head_wb_enable) 17059da57d7bSbt150084 *tx_ring->tbd_head_wb = 0; 17069da57d7bSbt150084 17079da57d7bSbt150084 IXGBE_WRITE_REG(&ixgbe->hw, 17089da57d7bSbt150084 IXGBE_TDH(tx_ring->index), 0); 17099da57d7bSbt150084 IXGBE_WRITE_REG(&ixgbe->hw, 17109da57d7bSbt150084 IXGBE_TDT(tx_ring->index), 0); 17119da57d7bSbt150084 } 17129da57d7bSbt150084 17139da57d7bSbt150084 mutex_exit(&tx_ring->recycle_lock); 17149da57d7bSbt150084 17159da57d7bSbt150084 /* 17169da57d7bSbt150084 * Add the tx control blocks in the pending list to 17179da57d7bSbt150084 * the free list. 17189da57d7bSbt150084 */ 17199da57d7bSbt150084 ixgbe_put_free_list(tx_ring, &pending_list); 17209da57d7bSbt150084 } 17219da57d7bSbt150084 } 17229da57d7bSbt150084 17239da57d7bSbt150084 /* 17249da57d7bSbt150084 * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be 17259da57d7bSbt150084 * transmitted. 17269da57d7bSbt150084 */ 17279da57d7bSbt150084 static boolean_t 17289da57d7bSbt150084 ixgbe_tx_drain(ixgbe_t *ixgbe) 17299da57d7bSbt150084 { 17309da57d7bSbt150084 ixgbe_tx_ring_t *tx_ring; 17319da57d7bSbt150084 boolean_t done; 17329da57d7bSbt150084 int i, j; 17339da57d7bSbt150084 17349da57d7bSbt150084 /* 17359da57d7bSbt150084 * Wait for a specific time to allow pending tx packets 17369da57d7bSbt150084 * to be transmitted. 17379da57d7bSbt150084 * 17389da57d7bSbt150084 * Check the counter tbd_free to see if transmission is done. 17399da57d7bSbt150084 * No lock protection is needed here. 17409da57d7bSbt150084 * 17419da57d7bSbt150084 * Return B_TRUE if all pending packets have been transmitted; 17429da57d7bSbt150084 * Otherwise return B_FALSE; 17439da57d7bSbt150084 */ 17449da57d7bSbt150084 for (i = 0; i < TX_DRAIN_TIME; i++) { 17459da57d7bSbt150084 17469da57d7bSbt150084 done = B_TRUE; 17479da57d7bSbt150084 for (j = 0; j < ixgbe->num_tx_rings; j++) { 17489da57d7bSbt150084 tx_ring = &ixgbe->tx_rings[j]; 17499da57d7bSbt150084 done = done && 17509da57d7bSbt150084 (tx_ring->tbd_free == tx_ring->ring_size); 17519da57d7bSbt150084 } 17529da57d7bSbt150084 17539da57d7bSbt150084 if (done) 17549da57d7bSbt150084 break; 17559da57d7bSbt150084 17569da57d7bSbt150084 msec_delay(1); 17579da57d7bSbt150084 } 17589da57d7bSbt150084 17599da57d7bSbt150084 return (done); 17609da57d7bSbt150084 } 17619da57d7bSbt150084 17629da57d7bSbt150084 /* 17639da57d7bSbt150084 * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer. 17649da57d7bSbt150084 */ 17659da57d7bSbt150084 static boolean_t 17669da57d7bSbt150084 ixgbe_rx_drain(ixgbe_t *ixgbe) 17679da57d7bSbt150084 { 1768ea65739eSchenlu chen - Sun Microsystems - Beijing China boolean_t done = B_TRUE; 1769ea65739eSchenlu chen - Sun Microsystems - Beijing China int i; 17709da57d7bSbt150084 17719da57d7bSbt150084 /* 17729da57d7bSbt150084 * Polling the rx free list to check if those rx buffers held by 17739da57d7bSbt150084 * the upper layer are released. 17749da57d7bSbt150084 * 17759da57d7bSbt150084 * Check the counter rcb_free to see if all pending buffers are 17769da57d7bSbt150084 * released. No lock protection is needed here. 17779da57d7bSbt150084 * 17789da57d7bSbt150084 * Return B_TRUE if all pending buffers have been released; 17799da57d7bSbt150084 * Otherwise return B_FALSE; 17809da57d7bSbt150084 */ 17819da57d7bSbt150084 for (i = 0; i < RX_DRAIN_TIME; i++) { 1782ea65739eSchenlu chen - Sun Microsystems - Beijing China done = (ixgbe->rcb_pending == 0); 17839da57d7bSbt150084 17849da57d7bSbt150084 if (done) 17859da57d7bSbt150084 break; 17869da57d7bSbt150084 17879da57d7bSbt150084 msec_delay(1); 17889da57d7bSbt150084 } 17899da57d7bSbt150084 17909da57d7bSbt150084 return (done); 17919da57d7bSbt150084 } 17929da57d7bSbt150084 17939da57d7bSbt150084 /* 17949da57d7bSbt150084 * ixgbe_start - Start the driver/chipset. 17959da57d7bSbt150084 */ 17969da57d7bSbt150084 int 1797ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer) 17989da57d7bSbt150084 { 17997e579c30SDale Ghent struct ixgbe_hw *hw = &ixgbe->hw; 18009da57d7bSbt150084 int i; 18019da57d7bSbt150084 18029da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 18039da57d7bSbt150084 1804ea65739eSchenlu chen - Sun Microsystems - Beijing China if (alloc_buffer) { 1805ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) { 1806ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, 1807ea65739eSchenlu chen - Sun Microsystems - Beijing China "Failed to allocate software receive rings"); 1808ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_FAILURE); 1809ea65739eSchenlu chen - Sun Microsystems - Beijing China } 1810ea65739eSchenlu chen - Sun Microsystems - Beijing China 1811ea65739eSchenlu chen - Sun Microsystems - Beijing China /* Allocate buffers for all the rx/tx rings */ 1812ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) { 1813ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, "Failed to allocate DMA resource"); 1814ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_FAILURE); 1815ea65739eSchenlu chen - Sun Microsystems - Beijing China } 1816ea65739eSchenlu chen - Sun Microsystems - Beijing China 1817ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->tx_ring_init = B_TRUE; 1818ea65739eSchenlu chen - Sun Microsystems - Beijing China } else { 1819ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->tx_ring_init = B_FALSE; 1820ea65739eSchenlu chen - Sun Microsystems - Beijing China } 1821ea65739eSchenlu chen - Sun Microsystems - Beijing China 18229da57d7bSbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) 18239da57d7bSbt150084 mutex_enter(&ixgbe->rx_rings[i].rx_lock); 18249da57d7bSbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) 18259da57d7bSbt150084 mutex_enter(&ixgbe->tx_rings[i].tx_lock); 18269da57d7bSbt150084 18279da57d7bSbt150084 /* 18289da57d7bSbt150084 * Start the chipset hardware 18299da57d7bSbt150084 */ 18309da57d7bSbt150084 if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { 18319da57d7bSbt150084 ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); 18329da57d7bSbt150084 goto start_failure; 18339da57d7bSbt150084 } 18349da57d7bSbt150084 18357e579c30SDale Ghent /* 18367e579c30SDale Ghent * Configure link now for X550 18377e579c30SDale Ghent * 18387e579c30SDale Ghent * X550 possesses a LPLU (Low-Power Link Up) mode which keeps the 18397e579c30SDale Ghent * resting state of the adapter at a 1Gb FDX speed. Prior to the X550, 18407e579c30SDale Ghent * the resting state of the link would be the maximum speed that 18417e579c30SDale Ghent * autonegotiation will allow (usually 10Gb, infrastructure allowing) 18427e579c30SDale Ghent * so we never bothered with explicitly setting the link to 10Gb as it 18437e579c30SDale Ghent * would already be at that state on driver attach. With X550, we must 18447e579c30SDale Ghent * trigger a re-negotiation of the link in order to switch from a LPLU 18457e579c30SDale Ghent * 1Gb link to 10Gb (cable and link partner permitting.) 18467e579c30SDale Ghent */ 18477e579c30SDale Ghent if (hw->mac.type == ixgbe_mac_X550 || 18487e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550EM_x) { 18497e579c30SDale Ghent (void) ixgbe_driver_setup_link(ixgbe, B_TRUE); 18507e579c30SDale Ghent ixgbe_get_hw_state(ixgbe); 18517e579c30SDale Ghent } 18527e579c30SDale Ghent 18539da57d7bSbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 18549da57d7bSbt150084 goto start_failure; 18559da57d7bSbt150084 } 18569da57d7bSbt150084 18579da57d7bSbt150084 /* 18589da57d7bSbt150084 * Setup the rx/tx rings 18599da57d7bSbt150084 */ 18609da57d7bSbt150084 ixgbe_setup_rings(ixgbe); 18619da57d7bSbt150084 18629da57d7bSbt150084 /* 186362e6e1adSPaul Guo * ixgbe_start() will be called when resetting, however if reset 18645b6dd21fSchenlu chen - Sun Microsystems - Beijing China * happens, we need to clear the ERROR, STALL and OVERTEMP flags 18655b6dd21fSchenlu chen - Sun Microsystems - Beijing China * before enabling the interrupts. 186662e6e1adSPaul Guo */ 18675b6dd21fSchenlu chen - Sun Microsystems - Beijing China atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR 18685b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_STALL| IXGBE_OVERTEMP)); 186962e6e1adSPaul Guo 187062e6e1adSPaul Guo /* 18719da57d7bSbt150084 * Enable adapter interrupts 18729da57d7bSbt150084 * The interrupts must be enabled after the driver state is START 18739da57d7bSbt150084 */ 18749da57d7bSbt150084 ixgbe_enable_adapter_interrupts(ixgbe); 18759da57d7bSbt150084 18769da57d7bSbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 18779da57d7bSbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 18789da57d7bSbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 18799da57d7bSbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 18809da57d7bSbt150084 18819da57d7bSbt150084 return (IXGBE_SUCCESS); 18829da57d7bSbt150084 18839da57d7bSbt150084 start_failure: 18849da57d7bSbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 18859da57d7bSbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 18869da57d7bSbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 18879da57d7bSbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 18889da57d7bSbt150084 18899da57d7bSbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 18909da57d7bSbt150084 18919da57d7bSbt150084 return (IXGBE_FAILURE); 18929da57d7bSbt150084 } 18939da57d7bSbt150084 18949da57d7bSbt150084 /* 18959da57d7bSbt150084 * ixgbe_stop - Stop the driver/chipset. 18969da57d7bSbt150084 */ 18979da57d7bSbt150084 void 1898ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer) 18999da57d7bSbt150084 { 19009da57d7bSbt150084 int i; 19019da57d7bSbt150084 19029da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 19039da57d7bSbt150084 19049da57d7bSbt150084 /* 19059da57d7bSbt150084 * Disable the adapter interrupts 19069da57d7bSbt150084 */ 19079da57d7bSbt150084 ixgbe_disable_adapter_interrupts(ixgbe); 19089da57d7bSbt150084 19099da57d7bSbt150084 /* 19109da57d7bSbt150084 * Drain the pending tx packets 19119da57d7bSbt150084 */ 19129da57d7bSbt150084 (void) ixgbe_tx_drain(ixgbe); 19139da57d7bSbt150084 19149da57d7bSbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) 19159da57d7bSbt150084 mutex_enter(&ixgbe->rx_rings[i].rx_lock); 19169da57d7bSbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) 19179da57d7bSbt150084 mutex_enter(&ixgbe->tx_rings[i].tx_lock); 19189da57d7bSbt150084 19199da57d7bSbt150084 /* 19209da57d7bSbt150084 * Stop the chipset hardware 19219da57d7bSbt150084 */ 19229da57d7bSbt150084 ixgbe_chip_stop(ixgbe); 19239da57d7bSbt150084 19249da57d7bSbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 19259da57d7bSbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 19269da57d7bSbt150084 } 19279da57d7bSbt150084 19289da57d7bSbt150084 /* 19299da57d7bSbt150084 * Clean the pending tx data/resources 19309da57d7bSbt150084 */ 19319da57d7bSbt150084 ixgbe_tx_clean(ixgbe); 19329da57d7bSbt150084 19339da57d7bSbt150084 for (i = ixgbe->num_tx_rings - 1; i >= 0; i--) 19349da57d7bSbt150084 mutex_exit(&ixgbe->tx_rings[i].tx_lock); 19359da57d7bSbt150084 for (i = ixgbe->num_rx_rings - 1; i >= 0; i--) 19369da57d7bSbt150084 mutex_exit(&ixgbe->rx_rings[i].rx_lock); 1937ea65739eSchenlu chen - Sun Microsystems - Beijing China 1938ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->link_state == LINK_STATE_UP) { 1939ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->link_state = LINK_STATE_UNKNOWN; 1940ea65739eSchenlu chen - Sun Microsystems - Beijing China mac_link_update(ixgbe->mac_hdl, ixgbe->link_state); 1941ea65739eSchenlu chen - Sun Microsystems - Beijing China } 1942ea65739eSchenlu chen - Sun Microsystems - Beijing China 1943ea65739eSchenlu chen - Sun Microsystems - Beijing China if (free_buffer) { 1944ea65739eSchenlu chen - Sun Microsystems - Beijing China /* 1945ea65739eSchenlu chen - Sun Microsystems - Beijing China * Release the DMA/memory resources of rx/tx rings 1946ea65739eSchenlu chen - Sun Microsystems - Beijing China */ 1947ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_dma(ixgbe); 1948ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_data(ixgbe); 1949ea65739eSchenlu chen - Sun Microsystems - Beijing China } 19509da57d7bSbt150084 } 19519da57d7bSbt150084 19529da57d7bSbt150084 /* 19530dc2366fSVenugopal Iyer * ixgbe_cbfunc - Driver interface for generic DDI callbacks 19540dc2366fSVenugopal Iyer */ 19550dc2366fSVenugopal Iyer /* ARGSUSED */ 19560dc2366fSVenugopal Iyer static int 19570dc2366fSVenugopal Iyer ixgbe_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg, 19580dc2366fSVenugopal Iyer void *arg1, void *arg2) 19590dc2366fSVenugopal Iyer { 19600dc2366fSVenugopal Iyer ixgbe_t *ixgbe = (ixgbe_t *)arg1; 19610dc2366fSVenugopal Iyer 19620dc2366fSVenugopal Iyer switch (cbaction) { 19630dc2366fSVenugopal Iyer /* IRM callback */ 19640dc2366fSVenugopal Iyer int count; 19650dc2366fSVenugopal Iyer case DDI_CB_INTR_ADD: 19660dc2366fSVenugopal Iyer case DDI_CB_INTR_REMOVE: 19670dc2366fSVenugopal Iyer count = (int)(uintptr_t)cbarg; 19680dc2366fSVenugopal Iyer ASSERT(ixgbe->intr_type == DDI_INTR_TYPE_MSIX); 19690dc2366fSVenugopal Iyer DTRACE_PROBE2(ixgbe__irm__callback, int, count, 19700dc2366fSVenugopal Iyer int, ixgbe->intr_cnt); 19710dc2366fSVenugopal Iyer if (ixgbe_intr_adjust(ixgbe, cbaction, count) != 19720dc2366fSVenugopal Iyer DDI_SUCCESS) { 19730dc2366fSVenugopal Iyer ixgbe_error(ixgbe, 19740dc2366fSVenugopal Iyer "IRM CB: Failed to adjust interrupts"); 19750dc2366fSVenugopal Iyer goto cb_fail; 19760dc2366fSVenugopal Iyer } 19770dc2366fSVenugopal Iyer break; 19780dc2366fSVenugopal Iyer default: 19790dc2366fSVenugopal Iyer IXGBE_DEBUGLOG_1(ixgbe, "DDI CB: action 0x%x NOT supported", 19800dc2366fSVenugopal Iyer cbaction); 19810dc2366fSVenugopal Iyer return (DDI_ENOTSUP); 19820dc2366fSVenugopal Iyer } 19830dc2366fSVenugopal Iyer return (DDI_SUCCESS); 19840dc2366fSVenugopal Iyer cb_fail: 19850dc2366fSVenugopal Iyer return (DDI_FAILURE); 19860dc2366fSVenugopal Iyer } 19870dc2366fSVenugopal Iyer 19880dc2366fSVenugopal Iyer /* 19890dc2366fSVenugopal Iyer * ixgbe_intr_adjust - Adjust interrupt to respond to IRM request. 19900dc2366fSVenugopal Iyer */ 19910dc2366fSVenugopal Iyer static int 19920dc2366fSVenugopal Iyer ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count) 19930dc2366fSVenugopal Iyer { 19940dc2366fSVenugopal Iyer int i, rc, actual; 19950dc2366fSVenugopal Iyer 19960dc2366fSVenugopal Iyer if (count == 0) 19970dc2366fSVenugopal Iyer return (DDI_SUCCESS); 19980dc2366fSVenugopal Iyer 19990dc2366fSVenugopal Iyer if ((cbaction == DDI_CB_INTR_ADD && 20000dc2366fSVenugopal Iyer ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) || 20010dc2366fSVenugopal Iyer (cbaction == DDI_CB_INTR_REMOVE && 20020dc2366fSVenugopal Iyer ixgbe->intr_cnt - count < ixgbe->intr_cnt_min)) 20030dc2366fSVenugopal Iyer return (DDI_FAILURE); 20040dc2366fSVenugopal Iyer 20050dc2366fSVenugopal Iyer if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) { 20060dc2366fSVenugopal Iyer return (DDI_FAILURE); 20070dc2366fSVenugopal Iyer } 20080dc2366fSVenugopal Iyer 20090dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_rx_rings; i++) 20100dc2366fSVenugopal Iyer mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL); 20110dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_tx_rings; i++) 20120dc2366fSVenugopal Iyer mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL); 20130dc2366fSVenugopal Iyer 20140dc2366fSVenugopal Iyer mutex_enter(&ixgbe->gen_lock); 20150dc2366fSVenugopal Iyer ixgbe->ixgbe_state &= ~IXGBE_STARTED; 20160dc2366fSVenugopal Iyer ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST; 20170dc2366fSVenugopal Iyer ixgbe->ixgbe_state |= IXGBE_SUSPENDED; 20180dc2366fSVenugopal Iyer mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN); 20190dc2366fSVenugopal Iyer 20200dc2366fSVenugopal Iyer ixgbe_stop(ixgbe, B_FALSE); 20210dc2366fSVenugopal Iyer /* 20220dc2366fSVenugopal Iyer * Disable interrupts 20230dc2366fSVenugopal Iyer */ 20240dc2366fSVenugopal Iyer if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) { 20250dc2366fSVenugopal Iyer rc = ixgbe_disable_intrs(ixgbe); 20260dc2366fSVenugopal Iyer ASSERT(rc == IXGBE_SUCCESS); 20270dc2366fSVenugopal Iyer } 20280dc2366fSVenugopal Iyer ixgbe->attach_progress &= ~ATTACH_PROGRESS_ENABLE_INTR; 20290dc2366fSVenugopal Iyer 20300dc2366fSVenugopal Iyer /* 20310dc2366fSVenugopal Iyer * Remove interrupt handlers 20320dc2366fSVenugopal Iyer */ 20330dc2366fSVenugopal Iyer if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) { 20340dc2366fSVenugopal Iyer ixgbe_rem_intr_handlers(ixgbe); 20350dc2366fSVenugopal Iyer } 20360dc2366fSVenugopal Iyer ixgbe->attach_progress &= ~ATTACH_PROGRESS_ADD_INTR; 20370dc2366fSVenugopal Iyer 20380dc2366fSVenugopal Iyer /* 20390dc2366fSVenugopal Iyer * Clear vect_map 20400dc2366fSVenugopal Iyer */ 20410dc2366fSVenugopal Iyer bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map)); 20420dc2366fSVenugopal Iyer switch (cbaction) { 20430dc2366fSVenugopal Iyer case DDI_CB_INTR_ADD: 20440dc2366fSVenugopal Iyer rc = ddi_intr_alloc(ixgbe->dip, ixgbe->htable, 20450dc2366fSVenugopal Iyer DDI_INTR_TYPE_MSIX, ixgbe->intr_cnt, count, &actual, 20460dc2366fSVenugopal Iyer DDI_INTR_ALLOC_NORMAL); 20470dc2366fSVenugopal Iyer if (rc != DDI_SUCCESS || actual != count) { 20480dc2366fSVenugopal Iyer ixgbe_log(ixgbe, "Adjust interrupts failed." 20490dc2366fSVenugopal Iyer "return: %d, irm cb size: %d, actual: %d", 20500dc2366fSVenugopal Iyer rc, count, actual); 20510dc2366fSVenugopal Iyer goto intr_adjust_fail; 20520dc2366fSVenugopal Iyer } 20530dc2366fSVenugopal Iyer ixgbe->intr_cnt += count; 20540dc2366fSVenugopal Iyer break; 20550dc2366fSVenugopal Iyer 20560dc2366fSVenugopal Iyer case DDI_CB_INTR_REMOVE: 20570dc2366fSVenugopal Iyer for (i = ixgbe->intr_cnt - count; 20580dc2366fSVenugopal Iyer i < ixgbe->intr_cnt; i ++) { 20590dc2366fSVenugopal Iyer rc = ddi_intr_free(ixgbe->htable[i]); 20600dc2366fSVenugopal Iyer ixgbe->htable[i] = NULL; 20610dc2366fSVenugopal Iyer if (rc != DDI_SUCCESS) { 20620dc2366fSVenugopal Iyer ixgbe_log(ixgbe, "Adjust interrupts failed." 20630dc2366fSVenugopal Iyer "return: %d, irm cb size: %d, actual: %d", 20640dc2366fSVenugopal Iyer rc, count, actual); 20650dc2366fSVenugopal Iyer goto intr_adjust_fail; 20660dc2366fSVenugopal Iyer } 20670dc2366fSVenugopal Iyer } 20680dc2366fSVenugopal Iyer ixgbe->intr_cnt -= count; 20690dc2366fSVenugopal Iyer break; 20700dc2366fSVenugopal Iyer } 20710dc2366fSVenugopal Iyer 20720dc2366fSVenugopal Iyer /* 20730dc2366fSVenugopal Iyer * Get priority for first vector, assume remaining are all the same 20740dc2366fSVenugopal Iyer */ 20750dc2366fSVenugopal Iyer rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri); 20760dc2366fSVenugopal Iyer if (rc != DDI_SUCCESS) { 20770dc2366fSVenugopal Iyer ixgbe_log(ixgbe, 20780dc2366fSVenugopal Iyer "Get interrupt priority failed: %d", rc); 20790dc2366fSVenugopal Iyer goto intr_adjust_fail; 20800dc2366fSVenugopal Iyer } 20810dc2366fSVenugopal Iyer rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap); 20820dc2366fSVenugopal Iyer if (rc != DDI_SUCCESS) { 20830dc2366fSVenugopal Iyer ixgbe_log(ixgbe, "Get interrupt cap failed: %d", rc); 20840dc2366fSVenugopal Iyer goto intr_adjust_fail; 20850dc2366fSVenugopal Iyer } 20860dc2366fSVenugopal Iyer ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR; 20870dc2366fSVenugopal Iyer 20880dc2366fSVenugopal Iyer /* 20890dc2366fSVenugopal Iyer * Map rings to interrupt vectors 20900dc2366fSVenugopal Iyer */ 20910dc2366fSVenugopal Iyer if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) { 20920dc2366fSVenugopal Iyer ixgbe_error(ixgbe, 20930dc2366fSVenugopal Iyer "IRM CB: Failed to map interrupts to vectors"); 20940dc2366fSVenugopal Iyer goto intr_adjust_fail; 20950dc2366fSVenugopal Iyer } 20960dc2366fSVenugopal Iyer 20970dc2366fSVenugopal Iyer /* 20980dc2366fSVenugopal Iyer * Add interrupt handlers 20990dc2366fSVenugopal Iyer */ 21000dc2366fSVenugopal Iyer if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) { 21010dc2366fSVenugopal Iyer ixgbe_error(ixgbe, "IRM CB: Failed to add interrupt handlers"); 21020dc2366fSVenugopal Iyer goto intr_adjust_fail; 21030dc2366fSVenugopal Iyer } 21040dc2366fSVenugopal Iyer ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR; 21050dc2366fSVenugopal Iyer 21060dc2366fSVenugopal Iyer /* 21070dc2366fSVenugopal Iyer * Now that mutex locks are initialized, and the chip is also 21080dc2366fSVenugopal Iyer * initialized, enable interrupts. 21090dc2366fSVenugopal Iyer */ 21100dc2366fSVenugopal Iyer if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) { 21110dc2366fSVenugopal Iyer ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts"); 21120dc2366fSVenugopal Iyer goto intr_adjust_fail; 21130dc2366fSVenugopal Iyer } 21140dc2366fSVenugopal Iyer ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; 21150dc2366fSVenugopal Iyer if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) { 21160dc2366fSVenugopal Iyer ixgbe_error(ixgbe, "IRM CB: Failed to start"); 21170dc2366fSVenugopal Iyer goto intr_adjust_fail; 21180dc2366fSVenugopal Iyer } 21190dc2366fSVenugopal Iyer ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST; 21200dc2366fSVenugopal Iyer ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED; 21210dc2366fSVenugopal Iyer ixgbe->ixgbe_state |= IXGBE_STARTED; 21220dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock); 21230dc2366fSVenugopal Iyer 21240dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_rx_rings; i++) { 21250dc2366fSVenugopal Iyer mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, 21260dc2366fSVenugopal Iyer ixgbe->htable[ixgbe->rx_rings[i].intr_vector]); 21270dc2366fSVenugopal Iyer } 21280dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_tx_rings; i++) { 21290dc2366fSVenugopal Iyer mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, 21300dc2366fSVenugopal Iyer ixgbe->htable[ixgbe->tx_rings[i].intr_vector]); 21310dc2366fSVenugopal Iyer } 21320dc2366fSVenugopal Iyer 21330dc2366fSVenugopal Iyer /* Wakeup all Tx rings */ 21340dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_tx_rings; i++) { 21350dc2366fSVenugopal Iyer mac_tx_ring_update(ixgbe->mac_hdl, 21360dc2366fSVenugopal Iyer ixgbe->tx_rings[i].ring_handle); 21370dc2366fSVenugopal Iyer } 21380dc2366fSVenugopal Iyer 21390dc2366fSVenugopal Iyer IXGBE_DEBUGLOG_3(ixgbe, 21400dc2366fSVenugopal Iyer "IRM CB: interrupts new value: 0x%x(0x%x:0x%x).", 21410dc2366fSVenugopal Iyer ixgbe->intr_cnt, ixgbe->intr_cnt_min, ixgbe->intr_cnt_max); 21420dc2366fSVenugopal Iyer return (DDI_SUCCESS); 21430dc2366fSVenugopal Iyer 21440dc2366fSVenugopal Iyer intr_adjust_fail: 21450dc2366fSVenugopal Iyer ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 21460dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock); 21470dc2366fSVenugopal Iyer return (DDI_FAILURE); 21480dc2366fSVenugopal Iyer } 21490dc2366fSVenugopal Iyer 21500dc2366fSVenugopal Iyer /* 21510dc2366fSVenugopal Iyer * ixgbe_intr_cb_register - Register interrupt callback function. 21520dc2366fSVenugopal Iyer */ 21530dc2366fSVenugopal Iyer static int 21540dc2366fSVenugopal Iyer ixgbe_intr_cb_register(ixgbe_t *ixgbe) 21550dc2366fSVenugopal Iyer { 21560dc2366fSVenugopal Iyer if (ddi_cb_register(ixgbe->dip, DDI_CB_FLAG_INTR, ixgbe_cbfunc, 21570dc2366fSVenugopal Iyer ixgbe, NULL, &ixgbe->cb_hdl) != DDI_SUCCESS) { 21580dc2366fSVenugopal Iyer return (IXGBE_FAILURE); 21590dc2366fSVenugopal Iyer } 21600dc2366fSVenugopal Iyer IXGBE_DEBUGLOG_0(ixgbe, "Interrupt callback function registered."); 21610dc2366fSVenugopal Iyer return (IXGBE_SUCCESS); 21620dc2366fSVenugopal Iyer } 21630dc2366fSVenugopal Iyer 21640dc2366fSVenugopal Iyer /* 21659da57d7bSbt150084 * ixgbe_alloc_rings - Allocate memory space for rx/tx rings. 21669da57d7bSbt150084 */ 21679da57d7bSbt150084 static int 21689da57d7bSbt150084 ixgbe_alloc_rings(ixgbe_t *ixgbe) 21699da57d7bSbt150084 { 21709da57d7bSbt150084 /* 21719da57d7bSbt150084 * Allocate memory space for rx rings 21729da57d7bSbt150084 */ 21739da57d7bSbt150084 ixgbe->rx_rings = kmem_zalloc( 21749da57d7bSbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings, 21759da57d7bSbt150084 KM_NOSLEEP); 21769da57d7bSbt150084 21779da57d7bSbt150084 if (ixgbe->rx_rings == NULL) { 21789da57d7bSbt150084 return (IXGBE_FAILURE); 21799da57d7bSbt150084 } 21809da57d7bSbt150084 21819da57d7bSbt150084 /* 21829da57d7bSbt150084 * Allocate memory space for tx rings 21839da57d7bSbt150084 */ 21849da57d7bSbt150084 ixgbe->tx_rings = kmem_zalloc( 21859da57d7bSbt150084 sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings, 21869da57d7bSbt150084 KM_NOSLEEP); 21879da57d7bSbt150084 21889da57d7bSbt150084 if (ixgbe->tx_rings == NULL) { 21899da57d7bSbt150084 kmem_free(ixgbe->rx_rings, 21909da57d7bSbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 21919da57d7bSbt150084 ixgbe->rx_rings = NULL; 21929da57d7bSbt150084 return (IXGBE_FAILURE); 21939da57d7bSbt150084 } 21949da57d7bSbt150084 2195da14cebeSEric Cheng /* 2196da14cebeSEric Cheng * Allocate memory space for rx ring groups 2197da14cebeSEric Cheng */ 2198da14cebeSEric Cheng ixgbe->rx_groups = kmem_zalloc( 2199da14cebeSEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups, 2200da14cebeSEric Cheng KM_NOSLEEP); 2201da14cebeSEric Cheng 2202da14cebeSEric Cheng if (ixgbe->rx_groups == NULL) { 2203da14cebeSEric Cheng kmem_free(ixgbe->rx_rings, 2204da14cebeSEric Cheng sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 2205da14cebeSEric Cheng kmem_free(ixgbe->tx_rings, 2206da14cebeSEric Cheng sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings); 2207da14cebeSEric Cheng ixgbe->rx_rings = NULL; 2208da14cebeSEric Cheng ixgbe->tx_rings = NULL; 2209da14cebeSEric Cheng return (IXGBE_FAILURE); 2210da14cebeSEric Cheng } 2211da14cebeSEric Cheng 22129da57d7bSbt150084 return (IXGBE_SUCCESS); 22139da57d7bSbt150084 } 22149da57d7bSbt150084 22159da57d7bSbt150084 /* 22169da57d7bSbt150084 * ixgbe_free_rings - Free the memory space of rx/tx rings. 22179da57d7bSbt150084 */ 22189da57d7bSbt150084 static void 22199da57d7bSbt150084 ixgbe_free_rings(ixgbe_t *ixgbe) 22209da57d7bSbt150084 { 22219da57d7bSbt150084 if (ixgbe->rx_rings != NULL) { 22229da57d7bSbt150084 kmem_free(ixgbe->rx_rings, 22239da57d7bSbt150084 sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings); 22249da57d7bSbt150084 ixgbe->rx_rings = NULL; 22259da57d7bSbt150084 } 22269da57d7bSbt150084 22279da57d7bSbt150084 if (ixgbe->tx_rings != NULL) { 22289da57d7bSbt150084 kmem_free(ixgbe->tx_rings, 22299da57d7bSbt150084 sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings); 22309da57d7bSbt150084 ixgbe->tx_rings = NULL; 22319da57d7bSbt150084 } 2232da14cebeSEric Cheng 2233da14cebeSEric Cheng if (ixgbe->rx_groups != NULL) { 2234da14cebeSEric Cheng kmem_free(ixgbe->rx_groups, 2235da14cebeSEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups); 2236da14cebeSEric Cheng ixgbe->rx_groups = NULL; 2237da14cebeSEric Cheng } 22389da57d7bSbt150084 } 22399da57d7bSbt150084 2240ea65739eSchenlu chen - Sun Microsystems - Beijing China static int 2241ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_alloc_rx_data(ixgbe_t *ixgbe) 2242ea65739eSchenlu chen - Sun Microsystems - Beijing China { 2243ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_rx_ring_t *rx_ring; 2244ea65739eSchenlu chen - Sun Microsystems - Beijing China int i; 2245ea65739eSchenlu chen - Sun Microsystems - Beijing China 2246ea65739eSchenlu chen - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->num_rx_rings; i++) { 2247ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_ring = &ixgbe->rx_rings[i]; 2248ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS) 2249ea65739eSchenlu chen - Sun Microsystems - Beijing China goto alloc_rx_rings_failure; 2250ea65739eSchenlu chen - Sun Microsystems - Beijing China } 2251ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_SUCCESS); 2252ea65739eSchenlu chen - Sun Microsystems - Beijing China 2253ea65739eSchenlu chen - Sun Microsystems - Beijing China alloc_rx_rings_failure: 2254ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_data(ixgbe); 2255ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_FAILURE); 2256ea65739eSchenlu chen - Sun Microsystems - Beijing China } 2257ea65739eSchenlu chen - Sun Microsystems - Beijing China 2258ea65739eSchenlu chen - Sun Microsystems - Beijing China static void 2259ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_data(ixgbe_t *ixgbe) 2260ea65739eSchenlu chen - Sun Microsystems - Beijing China { 2261ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_rx_ring_t *rx_ring; 2262ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_rx_data_t *rx_data; 2263ea65739eSchenlu chen - Sun Microsystems - Beijing China int i; 2264ea65739eSchenlu chen - Sun Microsystems - Beijing China 2265ea65739eSchenlu chen - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->num_rx_rings; i++) { 2266ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_ring = &ixgbe->rx_rings[i]; 2267ea65739eSchenlu chen - Sun Microsystems - Beijing China 2268ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_enter(&ixgbe->rx_pending_lock); 2269ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_data = rx_ring->rx_data; 2270ea65739eSchenlu chen - Sun Microsystems - Beijing China 2271ea65739eSchenlu chen - Sun Microsystems - Beijing China if (rx_data != NULL) { 2272ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_data->flag |= IXGBE_RX_STOPPED; 2273ea65739eSchenlu chen - Sun Microsystems - Beijing China 2274ea65739eSchenlu chen - Sun Microsystems - Beijing China if (rx_data->rcb_pending == 0) { 2275ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_ring_data(rx_data); 2276ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_ring->rx_data = NULL; 2277ea65739eSchenlu chen - Sun Microsystems - Beijing China } 2278ea65739eSchenlu chen - Sun Microsystems - Beijing China } 2279ea65739eSchenlu chen - Sun Microsystems - Beijing China 2280ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->rx_pending_lock); 2281ea65739eSchenlu chen - Sun Microsystems - Beijing China } 2282ea65739eSchenlu chen - Sun Microsystems - Beijing China } 2283ea65739eSchenlu chen - Sun Microsystems - Beijing China 22849da57d7bSbt150084 /* 22859da57d7bSbt150084 * ixgbe_setup_rings - Setup rx/tx rings. 22869da57d7bSbt150084 */ 22879da57d7bSbt150084 static void 22889da57d7bSbt150084 ixgbe_setup_rings(ixgbe_t *ixgbe) 22899da57d7bSbt150084 { 22909da57d7bSbt150084 /* 22919da57d7bSbt150084 * Setup the rx/tx rings, including the following: 22929da57d7bSbt150084 * 22939da57d7bSbt150084 * 1. Setup the descriptor ring and the control block buffers; 22949da57d7bSbt150084 * 2. Initialize necessary registers for receive/transmit; 22959da57d7bSbt150084 * 3. Initialize software pointers/parameters for receive/transmit; 22969da57d7bSbt150084 */ 22979da57d7bSbt150084 ixgbe_setup_rx(ixgbe); 22989da57d7bSbt150084 22999da57d7bSbt150084 ixgbe_setup_tx(ixgbe); 23009da57d7bSbt150084 } 23019da57d7bSbt150084 23029da57d7bSbt150084 static void 23039da57d7bSbt150084 ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring) 23049da57d7bSbt150084 { 23059da57d7bSbt150084 ixgbe_t *ixgbe = rx_ring->ixgbe; 2306ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_rx_data_t *rx_data = rx_ring->rx_data; 23079da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 23089da57d7bSbt150084 rx_control_block_t *rcb; 23099da57d7bSbt150084 union ixgbe_adv_rx_desc *rbd; 23109da57d7bSbt150084 uint32_t size; 23119da57d7bSbt150084 uint32_t buf_low; 23129da57d7bSbt150084 uint32_t buf_high; 23139da57d7bSbt150084 uint32_t reg_val; 23149da57d7bSbt150084 int i; 23159da57d7bSbt150084 23169da57d7bSbt150084 ASSERT(mutex_owned(&rx_ring->rx_lock)); 23179da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 23189da57d7bSbt150084 23199da57d7bSbt150084 for (i = 0; i < ixgbe->rx_ring_size; i++) { 2320ea65739eSchenlu chen - Sun Microsystems - Beijing China rcb = rx_data->work_list[i]; 2321ea65739eSchenlu chen - Sun Microsystems - Beijing China rbd = &rx_data->rbd_ring[i]; 23229da57d7bSbt150084 23239da57d7bSbt150084 rbd->read.pkt_addr = rcb->rx_buf.dma_address; 23249da57d7bSbt150084 rbd->read.hdr_addr = NULL; 23259da57d7bSbt150084 } 23269da57d7bSbt150084 23279da57d7bSbt150084 /* 23289da57d7bSbt150084 * Initialize the length register 23299da57d7bSbt150084 */ 2330ea65739eSchenlu chen - Sun Microsystems - Beijing China size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc); 23310dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->hw_index), size); 23329da57d7bSbt150084 23339da57d7bSbt150084 /* 23349da57d7bSbt150084 * Initialize the base address registers 23359da57d7bSbt150084 */ 2336ea65739eSchenlu chen - Sun Microsystems - Beijing China buf_low = (uint32_t)rx_data->rbd_area.dma_address; 2337ea65739eSchenlu chen - Sun Microsystems - Beijing China buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32); 23380dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->hw_index), buf_high); 23390dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->hw_index), buf_low); 23409da57d7bSbt150084 23419da57d7bSbt150084 /* 23429da57d7bSbt150084 * Setup head & tail pointers 23439da57d7bSbt150084 */ 23440dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->hw_index), 23450dc2366fSVenugopal Iyer rx_data->ring_size - 1); 23460dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->hw_index), 0); 23479da57d7bSbt150084 2348ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_data->rbd_next = 0; 2349ffd8e883SWinson Wang - Sun Microsystems - Beijing China rx_data->lro_first = 0; 23509da57d7bSbt150084 23519da57d7bSbt150084 /* 23529da57d7bSbt150084 * Setup the Receive Descriptor Control Register (RXDCTL) 23539da57d7bSbt150084 * PTHRESH=32 descriptors (half the internal cache) 23549da57d7bSbt150084 * HTHRESH=0 descriptors (to minimize latency on fetch) 23559da57d7bSbt150084 * WTHRESH defaults to 1 (writeback each descriptor) 23569da57d7bSbt150084 */ 23570dc2366fSVenugopal Iyer reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index)); 23589da57d7bSbt150084 reg_val |= IXGBE_RXDCTL_ENABLE; /* enable queue */ 235973cd555cSBin Tu - Sun Microsystems - Beijing China 23607e579c30SDale Ghent /* Not a valid value for 82599, X540 or X550 */ 236169b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82598EB) { 23629da57d7bSbt150084 reg_val |= 0x0020; /* pthresh */ 236373cd555cSBin Tu - Sun Microsystems - Beijing China } 23640dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val); 23659da57d7bSbt150084 236669b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82599EB || 23677e579c30SDale Ghent hw->mac.type == ixgbe_mac_X540 || 23687e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550 || 23697e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550EM_x) { 237073cd555cSBin Tu - Sun Microsystems - Beijing China reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 237173cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS); 237273cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); 237373cd555cSBin Tu - Sun Microsystems - Beijing China } 237473cd555cSBin Tu - Sun Microsystems - Beijing China 23759da57d7bSbt150084 /* 23769da57d7bSbt150084 * Setup the Split and Replication Receive Control Register. 23779da57d7bSbt150084 * Set the rx buffer size and the advanced descriptor type. 23789da57d7bSbt150084 */ 23799da57d7bSbt150084 reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) | 23809da57d7bSbt150084 IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; 238173cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= IXGBE_SRRCTL_DROP_EN; 23820dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->hw_index), reg_val); 23839da57d7bSbt150084 } 23849da57d7bSbt150084 23859da57d7bSbt150084 static void 23869da57d7bSbt150084 ixgbe_setup_rx(ixgbe_t *ixgbe) 23879da57d7bSbt150084 { 23889da57d7bSbt150084 ixgbe_rx_ring_t *rx_ring; 23899da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 23909da57d7bSbt150084 uint32_t reg_val; 2391da14cebeSEric Cheng uint32_t ring_mapping; 23920dc2366fSVenugopal Iyer uint32_t i, index; 23930dc2366fSVenugopal Iyer uint32_t psrtype_rss_bit; 23949da57d7bSbt150084 23957e579c30SDale Ghent /* 23967e579c30SDale Ghent * Ensure that Rx is disabled while setting up 23977e579c30SDale Ghent * the Rx unit and Rx descriptor ring(s) 23987e579c30SDale Ghent */ 23997e579c30SDale Ghent ixgbe_disable_rx(hw); 24007e579c30SDale Ghent 240173cd555cSBin Tu - Sun Microsystems - Beijing China /* PSRTYPE must be configured for 82599 */ 24020dc2366fSVenugopal Iyer if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ && 24030dc2366fSVenugopal Iyer ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) { 240473cd555cSBin Tu - Sun Microsystems - Beijing China reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | 240573cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR; 24060dc2366fSVenugopal Iyer reg_val |= IXGBE_PSRTYPE_L2HDR; 24070dc2366fSVenugopal Iyer reg_val |= 0x80000000; 240873cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val); 24090dc2366fSVenugopal Iyer } else { 24100dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups > 32) { 24110dc2366fSVenugopal Iyer psrtype_rss_bit = 0x20000000; 24120dc2366fSVenugopal Iyer } else { 24130dc2366fSVenugopal Iyer psrtype_rss_bit = 0x40000000; 24140dc2366fSVenugopal Iyer } 24150dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->capab->max_rx_grp_num; i++) { 24160dc2366fSVenugopal Iyer reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | 24170dc2366fSVenugopal Iyer IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR; 24180dc2366fSVenugopal Iyer reg_val |= IXGBE_PSRTYPE_L2HDR; 24190dc2366fSVenugopal Iyer reg_val |= psrtype_rss_bit; 24200dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val); 24210dc2366fSVenugopal Iyer } 24220dc2366fSVenugopal Iyer } 242373cd555cSBin Tu - Sun Microsystems - Beijing China 24249da57d7bSbt150084 /* 24257e579c30SDale Ghent * Set filter control in FCTRL to determine types of packets are passed 24267e579c30SDale Ghent * up to the driver. 24277e579c30SDale Ghent * - Pass broadcast packets. 24287e579c30SDale Ghent * - Do not pass flow control pause frames (82598-specific) 24299da57d7bSbt150084 */ 24309da57d7bSbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL); 24317e579c30SDale Ghent reg_val |= IXGBE_FCTRL_BAM; /* Broadcast Accept Mode */ 24327e579c30SDale Ghent if (hw->mac.type == ixgbe_mac_82598EB) { 24337e579c30SDale Ghent reg_val |= IXGBE_FCTRL_DPF; /* Discard Pause Frames */ 24347e579c30SDale Ghent } 24359da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val); 24369da57d7bSbt150084 24379da57d7bSbt150084 /* 24380dc2366fSVenugopal Iyer * Hardware checksum settings 24390dc2366fSVenugopal Iyer */ 24400dc2366fSVenugopal Iyer if (ixgbe->rx_hcksum_enable) { 24417e579c30SDale Ghent reg_val = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 24427e579c30SDale Ghent reg_val |= IXGBE_RXCSUM_IPPCSE; /* IP checksum */ 24430dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val); 24440dc2366fSVenugopal Iyer } 24450dc2366fSVenugopal Iyer 24460dc2366fSVenugopal Iyer /* 24470dc2366fSVenugopal Iyer * Setup VMDq and RSS for multiple receive queues 24480dc2366fSVenugopal Iyer */ 24490dc2366fSVenugopal Iyer switch (ixgbe->classify_mode) { 24500dc2366fSVenugopal Iyer case IXGBE_CLASSIFY_RSS: 24510dc2366fSVenugopal Iyer /* 24520dc2366fSVenugopal Iyer * One group, only RSS is needed when more than 24530dc2366fSVenugopal Iyer * one ring enabled. 24540dc2366fSVenugopal Iyer */ 24550dc2366fSVenugopal Iyer ixgbe_setup_rss(ixgbe); 24560dc2366fSVenugopal Iyer break; 24570dc2366fSVenugopal Iyer 24580dc2366fSVenugopal Iyer case IXGBE_CLASSIFY_VMDQ: 24590dc2366fSVenugopal Iyer /* 24600dc2366fSVenugopal Iyer * Multiple groups, each group has one ring, 24610dc2366fSVenugopal Iyer * only VMDq is needed. 24620dc2366fSVenugopal Iyer */ 24630dc2366fSVenugopal Iyer ixgbe_setup_vmdq(ixgbe); 24640dc2366fSVenugopal Iyer break; 24650dc2366fSVenugopal Iyer 24660dc2366fSVenugopal Iyer case IXGBE_CLASSIFY_VMDQ_RSS: 24670dc2366fSVenugopal Iyer /* 24680dc2366fSVenugopal Iyer * Multiple groups and multiple rings, both 24690dc2366fSVenugopal Iyer * VMDq and RSS are needed. 24700dc2366fSVenugopal Iyer */ 24710dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss(ixgbe); 24720dc2366fSVenugopal Iyer break; 24730dc2366fSVenugopal Iyer 24740dc2366fSVenugopal Iyer default: 24750dc2366fSVenugopal Iyer break; 24760dc2366fSVenugopal Iyer } 24770dc2366fSVenugopal Iyer 24780dc2366fSVenugopal Iyer /* 24799da57d7bSbt150084 * Enable the receive unit. This must be done after filter 24807e579c30SDale Ghent * control is set in FCTRL. On 82598, we disable the descriptor monitor. 24817e579c30SDale Ghent * 82598 is the only adapter which defines this RXCTRL option. 24829da57d7bSbt150084 */ 24837e579c30SDale Ghent reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL); 24847e579c30SDale Ghent if (hw->mac.type == ixgbe_mac_82598EB) 24857e579c30SDale Ghent reg_val |= IXGBE_RXCTRL_DMBYPS; /* descriptor monitor bypass */ 24867e579c30SDale Ghent reg_val |= IXGBE_RXCTRL_RXEN; 24877e579c30SDale Ghent (void) ixgbe_enable_rx_dma(hw, reg_val); 24889da57d7bSbt150084 24899da57d7bSbt150084 /* 24909da57d7bSbt150084 * ixgbe_setup_rx_ring must be called after configuring RXCTRL 24919da57d7bSbt150084 */ 24929da57d7bSbt150084 for (i = 0; i < ixgbe->num_rx_rings; i++) { 24939da57d7bSbt150084 rx_ring = &ixgbe->rx_rings[i]; 24949da57d7bSbt150084 ixgbe_setup_rx_ring(rx_ring); 24959da57d7bSbt150084 } 24969da57d7bSbt150084 24979da57d7bSbt150084 /* 2498da14cebeSEric Cheng * Setup the per-ring statistics mapping. 2499da14cebeSEric Cheng */ 2500da14cebeSEric Cheng ring_mapping = 0; 2501da14cebeSEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) { 25020dc2366fSVenugopal Iyer index = ixgbe->rx_rings[i].hw_index; 25030dc2366fSVenugopal Iyer ring_mapping = IXGBE_READ_REG(hw, IXGBE_RQSMR(index >> 2)); 25040dc2366fSVenugopal Iyer ring_mapping |= (i & 0xF) << (8 * (index & 0x3)); 25050dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RQSMR(index >> 2), ring_mapping); 2506da14cebeSEric Cheng } 2507da14cebeSEric Cheng 2508da14cebeSEric Cheng /* 250973cd555cSBin Tu - Sun Microsystems - Beijing China * The Max Frame Size in MHADD/MAXFRS will be internally increased 251073cd555cSBin Tu - Sun Microsystems - Beijing China * by four bytes if the packet has a VLAN field, so includes MTU, 251173cd555cSBin Tu - Sun Microsystems - Beijing China * ethernet header and frame check sequence. 251273cd555cSBin Tu - Sun Microsystems - Beijing China * Register is MAXFRS in 82599. 25139da57d7bSbt150084 */ 25147e579c30SDale Ghent reg_val = IXGBE_READ_REG(hw, IXGBE_MHADD); 25157e579c30SDale Ghent reg_val &= ~IXGBE_MHADD_MFS_MASK; 25167e579c30SDale Ghent reg_val |= (ixgbe->default_mtu + sizeof (struct ether_header) 25179da57d7bSbt150084 + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT; 25189da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val); 25199da57d7bSbt150084 25209da57d7bSbt150084 /* 25219da57d7bSbt150084 * Setup Jumbo Frame enable bit 25229da57d7bSbt150084 */ 25239da57d7bSbt150084 reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); 25247e579c30SDale Ghent if (ixgbe->default_mtu > ETHERMTU) 25259da57d7bSbt150084 reg_val |= IXGBE_HLREG0_JUMBOEN; 25267e579c30SDale Ghent else 25277e579c30SDale Ghent reg_val &= ~IXGBE_HLREG0_JUMBOEN; 25289da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); 25291878b971SVenugopal Iyer 25301878b971SVenugopal Iyer /* 25311878b971SVenugopal Iyer * Setup RSC for multiple receive queues. 25321878b971SVenugopal Iyer */ 25331878b971SVenugopal Iyer if (ixgbe->lro_enable) { 25341878b971SVenugopal Iyer for (i = 0; i < ixgbe->num_rx_rings; i++) { 25351878b971SVenugopal Iyer /* 25361878b971SVenugopal Iyer * Make sure rx_buf_size * MAXDESC not greater 25371878b971SVenugopal Iyer * than 65535. 25381878b971SVenugopal Iyer * Intel recommends 4 for MAXDESC field value. 25391878b971SVenugopal Iyer */ 25401878b971SVenugopal Iyer reg_val = IXGBE_READ_REG(hw, IXGBE_RSCCTL(i)); 25411878b971SVenugopal Iyer reg_val |= IXGBE_RSCCTL_RSCEN; 25421878b971SVenugopal Iyer if (ixgbe->rx_buf_size == IXGBE_PKG_BUF_16k) 25431878b971SVenugopal Iyer reg_val |= IXGBE_RSCCTL_MAXDESC_1; 25441878b971SVenugopal Iyer else 25451878b971SVenugopal Iyer reg_val |= IXGBE_RSCCTL_MAXDESC_4; 25461878b971SVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(i), reg_val); 25471878b971SVenugopal Iyer } 25481878b971SVenugopal Iyer 25491878b971SVenugopal Iyer reg_val = IXGBE_READ_REG(hw, IXGBE_RSCDBU); 25501878b971SVenugopal Iyer reg_val |= IXGBE_RSCDBU_RSCACKDIS; 25511878b971SVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, reg_val); 25521878b971SVenugopal Iyer 25531878b971SVenugopal Iyer reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); 25541878b971SVenugopal Iyer reg_val |= IXGBE_RDRXCTL_RSCACKC; 255519843f01SPaul Guo reg_val |= IXGBE_RDRXCTL_FCOE_WRFIX; 25561878b971SVenugopal Iyer reg_val &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; 25571878b971SVenugopal Iyer 25581878b971SVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); 25591878b971SVenugopal Iyer } 25609da57d7bSbt150084 } 25619da57d7bSbt150084 25629da57d7bSbt150084 static void 25639da57d7bSbt150084 ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring) 25649da57d7bSbt150084 { 25659da57d7bSbt150084 ixgbe_t *ixgbe = tx_ring->ixgbe; 25669da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 25679da57d7bSbt150084 uint32_t size; 25689da57d7bSbt150084 uint32_t buf_low; 25699da57d7bSbt150084 uint32_t buf_high; 25709da57d7bSbt150084 uint32_t reg_val; 25719da57d7bSbt150084 25729da57d7bSbt150084 ASSERT(mutex_owned(&tx_ring->tx_lock)); 25739da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 25749da57d7bSbt150084 25759da57d7bSbt150084 /* 25769da57d7bSbt150084 * Initialize the length register 25779da57d7bSbt150084 */ 25789da57d7bSbt150084 size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc); 25799da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size); 25809da57d7bSbt150084 25819da57d7bSbt150084 /* 25829da57d7bSbt150084 * Initialize the base address registers 25839da57d7bSbt150084 */ 25849da57d7bSbt150084 buf_low = (uint32_t)tx_ring->tbd_area.dma_address; 25859da57d7bSbt150084 buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32); 25869da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low); 25879da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high); 25889da57d7bSbt150084 25899da57d7bSbt150084 /* 25909da57d7bSbt150084 * Setup head & tail pointers 25919da57d7bSbt150084 */ 25929da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0); 25939da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0); 25949da57d7bSbt150084 25959da57d7bSbt150084 /* 25969da57d7bSbt150084 * Setup head write-back 25979da57d7bSbt150084 */ 25989da57d7bSbt150084 if (ixgbe->tx_head_wb_enable) { 25999da57d7bSbt150084 /* 26009da57d7bSbt150084 * The memory of the head write-back is allocated using 26019da57d7bSbt150084 * the extra tbd beyond the tail of the tbd ring. 26029da57d7bSbt150084 */ 26039da57d7bSbt150084 tx_ring->tbd_head_wb = (uint32_t *) 26049da57d7bSbt150084 ((uintptr_t)tx_ring->tbd_area.address + size); 26059da57d7bSbt150084 *tx_ring->tbd_head_wb = 0; 26069da57d7bSbt150084 26079da57d7bSbt150084 buf_low = (uint32_t) 26089da57d7bSbt150084 (tx_ring->tbd_area.dma_address + size); 26099da57d7bSbt150084 buf_high = (uint32_t) 26109da57d7bSbt150084 ((tx_ring->tbd_area.dma_address + size) >> 32); 26119da57d7bSbt150084 26129da57d7bSbt150084 /* Set the head write-back enable bit */ 26139da57d7bSbt150084 buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE; 26149da57d7bSbt150084 26159da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low); 26169da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high); 26179da57d7bSbt150084 26189da57d7bSbt150084 /* 26199da57d7bSbt150084 * Turn off relaxed ordering for head write back or it will 26209da57d7bSbt150084 * cause problems with the tx recycling 26219da57d7bSbt150084 */ 262269b5a878SDan McDonald 262369b5a878SDan McDonald reg_val = (hw->mac.type == ixgbe_mac_82598EB) ? 262469b5a878SDan McDonald IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(tx_ring->index)) : 262569b5a878SDan McDonald IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(tx_ring->index)); 262669b5a878SDan McDonald reg_val &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; 262769b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82598EB) { 26289da57d7bSbt150084 IXGBE_WRITE_REG(hw, 26299da57d7bSbt150084 IXGBE_DCA_TXCTRL(tx_ring->index), reg_val); 26309da57d7bSbt150084 } else { 263169b5a878SDan McDonald IXGBE_WRITE_REG(hw, 263269b5a878SDan McDonald IXGBE_DCA_TXCTRL_82599(tx_ring->index), reg_val); 263369b5a878SDan McDonald } 263469b5a878SDan McDonald } else { 26359da57d7bSbt150084 tx_ring->tbd_head_wb = NULL; 26369da57d7bSbt150084 } 26379da57d7bSbt150084 26389da57d7bSbt150084 tx_ring->tbd_head = 0; 26399da57d7bSbt150084 tx_ring->tbd_tail = 0; 26409da57d7bSbt150084 tx_ring->tbd_free = tx_ring->ring_size; 26419da57d7bSbt150084 2642ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->tx_ring_init == B_TRUE) { 26439da57d7bSbt150084 tx_ring->tcb_head = 0; 26449da57d7bSbt150084 tx_ring->tcb_tail = 0; 26459da57d7bSbt150084 tx_ring->tcb_free = tx_ring->free_list_size; 26469da57d7bSbt150084 } 26479da57d7bSbt150084 26489da57d7bSbt150084 /* 2649f27d3025Sgg161487 * Initialize the s/w context structure 26509da57d7bSbt150084 */ 2651f27d3025Sgg161487 bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t)); 26529da57d7bSbt150084 } 26539da57d7bSbt150084 26549da57d7bSbt150084 static void 26559da57d7bSbt150084 ixgbe_setup_tx(ixgbe_t *ixgbe) 26569da57d7bSbt150084 { 2657c971fb7eSgg161487 struct ixgbe_hw *hw = &ixgbe->hw; 26589da57d7bSbt150084 ixgbe_tx_ring_t *tx_ring; 2659c971fb7eSgg161487 uint32_t reg_val; 2660da14cebeSEric Cheng uint32_t ring_mapping; 26619da57d7bSbt150084 int i; 26629da57d7bSbt150084 26639da57d7bSbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 26649da57d7bSbt150084 tx_ring = &ixgbe->tx_rings[i]; 26659da57d7bSbt150084 ixgbe_setup_tx_ring(tx_ring); 26669da57d7bSbt150084 } 2667c971fb7eSgg161487 2668c971fb7eSgg161487 /* 2669da14cebeSEric Cheng * Setup the per-ring statistics mapping. 2670da14cebeSEric Cheng */ 2671da14cebeSEric Cheng ring_mapping = 0; 2672da14cebeSEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) { 2673da14cebeSEric Cheng ring_mapping |= (i & 0xF) << (8 * (i & 0x3)); 2674da14cebeSEric Cheng if ((i & 0x3) == 0x3) { 26755b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 26765b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 267773cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), 267873cd555cSBin Tu - Sun Microsystems - Beijing China ring_mapping); 26795b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 26805b6dd21fSchenlu chen - Sun Microsystems - Beijing China 26815b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 268269b5a878SDan McDonald case ixgbe_mac_X540: 26837e579c30SDale Ghent case ixgbe_mac_X550: 26847e579c30SDale Ghent case ixgbe_mac_X550EM_x: 26855b6dd21fSchenlu chen - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), 26865b6dd21fSchenlu chen - Sun Microsystems - Beijing China ring_mapping); 26875b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 26885b6dd21fSchenlu chen - Sun Microsystems - Beijing China 26895b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 26905b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 269173cd555cSBin Tu - Sun Microsystems - Beijing China } 26925b6dd21fSchenlu chen - Sun Microsystems - Beijing China 2693da14cebeSEric Cheng ring_mapping = 0; 2694da14cebeSEric Cheng } 2695da14cebeSEric Cheng } 26965b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (i & 0x3) { 26975b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 26985b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 2699da14cebeSEric Cheng IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping); 27005b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 27015b6dd21fSchenlu chen - Sun Microsystems - Beijing China 27025b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 270369b5a878SDan McDonald case ixgbe_mac_X540: 27047e579c30SDale Ghent case ixgbe_mac_X550: 27057e579c30SDale Ghent case ixgbe_mac_X550EM_x: 27065b6dd21fSchenlu chen - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping); 27075b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 27085b6dd21fSchenlu chen - Sun Microsystems - Beijing China 27095b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 27105b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 27115b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 271273cd555cSBin Tu - Sun Microsystems - Beijing China } 2713da14cebeSEric Cheng 2714da14cebeSEric Cheng /* 2715c971fb7eSgg161487 * Enable CRC appending and TX padding (for short tx frames) 2716c971fb7eSgg161487 */ 2717c971fb7eSgg161487 reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); 2718c971fb7eSgg161487 reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN; 2719c971fb7eSgg161487 IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); 272073cd555cSBin Tu - Sun Microsystems - Beijing China 272173cd555cSBin Tu - Sun Microsystems - Beijing China /* 27227e579c30SDale Ghent * enable DMA for 82599, X540 and X550 parts 272373cd555cSBin Tu - Sun Microsystems - Beijing China */ 272469b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82599EB || 27257e579c30SDale Ghent hw->mac.type == ixgbe_mac_X540 || 27267e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550 || 27277e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550EM_x) { 272873cd555cSBin Tu - Sun Microsystems - Beijing China /* DMATXCTL.TE must be set after all Tx config is complete */ 272973cd555cSBin Tu - Sun Microsystems - Beijing China reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); 273073cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= IXGBE_DMATXCTL_TE; 273173cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val); 273269b5a878SDan McDonald 273369b5a878SDan McDonald /* Disable arbiter to set MTQC */ 273469b5a878SDan McDonald reg_val = IXGBE_READ_REG(hw, IXGBE_RTTDCS); 273569b5a878SDan McDonald reg_val |= IXGBE_RTTDCS_ARBDIS; 273669b5a878SDan McDonald IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg_val); 273769b5a878SDan McDonald IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); 273869b5a878SDan McDonald reg_val &= ~IXGBE_RTTDCS_ARBDIS; 273969b5a878SDan McDonald IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg_val); 274073cd555cSBin Tu - Sun Microsystems - Beijing China } 274173cd555cSBin Tu - Sun Microsystems - Beijing China 274273cd555cSBin Tu - Sun Microsystems - Beijing China /* 274373cd555cSBin Tu - Sun Microsystems - Beijing China * Enabling tx queues .. 274473cd555cSBin Tu - Sun Microsystems - Beijing China * For 82599 must be done after DMATXCTL.TE is set 274573cd555cSBin Tu - Sun Microsystems - Beijing China */ 274673cd555cSBin Tu - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->num_tx_rings; i++) { 274773cd555cSBin Tu - Sun Microsystems - Beijing China tx_ring = &ixgbe->tx_rings[i]; 274873cd555cSBin Tu - Sun Microsystems - Beijing China reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index)); 274973cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= IXGBE_TXDCTL_ENABLE; 275073cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val); 275173cd555cSBin Tu - Sun Microsystems - Beijing China } 27529da57d7bSbt150084 } 27539da57d7bSbt150084 27549da57d7bSbt150084 /* 27559da57d7bSbt150084 * ixgbe_setup_rss - Setup receive-side scaling feature. 27569da57d7bSbt150084 */ 27579da57d7bSbt150084 static void 27589da57d7bSbt150084 ixgbe_setup_rss(ixgbe_t *ixgbe) 27599da57d7bSbt150084 { 27609da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 27617e579c30SDale Ghent uint32_t mrqc; 27629da57d7bSbt150084 27639da57d7bSbt150084 /* 27647e579c30SDale Ghent * Initialize RETA/ERETA table 27659da57d7bSbt150084 */ 27667e579c30SDale Ghent ixgbe_setup_rss_table(ixgbe); 27679da57d7bSbt150084 27689da57d7bSbt150084 /* 2769c971fb7eSgg161487 * Enable RSS & perform hash on these packet types 27709da57d7bSbt150084 */ 27719da57d7bSbt150084 mrqc = IXGBE_MRQC_RSSEN | 27729da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV4 | 27739da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 27749da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 27759da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 27769da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX | 27779da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV6 | 27789da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 27799da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 27809da57d7bSbt150084 IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 27819da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 27829da57d7bSbt150084 } 27839da57d7bSbt150084 27849da57d7bSbt150084 /* 27850dc2366fSVenugopal Iyer * ixgbe_setup_vmdq - Setup MAC classification feature 27860dc2366fSVenugopal Iyer */ 27870dc2366fSVenugopal Iyer static void 27880dc2366fSVenugopal Iyer ixgbe_setup_vmdq(ixgbe_t *ixgbe) 27890dc2366fSVenugopal Iyer { 27900dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw; 27910dc2366fSVenugopal Iyer uint32_t vmdctl, i, vtctl; 27920dc2366fSVenugopal Iyer 27930dc2366fSVenugopal Iyer /* 27940dc2366fSVenugopal Iyer * Setup the VMDq Control register, enable VMDq based on 27950dc2366fSVenugopal Iyer * packet destination MAC address: 27960dc2366fSVenugopal Iyer */ 27970dc2366fSVenugopal Iyer switch (hw->mac.type) { 27980dc2366fSVenugopal Iyer case ixgbe_mac_82598EB: 27990dc2366fSVenugopal Iyer /* 28000dc2366fSVenugopal Iyer * VMDq Enable = 1; 28010dc2366fSVenugopal Iyer * VMDq Filter = 0; MAC filtering 28020dc2366fSVenugopal Iyer * Default VMDq output index = 0; 28030dc2366fSVenugopal Iyer */ 28040dc2366fSVenugopal Iyer vmdctl = IXGBE_VMD_CTL_VMDQ_EN; 28050dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl); 28060dc2366fSVenugopal Iyer break; 28070dc2366fSVenugopal Iyer 28080dc2366fSVenugopal Iyer case ixgbe_mac_82599EB: 280969b5a878SDan McDonald case ixgbe_mac_X540: 28107e579c30SDale Ghent case ixgbe_mac_X550: 28117e579c30SDale Ghent case ixgbe_mac_X550EM_x: 28120dc2366fSVenugopal Iyer /* 28130dc2366fSVenugopal Iyer * Enable VMDq-only. 28140dc2366fSVenugopal Iyer */ 28150dc2366fSVenugopal Iyer vmdctl = IXGBE_MRQC_VMDQEN; 28160dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl); 28170dc2366fSVenugopal Iyer 28180dc2366fSVenugopal Iyer for (i = 0; i < hw->mac.num_rar_entries; i++) { 28190dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0); 28200dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0); 28210dc2366fSVenugopal Iyer } 28220dc2366fSVenugopal Iyer 28230dc2366fSVenugopal Iyer /* 28240dc2366fSVenugopal Iyer * Enable Virtualization and Replication. 28250dc2366fSVenugopal Iyer */ 28260dc2366fSVenugopal Iyer vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 28270dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl); 28280dc2366fSVenugopal Iyer 28290dc2366fSVenugopal Iyer /* 28300dc2366fSVenugopal Iyer * Enable receiving packets to all VFs 28310dc2366fSVenugopal Iyer */ 28320dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL); 28330dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL); 28340dc2366fSVenugopal Iyer break; 28350dc2366fSVenugopal Iyer 28360dc2366fSVenugopal Iyer default: 28370dc2366fSVenugopal Iyer break; 28380dc2366fSVenugopal Iyer } 28390dc2366fSVenugopal Iyer } 28400dc2366fSVenugopal Iyer 28410dc2366fSVenugopal Iyer /* 28420dc2366fSVenugopal Iyer * ixgbe_setup_vmdq_rss - Setup both vmdq feature and rss feature. 28430dc2366fSVenugopal Iyer */ 28440dc2366fSVenugopal Iyer static void 28450dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe) 28460dc2366fSVenugopal Iyer { 28470dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw; 28487e579c30SDale Ghent uint32_t i, mrqc; 28497e579c30SDale Ghent uint32_t vtctl, vmdctl; 28500dc2366fSVenugopal Iyer 28510dc2366fSVenugopal Iyer /* 28527e579c30SDale Ghent * Initialize RETA/ERETA table 28530dc2366fSVenugopal Iyer */ 28547e579c30SDale Ghent ixgbe_setup_rss_table(ixgbe); 28550dc2366fSVenugopal Iyer 28560dc2366fSVenugopal Iyer /* 28570dc2366fSVenugopal Iyer * Enable and setup RSS and VMDq 28580dc2366fSVenugopal Iyer */ 28590dc2366fSVenugopal Iyer switch (hw->mac.type) { 28600dc2366fSVenugopal Iyer case ixgbe_mac_82598EB: 28610dc2366fSVenugopal Iyer /* 28620dc2366fSVenugopal Iyer * Enable RSS & Setup RSS Hash functions 28630dc2366fSVenugopal Iyer */ 28640dc2366fSVenugopal Iyer mrqc = IXGBE_MRQC_RSSEN | 28650dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4 | 28660dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 28670dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 28680dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 28690dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX | 28700dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6 | 28710dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 28720dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 28730dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 28740dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 28750dc2366fSVenugopal Iyer 28760dc2366fSVenugopal Iyer /* 28770dc2366fSVenugopal Iyer * Enable and Setup VMDq 28780dc2366fSVenugopal Iyer * VMDq Filter = 0; MAC filtering 28790dc2366fSVenugopal Iyer * Default VMDq output index = 0; 28800dc2366fSVenugopal Iyer */ 28810dc2366fSVenugopal Iyer vmdctl = IXGBE_VMD_CTL_VMDQ_EN; 28820dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl); 28830dc2366fSVenugopal Iyer break; 28840dc2366fSVenugopal Iyer 28850dc2366fSVenugopal Iyer case ixgbe_mac_82599EB: 288669b5a878SDan McDonald case ixgbe_mac_X540: 28877e579c30SDale Ghent case ixgbe_mac_X550: 28887e579c30SDale Ghent case ixgbe_mac_X550EM_x: 28890dc2366fSVenugopal Iyer /* 28900dc2366fSVenugopal Iyer * Enable RSS & Setup RSS Hash functions 28910dc2366fSVenugopal Iyer */ 28920dc2366fSVenugopal Iyer mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 | 28930dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4_TCP | 28940dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4_UDP | 28950dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | 28960dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX | 28970dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6 | 28980dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_TCP | 28990dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_UDP | 29000dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; 29010dc2366fSVenugopal Iyer 29020dc2366fSVenugopal Iyer /* 29030dc2366fSVenugopal Iyer * Enable VMDq+RSS. 29040dc2366fSVenugopal Iyer */ 29050dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups > 32) { 29060dc2366fSVenugopal Iyer mrqc = mrqc | IXGBE_MRQC_VMDQRSS64EN; 29070dc2366fSVenugopal Iyer } else { 29080dc2366fSVenugopal Iyer mrqc = mrqc | IXGBE_MRQC_VMDQRSS32EN; 29090dc2366fSVenugopal Iyer } 29100dc2366fSVenugopal Iyer 29110dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); 29120dc2366fSVenugopal Iyer 29130dc2366fSVenugopal Iyer for (i = 0; i < hw->mac.num_rar_entries; i++) { 29140dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0); 29150dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0); 29160dc2366fSVenugopal Iyer } 29170dc2366fSVenugopal Iyer break; 29180dc2366fSVenugopal Iyer 29190dc2366fSVenugopal Iyer default: 29200dc2366fSVenugopal Iyer break; 29210dc2366fSVenugopal Iyer 29220dc2366fSVenugopal Iyer } 29230dc2366fSVenugopal Iyer 292469b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82599EB || 29257e579c30SDale Ghent hw->mac.type == ixgbe_mac_X540 || 29267e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550 || 29277e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550EM_x) { 29280dc2366fSVenugopal Iyer /* 29290dc2366fSVenugopal Iyer * Enable Virtualization and Replication. 29300dc2366fSVenugopal Iyer */ 29310dc2366fSVenugopal Iyer vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; 29320dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl); 29330dc2366fSVenugopal Iyer 29340dc2366fSVenugopal Iyer /* 29350dc2366fSVenugopal Iyer * Enable receiving packets to all VFs 29360dc2366fSVenugopal Iyer */ 29370dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL); 29380dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL); 29390dc2366fSVenugopal Iyer } 29400dc2366fSVenugopal Iyer } 29410dc2366fSVenugopal Iyer 29420dc2366fSVenugopal Iyer /* 29437e579c30SDale Ghent * ixgbe_setup_rss_table - Setup RSS table 29447e579c30SDale Ghent */ 29457e579c30SDale Ghent static void 29467e579c30SDale Ghent ixgbe_setup_rss_table(ixgbe_t *ixgbe) 29477e579c30SDale Ghent { 29487e579c30SDale Ghent struct ixgbe_hw *hw = &ixgbe->hw; 29497e579c30SDale Ghent uint32_t i, j; 29507e579c30SDale Ghent uint32_t random; 29517e579c30SDale Ghent uint32_t reta; 29527e579c30SDale Ghent uint32_t ring_per_group; 29537e579c30SDale Ghent uint32_t ring; 29547e579c30SDale Ghent uint32_t table_size; 29557e579c30SDale Ghent uint32_t index_mult; 29567e579c30SDale Ghent uint32_t rxcsum; 29577e579c30SDale Ghent 29587e579c30SDale Ghent /* 29597e579c30SDale Ghent * Set multiplier for RETA setup and table size based on MAC type. 29607e579c30SDale Ghent * RETA table sizes vary by model: 29617e579c30SDale Ghent * 29627e579c30SDale Ghent * 82598, 82599, X540: 128 table entries. 29637e579c30SDale Ghent * X550: 512 table entries. 29647e579c30SDale Ghent */ 29657e579c30SDale Ghent index_mult = 0x1; 29667e579c30SDale Ghent table_size = 128; 29677e579c30SDale Ghent switch (ixgbe->hw.mac.type) { 29687e579c30SDale Ghent case ixgbe_mac_82598EB: 29697e579c30SDale Ghent index_mult = 0x11; 29707e579c30SDale Ghent break; 29717e579c30SDale Ghent case ixgbe_mac_X550: 29727e579c30SDale Ghent case ixgbe_mac_X550EM_x: 29737e579c30SDale Ghent table_size = 512; 29747e579c30SDale Ghent break; 29757e579c30SDale Ghent default: 29767e579c30SDale Ghent break; 29777e579c30SDale Ghent } 29787e579c30SDale Ghent 29797e579c30SDale Ghent /* 29807e579c30SDale Ghent * Fill out RSS redirection table. The configuation of the indices is 29817e579c30SDale Ghent * hardware-dependent. 29827e579c30SDale Ghent * 29837e579c30SDale Ghent * 82598: 8 bits wide containing two 4 bit RSS indices 29847e579c30SDale Ghent * 82599, X540: 8 bits wide containing one 4 bit RSS index 29857e579c30SDale Ghent * X550: 8 bits wide containing one 6 bit RSS index 29867e579c30SDale Ghent */ 29877e579c30SDale Ghent reta = 0; 29887e579c30SDale Ghent ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 29897e579c30SDale Ghent 29907e579c30SDale Ghent for (i = 0, j = 0; i < table_size; i++, j++) { 29917e579c30SDale Ghent if (j == ring_per_group) j = 0; 29927e579c30SDale Ghent 29937e579c30SDale Ghent /* 29947e579c30SDale Ghent * The low 8 bits are for hash value (n+0); 29957e579c30SDale Ghent * The next 8 bits are for hash value (n+1), etc. 29967e579c30SDale Ghent */ 29977e579c30SDale Ghent ring = (j * index_mult); 29987e579c30SDale Ghent reta = reta >> 8; 29997e579c30SDale Ghent reta = reta | (((uint32_t)ring) << 24); 30007e579c30SDale Ghent 300105d069e4SToomas Soome if ((i & 3) == 3) { 30027e579c30SDale Ghent /* 30037e579c30SDale Ghent * The first 128 table entries are programmed into the 30047e579c30SDale Ghent * RETA register, with any beyond that (eg; on X550) 30057e579c30SDale Ghent * into ERETA. 30067e579c30SDale Ghent */ 30077e579c30SDale Ghent if (i < 128) 30087e579c30SDale Ghent IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); 30097e579c30SDale Ghent else 30107e579c30SDale Ghent IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), 30117e579c30SDale Ghent reta); 30127e579c30SDale Ghent reta = 0; 30137e579c30SDale Ghent } 301405d069e4SToomas Soome } 30157e579c30SDale Ghent 30167e579c30SDale Ghent /* 30177e579c30SDale Ghent * Fill out hash function seeds with a random constant 30187e579c30SDale Ghent */ 30197e579c30SDale Ghent for (i = 0; i < 10; i++) { 30207e579c30SDale Ghent (void) random_get_pseudo_bytes((uint8_t *)&random, 30217e579c30SDale Ghent sizeof (uint32_t)); 30227e579c30SDale Ghent IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); 30237e579c30SDale Ghent } 30247e579c30SDale Ghent 30257e579c30SDale Ghent /* 30267e579c30SDale Ghent * Disable Packet Checksum to enable RSS for multiple receive queues. 30277e579c30SDale Ghent * It is an adapter hardware limitation that Packet Checksum is 30287e579c30SDale Ghent * mutually exclusive with RSS. 30297e579c30SDale Ghent */ 30307e579c30SDale Ghent rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); 30317e579c30SDale Ghent rxcsum |= IXGBE_RXCSUM_PCSD; 30327e579c30SDale Ghent rxcsum &= ~IXGBE_RXCSUM_IPPCSE; 30337e579c30SDale Ghent IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); 30347e579c30SDale Ghent } 30357e579c30SDale Ghent 30367e579c30SDale Ghent /* 30379da57d7bSbt150084 * ixgbe_init_unicst - Initialize the unicast addresses. 30389da57d7bSbt150084 */ 30399da57d7bSbt150084 static void 30409da57d7bSbt150084 ixgbe_init_unicst(ixgbe_t *ixgbe) 30419da57d7bSbt150084 { 30429da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 3043da14cebeSEric Cheng uint8_t *mac_addr; 30449da57d7bSbt150084 int slot; 30459da57d7bSbt150084 /* 30469da57d7bSbt150084 * Here we should consider two situations: 30479da57d7bSbt150084 * 3048da14cebeSEric Cheng * 1. Chipset is initialized at the first time, 3049da14cebeSEric Cheng * Clear all the multiple unicast addresses. 30509da57d7bSbt150084 * 30519da57d7bSbt150084 * 2. Chipset is reset 30529da57d7bSbt150084 * Recover the multiple unicast addresses from the 30539da57d7bSbt150084 * software data structure to the RAR registers. 30549da57d7bSbt150084 */ 30559da57d7bSbt150084 if (!ixgbe->unicst_init) { 30569da57d7bSbt150084 /* 30579da57d7bSbt150084 * Initialize the multiple unicast addresses 30589da57d7bSbt150084 */ 30590dc2366fSVenugopal Iyer ixgbe->unicst_total = hw->mac.num_rar_entries; 3060da14cebeSEric Cheng ixgbe->unicst_avail = ixgbe->unicst_total; 3061da14cebeSEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 3062da14cebeSEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr; 3063da14cebeSEric Cheng bzero(mac_addr, ETHERADDRL); 3064da14cebeSEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, NULL, NULL); 30659da57d7bSbt150084 ixgbe->unicst_addr[slot].mac.set = 0; 3066da14cebeSEric Cheng } 30679da57d7bSbt150084 ixgbe->unicst_init = B_TRUE; 30689da57d7bSbt150084 } else { 30699da57d7bSbt150084 /* Re-configure the RAR registers */ 3070da14cebeSEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 3071da14cebeSEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr; 3072da14cebeSEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 1) { 3073da14cebeSEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, 30740dc2366fSVenugopal Iyer ixgbe->unicst_addr[slot].mac.group_index, 30750dc2366fSVenugopal Iyer IXGBE_RAH_AV); 3076da14cebeSEric Cheng } else { 3077da14cebeSEric Cheng bzero(mac_addr, ETHERADDRL); 3078da14cebeSEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr, 3079da14cebeSEric Cheng NULL, NULL); 30809da57d7bSbt150084 } 30819da57d7bSbt150084 } 3082da14cebeSEric Cheng } 3083da14cebeSEric Cheng } 3084da14cebeSEric Cheng 30859da57d7bSbt150084 /* 3086da14cebeSEric Cheng * ixgbe_unicst_find - Find the slot for the specified unicast address 3087da14cebeSEric Cheng */ 3088da14cebeSEric Cheng int 3089da14cebeSEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr) 3090da14cebeSEric Cheng { 3091da14cebeSEric Cheng int slot; 3092da14cebeSEric Cheng 3093da14cebeSEric Cheng ASSERT(mutex_owned(&ixgbe->gen_lock)); 3094da14cebeSEric Cheng 3095da14cebeSEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) { 3096da14cebeSEric Cheng if (bcmp(ixgbe->unicst_addr[slot].mac.addr, 3097da14cebeSEric Cheng mac_addr, ETHERADDRL) == 0) 3098da14cebeSEric Cheng return (slot); 3099da14cebeSEric Cheng } 3100da14cebeSEric Cheng 3101da14cebeSEric Cheng return (-1); 3102da14cebeSEric Cheng } 3103da14cebeSEric Cheng 3104da14cebeSEric Cheng /* 31059da57d7bSbt150084 * ixgbe_multicst_add - Add a multicst address. 31069da57d7bSbt150084 */ 31079da57d7bSbt150084 int 31089da57d7bSbt150084 ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr) 31099da57d7bSbt150084 { 31109da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 31119da57d7bSbt150084 31129da57d7bSbt150084 if ((multiaddr[0] & 01) == 0) { 31139da57d7bSbt150084 return (EINVAL); 31149da57d7bSbt150084 } 31159da57d7bSbt150084 31169da57d7bSbt150084 if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) { 31179da57d7bSbt150084 return (ENOENT); 31189da57d7bSbt150084 } 31199da57d7bSbt150084 31209da57d7bSbt150084 bcopy(multiaddr, 31219da57d7bSbt150084 &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL); 31229da57d7bSbt150084 ixgbe->mcast_count++; 31239da57d7bSbt150084 31249da57d7bSbt150084 /* 31259da57d7bSbt150084 * Update the multicast table in the hardware 31269da57d7bSbt150084 */ 31279da57d7bSbt150084 ixgbe_setup_multicst(ixgbe); 31289da57d7bSbt150084 31299da57d7bSbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 31309da57d7bSbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 31319da57d7bSbt150084 return (EIO); 31329da57d7bSbt150084 } 31339da57d7bSbt150084 31349da57d7bSbt150084 return (0); 31359da57d7bSbt150084 } 31369da57d7bSbt150084 31379da57d7bSbt150084 /* 31389da57d7bSbt150084 * ixgbe_multicst_remove - Remove a multicst address. 31399da57d7bSbt150084 */ 31409da57d7bSbt150084 int 31419da57d7bSbt150084 ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr) 31429da57d7bSbt150084 { 31439da57d7bSbt150084 int i; 31449da57d7bSbt150084 31459da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 31469da57d7bSbt150084 31479da57d7bSbt150084 for (i = 0; i < ixgbe->mcast_count; i++) { 31489da57d7bSbt150084 if (bcmp(multiaddr, &ixgbe->mcast_table[i], 31499da57d7bSbt150084 ETHERADDRL) == 0) { 31509da57d7bSbt150084 for (i++; i < ixgbe->mcast_count; i++) { 31519da57d7bSbt150084 ixgbe->mcast_table[i - 1] = 31529da57d7bSbt150084 ixgbe->mcast_table[i]; 31539da57d7bSbt150084 } 31549da57d7bSbt150084 ixgbe->mcast_count--; 31559da57d7bSbt150084 break; 31569da57d7bSbt150084 } 31579da57d7bSbt150084 } 31589da57d7bSbt150084 31599da57d7bSbt150084 /* 31609da57d7bSbt150084 * Update the multicast table in the hardware 31619da57d7bSbt150084 */ 31629da57d7bSbt150084 ixgbe_setup_multicst(ixgbe); 31639da57d7bSbt150084 31649da57d7bSbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 31659da57d7bSbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 31669da57d7bSbt150084 return (EIO); 31679da57d7bSbt150084 } 31689da57d7bSbt150084 31699da57d7bSbt150084 return (0); 31709da57d7bSbt150084 } 31719da57d7bSbt150084 31729da57d7bSbt150084 /* 31739da57d7bSbt150084 * ixgbe_setup_multicast - Setup multicast data structures. 31749da57d7bSbt150084 * 31759da57d7bSbt150084 * This routine initializes all of the multicast related structures 31769da57d7bSbt150084 * and save them in the hardware registers. 31779da57d7bSbt150084 */ 31789da57d7bSbt150084 static void 31799da57d7bSbt150084 ixgbe_setup_multicst(ixgbe_t *ixgbe) 31809da57d7bSbt150084 { 31819da57d7bSbt150084 uint8_t *mc_addr_list; 31829da57d7bSbt150084 uint32_t mc_addr_count; 31839da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 31849da57d7bSbt150084 31859da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 31869da57d7bSbt150084 31879da57d7bSbt150084 ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES); 31889da57d7bSbt150084 31899da57d7bSbt150084 mc_addr_list = (uint8_t *)ixgbe->mcast_table; 31909da57d7bSbt150084 mc_addr_count = ixgbe->mcast_count; 31919da57d7bSbt150084 31929da57d7bSbt150084 /* 31939da57d7bSbt150084 * Update the multicast addresses to the MTA registers 31949da57d7bSbt150084 */ 31959da57d7bSbt150084 (void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count, 319669b5a878SDan McDonald ixgbe_mc_table_itr, TRUE); 31979da57d7bSbt150084 } 31989da57d7bSbt150084 31999da57d7bSbt150084 /* 32000dc2366fSVenugopal Iyer * ixgbe_setup_vmdq_rss_conf - Configure vmdq and rss (number and mode). 32010dc2366fSVenugopal Iyer * 32020dc2366fSVenugopal Iyer * Configure the rx classification mode (vmdq & rss) and vmdq & rss numbers. 32030dc2366fSVenugopal Iyer * Different chipsets may have different allowed configuration of vmdq and rss. 32040dc2366fSVenugopal Iyer */ 32050dc2366fSVenugopal Iyer static void 32060dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe) 32070dc2366fSVenugopal Iyer { 32080dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw; 32090dc2366fSVenugopal Iyer uint32_t ring_per_group; 32100dc2366fSVenugopal Iyer 32110dc2366fSVenugopal Iyer switch (hw->mac.type) { 32120dc2366fSVenugopal Iyer case ixgbe_mac_82598EB: 32130dc2366fSVenugopal Iyer /* 32140dc2366fSVenugopal Iyer * 82598 supports the following combination: 32150dc2366fSVenugopal Iyer * vmdq no. x rss no. 32160dc2366fSVenugopal Iyer * [5..16] x 1 32170dc2366fSVenugopal Iyer * [1..4] x [1..16] 32180dc2366fSVenugopal Iyer * However 8 rss queue per pool (vmdq) is sufficient for 32190dc2366fSVenugopal Iyer * most cases. 32200dc2366fSVenugopal Iyer */ 32210dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 32220dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups > 4) { 32230dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups; 32240dc2366fSVenugopal Iyer } else { 32250dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups * 32260dc2366fSVenugopal Iyer min(8, ring_per_group); 32270dc2366fSVenugopal Iyer } 32280dc2366fSVenugopal Iyer 32290dc2366fSVenugopal Iyer break; 32300dc2366fSVenugopal Iyer 32310dc2366fSVenugopal Iyer case ixgbe_mac_82599EB: 323269b5a878SDan McDonald case ixgbe_mac_X540: 32337e579c30SDale Ghent case ixgbe_mac_X550: 32347e579c30SDale Ghent case ixgbe_mac_X550EM_x: 32350dc2366fSVenugopal Iyer /* 32360dc2366fSVenugopal Iyer * 82599 supports the following combination: 32370dc2366fSVenugopal Iyer * vmdq no. x rss no. 32380dc2366fSVenugopal Iyer * [33..64] x [1..2] 32390dc2366fSVenugopal Iyer * [2..32] x [1..4] 32400dc2366fSVenugopal Iyer * 1 x [1..16] 32410dc2366fSVenugopal Iyer * However 8 rss queue per pool (vmdq) is sufficient for 32420dc2366fSVenugopal Iyer * most cases. 324369b5a878SDan McDonald * 32447e579c30SDale Ghent * For now, treat X540 and X550 like the 82599. 32450dc2366fSVenugopal Iyer */ 32460dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 32470dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups == 1) { 32480dc2366fSVenugopal Iyer ixgbe->num_rx_rings = min(8, ring_per_group); 32490dc2366fSVenugopal Iyer } else if (ixgbe->num_rx_groups <= 32) { 32500dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups * 32510dc2366fSVenugopal Iyer min(4, ring_per_group); 32520dc2366fSVenugopal Iyer } else if (ixgbe->num_rx_groups <= 64) { 32530dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups * 32540dc2366fSVenugopal Iyer min(2, ring_per_group); 32550dc2366fSVenugopal Iyer } 32560dc2366fSVenugopal Iyer break; 32570dc2366fSVenugopal Iyer 32580dc2366fSVenugopal Iyer default: 32590dc2366fSVenugopal Iyer break; 32600dc2366fSVenugopal Iyer } 32610dc2366fSVenugopal Iyer 32620dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 32630dc2366fSVenugopal Iyer 32640dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups == 1 && ring_per_group == 1) { 32650dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 32660dc2366fSVenugopal Iyer } else if (ixgbe->num_rx_groups != 1 && ring_per_group == 1) { 32670dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ; 32680dc2366fSVenugopal Iyer } else if (ixgbe->num_rx_groups != 1 && ring_per_group != 1) { 32690dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ_RSS; 32700dc2366fSVenugopal Iyer } else { 32710dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_RSS; 32720dc2366fSVenugopal Iyer } 32730dc2366fSVenugopal Iyer 327419843f01SPaul Guo IXGBE_DEBUGLOG_2(ixgbe, "rx group number:%d, rx ring number:%d", 32750dc2366fSVenugopal Iyer ixgbe->num_rx_groups, ixgbe->num_rx_rings); 32760dc2366fSVenugopal Iyer } 32770dc2366fSVenugopal Iyer 32780dc2366fSVenugopal Iyer /* 32799da57d7bSbt150084 * ixgbe_get_conf - Get driver configurations set in driver.conf. 32809da57d7bSbt150084 * 32819da57d7bSbt150084 * This routine gets user-configured values out of the configuration 32829da57d7bSbt150084 * file ixgbe.conf. 32839da57d7bSbt150084 * 32849da57d7bSbt150084 * For each configurable value, there is a minimum, a maximum, and a 32859da57d7bSbt150084 * default. 32869da57d7bSbt150084 * If user does not configure a value, use the default. 32879da57d7bSbt150084 * If user configures below the minimum, use the minumum. 32889da57d7bSbt150084 * If user configures above the maximum, use the maxumum. 32899da57d7bSbt150084 */ 32909da57d7bSbt150084 static void 32919da57d7bSbt150084 ixgbe_get_conf(ixgbe_t *ixgbe) 32929da57d7bSbt150084 { 32939da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 32949da57d7bSbt150084 uint32_t flow_control; 32959da57d7bSbt150084 32969da57d7bSbt150084 /* 32979da57d7bSbt150084 * ixgbe driver supports the following user configurations: 32989da57d7bSbt150084 * 32999da57d7bSbt150084 * Jumbo frame configuration: 33009da57d7bSbt150084 * default_mtu 33019da57d7bSbt150084 * 33029da57d7bSbt150084 * Ethernet flow control configuration: 33039da57d7bSbt150084 * flow_control 33049da57d7bSbt150084 * 33059da57d7bSbt150084 * Multiple rings configurations: 33069da57d7bSbt150084 * tx_queue_number 33079da57d7bSbt150084 * tx_ring_size 33089da57d7bSbt150084 * rx_queue_number 33099da57d7bSbt150084 * rx_ring_size 33109da57d7bSbt150084 * 33119da57d7bSbt150084 * Call ixgbe_get_prop() to get the value for a specific 33129da57d7bSbt150084 * configuration parameter. 33139da57d7bSbt150084 */ 33149da57d7bSbt150084 33159da57d7bSbt150084 /* 33169da57d7bSbt150084 * Jumbo frame configuration - max_frame_size controls host buffer 33179da57d7bSbt150084 * allocation, so includes MTU, ethernet header, vlan tag and 33189da57d7bSbt150084 * frame check sequence. 33199da57d7bSbt150084 */ 33209da57d7bSbt150084 ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU, 33211fedc51fSWinson Wang - Sun Microsystems - Beijing China MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU); 33229da57d7bSbt150084 33239da57d7bSbt150084 ixgbe->max_frame_size = ixgbe->default_mtu + 33249da57d7bSbt150084 sizeof (struct ether_vlan_header) + ETHERFCSL; 33259da57d7bSbt150084 33269da57d7bSbt150084 /* 33279da57d7bSbt150084 * Ethernet flow control configuration 33289da57d7bSbt150084 */ 33299da57d7bSbt150084 flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL, 3330da14cebeSEric Cheng ixgbe_fc_none, 3, ixgbe_fc_none); 33319da57d7bSbt150084 if (flow_control == 3) 33329da57d7bSbt150084 flow_control = ixgbe_fc_default; 33339da57d7bSbt150084 333473cd555cSBin Tu - Sun Microsystems - Beijing China /* 333573cd555cSBin Tu - Sun Microsystems - Beijing China * fc.requested mode is what the user requests. After autoneg, 333673cd555cSBin Tu - Sun Microsystems - Beijing China * fc.current_mode will be the flow_control mode that was negotiated. 333773cd555cSBin Tu - Sun Microsystems - Beijing China */ 333873cd555cSBin Tu - Sun Microsystems - Beijing China hw->fc.requested_mode = flow_control; 33399da57d7bSbt150084 33409da57d7bSbt150084 /* 33419da57d7bSbt150084 * Multiple rings configurations 33429da57d7bSbt150084 */ 33439da57d7bSbt150084 ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM, 334413740cb2SPaul Guo ixgbe->capab->min_tx_que_num, 334513740cb2SPaul Guo ixgbe->capab->max_tx_que_num, 334613740cb2SPaul Guo ixgbe->capab->def_tx_que_num); 33479da57d7bSbt150084 ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE, 33489da57d7bSbt150084 MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE); 33499da57d7bSbt150084 33509da57d7bSbt150084 ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM, 335113740cb2SPaul Guo ixgbe->capab->min_rx_que_num, 335213740cb2SPaul Guo ixgbe->capab->max_rx_que_num, 335313740cb2SPaul Guo ixgbe->capab->def_rx_que_num); 33549da57d7bSbt150084 ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE, 33559da57d7bSbt150084 MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE); 33569da57d7bSbt150084 33579da57d7bSbt150084 /* 3358da14cebeSEric Cheng * Multiple groups configuration 3359da14cebeSEric Cheng */ 3360da14cebeSEric Cheng ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM, 33610dc2366fSVenugopal Iyer ixgbe->capab->min_rx_grp_num, ixgbe->capab->max_rx_grp_num, 33620dc2366fSVenugopal Iyer ixgbe->capab->def_rx_grp_num); 3363da14cebeSEric Cheng 3364da14cebeSEric Cheng ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE, 3365da14cebeSEric Cheng 0, 1, DEFAULT_MR_ENABLE); 3366da14cebeSEric Cheng 3367da14cebeSEric Cheng if (ixgbe->mr_enable == B_FALSE) { 3368da14cebeSEric Cheng ixgbe->num_tx_rings = 1; 3369da14cebeSEric Cheng ixgbe->num_rx_rings = 1; 3370da14cebeSEric Cheng ixgbe->num_rx_groups = 1; 33710dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 33720dc2366fSVenugopal Iyer } else { 33730dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups * 33740dc2366fSVenugopal Iyer max(ixgbe->num_rx_rings / ixgbe->num_rx_groups, 1); 33750dc2366fSVenugopal Iyer /* 33760dc2366fSVenugopal Iyer * The combination of num_rx_rings and num_rx_groups 33770dc2366fSVenugopal Iyer * may be not supported by h/w. We need to adjust 33780dc2366fSVenugopal Iyer * them to appropriate values. 33790dc2366fSVenugopal Iyer */ 33800dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss_conf(ixgbe); 3381da14cebeSEric Cheng } 3382da14cebeSEric Cheng 3383da14cebeSEric Cheng /* 33849da57d7bSbt150084 * Tunable used to force an interrupt type. The only use is 33859da57d7bSbt150084 * for testing of the lesser interrupt types. 33869da57d7bSbt150084 * 0 = don't force interrupt type 3387da14cebeSEric Cheng * 1 = force interrupt type MSI-X 33889da57d7bSbt150084 * 2 = force interrupt type MSI 33899da57d7bSbt150084 * 3 = force interrupt type Legacy 33909da57d7bSbt150084 */ 33919da57d7bSbt150084 ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE, 33929da57d7bSbt150084 IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE); 33939da57d7bSbt150084 33949da57d7bSbt150084 ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE, 3395c971fb7eSgg161487 0, 1, DEFAULT_TX_HCKSUM_ENABLE); 33969da57d7bSbt150084 ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE, 3397c971fb7eSgg161487 0, 1, DEFAULT_RX_HCKSUM_ENABLE); 33989da57d7bSbt150084 ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE, 3399c971fb7eSgg161487 0, 1, DEFAULT_LSO_ENABLE); 3400ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe->lro_enable = ixgbe_get_prop(ixgbe, PROP_LRO_ENABLE, 3401ffd8e883SWinson Wang - Sun Microsystems - Beijing China 0, 1, DEFAULT_LRO_ENABLE); 34029da57d7bSbt150084 ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE, 3403c971fb7eSgg161487 0, 1, DEFAULT_TX_HEAD_WB_ENABLE); 34045b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->relax_order_enable = ixgbe_get_prop(ixgbe, 34055b6dd21fSchenlu chen - Sun Microsystems - Beijing China PROP_RELAX_ORDER_ENABLE, 0, 1, DEFAULT_RELAX_ORDER_ENABLE); 3406c971fb7eSgg161487 34077e579c30SDale Ghent /* Head Write Back not recommended for 82599, X540 and X550 */ 340869b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82599EB || 34097e579c30SDale Ghent hw->mac.type == ixgbe_mac_X540 || 34107e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550 || 34117e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550EM_x) { 341273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->tx_head_wb_enable = B_FALSE; 341373cd555cSBin Tu - Sun Microsystems - Beijing China } 341473cd555cSBin Tu - Sun Microsystems - Beijing China 3415c971fb7eSgg161487 /* 3416c971fb7eSgg161487 * ixgbe LSO needs the tx h/w checksum support. 3417c971fb7eSgg161487 * LSO will be disabled if tx h/w checksum is not 3418c971fb7eSgg161487 * enabled. 3419c971fb7eSgg161487 */ 3420c971fb7eSgg161487 if (ixgbe->tx_hcksum_enable == B_FALSE) { 3421c971fb7eSgg161487 ixgbe->lso_enable = B_FALSE; 3422c971fb7eSgg161487 } 34239da57d7bSbt150084 3424ffd8e883SWinson Wang - Sun Microsystems - Beijing China /* 3425ffd8e883SWinson Wang - Sun Microsystems - Beijing China * ixgbe LRO needs the rx h/w checksum support. 3426ffd8e883SWinson Wang - Sun Microsystems - Beijing China * LRO will be disabled if rx h/w checksum is not 3427ffd8e883SWinson Wang - Sun Microsystems - Beijing China * enabled. 3428ffd8e883SWinson Wang - Sun Microsystems - Beijing China */ 3429ffd8e883SWinson Wang - Sun Microsystems - Beijing China if (ixgbe->rx_hcksum_enable == B_FALSE) { 3430ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe->lro_enable = B_FALSE; 3431ffd8e883SWinson Wang - Sun Microsystems - Beijing China } 3432ffd8e883SWinson Wang - Sun Microsystems - Beijing China 3433ffd8e883SWinson Wang - Sun Microsystems - Beijing China /* 34347e579c30SDale Ghent * ixgbe LRO only supported by 82599, X540 and X550 3435ffd8e883SWinson Wang - Sun Microsystems - Beijing China */ 343669b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82598EB) { 3437ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe->lro_enable = B_FALSE; 3438ffd8e883SWinson Wang - Sun Microsystems - Beijing China } 34399da57d7bSbt150084 ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD, 34409da57d7bSbt150084 MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD, 34419da57d7bSbt150084 DEFAULT_TX_COPY_THRESHOLD); 34429da57d7bSbt150084 ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe, 34439da57d7bSbt150084 PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD, 34449da57d7bSbt150084 MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD); 34459da57d7bSbt150084 ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe, 34469da57d7bSbt150084 PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD, 34479da57d7bSbt150084 MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD); 34489da57d7bSbt150084 ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe, 34499da57d7bSbt150084 PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD, 34509da57d7bSbt150084 MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD); 34519da57d7bSbt150084 34529da57d7bSbt150084 ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD, 34539da57d7bSbt150084 MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD, 34549da57d7bSbt150084 DEFAULT_RX_COPY_THRESHOLD); 34559da57d7bSbt150084 ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR, 34569da57d7bSbt150084 MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR, 34579da57d7bSbt150084 DEFAULT_RX_LIMIT_PER_INTR); 34589da57d7bSbt150084 3459ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING, 3460ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->min_intr_throttle, 3461ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->max_intr_throttle, 3462ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->def_intr_throttle); 3463185c5677SPaul Guo /* 34647e579c30SDale Ghent * 82599, X540 and X550 require the interrupt throttling rate is 34657e579c30SDale Ghent * a multiple of 8. This is enforced by the register definiton. 3466185c5677SPaul Guo */ 34677e579c30SDale Ghent if (hw->mac.type == ixgbe_mac_82599EB || 34687e579c30SDale Ghent hw->mac.type == ixgbe_mac_X540 || 34697e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550 || 34707e579c30SDale Ghent hw->mac.type == ixgbe_mac_X550EM_x) 3471ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8; 347243fab1a9SSaso Kiselkov 347343fab1a9SSaso Kiselkov hw->allow_unsupported_sfp = ixgbe_get_prop(ixgbe, 347443fab1a9SSaso Kiselkov PROP_ALLOW_UNSUPPORTED_SFP, 0, 1, DEFAULT_ALLOW_UNSUPPORTED_SFP); 347573cd555cSBin Tu - Sun Microsystems - Beijing China } 3476ea65739eSchenlu chen - Sun Microsystems - Beijing China 3477ea65739eSchenlu chen - Sun Microsystems - Beijing China static void 3478ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_init_params(ixgbe_t *ixgbe) 3479ea65739eSchenlu chen - Sun Microsystems - Beijing China { 34807e579c30SDale Ghent struct ixgbe_hw *hw = &ixgbe->hw; 34817e579c30SDale Ghent ixgbe_link_speed speeds_supported = 0; 34827e579c30SDale Ghent boolean_t negotiate; 34837e579c30SDale Ghent 34847e579c30SDale Ghent /* 34857e579c30SDale Ghent * Get a list of speeds the adapter supports. If the hw struct hasn't 34867e579c30SDale Ghent * been populated with this information yet, retrieve it from the 34877e579c30SDale Ghent * adapter and save it to our own variable. 34887e579c30SDale Ghent * 34897e579c30SDale Ghent * On certain adapters, such as ones which use SFPs, the contents of 34907e579c30SDale Ghent * hw->phy.speeds_supported (and hw->phy.autoneg_advertised) are not 34917e579c30SDale Ghent * updated, so we must rely on calling ixgbe_get_link_capabilities() 34927e579c30SDale Ghent * in order to ascertain the speeds which we are capable of supporting, 34937e579c30SDale Ghent * and in the case of SFP-equipped adapters, which speed we are 34947e579c30SDale Ghent * advertising. If ixgbe_get_link_capabilities() fails for some reason, 34957e579c30SDale Ghent * we'll go with a default list of speeds as a last resort. 34967e579c30SDale Ghent */ 34977e579c30SDale Ghent speeds_supported = hw->phy.speeds_supported; 34987e579c30SDale Ghent 34997e579c30SDale Ghent if (speeds_supported == 0) { 35007e579c30SDale Ghent if (ixgbe_get_link_capabilities(hw, &speeds_supported, 35017e579c30SDale Ghent &negotiate) != IXGBE_SUCCESS) { 35027e579c30SDale Ghent if (hw->mac.type == ixgbe_mac_82598EB) { 35037e579c30SDale Ghent speeds_supported = 35047e579c30SDale Ghent IXGBE_LINK_SPEED_82598_AUTONEG; 35057e579c30SDale Ghent } else { 35067e579c30SDale Ghent speeds_supported = 35077e579c30SDale Ghent IXGBE_LINK_SPEED_82599_AUTONEG; 35087e579c30SDale Ghent } 35097e579c30SDale Ghent } 35107e579c30SDale Ghent } 35117e579c30SDale Ghent ixgbe->speeds_supported = speeds_supported; 35127e579c30SDale Ghent 35137e579c30SDale Ghent /* 35147e579c30SDale Ghent * By default, all supported speeds are enabled and advertised. 35157e579c30SDale Ghent */ 35167e579c30SDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_10GB_FULL) { 3517ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_en_10000fdx_cap = 1; 3518ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_10000fdx_cap = 1; 35197e579c30SDale Ghent } else { 35207e579c30SDale Ghent ixgbe->param_en_10000fdx_cap = 0; 35217e579c30SDale Ghent ixgbe->param_adv_10000fdx_cap = 0; 35227e579c30SDale Ghent } 35237e579c30SDale Ghent 35247e579c30SDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_5GB_FULL) { 35257e579c30SDale Ghent ixgbe->param_en_5000fdx_cap = 1; 35267e579c30SDale Ghent ixgbe->param_adv_5000fdx_cap = 1; 35277e579c30SDale Ghent } else { 35287e579c30SDale Ghent ixgbe->param_en_5000fdx_cap = 0; 35297e579c30SDale Ghent ixgbe->param_adv_5000fdx_cap = 0; 35307e579c30SDale Ghent } 35317e579c30SDale Ghent 35327e579c30SDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_2_5GB_FULL) { 35337e579c30SDale Ghent ixgbe->param_en_2500fdx_cap = 1; 35347e579c30SDale Ghent ixgbe->param_adv_2500fdx_cap = 1; 35357e579c30SDale Ghent } else { 35367e579c30SDale Ghent ixgbe->param_en_2500fdx_cap = 0; 35377e579c30SDale Ghent ixgbe->param_adv_2500fdx_cap = 0; 35387e579c30SDale Ghent } 35397e579c30SDale Ghent 35407e579c30SDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_1GB_FULL) { 35417e579c30SDale Ghent ixgbe->param_en_1000fdx_cap = 1; 3542ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_1000fdx_cap = 1; 35437e579c30SDale Ghent } else { 35447e579c30SDale Ghent ixgbe->param_en_1000fdx_cap = 0; 35457e579c30SDale Ghent ixgbe->param_adv_1000fdx_cap = 0; 35467e579c30SDale Ghent } 35477e579c30SDale Ghent 35487e579c30SDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_100_FULL) { 35497e579c30SDale Ghent ixgbe->param_en_100fdx_cap = 1; 3550ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_100fdx_cap = 1; 35517e579c30SDale Ghent } else { 35527e579c30SDale Ghent ixgbe->param_en_100fdx_cap = 0; 35537e579c30SDale Ghent ixgbe->param_adv_100fdx_cap = 0; 35547e579c30SDale Ghent } 3555ea65739eSchenlu chen - Sun Microsystems - Beijing China 3556ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_pause_cap = 1; 3557ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_asym_pause_cap = 1; 3558ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_rem_fault = 0; 3559ea65739eSchenlu chen - Sun Microsystems - Beijing China 3560ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_autoneg_cap = 1; 3561ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_pause_cap = 1; 3562ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_asym_pause_cap = 1; 3563ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_rem_fault = 0; 3564ea65739eSchenlu chen - Sun Microsystems - Beijing China 3565ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_10000fdx_cap = 0; 35667e579c30SDale Ghent ixgbe->param_lp_5000fdx_cap = 0; 35677e579c30SDale Ghent ixgbe->param_lp_2500fdx_cap = 0; 3568ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_1000fdx_cap = 0; 3569ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_100fdx_cap = 0; 3570ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_autoneg_cap = 0; 3571ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_pause_cap = 0; 3572ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_asym_pause_cap = 0; 3573ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_rem_fault = 0; 35749da57d7bSbt150084 } 35759da57d7bSbt150084 35769da57d7bSbt150084 /* 35779da57d7bSbt150084 * ixgbe_get_prop - Get a property value out of the configuration file 35789da57d7bSbt150084 * ixgbe.conf. 35799da57d7bSbt150084 * 35809da57d7bSbt150084 * Caller provides the name of the property, a default value, a minimum 35819da57d7bSbt150084 * value, and a maximum value. 35829da57d7bSbt150084 * 35839da57d7bSbt150084 * Return configured value of the property, with default, minimum and 35849da57d7bSbt150084 * maximum properly applied. 35859da57d7bSbt150084 */ 35869da57d7bSbt150084 static int 35879da57d7bSbt150084 ixgbe_get_prop(ixgbe_t *ixgbe, 35889da57d7bSbt150084 char *propname, /* name of the property */ 35899da57d7bSbt150084 int minval, /* minimum acceptable value */ 35909da57d7bSbt150084 int maxval, /* maximim acceptable value */ 35919da57d7bSbt150084 int defval) /* default value */ 35929da57d7bSbt150084 { 35939da57d7bSbt150084 int value; 35949da57d7bSbt150084 35959da57d7bSbt150084 /* 35969da57d7bSbt150084 * Call ddi_prop_get_int() to read the conf settings 35979da57d7bSbt150084 */ 35989da57d7bSbt150084 value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip, 35999da57d7bSbt150084 DDI_PROP_DONTPASS, propname, defval); 36009da57d7bSbt150084 if (value > maxval) 36019da57d7bSbt150084 value = maxval; 36029da57d7bSbt150084 36039da57d7bSbt150084 if (value < minval) 36049da57d7bSbt150084 value = minval; 36059da57d7bSbt150084 36069da57d7bSbt150084 return (value); 36079da57d7bSbt150084 } 36089da57d7bSbt150084 36099da57d7bSbt150084 /* 36109da57d7bSbt150084 * ixgbe_driver_setup_link - Using the link properties to setup the link. 36119da57d7bSbt150084 */ 36129da57d7bSbt150084 int 36139da57d7bSbt150084 ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw) 36149da57d7bSbt150084 { 36157e579c30SDale Ghent struct ixgbe_hw *hw = &ixgbe->hw; 36167e579c30SDale Ghent ixgbe_link_speed advertised = 0; 36179da57d7bSbt150084 36189da57d7bSbt150084 /* 36197e579c30SDale Ghent * Assemble a list of enabled speeds to auto-negotiate with. 36209da57d7bSbt150084 */ 36217e579c30SDale Ghent if (ixgbe->param_en_10000fdx_cap == 1) 36227e579c30SDale Ghent advertised |= IXGBE_LINK_SPEED_10GB_FULL; 36239da57d7bSbt150084 36247e579c30SDale Ghent if (ixgbe->param_en_5000fdx_cap == 1) 36257e579c30SDale Ghent advertised |= IXGBE_LINK_SPEED_5GB_FULL; 36269da57d7bSbt150084 36277e579c30SDale Ghent if (ixgbe->param_en_2500fdx_cap == 1) 36287e579c30SDale Ghent advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; 36299da57d7bSbt150084 36307e579c30SDale Ghent if (ixgbe->param_en_1000fdx_cap == 1) 36317e579c30SDale Ghent advertised |= IXGBE_LINK_SPEED_1GB_FULL; 36329da57d7bSbt150084 36337e579c30SDale Ghent if (ixgbe->param_en_100fdx_cap == 1) 36347e579c30SDale Ghent advertised |= IXGBE_LINK_SPEED_100_FULL; 36357e579c30SDale Ghent 36367e579c30SDale Ghent /* 36377e579c30SDale Ghent * As a last resort, autoneg with a default list of speeds. 36387e579c30SDale Ghent */ 36397e579c30SDale Ghent if (ixgbe->param_adv_autoneg_cap == 1 && advertised == 0) { 36407e579c30SDale Ghent ixgbe_notice(ixgbe, "Invalid link settings. Setting link " 36417e579c30SDale Ghent "to autonegotiate with full capabilities."); 36427e579c30SDale Ghent 36437e579c30SDale Ghent if (hw->mac.type == ixgbe_mac_82598EB) 36447e579c30SDale Ghent advertised = IXGBE_LINK_SPEED_82598_AUTONEG; 36457e579c30SDale Ghent else 36467e579c30SDale Ghent advertised = IXGBE_LINK_SPEED_82599_AUTONEG; 36479da57d7bSbt150084 } 36489da57d7bSbt150084 36499da57d7bSbt150084 if (setup_hw) { 36507e579c30SDale Ghent if (ixgbe_setup_link(&ixgbe->hw, advertised, 36517e579c30SDale Ghent ixgbe->param_adv_autoneg_cap) != IXGBE_SUCCESS) { 365273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_notice(ixgbe, "Setup link failed on this " 365373cd555cSBin Tu - Sun Microsystems - Beijing China "device."); 36549da57d7bSbt150084 return (IXGBE_FAILURE); 36559da57d7bSbt150084 } 365673cd555cSBin Tu - Sun Microsystems - Beijing China } 36579da57d7bSbt150084 36589da57d7bSbt150084 return (IXGBE_SUCCESS); 36599da57d7bSbt150084 } 36609da57d7bSbt150084 36619da57d7bSbt150084 /* 366262e6e1adSPaul Guo * ixgbe_driver_link_check - Link status processing. 366362e6e1adSPaul Guo * 366462e6e1adSPaul Guo * This function can be called in both kernel context and interrupt context 36659da57d7bSbt150084 */ 366613740cb2SPaul Guo static void 366762e6e1adSPaul Guo ixgbe_driver_link_check(ixgbe_t *ixgbe) 36689da57d7bSbt150084 { 36699da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 36709da57d7bSbt150084 ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN; 36719da57d7bSbt150084 boolean_t link_up = B_FALSE; 36729da57d7bSbt150084 boolean_t link_changed = B_FALSE; 36739da57d7bSbt150084 367462e6e1adSPaul Guo ASSERT(mutex_owned(&ixgbe->gen_lock)); 36759da57d7bSbt150084 36767e579c30SDale Ghent (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE); 36779da57d7bSbt150084 if (link_up) { 367862e6e1adSPaul Guo ixgbe->link_check_complete = B_TRUE; 367962e6e1adSPaul Guo 368073cd555cSBin Tu - Sun Microsystems - Beijing China /* Link is up, enable flow control settings */ 368169b5a878SDan McDonald (void) ixgbe_fc_enable(hw); 368273cd555cSBin Tu - Sun Microsystems - Beijing China 36839da57d7bSbt150084 /* 36849da57d7bSbt150084 * The Link is up, check whether it was marked as down earlier 36859da57d7bSbt150084 */ 36869da57d7bSbt150084 if (ixgbe->link_state != LINK_STATE_UP) { 36879da57d7bSbt150084 switch (speed) { 36889da57d7bSbt150084 case IXGBE_LINK_SPEED_10GB_FULL: 36899da57d7bSbt150084 ixgbe->link_speed = SPEED_10GB; 36909da57d7bSbt150084 break; 36917e579c30SDale Ghent case IXGBE_LINK_SPEED_5GB_FULL: 36927e579c30SDale Ghent ixgbe->link_speed = SPEED_5GB; 36937e579c30SDale Ghent break; 36947e579c30SDale Ghent case IXGBE_LINK_SPEED_2_5GB_FULL: 36957e579c30SDale Ghent ixgbe->link_speed = SPEED_2_5GB; 36967e579c30SDale Ghent break; 36979da57d7bSbt150084 case IXGBE_LINK_SPEED_1GB_FULL: 36989da57d7bSbt150084 ixgbe->link_speed = SPEED_1GB; 36999da57d7bSbt150084 break; 37009da57d7bSbt150084 case IXGBE_LINK_SPEED_100_FULL: 37019da57d7bSbt150084 ixgbe->link_speed = SPEED_100; 37029da57d7bSbt150084 } 37039da57d7bSbt150084 ixgbe->link_duplex = LINK_DUPLEX_FULL; 37049da57d7bSbt150084 ixgbe->link_state = LINK_STATE_UP; 37059da57d7bSbt150084 link_changed = B_TRUE; 37069da57d7bSbt150084 } 37079da57d7bSbt150084 } else { 370862e6e1adSPaul Guo if (ixgbe->link_check_complete == B_TRUE || 370962e6e1adSPaul Guo (ixgbe->link_check_complete == B_FALSE && 371062e6e1adSPaul Guo gethrtime() >= ixgbe->link_check_hrtime)) { 371162e6e1adSPaul Guo /* 371262e6e1adSPaul Guo * The link is really down 371362e6e1adSPaul Guo */ 371462e6e1adSPaul Guo ixgbe->link_check_complete = B_TRUE; 371562e6e1adSPaul Guo 37169da57d7bSbt150084 if (ixgbe->link_state != LINK_STATE_DOWN) { 37179da57d7bSbt150084 ixgbe->link_speed = 0; 371862e6e1adSPaul Guo ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN; 37199da57d7bSbt150084 ixgbe->link_state = LINK_STATE_DOWN; 37209da57d7bSbt150084 link_changed = B_TRUE; 37219da57d7bSbt150084 } 37229da57d7bSbt150084 } 372362e6e1adSPaul Guo } 37249da57d7bSbt150084 372513740cb2SPaul Guo /* 372662e6e1adSPaul Guo * If we are in an interrupt context, need to re-enable the 372762e6e1adSPaul Guo * interrupt, which was automasked 372862e6e1adSPaul Guo */ 372962e6e1adSPaul Guo if (servicing_interrupt() != 0) { 373013740cb2SPaul Guo ixgbe->eims |= IXGBE_EICR_LSC; 373113740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 373262e6e1adSPaul Guo } 373313740cb2SPaul Guo 373413740cb2SPaul Guo if (link_changed) { 373513740cb2SPaul Guo mac_link_update(ixgbe->mac_hdl, ixgbe->link_state); 373613740cb2SPaul Guo } 37379da57d7bSbt150084 } 37389da57d7bSbt150084 37399da57d7bSbt150084 /* 374073cd555cSBin Tu - Sun Microsystems - Beijing China * ixgbe_sfp_check - sfp module processing done in taskq only for 82599. 374173cd555cSBin Tu - Sun Microsystems - Beijing China */ 374273cd555cSBin Tu - Sun Microsystems - Beijing China static void 374373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_sfp_check(void *arg) 374473cd555cSBin Tu - Sun Microsystems - Beijing China { 374573cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_t *ixgbe = (ixgbe_t *)arg; 374673cd555cSBin Tu - Sun Microsystems - Beijing China uint32_t eicr = ixgbe->eicr; 374773cd555cSBin Tu - Sun Microsystems - Beijing China struct ixgbe_hw *hw = &ixgbe->hw; 374873cd555cSBin Tu - Sun Microsystems - Beijing China 374962e6e1adSPaul Guo mutex_enter(&ixgbe->gen_lock); 3750*59596c01SRobert Mustacchi (void) hw->phy.ops.identify_sfp(hw); 37517e579c30SDale Ghent if (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { 375273cd555cSBin Tu - Sun Microsystems - Beijing China /* clear the interrupt */ 37537e579c30SDale Ghent IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); 375473cd555cSBin Tu - Sun Microsystems - Beijing China 375573cd555cSBin Tu - Sun Microsystems - Beijing China /* if link up, do multispeed fiber setup */ 37563cfa0eb9Schenlu chen - Sun Microsystems - Beijing China (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, 37577e579c30SDale Ghent B_TRUE); 375873cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_driver_link_check(ixgbe); 37595b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_get_hw_state(ixgbe); 37607e579c30SDale Ghent } else if (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)) { 376173cd555cSBin Tu - Sun Microsystems - Beijing China /* clear the interrupt */ 37627e579c30SDale Ghent IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2_BY_MAC(hw)); 376373cd555cSBin Tu - Sun Microsystems - Beijing China 376473cd555cSBin Tu - Sun Microsystems - Beijing China /* if link up, do sfp module setup */ 376573cd555cSBin Tu - Sun Microsystems - Beijing China (void) hw->mac.ops.setup_sfp(hw); 376673cd555cSBin Tu - Sun Microsystems - Beijing China 376773cd555cSBin Tu - Sun Microsystems - Beijing China /* do multispeed fiber setup */ 37683cfa0eb9Schenlu chen - Sun Microsystems - Beijing China (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, 37697e579c30SDale Ghent B_TRUE); 377073cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_driver_link_check(ixgbe); 37715b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_get_hw_state(ixgbe); 377273cd555cSBin Tu - Sun Microsystems - Beijing China } 377362e6e1adSPaul Guo mutex_exit(&ixgbe->gen_lock); 37745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 37755b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* 37765b6dd21fSchenlu chen - Sun Microsystems - Beijing China * We need to fully re-check the link later. 37775b6dd21fSchenlu chen - Sun Microsystems - Beijing China */ 37785b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->link_check_complete = B_FALSE; 37795b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->link_check_hrtime = gethrtime() + 37805b6dd21fSchenlu chen - Sun Microsystems - Beijing China (IXGBE_LINK_UP_TIME * 100000000ULL); 37815b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 37825b6dd21fSchenlu chen - Sun Microsystems - Beijing China 37835b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* 37845b6dd21fSchenlu chen - Sun Microsystems - Beijing China * ixgbe_overtemp_check - overtemp module processing done in taskq 37855b6dd21fSchenlu chen - Sun Microsystems - Beijing China * 37865b6dd21fSchenlu chen - Sun Microsystems - Beijing China * This routine will only be called on adapters with temperature sensor. 37875b6dd21fSchenlu chen - Sun Microsystems - Beijing China * The indication of over-temperature can be either SDP0 interrupt or the link 37885b6dd21fSchenlu chen - Sun Microsystems - Beijing China * status change interrupt. 37895b6dd21fSchenlu chen - Sun Microsystems - Beijing China */ 37905b6dd21fSchenlu chen - Sun Microsystems - Beijing China static void 37915b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_overtemp_check(void *arg) 37925b6dd21fSchenlu chen - Sun Microsystems - Beijing China { 37935b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_t *ixgbe = (ixgbe_t *)arg; 37945b6dd21fSchenlu chen - Sun Microsystems - Beijing China struct ixgbe_hw *hw = &ixgbe->hw; 37955b6dd21fSchenlu chen - Sun Microsystems - Beijing China uint32_t eicr = ixgbe->eicr; 37965b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_link_speed speed; 37975b6dd21fSchenlu chen - Sun Microsystems - Beijing China boolean_t link_up; 37985b6dd21fSchenlu chen - Sun Microsystems - Beijing China 37995b6dd21fSchenlu chen - Sun Microsystems - Beijing China mutex_enter(&ixgbe->gen_lock); 38005b6dd21fSchenlu chen - Sun Microsystems - Beijing China 38015b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* make sure we know current state of link */ 38027e579c30SDale Ghent (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE); 38035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 38045b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* check over-temp condition */ 38057e579c30SDale Ghent if (((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) && (!link_up)) || 38065b6dd21fSchenlu chen - Sun Microsystems - Beijing China (eicr & IXGBE_EICR_LSC)) { 38075b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) { 38085b6dd21fSchenlu chen - Sun Microsystems - Beijing China atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP); 38095b6dd21fSchenlu chen - Sun Microsystems - Beijing China 38105b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* 38115b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Disable the adapter interrupts 38125b6dd21fSchenlu chen - Sun Microsystems - Beijing China */ 38135b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_disable_adapter_interrupts(ixgbe); 38145b6dd21fSchenlu chen - Sun Microsystems - Beijing China 38155b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* 38165b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Disable Rx/Tx units 38175b6dd21fSchenlu chen - Sun Microsystems - Beijing China */ 38185b6dd21fSchenlu chen - Sun Microsystems - Beijing China (void) ixgbe_stop_adapter(hw); 38195b6dd21fSchenlu chen - Sun Microsystems - Beijing China 38205b6dd21fSchenlu chen - Sun Microsystems - Beijing China ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 38215b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, 38225b6dd21fSchenlu chen - Sun Microsystems - Beijing China "Problem: Network adapter has been stopped " 38235b6dd21fSchenlu chen - Sun Microsystems - Beijing China "because it has overheated"); 38245b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, 38255b6dd21fSchenlu chen - Sun Microsystems - Beijing China "Action: Restart the computer. " 38265b6dd21fSchenlu chen - Sun Microsystems - Beijing China "If the problem persists, power off the system " 38275b6dd21fSchenlu chen - Sun Microsystems - Beijing China "and replace the adapter"); 38285b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 38295b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 38305b6dd21fSchenlu chen - Sun Microsystems - Beijing China 38315b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* write to clear the interrupt */ 38325b6dd21fSchenlu chen - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr); 38335b6dd21fSchenlu chen - Sun Microsystems - Beijing China 38345b6dd21fSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock); 383562e6e1adSPaul Guo } 383662e6e1adSPaul Guo 383762e6e1adSPaul Guo /* 38387e579c30SDale Ghent * ixgbe_phy_check - taskq to process interrupts from an external PHY 38397e579c30SDale Ghent * 38407e579c30SDale Ghent * This routine will only be called on adapters with external PHYs 38417e579c30SDale Ghent * (such as X550) that may be trying to raise our attention to some event. 38427e579c30SDale Ghent * Currently, this is limited to claiming PHY overtemperature and link status 38437e579c30SDale Ghent * change (LSC) events, however this may expand to include other things in 38447e579c30SDale Ghent * future adapters. 38457e579c30SDale Ghent */ 38467e579c30SDale Ghent static void 38477e579c30SDale Ghent ixgbe_phy_check(void *arg) 38487e579c30SDale Ghent { 38497e579c30SDale Ghent ixgbe_t *ixgbe = (ixgbe_t *)arg; 38507e579c30SDale Ghent struct ixgbe_hw *hw = &ixgbe->hw; 38517e579c30SDale Ghent int rv; 38527e579c30SDale Ghent 38537e579c30SDale Ghent mutex_enter(&ixgbe->gen_lock); 38547e579c30SDale Ghent 38557e579c30SDale Ghent /* 38567e579c30SDale Ghent * X550 baseT PHY overtemp and LSC events are handled here. 38577e579c30SDale Ghent * 38587e579c30SDale Ghent * If an overtemp event occurs, it will be reflected in the 38597e579c30SDale Ghent * return value of phy.ops.handle_lasi() and the common code will 38607e579c30SDale Ghent * automatically power off the baseT PHY. This is our cue to trigger 38617e579c30SDale Ghent * an FMA event. 38627e579c30SDale Ghent * 38637e579c30SDale Ghent * If a link status change event occurs, phy.ops.handle_lasi() will 38647e579c30SDale Ghent * automatically initiate a link setup between the integrated KR PHY 38657e579c30SDale Ghent * and the external X557 PHY to ensure that the link speed between 38667e579c30SDale Ghent * them matches the link speed of the baseT link. 38677e579c30SDale Ghent */ 38687e579c30SDale Ghent rv = ixgbe_handle_lasi(hw); 38697e579c30SDale Ghent 38707e579c30SDale Ghent if (rv == IXGBE_ERR_OVERTEMP) { 38717e579c30SDale Ghent atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP); 38727e579c30SDale Ghent 38737e579c30SDale Ghent /* 38747e579c30SDale Ghent * Disable the adapter interrupts 38757e579c30SDale Ghent */ 38767e579c30SDale Ghent ixgbe_disable_adapter_interrupts(ixgbe); 38777e579c30SDale Ghent 38787e579c30SDale Ghent /* 38797e579c30SDale Ghent * Disable Rx/Tx units 38807e579c30SDale Ghent */ 38817e579c30SDale Ghent (void) ixgbe_stop_adapter(hw); 38827e579c30SDale Ghent 38837e579c30SDale Ghent ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 38847e579c30SDale Ghent ixgbe_error(ixgbe, 38857e579c30SDale Ghent "Problem: Network adapter has been stopped due to a " 38867e579c30SDale Ghent "overtemperature event being detected."); 38877e579c30SDale Ghent ixgbe_error(ixgbe, 38887e579c30SDale Ghent "Action: Shut down or restart the computer. If the issue " 38897e579c30SDale Ghent "persists, please take action in accordance with the " 38907e579c30SDale Ghent "recommendations from your system vendor."); 38917e579c30SDale Ghent } 38927e579c30SDale Ghent 38937e579c30SDale Ghent mutex_exit(&ixgbe->gen_lock); 38947e579c30SDale Ghent } 38957e579c30SDale Ghent 38967e579c30SDale Ghent /* 389762e6e1adSPaul Guo * ixgbe_link_timer - timer for link status detection 389862e6e1adSPaul Guo */ 389962e6e1adSPaul Guo static void 390062e6e1adSPaul Guo ixgbe_link_timer(void *arg) 390162e6e1adSPaul Guo { 390262e6e1adSPaul Guo ixgbe_t *ixgbe = (ixgbe_t *)arg; 390362e6e1adSPaul Guo 390462e6e1adSPaul Guo mutex_enter(&ixgbe->gen_lock); 390562e6e1adSPaul Guo ixgbe_driver_link_check(ixgbe); 390662e6e1adSPaul Guo mutex_exit(&ixgbe->gen_lock); 390773cd555cSBin Tu - Sun Microsystems - Beijing China } 390873cd555cSBin Tu - Sun Microsystems - Beijing China 390973cd555cSBin Tu - Sun Microsystems - Beijing China /* 39109da57d7bSbt150084 * ixgbe_local_timer - Driver watchdog function. 39119da57d7bSbt150084 * 391262e6e1adSPaul Guo * This function will handle the transmit stall check and other routines. 39139da57d7bSbt150084 */ 39149da57d7bSbt150084 static void 39159da57d7bSbt150084 ixgbe_local_timer(void *arg) 39169da57d7bSbt150084 { 39179da57d7bSbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg; 39189da57d7bSbt150084 39195b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->ixgbe_state & IXGBE_OVERTEMP) 39205b6dd21fSchenlu chen - Sun Microsystems - Beijing China goto out; 39215b6dd21fSchenlu chen - Sun Microsystems - Beijing China 392262e6e1adSPaul Guo if (ixgbe->ixgbe_state & IXGBE_ERROR) { 39239da57d7bSbt150084 ixgbe->reset_count++; 39249da57d7bSbt150084 if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS) 39259da57d7bSbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED); 39265b6dd21fSchenlu chen - Sun Microsystems - Beijing China goto out; 39279da57d7bSbt150084 } 39289da57d7bSbt150084 392962e6e1adSPaul Guo if (ixgbe_stall_check(ixgbe)) { 393062e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL); 393162e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 393262e6e1adSPaul Guo 393362e6e1adSPaul Guo ixgbe->reset_count++; 393462e6e1adSPaul Guo if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS) 393562e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED); 39369da57d7bSbt150084 } 3937ffd8e883SWinson Wang - Sun Microsystems - Beijing China 39385b6dd21fSchenlu chen - Sun Microsystems - Beijing China out: 3939ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe_restart_watchdog_timer(ixgbe); 394062e6e1adSPaul Guo } 39419da57d7bSbt150084 39429da57d7bSbt150084 /* 39439da57d7bSbt150084 * ixgbe_stall_check - Check for transmit stall. 39449da57d7bSbt150084 * 39459da57d7bSbt150084 * This function checks if the adapter is stalled (in transmit). 39469da57d7bSbt150084 * 39479da57d7bSbt150084 * It is called each time the watchdog timeout is invoked. 39489da57d7bSbt150084 * If the transmit descriptor reclaim continuously fails, 39499da57d7bSbt150084 * the watchdog value will increment by 1. If the watchdog 39509da57d7bSbt150084 * value exceeds the threshold, the ixgbe is assumed to 39519da57d7bSbt150084 * have stalled and need to be reset. 39529da57d7bSbt150084 */ 39539da57d7bSbt150084 static boolean_t 39549da57d7bSbt150084 ixgbe_stall_check(ixgbe_t *ixgbe) 39559da57d7bSbt150084 { 39569da57d7bSbt150084 ixgbe_tx_ring_t *tx_ring; 39579da57d7bSbt150084 boolean_t result; 39589da57d7bSbt150084 int i; 39599da57d7bSbt150084 39609da57d7bSbt150084 if (ixgbe->link_state != LINK_STATE_UP) 39619da57d7bSbt150084 return (B_FALSE); 39629da57d7bSbt150084 39639da57d7bSbt150084 /* 39649da57d7bSbt150084 * If any tx ring is stalled, we'll reset the chipset 39659da57d7bSbt150084 */ 39669da57d7bSbt150084 result = B_FALSE; 39679da57d7bSbt150084 for (i = 0; i < ixgbe->num_tx_rings; i++) { 39689da57d7bSbt150084 tx_ring = &ixgbe->tx_rings[i]; 3969ea65739eSchenlu chen - Sun Microsystems - Beijing China if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) { 3970da14cebeSEric Cheng tx_ring->tx_recycle(tx_ring); 3971185c5677SPaul Guo } 39729da57d7bSbt150084 39739da57d7bSbt150084 if (tx_ring->recycle_fail > 0) 39749da57d7bSbt150084 tx_ring->stall_watchdog++; 39759da57d7bSbt150084 else 39769da57d7bSbt150084 tx_ring->stall_watchdog = 0; 39779da57d7bSbt150084 39789da57d7bSbt150084 if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) { 39799da57d7bSbt150084 result = B_TRUE; 39809da57d7bSbt150084 break; 39819da57d7bSbt150084 } 39829da57d7bSbt150084 } 39839da57d7bSbt150084 39849da57d7bSbt150084 if (result) { 39859da57d7bSbt150084 tx_ring->stall_watchdog = 0; 39869da57d7bSbt150084 tx_ring->recycle_fail = 0; 39879da57d7bSbt150084 } 39889da57d7bSbt150084 39899da57d7bSbt150084 return (result); 39909da57d7bSbt150084 } 39919da57d7bSbt150084 39929da57d7bSbt150084 39939da57d7bSbt150084 /* 39949da57d7bSbt150084 * is_valid_mac_addr - Check if the mac address is valid. 39959da57d7bSbt150084 */ 39969da57d7bSbt150084 static boolean_t 39979da57d7bSbt150084 is_valid_mac_addr(uint8_t *mac_addr) 39989da57d7bSbt150084 { 39999da57d7bSbt150084 const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 }; 40009da57d7bSbt150084 const uint8_t addr_test2[6] = 40019da57d7bSbt150084 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 40029da57d7bSbt150084 40039da57d7bSbt150084 if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) || 40049da57d7bSbt150084 !(bcmp(addr_test2, mac_addr, ETHERADDRL))) 40059da57d7bSbt150084 return (B_FALSE); 40069da57d7bSbt150084 40079da57d7bSbt150084 return (B_TRUE); 40089da57d7bSbt150084 } 40099da57d7bSbt150084 40109da57d7bSbt150084 static boolean_t 40119da57d7bSbt150084 ixgbe_find_mac_address(ixgbe_t *ixgbe) 40129da57d7bSbt150084 { 40139da57d7bSbt150084 #ifdef __sparc 40149da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 40159da57d7bSbt150084 uchar_t *bytes; 40169da57d7bSbt150084 struct ether_addr sysaddr; 40179da57d7bSbt150084 uint_t nelts; 40189da57d7bSbt150084 int err; 40199da57d7bSbt150084 boolean_t found = B_FALSE; 40209da57d7bSbt150084 40219da57d7bSbt150084 /* 40229da57d7bSbt150084 * The "vendor's factory-set address" may already have 40239da57d7bSbt150084 * been extracted from the chip, but if the property 40249da57d7bSbt150084 * "local-mac-address" is set we use that instead. 40259da57d7bSbt150084 * 40269da57d7bSbt150084 * We check whether it looks like an array of 6 40279da57d7bSbt150084 * bytes (which it should, if OBP set it). If we can't 40289da57d7bSbt150084 * make sense of it this way, we'll ignore it. 40299da57d7bSbt150084 */ 40309da57d7bSbt150084 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 40319da57d7bSbt150084 DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts); 40329da57d7bSbt150084 if (err == DDI_PROP_SUCCESS) { 40339da57d7bSbt150084 if (nelts == ETHERADDRL) { 40349da57d7bSbt150084 while (nelts--) 40359da57d7bSbt150084 hw->mac.addr[nelts] = bytes[nelts]; 40369da57d7bSbt150084 found = B_TRUE; 40379da57d7bSbt150084 } 40389da57d7bSbt150084 ddi_prop_free(bytes); 40399da57d7bSbt150084 } 40409da57d7bSbt150084 40419da57d7bSbt150084 /* 40429da57d7bSbt150084 * Look up the OBP property "local-mac-address?". If the user has set 40439da57d7bSbt150084 * 'local-mac-address? = false', use "the system address" instead. 40449da57d7bSbt150084 */ 40459da57d7bSbt150084 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0, 40469da57d7bSbt150084 "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) { 40479da57d7bSbt150084 if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) { 40489da57d7bSbt150084 if (localetheraddr(NULL, &sysaddr) != 0) { 40499da57d7bSbt150084 bcopy(&sysaddr, hw->mac.addr, ETHERADDRL); 40509da57d7bSbt150084 found = B_TRUE; 40519da57d7bSbt150084 } 40529da57d7bSbt150084 } 40539da57d7bSbt150084 ddi_prop_free(bytes); 40549da57d7bSbt150084 } 40559da57d7bSbt150084 40569da57d7bSbt150084 /* 40579da57d7bSbt150084 * Finally(!), if there's a valid "mac-address" property (created 40589da57d7bSbt150084 * if we netbooted from this interface), we must use this instead 40599da57d7bSbt150084 * of any of the above to ensure that the NFS/install server doesn't 40607e579c30SDale Ghent * get confused by the address changing as illumos takes over! 40619da57d7bSbt150084 */ 40629da57d7bSbt150084 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 40639da57d7bSbt150084 DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts); 40649da57d7bSbt150084 if (err == DDI_PROP_SUCCESS) { 40659da57d7bSbt150084 if (nelts == ETHERADDRL) { 40669da57d7bSbt150084 while (nelts--) 40679da57d7bSbt150084 hw->mac.addr[nelts] = bytes[nelts]; 40689da57d7bSbt150084 found = B_TRUE; 40699da57d7bSbt150084 } 40709da57d7bSbt150084 ddi_prop_free(bytes); 40719da57d7bSbt150084 } 40729da57d7bSbt150084 40739da57d7bSbt150084 if (found) { 40749da57d7bSbt150084 bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL); 40759da57d7bSbt150084 return (B_TRUE); 40769da57d7bSbt150084 } 40779da57d7bSbt150084 #else 40789da57d7bSbt150084 _NOTE(ARGUNUSED(ixgbe)); 40799da57d7bSbt150084 #endif 40809da57d7bSbt150084 40819da57d7bSbt150084 return (B_TRUE); 40829da57d7bSbt150084 } 40839da57d7bSbt150084 40849da57d7bSbt150084 #pragma inline(ixgbe_arm_watchdog_timer) 40859da57d7bSbt150084 static void 40869da57d7bSbt150084 ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe) 40879da57d7bSbt150084 { 40889da57d7bSbt150084 /* 40899da57d7bSbt150084 * Fire a watchdog timer 40909da57d7bSbt150084 */ 40919da57d7bSbt150084 ixgbe->watchdog_tid = 40929da57d7bSbt150084 timeout(ixgbe_local_timer, 40939da57d7bSbt150084 (void *)ixgbe, 1 * drv_usectohz(1000000)); 40949da57d7bSbt150084 40959da57d7bSbt150084 } 40969da57d7bSbt150084 40979da57d7bSbt150084 /* 40989da57d7bSbt150084 * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer. 40999da57d7bSbt150084 */ 41009da57d7bSbt150084 void 41019da57d7bSbt150084 ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe) 41029da57d7bSbt150084 { 41039da57d7bSbt150084 mutex_enter(&ixgbe->watchdog_lock); 41049da57d7bSbt150084 41059da57d7bSbt150084 if (!ixgbe->watchdog_enable) { 41069da57d7bSbt150084 ixgbe->watchdog_enable = B_TRUE; 41079da57d7bSbt150084 ixgbe->watchdog_start = B_TRUE; 41089da57d7bSbt150084 ixgbe_arm_watchdog_timer(ixgbe); 41099da57d7bSbt150084 } 41109da57d7bSbt150084 41119da57d7bSbt150084 mutex_exit(&ixgbe->watchdog_lock); 41129da57d7bSbt150084 } 41139da57d7bSbt150084 41149da57d7bSbt150084 /* 41159da57d7bSbt150084 * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer. 41169da57d7bSbt150084 */ 41179da57d7bSbt150084 void 41189da57d7bSbt150084 ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe) 41199da57d7bSbt150084 { 41209da57d7bSbt150084 timeout_id_t tid; 41219da57d7bSbt150084 41229da57d7bSbt150084 mutex_enter(&ixgbe->watchdog_lock); 41239da57d7bSbt150084 41249da57d7bSbt150084 ixgbe->watchdog_enable = B_FALSE; 41259da57d7bSbt150084 ixgbe->watchdog_start = B_FALSE; 41269da57d7bSbt150084 tid = ixgbe->watchdog_tid; 41279da57d7bSbt150084 ixgbe->watchdog_tid = 0; 41289da57d7bSbt150084 41299da57d7bSbt150084 mutex_exit(&ixgbe->watchdog_lock); 41309da57d7bSbt150084 41319da57d7bSbt150084 if (tid != 0) 41329da57d7bSbt150084 (void) untimeout(tid); 41339da57d7bSbt150084 } 41349da57d7bSbt150084 41359da57d7bSbt150084 /* 41369da57d7bSbt150084 * ixgbe_start_watchdog_timer - Start the driver watchdog timer. 41379da57d7bSbt150084 */ 413813740cb2SPaul Guo void 41399da57d7bSbt150084 ixgbe_start_watchdog_timer(ixgbe_t *ixgbe) 41409da57d7bSbt150084 { 41419da57d7bSbt150084 mutex_enter(&ixgbe->watchdog_lock); 41429da57d7bSbt150084 41439da57d7bSbt150084 if (ixgbe->watchdog_enable) { 41449da57d7bSbt150084 if (!ixgbe->watchdog_start) { 41459da57d7bSbt150084 ixgbe->watchdog_start = B_TRUE; 41469da57d7bSbt150084 ixgbe_arm_watchdog_timer(ixgbe); 41479da57d7bSbt150084 } 41489da57d7bSbt150084 } 41499da57d7bSbt150084 41509da57d7bSbt150084 mutex_exit(&ixgbe->watchdog_lock); 41519da57d7bSbt150084 } 41529da57d7bSbt150084 41539da57d7bSbt150084 /* 41549da57d7bSbt150084 * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer. 41559da57d7bSbt150084 */ 41569da57d7bSbt150084 static void 41579da57d7bSbt150084 ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe) 41589da57d7bSbt150084 { 41599da57d7bSbt150084 mutex_enter(&ixgbe->watchdog_lock); 41609da57d7bSbt150084 41619da57d7bSbt150084 if (ixgbe->watchdog_start) 41629da57d7bSbt150084 ixgbe_arm_watchdog_timer(ixgbe); 41639da57d7bSbt150084 41649da57d7bSbt150084 mutex_exit(&ixgbe->watchdog_lock); 41659da57d7bSbt150084 } 41669da57d7bSbt150084 41679da57d7bSbt150084 /* 41689da57d7bSbt150084 * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer. 41699da57d7bSbt150084 */ 417013740cb2SPaul Guo void 41719da57d7bSbt150084 ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe) 41729da57d7bSbt150084 { 41739da57d7bSbt150084 timeout_id_t tid; 41749da57d7bSbt150084 41759da57d7bSbt150084 mutex_enter(&ixgbe->watchdog_lock); 41769da57d7bSbt150084 41779da57d7bSbt150084 ixgbe->watchdog_start = B_FALSE; 41789da57d7bSbt150084 tid = ixgbe->watchdog_tid; 41799da57d7bSbt150084 ixgbe->watchdog_tid = 0; 41809da57d7bSbt150084 41819da57d7bSbt150084 mutex_exit(&ixgbe->watchdog_lock); 41829da57d7bSbt150084 41839da57d7bSbt150084 if (tid != 0) 41849da57d7bSbt150084 (void) untimeout(tid); 41859da57d7bSbt150084 } 41869da57d7bSbt150084 41879da57d7bSbt150084 /* 41889da57d7bSbt150084 * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts. 41899da57d7bSbt150084 */ 41909da57d7bSbt150084 static void 41919da57d7bSbt150084 ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe) 41929da57d7bSbt150084 { 41939da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 41949da57d7bSbt150084 41959da57d7bSbt150084 /* 41969da57d7bSbt150084 * mask all interrupts off 41979da57d7bSbt150084 */ 41989da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff); 41999da57d7bSbt150084 42009da57d7bSbt150084 /* 42019da57d7bSbt150084 * for MSI-X, also disable autoclear 42029da57d7bSbt150084 */ 42039da57d7bSbt150084 if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) { 42049da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0); 42059da57d7bSbt150084 } 42069da57d7bSbt150084 42079da57d7bSbt150084 IXGBE_WRITE_FLUSH(hw); 42089da57d7bSbt150084 } 42099da57d7bSbt150084 42109da57d7bSbt150084 /* 42119da57d7bSbt150084 * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts. 42129da57d7bSbt150084 */ 42139da57d7bSbt150084 static void 42149da57d7bSbt150084 ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe) 42159da57d7bSbt150084 { 42169da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 421713740cb2SPaul Guo uint32_t eiac, eiam; 421813740cb2SPaul Guo uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); 42199da57d7bSbt150084 422013740cb2SPaul Guo /* interrupt types to enable */ 422113740cb2SPaul Guo ixgbe->eims = IXGBE_EIMS_ENABLE_MASK; /* shared code default */ 422213740cb2SPaul Guo ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER; /* minus tcp timer */ 422313740cb2SPaul Guo ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */ 422413740cb2SPaul Guo 422513740cb2SPaul Guo /* enable automask on "other" causes that this adapter can generate */ 422613740cb2SPaul Guo eiam = ixgbe->capab->other_intr; 42279da57d7bSbt150084 42289da57d7bSbt150084 /* 42299da57d7bSbt150084 * msi-x mode 42309da57d7bSbt150084 */ 42319da57d7bSbt150084 if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) { 42329da57d7bSbt150084 /* enable autoclear but not on bits 29:20 */ 423313740cb2SPaul Guo eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR); 42349da57d7bSbt150084 42359da57d7bSbt150084 /* general purpose interrupt enable */ 423613740cb2SPaul Guo gpie |= (IXGBE_GPIE_MSIX_MODE 423713740cb2SPaul Guo | IXGBE_GPIE_PBA_SUPPORT 423813740cb2SPaul Guo | IXGBE_GPIE_OCD 423913740cb2SPaul Guo | IXGBE_GPIE_EIAME); 42409da57d7bSbt150084 /* 42419da57d7bSbt150084 * non-msi-x mode 42429da57d7bSbt150084 */ 42439da57d7bSbt150084 } else { 42449da57d7bSbt150084 42459da57d7bSbt150084 /* disable autoclear, leave gpie at default */ 42469da57d7bSbt150084 eiac = 0; 424713740cb2SPaul Guo 424873cd555cSBin Tu - Sun Microsystems - Beijing China /* 424973cd555cSBin Tu - Sun Microsystems - Beijing China * General purpose interrupt enable. 42507e579c30SDale Ghent * For 82599, X540 and X550, extended interrupt 42517e579c30SDale Ghent * automask enable only in MSI or MSI-X mode 425273cd555cSBin Tu - Sun Microsystems - Beijing China */ 425369b5a878SDan McDonald if ((hw->mac.type == ixgbe_mac_82598EB) || 425473cd555cSBin Tu - Sun Microsystems - Beijing China (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) { 425513740cb2SPaul Guo gpie |= IXGBE_GPIE_EIAME; 42569da57d7bSbt150084 } 425773cd555cSBin Tu - Sun Microsystems - Beijing China } 42585b6dd21fSchenlu chen - Sun Microsystems - Beijing China 42595b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* Enable specific "other" interrupt types */ 42605b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 42615b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 42625b6dd21fSchenlu chen - Sun Microsystems - Beijing China gpie |= ixgbe->capab->other_gpie; 42635b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 42645b6dd21fSchenlu chen - Sun Microsystems - Beijing China 42655b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 426669b5a878SDan McDonald case ixgbe_mac_X540: 42677e579c30SDale Ghent case ixgbe_mac_X550: 42687e579c30SDale Ghent case ixgbe_mac_X550EM_x: 42695b6dd21fSchenlu chen - Sun Microsystems - Beijing China gpie |= ixgbe->capab->other_gpie; 42705b6dd21fSchenlu chen - Sun Microsystems - Beijing China 42715b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* Enable RSC Delay 8us when LRO enabled */ 4272ffd8e883SWinson Wang - Sun Microsystems - Beijing China if (ixgbe->lro_enable) { 4273ffd8e883SWinson Wang - Sun Microsystems - Beijing China gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT); 4274ffd8e883SWinson Wang - Sun Microsystems - Beijing China } 42755b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 42765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 42775b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 42785b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 42795b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 42805b6dd21fSchenlu chen - Sun Microsystems - Beijing China 428113740cb2SPaul Guo /* write to interrupt control registers */ 428213740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 42839da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac); 428413740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam); 42859da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); 42869da57d7bSbt150084 IXGBE_WRITE_FLUSH(hw); 42879da57d7bSbt150084 } 42889da57d7bSbt150084 42899da57d7bSbt150084 /* 42909da57d7bSbt150084 * ixgbe_loopback_ioctl - Loopback support. 42919da57d7bSbt150084 */ 42929da57d7bSbt150084 enum ioc_reply 42939da57d7bSbt150084 ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp) 42949da57d7bSbt150084 { 42959da57d7bSbt150084 lb_info_sz_t *lbsp; 42969da57d7bSbt150084 lb_property_t *lbpp; 42979da57d7bSbt150084 uint32_t *lbmp; 42989da57d7bSbt150084 uint32_t size; 42999da57d7bSbt150084 uint32_t value; 43009da57d7bSbt150084 43019da57d7bSbt150084 if (mp->b_cont == NULL) 43029da57d7bSbt150084 return (IOC_INVAL); 43039da57d7bSbt150084 43049da57d7bSbt150084 switch (iocp->ioc_cmd) { 43059da57d7bSbt150084 default: 43069da57d7bSbt150084 return (IOC_INVAL); 43079da57d7bSbt150084 43089da57d7bSbt150084 case LB_GET_INFO_SIZE: 43099da57d7bSbt150084 size = sizeof (lb_info_sz_t); 43109da57d7bSbt150084 if (iocp->ioc_count != size) 43119da57d7bSbt150084 return (IOC_INVAL); 43129da57d7bSbt150084 43139da57d7bSbt150084 value = sizeof (lb_normal); 43149da57d7bSbt150084 value += sizeof (lb_mac); 43151fedc51fSWinson Wang - Sun Microsystems - Beijing China value += sizeof (lb_external); 43169da57d7bSbt150084 43179da57d7bSbt150084 lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr; 43189da57d7bSbt150084 *lbsp = value; 43199da57d7bSbt150084 break; 43209da57d7bSbt150084 43219da57d7bSbt150084 case LB_GET_INFO: 43229da57d7bSbt150084 value = sizeof (lb_normal); 43239da57d7bSbt150084 value += sizeof (lb_mac); 43241fedc51fSWinson Wang - Sun Microsystems - Beijing China value += sizeof (lb_external); 43259da57d7bSbt150084 43269da57d7bSbt150084 size = value; 43279da57d7bSbt150084 if (iocp->ioc_count != size) 43289da57d7bSbt150084 return (IOC_INVAL); 43299da57d7bSbt150084 43309da57d7bSbt150084 value = 0; 43319da57d7bSbt150084 lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr; 43329da57d7bSbt150084 43339da57d7bSbt150084 lbpp[value++] = lb_normal; 43349da57d7bSbt150084 lbpp[value++] = lb_mac; 43351fedc51fSWinson Wang - Sun Microsystems - Beijing China lbpp[value++] = lb_external; 43369da57d7bSbt150084 break; 43379da57d7bSbt150084 43389da57d7bSbt150084 case LB_GET_MODE: 43399da57d7bSbt150084 size = sizeof (uint32_t); 43409da57d7bSbt150084 if (iocp->ioc_count != size) 43419da57d7bSbt150084 return (IOC_INVAL); 43429da57d7bSbt150084 43439da57d7bSbt150084 lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 43449da57d7bSbt150084 *lbmp = ixgbe->loopback_mode; 43459da57d7bSbt150084 break; 43469da57d7bSbt150084 43479da57d7bSbt150084 case LB_SET_MODE: 43489da57d7bSbt150084 size = 0; 43499da57d7bSbt150084 if (iocp->ioc_count != sizeof (uint32_t)) 43509da57d7bSbt150084 return (IOC_INVAL); 43519da57d7bSbt150084 43529da57d7bSbt150084 lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr; 43539da57d7bSbt150084 if (!ixgbe_set_loopback_mode(ixgbe, *lbmp)) 43549da57d7bSbt150084 return (IOC_INVAL); 43559da57d7bSbt150084 break; 43569da57d7bSbt150084 } 43579da57d7bSbt150084 43589da57d7bSbt150084 iocp->ioc_count = size; 43599da57d7bSbt150084 iocp->ioc_error = 0; 43609da57d7bSbt150084 43619da57d7bSbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 43629da57d7bSbt150084 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 43639da57d7bSbt150084 return (IOC_INVAL); 43649da57d7bSbt150084 } 43659da57d7bSbt150084 43669da57d7bSbt150084 return (IOC_REPLY); 43679da57d7bSbt150084 } 43689da57d7bSbt150084 43699da57d7bSbt150084 /* 43709da57d7bSbt150084 * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode. 43719da57d7bSbt150084 */ 43729da57d7bSbt150084 static boolean_t 43739da57d7bSbt150084 ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode) 43749da57d7bSbt150084 { 43759da57d7bSbt150084 if (mode == ixgbe->loopback_mode) 43769da57d7bSbt150084 return (B_TRUE); 43779da57d7bSbt150084 43789da57d7bSbt150084 ixgbe->loopback_mode = mode; 43799da57d7bSbt150084 43809da57d7bSbt150084 if (mode == IXGBE_LB_NONE) { 43819da57d7bSbt150084 /* 43829da57d7bSbt150084 * Reset the chip 43839da57d7bSbt150084 */ 43849da57d7bSbt150084 (void) ixgbe_reset(ixgbe); 43859da57d7bSbt150084 return (B_TRUE); 43869da57d7bSbt150084 } 43879da57d7bSbt150084 43889da57d7bSbt150084 mutex_enter(&ixgbe->gen_lock); 43899da57d7bSbt150084 43909da57d7bSbt150084 switch (mode) { 43919da57d7bSbt150084 default: 43929da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 43939da57d7bSbt150084 return (B_FALSE); 43949da57d7bSbt150084 43951fedc51fSWinson Wang - Sun Microsystems - Beijing China case IXGBE_LB_EXTERNAL: 43961fedc51fSWinson Wang - Sun Microsystems - Beijing China break; 43971fedc51fSWinson Wang - Sun Microsystems - Beijing China 43989da57d7bSbt150084 case IXGBE_LB_INTERNAL_MAC: 43999da57d7bSbt150084 ixgbe_set_internal_mac_loopback(ixgbe); 44009da57d7bSbt150084 break; 44019da57d7bSbt150084 } 44029da57d7bSbt150084 44039da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 44049da57d7bSbt150084 44059da57d7bSbt150084 return (B_TRUE); 44069da57d7bSbt150084 } 44079da57d7bSbt150084 44089da57d7bSbt150084 /* 44099da57d7bSbt150084 * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode. 44109da57d7bSbt150084 */ 44119da57d7bSbt150084 static void 44129da57d7bSbt150084 ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe) 44139da57d7bSbt150084 { 44149da57d7bSbt150084 struct ixgbe_hw *hw; 44159da57d7bSbt150084 uint32_t reg; 44169da57d7bSbt150084 uint8_t atlas; 44179da57d7bSbt150084 44189da57d7bSbt150084 hw = &ixgbe->hw; 44199da57d7bSbt150084 44209da57d7bSbt150084 /* 44219da57d7bSbt150084 * Setup MAC loopback 44229da57d7bSbt150084 */ 44239da57d7bSbt150084 reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0); 44249da57d7bSbt150084 reg |= IXGBE_HLREG0_LPBK; 44259da57d7bSbt150084 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg); 44269da57d7bSbt150084 44279da57d7bSbt150084 reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC); 44289da57d7bSbt150084 reg &= ~IXGBE_AUTOC_LMS_MASK; 44299da57d7bSbt150084 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg); 44309da57d7bSbt150084 44319da57d7bSbt150084 /* 44329da57d7bSbt150084 * Disable Atlas Tx lanes to keep packets in loopback and not on wire 44339da57d7bSbt150084 */ 44345b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 44355b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 44369da57d7bSbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK, 44379da57d7bSbt150084 &atlas); 44389da57d7bSbt150084 atlas |= IXGBE_ATLAS_PDN_TX_REG_EN; 44399da57d7bSbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK, 44409da57d7bSbt150084 atlas); 44419da57d7bSbt150084 44429da57d7bSbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G, 44439da57d7bSbt150084 &atlas); 44449da57d7bSbt150084 atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL; 44459da57d7bSbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G, 44469da57d7bSbt150084 atlas); 44479da57d7bSbt150084 44489da57d7bSbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G, 44499da57d7bSbt150084 &atlas); 44509da57d7bSbt150084 atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL; 44519da57d7bSbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G, 44529da57d7bSbt150084 atlas); 44539da57d7bSbt150084 44549da57d7bSbt150084 (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN, 44559da57d7bSbt150084 &atlas); 44569da57d7bSbt150084 atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL; 44579da57d7bSbt150084 (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN, 44589da57d7bSbt150084 atlas); 44595b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 44605b6dd21fSchenlu chen - Sun Microsystems - Beijing China 44615b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 446269b5a878SDan McDonald case ixgbe_mac_X540: 44637e579c30SDale Ghent case ixgbe_mac_X550: 44647e579c30SDale Ghent case ixgbe_mac_X550EM_x: 446500f1c25aSchenlu chen - Sun Microsystems - Beijing China reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC); 446600f1c25aSchenlu chen - Sun Microsystems - Beijing China reg |= (IXGBE_AUTOC_FLU | 446700f1c25aSchenlu chen - Sun Microsystems - Beijing China IXGBE_AUTOC_10G_KX4); 446800f1c25aSchenlu chen - Sun Microsystems - Beijing China IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg); 446900f1c25aSchenlu chen - Sun Microsystems - Beijing China 447000f1c25aSchenlu chen - Sun Microsystems - Beijing China (void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL, 44717e579c30SDale Ghent B_FALSE); 44725b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 44735b6dd21fSchenlu chen - Sun Microsystems - Beijing China 44745b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 44755b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 44769da57d7bSbt150084 } 44779da57d7bSbt150084 } 44789da57d7bSbt150084 44799da57d7bSbt150084 #pragma inline(ixgbe_intr_rx_work) 44809da57d7bSbt150084 /* 44819da57d7bSbt150084 * ixgbe_intr_rx_work - RX processing of ISR. 44829da57d7bSbt150084 */ 44839da57d7bSbt150084 static void 44849da57d7bSbt150084 ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring) 44859da57d7bSbt150084 { 44869da57d7bSbt150084 mblk_t *mp; 44879da57d7bSbt150084 44889da57d7bSbt150084 mutex_enter(&rx_ring->rx_lock); 44899da57d7bSbt150084 4490da14cebeSEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL); 44919da57d7bSbt150084 mutex_exit(&rx_ring->rx_lock); 44929da57d7bSbt150084 44939da57d7bSbt150084 if (mp != NULL) 4494da14cebeSEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp, 4495da14cebeSEric Cheng rx_ring->ring_gen_num); 44969da57d7bSbt150084 } 44979da57d7bSbt150084 44989da57d7bSbt150084 #pragma inline(ixgbe_intr_tx_work) 44999da57d7bSbt150084 /* 45009da57d7bSbt150084 * ixgbe_intr_tx_work - TX processing of ISR. 45019da57d7bSbt150084 */ 45029da57d7bSbt150084 static void 45039da57d7bSbt150084 ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring) 45049da57d7bSbt150084 { 4505ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_t *ixgbe = tx_ring->ixgbe; 4506ea65739eSchenlu chen - Sun Microsystems - Beijing China 45079da57d7bSbt150084 /* 45089da57d7bSbt150084 * Recycle the tx descriptors 45099da57d7bSbt150084 */ 45109da57d7bSbt150084 tx_ring->tx_recycle(tx_ring); 45119da57d7bSbt150084 45129da57d7bSbt150084 /* 45139da57d7bSbt150084 * Schedule the re-transmit 45149da57d7bSbt150084 */ 45159da57d7bSbt150084 if (tx_ring->reschedule && 4516ea65739eSchenlu chen - Sun Microsystems - Beijing China (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) { 45179da57d7bSbt150084 tx_ring->reschedule = B_FALSE; 4518da14cebeSEric Cheng mac_tx_ring_update(tx_ring->ixgbe->mac_hdl, 4519da14cebeSEric Cheng tx_ring->ring_handle); 4520abcd9e32SRyan Zezeski tx_ring->stat_reschedule++; 45219da57d7bSbt150084 } 45229da57d7bSbt150084 } 45239da57d7bSbt150084 45249da57d7bSbt150084 #pragma inline(ixgbe_intr_other_work) 45259da57d7bSbt150084 /* 452613740cb2SPaul Guo * ixgbe_intr_other_work - Process interrupt types other than tx/rx 45279da57d7bSbt150084 */ 45289da57d7bSbt150084 static void 452913740cb2SPaul Guo ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr) 45309da57d7bSbt150084 { 45317e579c30SDale Ghent struct ixgbe_hw *hw = &ixgbe->hw; 45327e579c30SDale Ghent 453362e6e1adSPaul Guo ASSERT(mutex_owned(&ixgbe->gen_lock)); 453462e6e1adSPaul Guo 453513740cb2SPaul Guo /* 453662e6e1adSPaul Guo * handle link status change 453713740cb2SPaul Guo */ 453813740cb2SPaul Guo if (eicr & IXGBE_EICR_LSC) { 453962e6e1adSPaul Guo ixgbe_driver_link_check(ixgbe); 45405b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_get_hw_state(ixgbe); 454113740cb2SPaul Guo } 45429da57d7bSbt150084 45439da57d7bSbt150084 /* 454413740cb2SPaul Guo * check for fan failure on adapters with fans 45459da57d7bSbt150084 */ 454613740cb2SPaul Guo if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) && 454713740cb2SPaul Guo (eicr & IXGBE_EICR_GPI_SDP1)) { 45485b6dd21fSchenlu chen - Sun Microsystems - Beijing China atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP); 45495b6dd21fSchenlu chen - Sun Microsystems - Beijing China 45505b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* 45515b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Disable the adapter interrupts 45525b6dd21fSchenlu chen - Sun Microsystems - Beijing China */ 45535b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_disable_adapter_interrupts(ixgbe); 45545b6dd21fSchenlu chen - Sun Microsystems - Beijing China 45555b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* 45565b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Disable Rx/Tx units 45575b6dd21fSchenlu chen - Sun Microsystems - Beijing China */ 45585b6dd21fSchenlu chen - Sun Microsystems - Beijing China (void) ixgbe_stop_adapter(&ixgbe->hw); 45595b6dd21fSchenlu chen - Sun Microsystems - Beijing China 45605b6dd21fSchenlu chen - Sun Microsystems - Beijing China ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); 45615b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, 45625b6dd21fSchenlu chen - Sun Microsystems - Beijing China "Problem: Network adapter has been stopped " 45635b6dd21fSchenlu chen - Sun Microsystems - Beijing China "because the fan has stopped.\n"); 45645b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, 45655b6dd21fSchenlu chen - Sun Microsystems - Beijing China "Action: Replace the adapter.\n"); 45669da57d7bSbt150084 456713740cb2SPaul Guo /* re-enable the interrupt, which was automasked */ 456813740cb2SPaul Guo ixgbe->eims |= IXGBE_EICR_GPI_SDP1; 456913740cb2SPaul Guo } 45709da57d7bSbt150084 45719da57d7bSbt150084 /* 45725b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Do SFP check for adapters with hot-plug capability 457373cd555cSBin Tu - Sun Microsystems - Beijing China */ 45745b6dd21fSchenlu chen - Sun Microsystems - Beijing China if ((ixgbe->capab->flags & IXGBE_FLAG_SFP_PLUG_CAPABLE) && 45757e579c30SDale Ghent ((eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) || 45767e579c30SDale Ghent (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)))) { 45775b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->eicr = eicr; 457862e6e1adSPaul Guo if ((ddi_taskq_dispatch(ixgbe->sfp_taskq, 457973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_sfp_check, (void *)ixgbe, 458073cd555cSBin Tu - Sun Microsystems - Beijing China DDI_NOSLEEP)) != DDI_SUCCESS) { 4581185c5677SPaul Guo ixgbe_log(ixgbe, "No memory available to dispatch " 4582185c5677SPaul Guo "taskq for SFP check"); 458373cd555cSBin Tu - Sun Microsystems - Beijing China } 45845b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 458562e6e1adSPaul Guo 458662e6e1adSPaul Guo /* 45875b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Do over-temperature check for adapters with temp sensor 458862e6e1adSPaul Guo */ 45895b6dd21fSchenlu chen - Sun Microsystems - Beijing China if ((ixgbe->capab->flags & IXGBE_FLAG_TEMP_SENSOR_CAPABLE) && 45907e579c30SDale Ghent ((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) || 45917e579c30SDale Ghent (eicr & IXGBE_EICR_LSC))) { 45925b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->eicr = eicr; 45935b6dd21fSchenlu chen - Sun Microsystems - Beijing China if ((ddi_taskq_dispatch(ixgbe->overtemp_taskq, 45945b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_overtemp_check, (void *)ixgbe, 45955b6dd21fSchenlu chen - Sun Microsystems - Beijing China DDI_NOSLEEP)) != DDI_SUCCESS) { 45965b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_log(ixgbe, "No memory available to dispatch " 45975b6dd21fSchenlu chen - Sun Microsystems - Beijing China "taskq for overtemp check"); 45985b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 459973cd555cSBin Tu - Sun Microsystems - Beijing China } 46007e579c30SDale Ghent 46017e579c30SDale Ghent /* 46027e579c30SDale Ghent * Process an external PHY interrupt 46037e579c30SDale Ghent */ 46047e579c30SDale Ghent if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && 46057e579c30SDale Ghent (eicr & IXGBE_EICR_GPI_SDP0_X540)) { 46067e579c30SDale Ghent ixgbe->eicr = eicr; 46077e579c30SDale Ghent if ((ddi_taskq_dispatch(ixgbe->phy_taskq, 46087e579c30SDale Ghent ixgbe_phy_check, (void *)ixgbe, 46097e579c30SDale Ghent DDI_NOSLEEP)) != DDI_SUCCESS) { 46107e579c30SDale Ghent ixgbe_log(ixgbe, "No memory available to dispatch " 46117e579c30SDale Ghent "taskq for PHY check"); 46127e579c30SDale Ghent } 46137e579c30SDale Ghent } 461473cd555cSBin Tu - Sun Microsystems - Beijing China } 461573cd555cSBin Tu - Sun Microsystems - Beijing China 461673cd555cSBin Tu - Sun Microsystems - Beijing China /* 46179da57d7bSbt150084 * ixgbe_intr_legacy - Interrupt handler for legacy interrupts. 46189da57d7bSbt150084 */ 46199da57d7bSbt150084 static uint_t 46209da57d7bSbt150084 ixgbe_intr_legacy(void *arg1, void *arg2) 46219da57d7bSbt150084 { 46229da57d7bSbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg1; 46239da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 46249da57d7bSbt150084 ixgbe_tx_ring_t *tx_ring; 4625da14cebeSEric Cheng ixgbe_rx_ring_t *rx_ring; 46269da57d7bSbt150084 uint32_t eicr; 46279da57d7bSbt150084 mblk_t *mp; 46289da57d7bSbt150084 boolean_t tx_reschedule; 46299da57d7bSbt150084 uint_t result; 46309da57d7bSbt150084 463113740cb2SPaul Guo _NOTE(ARGUNUSED(arg2)); 46329da57d7bSbt150084 46339da57d7bSbt150084 mutex_enter(&ixgbe->gen_lock); 46349da57d7bSbt150084 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 46359da57d7bSbt150084 mutex_exit(&ixgbe->gen_lock); 46369da57d7bSbt150084 return (DDI_INTR_UNCLAIMED); 46379da57d7bSbt150084 } 46389da57d7bSbt150084 46399da57d7bSbt150084 mp = NULL; 46409da57d7bSbt150084 tx_reschedule = B_FALSE; 46419da57d7bSbt150084 46429da57d7bSbt150084 /* 46439da57d7bSbt150084 * Any bit set in eicr: claim this interrupt 46449da57d7bSbt150084 */ 46459da57d7bSbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 464662e6e1adSPaul Guo 464762e6e1adSPaul Guo if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 464819843f01SPaul Guo mutex_exit(&ixgbe->gen_lock); 464962e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 465062e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 465162e6e1adSPaul Guo return (DDI_INTR_CLAIMED); 465262e6e1adSPaul Guo } 465362e6e1adSPaul Guo 46549da57d7bSbt150084 if (eicr) { 46559da57d7bSbt150084 /* 46569da57d7bSbt150084 * For legacy interrupt, we have only one interrupt, 46579da57d7bSbt150084 * so we have only one rx ring and one tx ring enabled. 46589da57d7bSbt150084 */ 46599da57d7bSbt150084 ASSERT(ixgbe->num_rx_rings == 1); 46609da57d7bSbt150084 ASSERT(ixgbe->num_tx_rings == 1); 46619da57d7bSbt150084 46629da57d7bSbt150084 /* 4663da14cebeSEric Cheng * For legacy interrupt, rx rings[0] will use RTxQ[0]. 46649da57d7bSbt150084 */ 4665da14cebeSEric Cheng if (eicr & 0x1) { 466673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE; 466773cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 466873cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; 46699da57d7bSbt150084 /* 46709da57d7bSbt150084 * Clean the rx descriptors 46719da57d7bSbt150084 */ 4672da14cebeSEric Cheng rx_ring = &ixgbe->rx_rings[0]; 4673da14cebeSEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL); 4674da14cebeSEric Cheng } 46759da57d7bSbt150084 46769da57d7bSbt150084 /* 4677da14cebeSEric Cheng * For legacy interrupt, tx rings[0] will use RTxQ[1]. 4678da14cebeSEric Cheng */ 4679da14cebeSEric Cheng if (eicr & 0x2) { 4680da14cebeSEric Cheng /* 46819da57d7bSbt150084 * Recycle the tx descriptors 46829da57d7bSbt150084 */ 46839da57d7bSbt150084 tx_ring = &ixgbe->tx_rings[0]; 46849da57d7bSbt150084 tx_ring->tx_recycle(tx_ring); 46859da57d7bSbt150084 46869da57d7bSbt150084 /* 46879da57d7bSbt150084 * Schedule the re-transmit 46889da57d7bSbt150084 */ 46899da57d7bSbt150084 tx_reschedule = (tx_ring->reschedule && 4690ea65739eSchenlu chen - Sun Microsystems - Beijing China (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)); 46919da57d7bSbt150084 } 46929da57d7bSbt150084 469313740cb2SPaul Guo /* any interrupt type other than tx/rx */ 469413740cb2SPaul Guo if (eicr & ixgbe->capab->other_intr) { 46955b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 46965b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 469713740cb2SPaul Guo ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 46985b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 46995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 47005b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 470169b5a878SDan McDonald case ixgbe_mac_X540: 47027e579c30SDale Ghent case ixgbe_mac_X550: 47037e579c30SDale Ghent case ixgbe_mac_X550EM_x: 470473cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eimc = IXGBE_82599_OTHER_INTR; 470573cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 47065b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 47075b6dd21fSchenlu chen - Sun Microsystems - Beijing China 47085b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 47095b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 471073cd555cSBin Tu - Sun Microsystems - Beijing China } 471113740cb2SPaul Guo ixgbe_intr_other_work(ixgbe, eicr); 471273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 47139da57d7bSbt150084 } 47149da57d7bSbt150084 471513740cb2SPaul Guo mutex_exit(&ixgbe->gen_lock); 471613740cb2SPaul Guo 47179da57d7bSbt150084 result = DDI_INTR_CLAIMED; 47189da57d7bSbt150084 } else { 471913740cb2SPaul Guo mutex_exit(&ixgbe->gen_lock); 472013740cb2SPaul Guo 47219da57d7bSbt150084 /* 47229da57d7bSbt150084 * No interrupt cause bits set: don't claim this interrupt. 47239da57d7bSbt150084 */ 47249da57d7bSbt150084 result = DDI_INTR_UNCLAIMED; 47259da57d7bSbt150084 } 47269da57d7bSbt150084 472713740cb2SPaul Guo /* re-enable the interrupts which were automasked */ 472813740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 47299da57d7bSbt150084 47309da57d7bSbt150084 /* 47319da57d7bSbt150084 * Do the following work outside of the gen_lock 47329da57d7bSbt150084 */ 473373cd555cSBin Tu - Sun Microsystems - Beijing China if (mp != NULL) { 4734da14cebeSEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp, 4735da14cebeSEric Cheng rx_ring->ring_gen_num); 473673cd555cSBin Tu - Sun Microsystems - Beijing China } 47379da57d7bSbt150084 47389da57d7bSbt150084 if (tx_reschedule) { 47399da57d7bSbt150084 tx_ring->reschedule = B_FALSE; 4740da14cebeSEric Cheng mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle); 4741abcd9e32SRyan Zezeski tx_ring->stat_reschedule++; 47429da57d7bSbt150084 } 47439da57d7bSbt150084 47449da57d7bSbt150084 return (result); 47459da57d7bSbt150084 } 47469da57d7bSbt150084 47479da57d7bSbt150084 /* 47489da57d7bSbt150084 * ixgbe_intr_msi - Interrupt handler for MSI. 47499da57d7bSbt150084 */ 47509da57d7bSbt150084 static uint_t 47519da57d7bSbt150084 ixgbe_intr_msi(void *arg1, void *arg2) 47529da57d7bSbt150084 { 47539da57d7bSbt150084 ixgbe_t *ixgbe = (ixgbe_t *)arg1; 47549da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 47559da57d7bSbt150084 uint32_t eicr; 47569da57d7bSbt150084 475713740cb2SPaul Guo _NOTE(ARGUNUSED(arg2)); 475813740cb2SPaul Guo 47599da57d7bSbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 47609da57d7bSbt150084 476162e6e1adSPaul Guo if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { 476262e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED); 476362e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 476462e6e1adSPaul Guo return (DDI_INTR_CLAIMED); 476562e6e1adSPaul Guo } 476662e6e1adSPaul Guo 47679da57d7bSbt150084 /* 47689da57d7bSbt150084 * For MSI interrupt, we have only one vector, 47699da57d7bSbt150084 * so we have only one rx ring and one tx ring enabled. 47709da57d7bSbt150084 */ 47719da57d7bSbt150084 ASSERT(ixgbe->num_rx_rings == 1); 47729da57d7bSbt150084 ASSERT(ixgbe->num_tx_rings == 1); 47739da57d7bSbt150084 47749da57d7bSbt150084 /* 4775da14cebeSEric Cheng * For MSI interrupt, rx rings[0] will use RTxQ[0]. 47769da57d7bSbt150084 */ 4777da14cebeSEric Cheng if (eicr & 0x1) { 47789da57d7bSbt150084 ixgbe_intr_rx_work(&ixgbe->rx_rings[0]); 4779da14cebeSEric Cheng } 4780da14cebeSEric Cheng 4781da14cebeSEric Cheng /* 4782da14cebeSEric Cheng * For MSI interrupt, tx rings[0] will use RTxQ[1]. 4783da14cebeSEric Cheng */ 4784da14cebeSEric Cheng if (eicr & 0x2) { 47859da57d7bSbt150084 ixgbe_intr_tx_work(&ixgbe->tx_rings[0]); 47869da57d7bSbt150084 } 47879da57d7bSbt150084 478813740cb2SPaul Guo /* any interrupt type other than tx/rx */ 478913740cb2SPaul Guo if (eicr & ixgbe->capab->other_intr) { 479013740cb2SPaul Guo mutex_enter(&ixgbe->gen_lock); 47915b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 47925b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 479313740cb2SPaul Guo ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 47945b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 47955b6dd21fSchenlu chen - Sun Microsystems - Beijing China 47965b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 479769b5a878SDan McDonald case ixgbe_mac_X540: 47987e579c30SDale Ghent case ixgbe_mac_X550: 47997e579c30SDale Ghent case ixgbe_mac_X550EM_x: 480073cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eimc = IXGBE_82599_OTHER_INTR; 480173cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); 48025b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 48035b6dd21fSchenlu chen - Sun Microsystems - Beijing China 48045b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 48055b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 480673cd555cSBin Tu - Sun Microsystems - Beijing China } 480713740cb2SPaul Guo ixgbe_intr_other_work(ixgbe, eicr); 480873cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 480913740cb2SPaul Guo mutex_exit(&ixgbe->gen_lock); 48109da57d7bSbt150084 } 48119da57d7bSbt150084 481213740cb2SPaul Guo /* re-enable the interrupts which were automasked */ 481313740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 481413740cb2SPaul Guo 48159da57d7bSbt150084 return (DDI_INTR_CLAIMED); 48169da57d7bSbt150084 } 48179da57d7bSbt150084 48189da57d7bSbt150084 /* 481973cd555cSBin Tu - Sun Microsystems - Beijing China * ixgbe_intr_msix - Interrupt handler for MSI-X. 48209da57d7bSbt150084 */ 48219da57d7bSbt150084 static uint_t 482273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_msix(void *arg1, void *arg2) 48239da57d7bSbt150084 { 482473cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1; 48259da57d7bSbt150084 ixgbe_t *ixgbe = vect->ixgbe; 482673cd555cSBin Tu - Sun Microsystems - Beijing China struct ixgbe_hw *hw = &ixgbe->hw; 482773cd555cSBin Tu - Sun Microsystems - Beijing China uint32_t eicr; 4828da14cebeSEric Cheng int r_idx = 0; 48299da57d7bSbt150084 483013740cb2SPaul Guo _NOTE(ARGUNUSED(arg2)); 483113740cb2SPaul Guo 48329da57d7bSbt150084 /* 4833da14cebeSEric Cheng * Clean each rx ring that has its bit set in the map 48349da57d7bSbt150084 */ 48359da57d7bSbt150084 r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1)); 48369da57d7bSbt150084 while (r_idx >= 0) { 48379da57d7bSbt150084 ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]); 48389da57d7bSbt150084 r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1), 48399da57d7bSbt150084 (ixgbe->num_rx_rings - 1)); 48409da57d7bSbt150084 } 48419da57d7bSbt150084 4842da14cebeSEric Cheng /* 4843da14cebeSEric Cheng * Clean each tx ring that has its bit set in the map 4844da14cebeSEric Cheng */ 4845da14cebeSEric Cheng r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1)); 4846da14cebeSEric Cheng while (r_idx >= 0) { 4847da14cebeSEric Cheng ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]); 4848da14cebeSEric Cheng r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1), 4849da14cebeSEric Cheng (ixgbe->num_tx_rings - 1)); 4850da14cebeSEric Cheng } 4851da14cebeSEric Cheng 48529da57d7bSbt150084 48539da57d7bSbt150084 /* 485473cd555cSBin Tu - Sun Microsystems - Beijing China * Clean other interrupt (link change) that has its bit set in the map 48559da57d7bSbt150084 */ 485673cd555cSBin Tu - Sun Microsystems - Beijing China if (BT_TEST(vect->other_map, 0) == 1) { 48579da57d7bSbt150084 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); 48589da57d7bSbt150084 485962e6e1adSPaul Guo if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != 486062e6e1adSPaul Guo DDI_FM_OK) { 486162e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip, 486262e6e1adSPaul Guo DDI_SERVICE_DEGRADED); 486362e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR); 486462e6e1adSPaul Guo return (DDI_INTR_CLAIMED); 486562e6e1adSPaul Guo } 486662e6e1adSPaul Guo 48679da57d7bSbt150084 /* 48685b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Check "other" cause bits: any interrupt type other than tx/rx 48699da57d7bSbt150084 */ 487013740cb2SPaul Guo if (eicr & ixgbe->capab->other_intr) { 487113740cb2SPaul Guo mutex_enter(&ixgbe->gen_lock); 48725b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 48735b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 487413740cb2SPaul Guo ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); 487513740cb2SPaul Guo ixgbe_intr_other_work(ixgbe, eicr); 48765b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 48775b6dd21fSchenlu chen - Sun Microsystems - Beijing China 48785b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 487969b5a878SDan McDonald case ixgbe_mac_X540: 48807e579c30SDale Ghent case ixgbe_mac_X550: 48817e579c30SDale Ghent case ixgbe_mac_X550EM_x: 488273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; 488373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_other_work(ixgbe, eicr); 48845b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 48855b6dd21fSchenlu chen - Sun Microsystems - Beijing China 48865b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 48875b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 48885b6dd21fSchenlu chen - Sun Microsystems - Beijing China } 488973cd555cSBin Tu - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock); 489073cd555cSBin Tu - Sun Microsystems - Beijing China } 48919da57d7bSbt150084 489213740cb2SPaul Guo /* re-enable the interrupts which were automasked */ 489313740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims); 489473cd555cSBin Tu - Sun Microsystems - Beijing China } 489513740cb2SPaul Guo 48969da57d7bSbt150084 return (DDI_INTR_CLAIMED); 48979da57d7bSbt150084 } 48989da57d7bSbt150084 48999da57d7bSbt150084 /* 49009da57d7bSbt150084 * ixgbe_alloc_intrs - Allocate interrupts for the driver. 49019da57d7bSbt150084 * 49029da57d7bSbt150084 * Normal sequence is to try MSI-X; if not sucessful, try MSI; 49039da57d7bSbt150084 * if not successful, try Legacy. 49049da57d7bSbt150084 * ixgbe->intr_force can be used to force sequence to start with 49059da57d7bSbt150084 * any of the 3 types. 49069da57d7bSbt150084 * If MSI-X is not used, number of tx/rx rings is forced to 1. 49079da57d7bSbt150084 */ 49089da57d7bSbt150084 static int 49099da57d7bSbt150084 ixgbe_alloc_intrs(ixgbe_t *ixgbe) 49109da57d7bSbt150084 { 49119da57d7bSbt150084 dev_info_t *devinfo; 49129da57d7bSbt150084 int intr_types; 49139da57d7bSbt150084 int rc; 49149da57d7bSbt150084 49159da57d7bSbt150084 devinfo = ixgbe->dip; 49169da57d7bSbt150084 49179da57d7bSbt150084 /* 49189da57d7bSbt150084 * Get supported interrupt types 49199da57d7bSbt150084 */ 49209da57d7bSbt150084 rc = ddi_intr_get_supported_types(devinfo, &intr_types); 49219da57d7bSbt150084 49229da57d7bSbt150084 if (rc != DDI_SUCCESS) { 49239da57d7bSbt150084 ixgbe_log(ixgbe, 49249da57d7bSbt150084 "Get supported interrupt types failed: %d", rc); 49259da57d7bSbt150084 return (IXGBE_FAILURE); 49269da57d7bSbt150084 } 49279da57d7bSbt150084 IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types); 49289da57d7bSbt150084 49299da57d7bSbt150084 ixgbe->intr_type = 0; 49309da57d7bSbt150084 49319da57d7bSbt150084 /* 49329da57d7bSbt150084 * Install MSI-X interrupts 49339da57d7bSbt150084 */ 49349da57d7bSbt150084 if ((intr_types & DDI_INTR_TYPE_MSIX) && 49359da57d7bSbt150084 (ixgbe->intr_force <= IXGBE_INTR_MSIX)) { 49369da57d7bSbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX); 49379da57d7bSbt150084 if (rc == IXGBE_SUCCESS) 49389da57d7bSbt150084 return (IXGBE_SUCCESS); 49399da57d7bSbt150084 49409da57d7bSbt150084 ixgbe_log(ixgbe, 49419da57d7bSbt150084 "Allocate MSI-X failed, trying MSI interrupts..."); 49429da57d7bSbt150084 } 49439da57d7bSbt150084 49449da57d7bSbt150084 /* 4945da14cebeSEric Cheng * MSI-X not used, force rings and groups to 1 49469da57d7bSbt150084 */ 49479da57d7bSbt150084 ixgbe->num_rx_rings = 1; 4948da14cebeSEric Cheng ixgbe->num_rx_groups = 1; 49499da57d7bSbt150084 ixgbe->num_tx_rings = 1; 49500dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_NONE; 49519da57d7bSbt150084 ixgbe_log(ixgbe, 4952da14cebeSEric Cheng "MSI-X not used, force rings and groups number to 1"); 49539da57d7bSbt150084 49549da57d7bSbt150084 /* 49559da57d7bSbt150084 * Install MSI interrupts 49569da57d7bSbt150084 */ 49579da57d7bSbt150084 if ((intr_types & DDI_INTR_TYPE_MSI) && 49589da57d7bSbt150084 (ixgbe->intr_force <= IXGBE_INTR_MSI)) { 49599da57d7bSbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI); 49609da57d7bSbt150084 if (rc == IXGBE_SUCCESS) 49619da57d7bSbt150084 return (IXGBE_SUCCESS); 49629da57d7bSbt150084 49639da57d7bSbt150084 ixgbe_log(ixgbe, 49649da57d7bSbt150084 "Allocate MSI failed, trying Legacy interrupts..."); 49659da57d7bSbt150084 } 49669da57d7bSbt150084 49679da57d7bSbt150084 /* 49689da57d7bSbt150084 * Install legacy interrupts 49699da57d7bSbt150084 */ 49709da57d7bSbt150084 if (intr_types & DDI_INTR_TYPE_FIXED) { 49717e579c30SDale Ghent /* 49727e579c30SDale Ghent * Disallow legacy interrupts for X550. X550 has a silicon 49737e579c30SDale Ghent * bug which prevents Shared Legacy interrupts from working. 49747e579c30SDale Ghent * For details, please reference: 49757e579c30SDale Ghent * 49767e579c30SDale Ghent * Intel Ethernet Controller X550 Specification Update rev. 2.1 49777e579c30SDale Ghent * May 2016, erratum 22: PCIe Interrupt Status Bit 49787e579c30SDale Ghent */ 49797e579c30SDale Ghent if (ixgbe->hw.mac.type == ixgbe_mac_X550 || 49807e579c30SDale Ghent ixgbe->hw.mac.type == ixgbe_mac_X550EM_x || 49817e579c30SDale Ghent ixgbe->hw.mac.type == ixgbe_mac_X550_vf || 49827e579c30SDale Ghent ixgbe->hw.mac.type == ixgbe_mac_X550EM_x_vf) { 49837e579c30SDale Ghent ixgbe_log(ixgbe, 49847e579c30SDale Ghent "Legacy interrupts are not supported on this " 49857e579c30SDale Ghent "adapter. Please use MSI or MSI-X instead."); 49867e579c30SDale Ghent return (IXGBE_FAILURE); 49877e579c30SDale Ghent } 49889da57d7bSbt150084 rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED); 49899da57d7bSbt150084 if (rc == IXGBE_SUCCESS) 49909da57d7bSbt150084 return (IXGBE_SUCCESS); 49919da57d7bSbt150084 49929da57d7bSbt150084 ixgbe_log(ixgbe, 49939da57d7bSbt150084 "Allocate Legacy interrupts failed"); 49949da57d7bSbt150084 } 49959da57d7bSbt150084 49969da57d7bSbt150084 /* 49979da57d7bSbt150084 * If none of the 3 types succeeded, return failure 49989da57d7bSbt150084 */ 49999da57d7bSbt150084 return (IXGBE_FAILURE); 50009da57d7bSbt150084 } 50019da57d7bSbt150084 50029da57d7bSbt150084 /* 50039da57d7bSbt150084 * ixgbe_alloc_intr_handles - Allocate interrupt handles. 50049da57d7bSbt150084 * 50059da57d7bSbt150084 * For legacy and MSI, only 1 handle is needed. For MSI-X, 50069da57d7bSbt150084 * if fewer than 2 handles are available, return failure. 5007da14cebeSEric Cheng * Upon success, this maps the vectors to rx and tx rings for 5008da14cebeSEric Cheng * interrupts. 50099da57d7bSbt150084 */ 50109da57d7bSbt150084 static int 50119da57d7bSbt150084 ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type) 50129da57d7bSbt150084 { 50139da57d7bSbt150084 dev_info_t *devinfo; 50140dc2366fSVenugopal Iyer int request, count, actual; 5015da14cebeSEric Cheng int minimum; 50169da57d7bSbt150084 int rc; 50170dc2366fSVenugopal Iyer uint32_t ring_per_group; 50189da57d7bSbt150084 50199da57d7bSbt150084 devinfo = ixgbe->dip; 50209da57d7bSbt150084 50219da57d7bSbt150084 switch (intr_type) { 50229da57d7bSbt150084 case DDI_INTR_TYPE_FIXED: 50239da57d7bSbt150084 request = 1; /* Request 1 legacy interrupt handle */ 50249da57d7bSbt150084 minimum = 1; 50259da57d7bSbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy"); 50269da57d7bSbt150084 break; 50279da57d7bSbt150084 50289da57d7bSbt150084 case DDI_INTR_TYPE_MSI: 50299da57d7bSbt150084 request = 1; /* Request 1 MSI interrupt handle */ 50309da57d7bSbt150084 minimum = 1; 50319da57d7bSbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI"); 50329da57d7bSbt150084 break; 50339da57d7bSbt150084 50349da57d7bSbt150084 case DDI_INTR_TYPE_MSIX: 50359da57d7bSbt150084 /* 50369da57d7bSbt150084 * Best number of vectors for the adapter is 50370dc2366fSVenugopal Iyer * (# rx rings + # tx rings), however we will 50380dc2366fSVenugopal Iyer * limit the request number. 50399da57d7bSbt150084 */ 50400dc2366fSVenugopal Iyer request = min(16, ixgbe->num_rx_rings + ixgbe->num_tx_rings); 504173cd555cSBin Tu - Sun Microsystems - Beijing China if (request > ixgbe->capab->max_ring_vect) 504273cd555cSBin Tu - Sun Microsystems - Beijing China request = ixgbe->capab->max_ring_vect; 50430dc2366fSVenugopal Iyer minimum = 1; 50449da57d7bSbt150084 IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X"); 50459da57d7bSbt150084 break; 50469da57d7bSbt150084 50479da57d7bSbt150084 default: 50489da57d7bSbt150084 ixgbe_log(ixgbe, 50499da57d7bSbt150084 "invalid call to ixgbe_alloc_intr_handles(): %d\n", 50509da57d7bSbt150084 intr_type); 50519da57d7bSbt150084 return (IXGBE_FAILURE); 50529da57d7bSbt150084 } 50539da57d7bSbt150084 IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d minimum: %d", 50549da57d7bSbt150084 request, minimum); 50559da57d7bSbt150084 50569da57d7bSbt150084 /* 50579da57d7bSbt150084 * Get number of supported interrupts 50589da57d7bSbt150084 */ 50599da57d7bSbt150084 rc = ddi_intr_get_nintrs(devinfo, intr_type, &count); 50609da57d7bSbt150084 if ((rc != DDI_SUCCESS) || (count < minimum)) { 50619da57d7bSbt150084 ixgbe_log(ixgbe, 50629da57d7bSbt150084 "Get interrupt number failed. Return: %d, count: %d", 50639da57d7bSbt150084 rc, count); 50649da57d7bSbt150084 return (IXGBE_FAILURE); 50659da57d7bSbt150084 } 50669da57d7bSbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count); 50679da57d7bSbt150084 50689da57d7bSbt150084 actual = 0; 50699da57d7bSbt150084 ixgbe->intr_cnt = 0; 50700dc2366fSVenugopal Iyer ixgbe->intr_cnt_max = 0; 50710dc2366fSVenugopal Iyer ixgbe->intr_cnt_min = 0; 50729da57d7bSbt150084 50739da57d7bSbt150084 /* 50749da57d7bSbt150084 * Allocate an array of interrupt handles 50759da57d7bSbt150084 */ 50769da57d7bSbt150084 ixgbe->intr_size = request * sizeof (ddi_intr_handle_t); 50779da57d7bSbt150084 ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP); 50789da57d7bSbt150084 50799da57d7bSbt150084 rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0, 50809da57d7bSbt150084 request, &actual, DDI_INTR_ALLOC_NORMAL); 50819da57d7bSbt150084 if (rc != DDI_SUCCESS) { 50829da57d7bSbt150084 ixgbe_log(ixgbe, "Allocate interrupts failed. " 50839da57d7bSbt150084 "return: %d, request: %d, actual: %d", 50849da57d7bSbt150084 rc, request, actual); 50859da57d7bSbt150084 goto alloc_handle_fail; 50869da57d7bSbt150084 } 50879da57d7bSbt150084 IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual); 50889da57d7bSbt150084 50890dc2366fSVenugopal Iyer /* 50900dc2366fSVenugopal Iyer * upper/lower limit of interrupts 50910dc2366fSVenugopal Iyer */ 50929da57d7bSbt150084 ixgbe->intr_cnt = actual; 50930dc2366fSVenugopal Iyer ixgbe->intr_cnt_max = request; 50940dc2366fSVenugopal Iyer ixgbe->intr_cnt_min = minimum; 50950dc2366fSVenugopal Iyer 50960dc2366fSVenugopal Iyer /* 50970dc2366fSVenugopal Iyer * rss number per group should not exceed the rx interrupt number, 50980dc2366fSVenugopal Iyer * else need to adjust rx ring number. 50990dc2366fSVenugopal Iyer */ 51000dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 51010dc2366fSVenugopal Iyer ASSERT((ixgbe->num_rx_rings % ixgbe->num_rx_groups) == 0); 51025b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (actual < ring_per_group) { 51035b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->num_rx_rings = ixgbe->num_rx_groups * actual; 51040dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss_conf(ixgbe); 51050dc2366fSVenugopal Iyer } 51069da57d7bSbt150084 51079da57d7bSbt150084 /* 5108da14cebeSEric Cheng * Now we know the actual number of vectors. Here we map the vector 5109da14cebeSEric Cheng * to other, rx rings and tx ring. 51109da57d7bSbt150084 */ 51119da57d7bSbt150084 if (actual < minimum) { 51129da57d7bSbt150084 ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d", 51139da57d7bSbt150084 actual); 51149da57d7bSbt150084 goto alloc_handle_fail; 51159da57d7bSbt150084 } 51169da57d7bSbt150084 51179da57d7bSbt150084 /* 51189da57d7bSbt150084 * Get priority for first vector, assume remaining are all the same 51199da57d7bSbt150084 */ 51209da57d7bSbt150084 rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri); 51219da57d7bSbt150084 if (rc != DDI_SUCCESS) { 51229da57d7bSbt150084 ixgbe_log(ixgbe, 51239da57d7bSbt150084 "Get interrupt priority failed: %d", rc); 51249da57d7bSbt150084 goto alloc_handle_fail; 51259da57d7bSbt150084 } 51269da57d7bSbt150084 51279da57d7bSbt150084 rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap); 51289da57d7bSbt150084 if (rc != DDI_SUCCESS) { 51299da57d7bSbt150084 ixgbe_log(ixgbe, 51309da57d7bSbt150084 "Get interrupt cap failed: %d", rc); 51319da57d7bSbt150084 goto alloc_handle_fail; 51329da57d7bSbt150084 } 51339da57d7bSbt150084 51349da57d7bSbt150084 ixgbe->intr_type = intr_type; 51359da57d7bSbt150084 51369da57d7bSbt150084 return (IXGBE_SUCCESS); 51379da57d7bSbt150084 51389da57d7bSbt150084 alloc_handle_fail: 51399da57d7bSbt150084 ixgbe_rem_intrs(ixgbe); 51409da57d7bSbt150084 51419da57d7bSbt150084 return (IXGBE_FAILURE); 51429da57d7bSbt150084 } 51439da57d7bSbt150084 51449da57d7bSbt150084 /* 51459da57d7bSbt150084 * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type. 51469da57d7bSbt150084 * 51479da57d7bSbt150084 * Before adding the interrupt handlers, the interrupt vectors have 51489da57d7bSbt150084 * been allocated, and the rx/tx rings have also been allocated. 51499da57d7bSbt150084 */ 51509da57d7bSbt150084 static int 51519da57d7bSbt150084 ixgbe_add_intr_handlers(ixgbe_t *ixgbe) 51529da57d7bSbt150084 { 5153da14cebeSEric Cheng int vector = 0; 51549da57d7bSbt150084 int rc; 51559da57d7bSbt150084 51569da57d7bSbt150084 switch (ixgbe->intr_type) { 51579da57d7bSbt150084 case DDI_INTR_TYPE_MSIX: 51589da57d7bSbt150084 /* 515973cd555cSBin Tu - Sun Microsystems - Beijing China * Add interrupt handler for all vectors 51609da57d7bSbt150084 */ 516173cd555cSBin Tu - Sun Microsystems - Beijing China for (vector = 0; vector < ixgbe->intr_cnt; vector++) { 51629da57d7bSbt150084 /* 51639da57d7bSbt150084 * install pointer to vect_map[vector] 51649da57d7bSbt150084 */ 51659da57d7bSbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 516673cd555cSBin Tu - Sun Microsystems - Beijing China (ddi_intr_handler_t *)ixgbe_intr_msix, 51679da57d7bSbt150084 (void *)&ixgbe->vect_map[vector], NULL); 51689da57d7bSbt150084 51699da57d7bSbt150084 if (rc != DDI_SUCCESS) { 51709da57d7bSbt150084 ixgbe_log(ixgbe, 517119843f01SPaul Guo "Add interrupt handler failed. " 5172da14cebeSEric Cheng "return: %d, vector: %d", rc, vector); 51739da57d7bSbt150084 for (vector--; vector >= 0; vector--) { 51749da57d7bSbt150084 (void) ddi_intr_remove_handler( 51759da57d7bSbt150084 ixgbe->htable[vector]); 51769da57d7bSbt150084 } 51779da57d7bSbt150084 return (IXGBE_FAILURE); 51789da57d7bSbt150084 } 51799da57d7bSbt150084 } 5180da14cebeSEric Cheng 51819da57d7bSbt150084 break; 51829da57d7bSbt150084 51839da57d7bSbt150084 case DDI_INTR_TYPE_MSI: 51849da57d7bSbt150084 /* 51859da57d7bSbt150084 * Add interrupt handlers for the only vector 51869da57d7bSbt150084 */ 51879da57d7bSbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 51889da57d7bSbt150084 (ddi_intr_handler_t *)ixgbe_intr_msi, 51899da57d7bSbt150084 (void *)ixgbe, NULL); 51909da57d7bSbt150084 51919da57d7bSbt150084 if (rc != DDI_SUCCESS) { 51929da57d7bSbt150084 ixgbe_log(ixgbe, 51939da57d7bSbt150084 "Add MSI interrupt handler failed: %d", rc); 51949da57d7bSbt150084 return (IXGBE_FAILURE); 51959da57d7bSbt150084 } 51969da57d7bSbt150084 51979da57d7bSbt150084 break; 51989da57d7bSbt150084 51999da57d7bSbt150084 case DDI_INTR_TYPE_FIXED: 52009da57d7bSbt150084 /* 52019da57d7bSbt150084 * Add interrupt handlers for the only vector 52029da57d7bSbt150084 */ 52039da57d7bSbt150084 rc = ddi_intr_add_handler(ixgbe->htable[vector], 52049da57d7bSbt150084 (ddi_intr_handler_t *)ixgbe_intr_legacy, 52059da57d7bSbt150084 (void *)ixgbe, NULL); 52069da57d7bSbt150084 52079da57d7bSbt150084 if (rc != DDI_SUCCESS) { 52089da57d7bSbt150084 ixgbe_log(ixgbe, 52099da57d7bSbt150084 "Add legacy interrupt handler failed: %d", rc); 52109da57d7bSbt150084 return (IXGBE_FAILURE); 52119da57d7bSbt150084 } 52129da57d7bSbt150084 52139da57d7bSbt150084 break; 52149da57d7bSbt150084 52159da57d7bSbt150084 default: 52169da57d7bSbt150084 return (IXGBE_FAILURE); 52179da57d7bSbt150084 } 52189da57d7bSbt150084 52199da57d7bSbt150084 return (IXGBE_SUCCESS); 52209da57d7bSbt150084 } 52219da57d7bSbt150084 52229da57d7bSbt150084 #pragma inline(ixgbe_map_rxring_to_vector) 52239da57d7bSbt150084 /* 52249da57d7bSbt150084 * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector. 52259da57d7bSbt150084 */ 52269da57d7bSbt150084 static void 52279da57d7bSbt150084 ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx) 52289da57d7bSbt150084 { 52299da57d7bSbt150084 /* 52309da57d7bSbt150084 * Set bit in map 52319da57d7bSbt150084 */ 52329da57d7bSbt150084 BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx); 52339da57d7bSbt150084 52349da57d7bSbt150084 /* 52359da57d7bSbt150084 * Count bits set 52369da57d7bSbt150084 */ 52379da57d7bSbt150084 ixgbe->vect_map[v_idx].rxr_cnt++; 52389da57d7bSbt150084 52399da57d7bSbt150084 /* 52409da57d7bSbt150084 * Remember bit position 52419da57d7bSbt150084 */ 5242da14cebeSEric Cheng ixgbe->rx_rings[r_idx].intr_vector = v_idx; 52439da57d7bSbt150084 ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx; 52449da57d7bSbt150084 } 52459da57d7bSbt150084 52469da57d7bSbt150084 #pragma inline(ixgbe_map_txring_to_vector) 52479da57d7bSbt150084 /* 52489da57d7bSbt150084 * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector. 52499da57d7bSbt150084 */ 52509da57d7bSbt150084 static void 52519da57d7bSbt150084 ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx) 52529da57d7bSbt150084 { 52539da57d7bSbt150084 /* 52549da57d7bSbt150084 * Set bit in map 52559da57d7bSbt150084 */ 52569da57d7bSbt150084 BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx); 52579da57d7bSbt150084 52589da57d7bSbt150084 /* 52599da57d7bSbt150084 * Count bits set 52609da57d7bSbt150084 */ 52619da57d7bSbt150084 ixgbe->vect_map[v_idx].txr_cnt++; 52629da57d7bSbt150084 52639da57d7bSbt150084 /* 52649da57d7bSbt150084 * Remember bit position 52659da57d7bSbt150084 */ 5266da14cebeSEric Cheng ixgbe->tx_rings[t_idx].intr_vector = v_idx; 52679da57d7bSbt150084 ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx; 52689da57d7bSbt150084 } 52699da57d7bSbt150084 52709da57d7bSbt150084 /* 5271da14cebeSEric Cheng * ixgbe_setup_ivar - Set the given entry in the given interrupt vector 52729da57d7bSbt150084 * allocation register (IVAR). 527373cd555cSBin Tu - Sun Microsystems - Beijing China * cause: 527473cd555cSBin Tu - Sun Microsystems - Beijing China * -1 : other cause 527573cd555cSBin Tu - Sun Microsystems - Beijing China * 0 : rx 527673cd555cSBin Tu - Sun Microsystems - Beijing China * 1 : tx 52779da57d7bSbt150084 */ 52789da57d7bSbt150084 static void 527973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector, 528073cd555cSBin Tu - Sun Microsystems - Beijing China int8_t cause) 52819da57d7bSbt150084 { 52829da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 52839da57d7bSbt150084 u32 ivar, index; 52849da57d7bSbt150084 528573cd555cSBin Tu - Sun Microsystems - Beijing China switch (hw->mac.type) { 528673cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 52879da57d7bSbt150084 msix_vector |= IXGBE_IVAR_ALLOC_VAL; 528873cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) { 528973cd555cSBin Tu - Sun Microsystems - Beijing China cause = 0; 529073cd555cSBin Tu - Sun Microsystems - Beijing China } 529173cd555cSBin Tu - Sun Microsystems - Beijing China index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 52929da57d7bSbt150084 ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 5293da14cebeSEric Cheng ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3))); 5294da14cebeSEric Cheng ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3))); 5295da14cebeSEric Cheng IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 529673cd555cSBin Tu - Sun Microsystems - Beijing China break; 52975b6dd21fSchenlu chen - Sun Microsystems - Beijing China 529873cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 529969b5a878SDan McDonald case ixgbe_mac_X540: 53007e579c30SDale Ghent case ixgbe_mac_X550: 53017e579c30SDale Ghent case ixgbe_mac_X550EM_x: 530273cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) { 530373cd555cSBin Tu - Sun Microsystems - Beijing China /* other causes */ 530473cd555cSBin Tu - Sun Microsystems - Beijing China msix_vector |= IXGBE_IVAR_ALLOC_VAL; 530573cd555cSBin Tu - Sun Microsystems - Beijing China index = (intr_alloc_entry & 1) * 8; 530673cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 530773cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(0xFF << index); 530873cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (msix_vector << index); 530973cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 531073cd555cSBin Tu - Sun Microsystems - Beijing China } else { 531173cd555cSBin Tu - Sun Microsystems - Beijing China /* tx or rx causes */ 531273cd555cSBin Tu - Sun Microsystems - Beijing China msix_vector |= IXGBE_IVAR_ALLOC_VAL; 531373cd555cSBin Tu - Sun Microsystems - Beijing China index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 531473cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, 531573cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_IVAR(intr_alloc_entry >> 1)); 531673cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(0xFF << index); 531773cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (msix_vector << index); 531873cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 531973cd555cSBin Tu - Sun Microsystems - Beijing China ivar); 532073cd555cSBin Tu - Sun Microsystems - Beijing China } 532173cd555cSBin Tu - Sun Microsystems - Beijing China break; 53225b6dd21fSchenlu chen - Sun Microsystems - Beijing China 532373cd555cSBin Tu - Sun Microsystems - Beijing China default: 532473cd555cSBin Tu - Sun Microsystems - Beijing China break; 532573cd555cSBin Tu - Sun Microsystems - Beijing China } 5326da14cebeSEric Cheng } 5327da14cebeSEric Cheng 5328da14cebeSEric Cheng /* 5329da14cebeSEric Cheng * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of 5330da14cebeSEric Cheng * given interrupt vector allocation register (IVAR). 533173cd555cSBin Tu - Sun Microsystems - Beijing China * cause: 533273cd555cSBin Tu - Sun Microsystems - Beijing China * -1 : other cause 533373cd555cSBin Tu - Sun Microsystems - Beijing China * 0 : rx 533473cd555cSBin Tu - Sun Microsystems - Beijing China * 1 : tx 5335da14cebeSEric Cheng */ 5336da14cebeSEric Cheng static void 533773cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause) 5338da14cebeSEric Cheng { 5339da14cebeSEric Cheng struct ixgbe_hw *hw = &ixgbe->hw; 5340da14cebeSEric Cheng u32 ivar, index; 5341da14cebeSEric Cheng 534273cd555cSBin Tu - Sun Microsystems - Beijing China switch (hw->mac.type) { 534373cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 534473cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) { 534573cd555cSBin Tu - Sun Microsystems - Beijing China cause = 0; 534673cd555cSBin Tu - Sun Microsystems - Beijing China } 534773cd555cSBin Tu - Sun Microsystems - Beijing China index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 5348da14cebeSEric Cheng ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 534973cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 * 535073cd555cSBin Tu - Sun Microsystems - Beijing China (intr_alloc_entry & 0x3))); 5351da14cebeSEric Cheng IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 535273cd555cSBin Tu - Sun Microsystems - Beijing China break; 53535b6dd21fSchenlu chen - Sun Microsystems - Beijing China 535473cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 535569b5a878SDan McDonald case ixgbe_mac_X540: 53567e579c30SDale Ghent case ixgbe_mac_X550: 53577e579c30SDale Ghent case ixgbe_mac_X550EM_x: 535873cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) { 535973cd555cSBin Tu - Sun Microsystems - Beijing China /* other causes */ 536073cd555cSBin Tu - Sun Microsystems - Beijing China index = (intr_alloc_entry & 1) * 8; 536173cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 536273cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (IXGBE_IVAR_ALLOC_VAL << index); 536373cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 536473cd555cSBin Tu - Sun Microsystems - Beijing China } else { 536573cd555cSBin Tu - Sun Microsystems - Beijing China /* tx or rx causes */ 536673cd555cSBin Tu - Sun Microsystems - Beijing China index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 536773cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, 536873cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_IVAR(intr_alloc_entry >> 1)); 536973cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (IXGBE_IVAR_ALLOC_VAL << index); 537073cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 537173cd555cSBin Tu - Sun Microsystems - Beijing China ivar); 537273cd555cSBin Tu - Sun Microsystems - Beijing China } 537373cd555cSBin Tu - Sun Microsystems - Beijing China break; 53745b6dd21fSchenlu chen - Sun Microsystems - Beijing China 537573cd555cSBin Tu - Sun Microsystems - Beijing China default: 537673cd555cSBin Tu - Sun Microsystems - Beijing China break; 537773cd555cSBin Tu - Sun Microsystems - Beijing China } 5378da14cebeSEric Cheng } 5379da14cebeSEric Cheng 5380da14cebeSEric Cheng /* 538173cd555cSBin Tu - Sun Microsystems - Beijing China * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of 5382da14cebeSEric Cheng * given interrupt vector allocation register (IVAR). 538373cd555cSBin Tu - Sun Microsystems - Beijing China * cause: 538473cd555cSBin Tu - Sun Microsystems - Beijing China * -1 : other cause 538573cd555cSBin Tu - Sun Microsystems - Beijing China * 0 : rx 538673cd555cSBin Tu - Sun Microsystems - Beijing China * 1 : tx 5387da14cebeSEric Cheng */ 5388da14cebeSEric Cheng static void 538973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause) 5390da14cebeSEric Cheng { 5391da14cebeSEric Cheng struct ixgbe_hw *hw = &ixgbe->hw; 5392da14cebeSEric Cheng u32 ivar, index; 5393da14cebeSEric Cheng 539473cd555cSBin Tu - Sun Microsystems - Beijing China switch (hw->mac.type) { 539573cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 539673cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) { 539773cd555cSBin Tu - Sun Microsystems - Beijing China cause = 0; 539873cd555cSBin Tu - Sun Microsystems - Beijing China } 539973cd555cSBin Tu - Sun Microsystems - Beijing China index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F; 5400da14cebeSEric Cheng ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); 540173cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 * 540273cd555cSBin Tu - Sun Microsystems - Beijing China (intr_alloc_entry & 0x3))); 54039da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); 540473cd555cSBin Tu - Sun Microsystems - Beijing China break; 54055b6dd21fSchenlu chen - Sun Microsystems - Beijing China 540673cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 540769b5a878SDan McDonald case ixgbe_mac_X540: 54087e579c30SDale Ghent case ixgbe_mac_X550: 54097e579c30SDale Ghent case ixgbe_mac_X550EM_x: 541073cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) { 541173cd555cSBin Tu - Sun Microsystems - Beijing China /* other causes */ 541273cd555cSBin Tu - Sun Microsystems - Beijing China index = (intr_alloc_entry & 1) * 8; 541373cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); 541473cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index); 541573cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); 541673cd555cSBin Tu - Sun Microsystems - Beijing China } else { 541773cd555cSBin Tu - Sun Microsystems - Beijing China /* tx or rx causes */ 541873cd555cSBin Tu - Sun Microsystems - Beijing China index = ((16 * (intr_alloc_entry & 1)) + (8 * cause)); 541973cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, 542073cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_IVAR(intr_alloc_entry >> 1)); 542173cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index); 542273cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1), 542373cd555cSBin Tu - Sun Microsystems - Beijing China ivar); 542473cd555cSBin Tu - Sun Microsystems - Beijing China } 542573cd555cSBin Tu - Sun Microsystems - Beijing China break; 54265b6dd21fSchenlu chen - Sun Microsystems - Beijing China 542773cd555cSBin Tu - Sun Microsystems - Beijing China default: 542873cd555cSBin Tu - Sun Microsystems - Beijing China break; 542973cd555cSBin Tu - Sun Microsystems - Beijing China } 54309da57d7bSbt150084 } 54319da57d7bSbt150084 54329da57d7bSbt150084 /* 54330dc2366fSVenugopal Iyer * Convert the rx ring index driver maintained to the rx ring index 54340dc2366fSVenugopal Iyer * in h/w. 54350dc2366fSVenugopal Iyer */ 54360dc2366fSVenugopal Iyer static uint32_t 54370dc2366fSVenugopal Iyer ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index) 54380dc2366fSVenugopal Iyer { 54390dc2366fSVenugopal Iyer 54400dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw; 54410dc2366fSVenugopal Iyer uint32_t rx_ring_per_group, hw_rx_index; 54420dc2366fSVenugopal Iyer 54430dc2366fSVenugopal Iyer if (ixgbe->classify_mode == IXGBE_CLASSIFY_RSS || 54440dc2366fSVenugopal Iyer ixgbe->classify_mode == IXGBE_CLASSIFY_NONE) { 54450dc2366fSVenugopal Iyer return (sw_rx_index); 54460dc2366fSVenugopal Iyer } else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ) { 54475b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 54485b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 54490dc2366fSVenugopal Iyer return (sw_rx_index); 54505b6dd21fSchenlu chen - Sun Microsystems - Beijing China 54515b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 545269b5a878SDan McDonald case ixgbe_mac_X540: 54537e579c30SDale Ghent case ixgbe_mac_X550: 54547e579c30SDale Ghent case ixgbe_mac_X550EM_x: 54550dc2366fSVenugopal Iyer return (sw_rx_index * 2); 54565b6dd21fSchenlu chen - Sun Microsystems - Beijing China 54575b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 54585b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 54590dc2366fSVenugopal Iyer } 54600dc2366fSVenugopal Iyer } else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) { 54610dc2366fSVenugopal Iyer rx_ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; 54620dc2366fSVenugopal Iyer 54635b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) { 54645b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 54650dc2366fSVenugopal Iyer hw_rx_index = (sw_rx_index / rx_ring_per_group) * 54660dc2366fSVenugopal Iyer 16 + (sw_rx_index % rx_ring_per_group); 54670dc2366fSVenugopal Iyer return (hw_rx_index); 54685b6dd21fSchenlu chen - Sun Microsystems - Beijing China 54695b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 547069b5a878SDan McDonald case ixgbe_mac_X540: 54717e579c30SDale Ghent case ixgbe_mac_X550: 54727e579c30SDale Ghent case ixgbe_mac_X550EM_x: 54730dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups > 32) { 54740dc2366fSVenugopal Iyer hw_rx_index = (sw_rx_index / 54750dc2366fSVenugopal Iyer rx_ring_per_group) * 2 + 54760dc2366fSVenugopal Iyer (sw_rx_index % rx_ring_per_group); 54770dc2366fSVenugopal Iyer } else { 54780dc2366fSVenugopal Iyer hw_rx_index = (sw_rx_index / 54790dc2366fSVenugopal Iyer rx_ring_per_group) * 4 + 54800dc2366fSVenugopal Iyer (sw_rx_index % rx_ring_per_group); 54810dc2366fSVenugopal Iyer } 54820dc2366fSVenugopal Iyer return (hw_rx_index); 54835b6dd21fSchenlu chen - Sun Microsystems - Beijing China 54845b6dd21fSchenlu chen - Sun Microsystems - Beijing China default: 54855b6dd21fSchenlu chen - Sun Microsystems - Beijing China break; 54860dc2366fSVenugopal Iyer } 54870dc2366fSVenugopal Iyer } 54880dc2366fSVenugopal Iyer 54890dc2366fSVenugopal Iyer /* 54900dc2366fSVenugopal Iyer * Should never reach. Just to make compiler happy. 54910dc2366fSVenugopal Iyer */ 54920dc2366fSVenugopal Iyer return (sw_rx_index); 54930dc2366fSVenugopal Iyer } 54940dc2366fSVenugopal Iyer 54950dc2366fSVenugopal Iyer /* 549673cd555cSBin Tu - Sun Microsystems - Beijing China * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors. 54979da57d7bSbt150084 * 549873cd555cSBin Tu - Sun Microsystems - Beijing China * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt 549973cd555cSBin Tu - Sun Microsystems - Beijing China * to vector[0 - (intr_cnt -1)]. 55009da57d7bSbt150084 */ 55019da57d7bSbt150084 static int 550273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe) 55039da57d7bSbt150084 { 55049da57d7bSbt150084 int i, vector = 0; 55059da57d7bSbt150084 55069da57d7bSbt150084 /* initialize vector map */ 55079da57d7bSbt150084 bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map)); 550873cd555cSBin Tu - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->intr_cnt; i++) { 550973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->vect_map[i].ixgbe = ixgbe; 551073cd555cSBin Tu - Sun Microsystems - Beijing China } 55119da57d7bSbt150084 55129da57d7bSbt150084 /* 5513da14cebeSEric Cheng * non-MSI-X case is very simple: rx rings[0] on RTxQ[0], 5514da14cebeSEric Cheng * tx rings[0] on RTxQ[1]. 55159da57d7bSbt150084 */ 55169da57d7bSbt150084 if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) { 55179da57d7bSbt150084 ixgbe_map_rxring_to_vector(ixgbe, 0, 0); 5518da14cebeSEric Cheng ixgbe_map_txring_to_vector(ixgbe, 0, 1); 55199da57d7bSbt150084 return (IXGBE_SUCCESS); 55209da57d7bSbt150084 } 55219da57d7bSbt150084 55229da57d7bSbt150084 /* 552373cd555cSBin Tu - Sun Microsystems - Beijing China * Interrupts/vectors mapping for MSI-X 55249da57d7bSbt150084 */ 55259da57d7bSbt150084 55269da57d7bSbt150084 /* 552773cd555cSBin Tu - Sun Microsystems - Beijing China * Map other interrupt to vector 0, 552873cd555cSBin Tu - Sun Microsystems - Beijing China * Set bit in map and count the bits set. 552973cd555cSBin Tu - Sun Microsystems - Beijing China */ 553073cd555cSBin Tu - Sun Microsystems - Beijing China BT_SET(ixgbe->vect_map[vector].other_map, 0); 553173cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->vect_map[vector].other_cnt++; 553273cd555cSBin Tu - Sun Microsystems - Beijing China 553373cd555cSBin Tu - Sun Microsystems - Beijing China /* 553473cd555cSBin Tu - Sun Microsystems - Beijing China * Map rx ring interrupts to vectors 55359da57d7bSbt150084 */ 5536da14cebeSEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) { 5537da14cebeSEric Cheng ixgbe_map_rxring_to_vector(ixgbe, i, vector); 553873cd555cSBin Tu - Sun Microsystems - Beijing China vector = (vector +1) % ixgbe->intr_cnt; 5539da14cebeSEric Cheng } 55409da57d7bSbt150084 55419da57d7bSbt150084 /* 554273cd555cSBin Tu - Sun Microsystems - Beijing China * Map tx ring interrupts to vectors 55439da57d7bSbt150084 */ 5544da14cebeSEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) { 5545da14cebeSEric Cheng ixgbe_map_txring_to_vector(ixgbe, i, vector); 554673cd555cSBin Tu - Sun Microsystems - Beijing China vector = (vector +1) % ixgbe->intr_cnt; 55479da57d7bSbt150084 } 55489da57d7bSbt150084 55499da57d7bSbt150084 return (IXGBE_SUCCESS); 55509da57d7bSbt150084 } 55519da57d7bSbt150084 55529da57d7bSbt150084 /* 55539da57d7bSbt150084 * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s). 55549da57d7bSbt150084 * 5555da14cebeSEric Cheng * This relies on ring/vector mapping already set up in the 55569da57d7bSbt150084 * vect_map[] structures 55579da57d7bSbt150084 */ 55589da57d7bSbt150084 static void 55599da57d7bSbt150084 ixgbe_setup_adapter_vector(ixgbe_t *ixgbe) 55609da57d7bSbt150084 { 55619da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 556273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_vector_t *vect; /* vector bitmap */ 55639da57d7bSbt150084 int r_idx; /* ring index */ 55649da57d7bSbt150084 int v_idx; /* vector index */ 55650dc2366fSVenugopal Iyer uint32_t hw_index; 55669da57d7bSbt150084 55679da57d7bSbt150084 /* 55689da57d7bSbt150084 * Clear any previous entries 55699da57d7bSbt150084 */ 557073cd555cSBin Tu - Sun Microsystems - Beijing China switch (hw->mac.type) { 557173cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82598EB: 557273cd555cSBin Tu - Sun Microsystems - Beijing China for (v_idx = 0; v_idx < 25; v_idx++) 55739da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); 557473cd555cSBin Tu - Sun Microsystems - Beijing China break; 55755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 557673cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB: 557769b5a878SDan McDonald case ixgbe_mac_X540: 55787e579c30SDale Ghent case ixgbe_mac_X550: 55797e579c30SDale Ghent case ixgbe_mac_X550EM_x: 558073cd555cSBin Tu - Sun Microsystems - Beijing China for (v_idx = 0; v_idx < 64; v_idx++) 558173cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); 558273cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0); 558373cd555cSBin Tu - Sun Microsystems - Beijing China break; 55845b6dd21fSchenlu chen - Sun Microsystems - Beijing China 558573cd555cSBin Tu - Sun Microsystems - Beijing China default: 558673cd555cSBin Tu - Sun Microsystems - Beijing China break; 558773cd555cSBin Tu - Sun Microsystems - Beijing China } 558873cd555cSBin Tu - Sun Microsystems - Beijing China 55899da57d7bSbt150084 /* 5590da14cebeSEric Cheng * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and 5591da14cebeSEric Cheng * tx rings[0] will use RTxQ[1]. 55929da57d7bSbt150084 */ 5593da14cebeSEric Cheng if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) { 559473cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe, 0, 0, 0); 559573cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe, 0, 1, 1); 5596da14cebeSEric Cheng return; 5597da14cebeSEric Cheng } 5598da14cebeSEric Cheng 5599da14cebeSEric Cheng /* 560073cd555cSBin Tu - Sun Microsystems - Beijing China * For MSI-X interrupt, "Other" is always on vector[0]. 5601da14cebeSEric Cheng */ 560273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1); 56039da57d7bSbt150084 56049da57d7bSbt150084 /* 56059da57d7bSbt150084 * For each interrupt vector, populate the IVAR table 56069da57d7bSbt150084 */ 56079da57d7bSbt150084 for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) { 56089da57d7bSbt150084 vect = &ixgbe->vect_map[v_idx]; 56099da57d7bSbt150084 56109da57d7bSbt150084 /* 56119da57d7bSbt150084 * For each rx ring bit set 56129da57d7bSbt150084 */ 56139da57d7bSbt150084 r_idx = bt_getlowbit(vect->rx_map, 0, 56149da57d7bSbt150084 (ixgbe->num_rx_rings - 1)); 56159da57d7bSbt150084 56169da57d7bSbt150084 while (r_idx >= 0) { 56170dc2366fSVenugopal Iyer hw_index = ixgbe->rx_rings[r_idx].hw_index; 56180dc2366fSVenugopal Iyer ixgbe_setup_ivar(ixgbe, hw_index, v_idx, 0); 56199da57d7bSbt150084 r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1), 56209da57d7bSbt150084 (ixgbe->num_rx_rings - 1)); 56219da57d7bSbt150084 } 56229da57d7bSbt150084 56239da57d7bSbt150084 /* 56249da57d7bSbt150084 * For each tx ring bit set 56259da57d7bSbt150084 */ 56269da57d7bSbt150084 r_idx = bt_getlowbit(vect->tx_map, 0, 56279da57d7bSbt150084 (ixgbe->num_tx_rings - 1)); 56289da57d7bSbt150084 56299da57d7bSbt150084 while (r_idx >= 0) { 563073cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1); 56319da57d7bSbt150084 r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1), 56329da57d7bSbt150084 (ixgbe->num_tx_rings - 1)); 56339da57d7bSbt150084 } 56349da57d7bSbt150084 } 56359da57d7bSbt150084 } 56369da57d7bSbt150084 56379da57d7bSbt150084 /* 56389da57d7bSbt150084 * ixgbe_rem_intr_handlers - Remove the interrupt handlers. 56399da57d7bSbt150084 */ 56409da57d7bSbt150084 static void 56419da57d7bSbt150084 ixgbe_rem_intr_handlers(ixgbe_t *ixgbe) 56429da57d7bSbt150084 { 56439da57d7bSbt150084 int i; 56449da57d7bSbt150084 int rc; 56459da57d7bSbt150084 56469da57d7bSbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 56479da57d7bSbt150084 rc = ddi_intr_remove_handler(ixgbe->htable[i]); 56489da57d7bSbt150084 if (rc != DDI_SUCCESS) { 56499da57d7bSbt150084 IXGBE_DEBUGLOG_1(ixgbe, 56509da57d7bSbt150084 "Remove intr handler failed: %d", rc); 56519da57d7bSbt150084 } 56529da57d7bSbt150084 } 56539da57d7bSbt150084 } 56549da57d7bSbt150084 56559da57d7bSbt150084 /* 56569da57d7bSbt150084 * ixgbe_rem_intrs - Remove the allocated interrupts. 56579da57d7bSbt150084 */ 56589da57d7bSbt150084 static void 56599da57d7bSbt150084 ixgbe_rem_intrs(ixgbe_t *ixgbe) 56609da57d7bSbt150084 { 56619da57d7bSbt150084 int i; 56629da57d7bSbt150084 int rc; 56639da57d7bSbt150084 56649da57d7bSbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 56659da57d7bSbt150084 rc = ddi_intr_free(ixgbe->htable[i]); 56669da57d7bSbt150084 if (rc != DDI_SUCCESS) { 56679da57d7bSbt150084 IXGBE_DEBUGLOG_1(ixgbe, 56689da57d7bSbt150084 "Free intr failed: %d", rc); 56699da57d7bSbt150084 } 56709da57d7bSbt150084 } 56719da57d7bSbt150084 56729da57d7bSbt150084 kmem_free(ixgbe->htable, ixgbe->intr_size); 56739da57d7bSbt150084 ixgbe->htable = NULL; 56749da57d7bSbt150084 } 56759da57d7bSbt150084 56769da57d7bSbt150084 /* 56779da57d7bSbt150084 * ixgbe_enable_intrs - Enable all the ddi interrupts. 56789da57d7bSbt150084 */ 56799da57d7bSbt150084 static int 56809da57d7bSbt150084 ixgbe_enable_intrs(ixgbe_t *ixgbe) 56819da57d7bSbt150084 { 56829da57d7bSbt150084 int i; 56839da57d7bSbt150084 int rc; 56849da57d7bSbt150084 56859da57d7bSbt150084 /* 56869da57d7bSbt150084 * Enable interrupts 56879da57d7bSbt150084 */ 56889da57d7bSbt150084 if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) { 56899da57d7bSbt150084 /* 56909da57d7bSbt150084 * Call ddi_intr_block_enable() for MSI 56919da57d7bSbt150084 */ 56929da57d7bSbt150084 rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt); 56939da57d7bSbt150084 if (rc != DDI_SUCCESS) { 56949da57d7bSbt150084 ixgbe_log(ixgbe, 56959da57d7bSbt150084 "Enable block intr failed: %d", rc); 56969da57d7bSbt150084 return (IXGBE_FAILURE); 56979da57d7bSbt150084 } 56989da57d7bSbt150084 } else { 56999da57d7bSbt150084 /* 57009da57d7bSbt150084 * Call ddi_intr_enable() for Legacy/MSI non block enable 57019da57d7bSbt150084 */ 57029da57d7bSbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 57039da57d7bSbt150084 rc = ddi_intr_enable(ixgbe->htable[i]); 57049da57d7bSbt150084 if (rc != DDI_SUCCESS) { 57059da57d7bSbt150084 ixgbe_log(ixgbe, 57069da57d7bSbt150084 "Enable intr failed: %d", rc); 57079da57d7bSbt150084 return (IXGBE_FAILURE); 57089da57d7bSbt150084 } 57099da57d7bSbt150084 } 57109da57d7bSbt150084 } 57119da57d7bSbt150084 57129da57d7bSbt150084 return (IXGBE_SUCCESS); 57139da57d7bSbt150084 } 57149da57d7bSbt150084 57159da57d7bSbt150084 /* 57169da57d7bSbt150084 * ixgbe_disable_intrs - Disable all the interrupts. 57179da57d7bSbt150084 */ 57189da57d7bSbt150084 static int 57199da57d7bSbt150084 ixgbe_disable_intrs(ixgbe_t *ixgbe) 57209da57d7bSbt150084 { 57219da57d7bSbt150084 int i; 57229da57d7bSbt150084 int rc; 57239da57d7bSbt150084 57249da57d7bSbt150084 /* 57259da57d7bSbt150084 * Disable all interrupts 57269da57d7bSbt150084 */ 57279da57d7bSbt150084 if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) { 57289da57d7bSbt150084 rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt); 57299da57d7bSbt150084 if (rc != DDI_SUCCESS) { 57309da57d7bSbt150084 ixgbe_log(ixgbe, 57319da57d7bSbt150084 "Disable block intr failed: %d", rc); 57329da57d7bSbt150084 return (IXGBE_FAILURE); 57339da57d7bSbt150084 } 57349da57d7bSbt150084 } else { 57359da57d7bSbt150084 for (i = 0; i < ixgbe->intr_cnt; i++) { 57369da57d7bSbt150084 rc = ddi_intr_disable(ixgbe->htable[i]); 57379da57d7bSbt150084 if (rc != DDI_SUCCESS) { 57389da57d7bSbt150084 ixgbe_log(ixgbe, 57399da57d7bSbt150084 "Disable intr failed: %d", rc); 57409da57d7bSbt150084 return (IXGBE_FAILURE); 57419da57d7bSbt150084 } 57429da57d7bSbt150084 } 57439da57d7bSbt150084 } 57449da57d7bSbt150084 57459da57d7bSbt150084 return (IXGBE_SUCCESS); 57469da57d7bSbt150084 } 57479da57d7bSbt150084 57489da57d7bSbt150084 /* 57499da57d7bSbt150084 * ixgbe_get_hw_state - Get and save parameters related to adapter hardware. 57509da57d7bSbt150084 */ 57519da57d7bSbt150084 static void 57529da57d7bSbt150084 ixgbe_get_hw_state(ixgbe_t *ixgbe) 57539da57d7bSbt150084 { 57549da57d7bSbt150084 struct ixgbe_hw *hw = &ixgbe->hw; 57557e579c30SDale Ghent ixgbe_link_speed speed = 0; 575613740cb2SPaul Guo boolean_t link_up = B_FALSE; 57579da57d7bSbt150084 uint32_t pcs1g_anlp = 0; 57589da57d7bSbt150084 57599da57d7bSbt150084 ASSERT(mutex_owned(&ixgbe->gen_lock)); 57609da57d7bSbt150084 ixgbe->param_lp_1000fdx_cap = 0; 57619da57d7bSbt150084 ixgbe->param_lp_100fdx_cap = 0; 57629da57d7bSbt150084 576313740cb2SPaul Guo /* check for link, don't wait */ 57647e579c30SDale Ghent (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE); 57655b6dd21fSchenlu chen - Sun Microsystems - Beijing China 57667e579c30SDale Ghent /* 57677e579c30SDale Ghent * Update the observed Link Partner's capabilities. Not all adapters 57687e579c30SDale Ghent * can provide full information on the LP's capable speeds, so we 57697e579c30SDale Ghent * provide what we can. 57707e579c30SDale Ghent */ 577113740cb2SPaul Guo if (link_up) { 57729da57d7bSbt150084 pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); 57739da57d7bSbt150084 57749da57d7bSbt150084 ixgbe->param_lp_1000fdx_cap = 57759da57d7bSbt150084 (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; 57769da57d7bSbt150084 ixgbe->param_lp_100fdx_cap = 57779da57d7bSbt150084 (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; 57789da57d7bSbt150084 } 57799da57d7bSbt150084 57807e579c30SDale Ghent /* 57817e579c30SDale Ghent * Update GLD's notion of the adapter's currently advertised speeds. 57827e579c30SDale Ghent * Since the common code doesn't always record the current autonegotiate 57837e579c30SDale Ghent * settings in the phy struct for all parts (specifically, adapters with 57847e579c30SDale Ghent * SFPs) we first test to see if it is 0, and if so, we fall back to 57857e579c30SDale Ghent * using the adapter's speed capabilities which we saved during instance 57867e579c30SDale Ghent * init in ixgbe_init_params(). 57877e579c30SDale Ghent * 57887e579c30SDale Ghent * Adapters with SFPs will always be shown as advertising all of their 57897e579c30SDale Ghent * supported speeds, and adapters with baseT PHYs (where the phy struct 57907e579c30SDale Ghent * is maintained by the common code) will always have a factual view of 57917e579c30SDale Ghent * their currently-advertised speeds. In the case of SFPs, this is 57927e579c30SDale Ghent * acceptable as we default to advertising all speeds that the adapter 57937e579c30SDale Ghent * claims to support, and those properties are immutable; unlike on 57947e579c30SDale Ghent * baseT (copper) PHYs, where speeds can be enabled or disabled at will. 57957e579c30SDale Ghent */ 57967e579c30SDale Ghent speed = hw->phy.autoneg_advertised; 57977e579c30SDale Ghent if (speed == 0) 57987e579c30SDale Ghent speed = ixgbe->speeds_supported; 57995b6dd21fSchenlu chen - Sun Microsystems - Beijing China 58007e579c30SDale Ghent ixgbe->param_adv_10000fdx_cap = 58017e579c30SDale Ghent (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 1 : 0; 58027e579c30SDale Ghent ixgbe->param_adv_5000fdx_cap = 58037e579c30SDale Ghent (speed & IXGBE_LINK_SPEED_5GB_FULL) ? 1 : 0; 58047e579c30SDale Ghent ixgbe->param_adv_2500fdx_cap = 58057e579c30SDale Ghent (speed & IXGBE_LINK_SPEED_2_5GB_FULL) ? 1 : 0; 58067e579c30SDale Ghent ixgbe->param_adv_1000fdx_cap = 58077e579c30SDale Ghent (speed & IXGBE_LINK_SPEED_1GB_FULL) ? 1 : 0; 58087e579c30SDale Ghent ixgbe->param_adv_100fdx_cap = 58097e579c30SDale Ghent (speed & IXGBE_LINK_SPEED_100_FULL) ? 1 : 0; 58109da57d7bSbt150084 } 58119da57d7bSbt150084 58129da57d7bSbt150084 /* 58139da57d7bSbt150084 * ixgbe_get_driver_control - Notify that driver is in control of device. 58149da57d7bSbt150084 */ 58159da57d7bSbt150084 static void 58169da57d7bSbt150084 ixgbe_get_driver_control(struct ixgbe_hw *hw) 58179da57d7bSbt150084 { 58189da57d7bSbt150084 uint32_t ctrl_ext; 58199da57d7bSbt150084 58209da57d7bSbt150084 /* 58219da57d7bSbt150084 * Notify firmware that driver is in control of device 58229da57d7bSbt150084 */ 58239da57d7bSbt150084 ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 58249da57d7bSbt150084 ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; 58259da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 58269da57d7bSbt150084 } 58279da57d7bSbt150084 58289da57d7bSbt150084 /* 58299da57d7bSbt150084 * ixgbe_release_driver_control - Notify that driver is no longer in control 58309da57d7bSbt150084 * of device. 58319da57d7bSbt150084 */ 58329da57d7bSbt150084 static void 58339da57d7bSbt150084 ixgbe_release_driver_control(struct ixgbe_hw *hw) 58349da57d7bSbt150084 { 58359da57d7bSbt150084 uint32_t ctrl_ext; 58369da57d7bSbt150084 58379da57d7bSbt150084 /* 58389da57d7bSbt150084 * Notify firmware that driver is no longer in control of device 58399da57d7bSbt150084 */ 58409da57d7bSbt150084 ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); 58419da57d7bSbt150084 ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; 58429da57d7bSbt150084 IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); 58439da57d7bSbt150084 } 58449da57d7bSbt150084 58459da57d7bSbt150084 /* 58469da57d7bSbt150084 * ixgbe_atomic_reserve - Atomic decrease operation. 58479da57d7bSbt150084 */ 58489da57d7bSbt150084 int 58499da57d7bSbt150084 ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n) 58509da57d7bSbt150084 { 58519da57d7bSbt150084 uint32_t oldval; 58529da57d7bSbt150084 uint32_t newval; 58539da57d7bSbt150084 58549da57d7bSbt150084 /* 58559da57d7bSbt150084 * ATOMICALLY 58569da57d7bSbt150084 */ 58579da57d7bSbt150084 do { 58589da57d7bSbt150084 oldval = *count_p; 58599da57d7bSbt150084 if (oldval < n) 58609da57d7bSbt150084 return (-1); 58619da57d7bSbt150084 newval = oldval - n; 58629da57d7bSbt150084 } while (atomic_cas_32(count_p, oldval, newval) != oldval); 58639da57d7bSbt150084 58649da57d7bSbt150084 return (newval); 58659da57d7bSbt150084 } 58669da57d7bSbt150084 58679da57d7bSbt150084 /* 58689da57d7bSbt150084 * ixgbe_mc_table_itr - Traverse the entries in the multicast table. 58699da57d7bSbt150084 */ 58709da57d7bSbt150084 static uint8_t * 58719da57d7bSbt150084 ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq) 58729da57d7bSbt150084 { 58739da57d7bSbt150084 uint8_t *addr = *upd_ptr; 58749da57d7bSbt150084 uint8_t *new_ptr; 58759da57d7bSbt150084 587613740cb2SPaul Guo _NOTE(ARGUNUSED(hw)); 587713740cb2SPaul Guo _NOTE(ARGUNUSED(vmdq)); 587813740cb2SPaul Guo 58799da57d7bSbt150084 new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; 58809da57d7bSbt150084 *upd_ptr = new_ptr; 58819da57d7bSbt150084 return (addr); 58829da57d7bSbt150084 } 58839da57d7bSbt150084 58849da57d7bSbt150084 /* 58859da57d7bSbt150084 * FMA support 58869da57d7bSbt150084 */ 58879da57d7bSbt150084 int 58889da57d7bSbt150084 ixgbe_check_acc_handle(ddi_acc_handle_t handle) 58899da57d7bSbt150084 { 58909da57d7bSbt150084 ddi_fm_error_t de; 58919da57d7bSbt150084 58929da57d7bSbt150084 ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 58939da57d7bSbt150084 ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 58949da57d7bSbt150084 return (de.fme_status); 58959da57d7bSbt150084 } 58969da57d7bSbt150084 58979da57d7bSbt150084 int 58989da57d7bSbt150084 ixgbe_check_dma_handle(ddi_dma_handle_t handle) 58999da57d7bSbt150084 { 59009da57d7bSbt150084 ddi_fm_error_t de; 59019da57d7bSbt150084 59029da57d7bSbt150084 ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 59039da57d7bSbt150084 return (de.fme_status); 59049da57d7bSbt150084 } 59059da57d7bSbt150084 59069da57d7bSbt150084 /* 59079da57d7bSbt150084 * ixgbe_fm_error_cb - The IO fault service error handling callback function. 59089da57d7bSbt150084 */ 59099da57d7bSbt150084 static int 59109da57d7bSbt150084 ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 59119da57d7bSbt150084 { 59129da57d7bSbt150084 _NOTE(ARGUNUSED(impl_data)); 59139da57d7bSbt150084 /* 59149da57d7bSbt150084 * as the driver can always deal with an error in any dma or 59159da57d7bSbt150084 * access handle, we can just return the fme_status value. 59169da57d7bSbt150084 */ 59179da57d7bSbt150084 pci_ereport_post(dip, err, NULL); 59189da57d7bSbt150084 return (err->fme_status); 59199da57d7bSbt150084 } 59209da57d7bSbt150084 59219da57d7bSbt150084 static void 59229da57d7bSbt150084 ixgbe_fm_init(ixgbe_t *ixgbe) 59239da57d7bSbt150084 { 59249da57d7bSbt150084 ddi_iblock_cookie_t iblk; 5925837c1ac4SStephen Hanson int fma_dma_flag; 59269da57d7bSbt150084 59279da57d7bSbt150084 /* 59289da57d7bSbt150084 * Only register with IO Fault Services if we have some capability 59299da57d7bSbt150084 */ 59309da57d7bSbt150084 if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) { 59319da57d7bSbt150084 ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; 59329da57d7bSbt150084 } else { 59339da57d7bSbt150084 ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; 59349da57d7bSbt150084 } 59359da57d7bSbt150084 59369da57d7bSbt150084 if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) { 59379da57d7bSbt150084 fma_dma_flag = 1; 59389da57d7bSbt150084 } else { 59399da57d7bSbt150084 fma_dma_flag = 0; 59409da57d7bSbt150084 } 59419da57d7bSbt150084 5942837c1ac4SStephen Hanson ixgbe_set_fma_flags(fma_dma_flag); 59439da57d7bSbt150084 59449da57d7bSbt150084 if (ixgbe->fm_capabilities) { 59459da57d7bSbt150084 59469da57d7bSbt150084 /* 59479da57d7bSbt150084 * Register capabilities with IO Fault Services 59489da57d7bSbt150084 */ 59499da57d7bSbt150084 ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk); 59509da57d7bSbt150084 59519da57d7bSbt150084 /* 59529da57d7bSbt150084 * Initialize pci ereport capabilities if ereport capable 59539da57d7bSbt150084 */ 59549da57d7bSbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) || 59559da57d7bSbt150084 DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 59569da57d7bSbt150084 pci_ereport_setup(ixgbe->dip); 59579da57d7bSbt150084 59589da57d7bSbt150084 /* 59599da57d7bSbt150084 * Register error callback if error callback capable 59609da57d7bSbt150084 */ 59619da57d7bSbt150084 if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 59629da57d7bSbt150084 ddi_fm_handler_register(ixgbe->dip, 59639da57d7bSbt150084 ixgbe_fm_error_cb, (void*) ixgbe); 59649da57d7bSbt150084 } 59659da57d7bSbt150084 } 59669da57d7bSbt150084 59679da57d7bSbt150084 static void 59689da57d7bSbt150084 ixgbe_fm_fini(ixgbe_t *ixgbe) 59699da57d7bSbt150084 { 59709da57d7bSbt150084 /* 59719da57d7bSbt150084 * Only unregister FMA capabilities if they are registered 59729da57d7bSbt150084 */ 59739da57d7bSbt150084 if (ixgbe->fm_capabilities) { 59749da57d7bSbt150084 59759da57d7bSbt150084 /* 59769da57d7bSbt150084 * Release any resources allocated by pci_ereport_setup() 59779da57d7bSbt150084 */ 59789da57d7bSbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) || 59799da57d7bSbt150084 DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 59809da57d7bSbt150084 pci_ereport_teardown(ixgbe->dip); 59819da57d7bSbt150084 59829da57d7bSbt150084 /* 59839da57d7bSbt150084 * Un-register error callback if error callback capable 59849da57d7bSbt150084 */ 59859da57d7bSbt150084 if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities)) 59869da57d7bSbt150084 ddi_fm_handler_unregister(ixgbe->dip); 59879da57d7bSbt150084 59889da57d7bSbt150084 /* 59899da57d7bSbt150084 * Unregister from IO Fault Service 59909da57d7bSbt150084 */ 59919da57d7bSbt150084 ddi_fm_fini(ixgbe->dip); 59929da57d7bSbt150084 } 59939da57d7bSbt150084 } 59949da57d7bSbt150084 59959da57d7bSbt150084 void 59969da57d7bSbt150084 ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail) 59979da57d7bSbt150084 { 59989da57d7bSbt150084 uint64_t ena; 59999da57d7bSbt150084 char buf[FM_MAX_CLASS]; 60009da57d7bSbt150084 60019da57d7bSbt150084 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 60029da57d7bSbt150084 ena = fm_ena_generate(0, FM_ENA_FMT1); 60039da57d7bSbt150084 if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) { 60049da57d7bSbt150084 ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP, 60059da57d7bSbt150084 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 60069da57d7bSbt150084 } 60079da57d7bSbt150084 } 6008da14cebeSEric Cheng 6009da14cebeSEric Cheng static int 6010da14cebeSEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 6011da14cebeSEric Cheng { 6012da14cebeSEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh; 6013da14cebeSEric Cheng 6014da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock); 6015da14cebeSEric Cheng rx_ring->ring_gen_num = mr_gen_num; 6016da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock); 6017da14cebeSEric Cheng return (0); 6018da14cebeSEric Cheng } 6019da14cebeSEric Cheng 6020da14cebeSEric Cheng /* 60210dc2366fSVenugopal Iyer * Get the global ring index by a ring index within a group. 60220dc2366fSVenugopal Iyer */ 60230dc2366fSVenugopal Iyer static int 60240dc2366fSVenugopal Iyer ixgbe_get_rx_ring_index(ixgbe_t *ixgbe, int gindex, int rindex) 60250dc2366fSVenugopal Iyer { 60260dc2366fSVenugopal Iyer ixgbe_rx_ring_t *rx_ring; 60270dc2366fSVenugopal Iyer int i; 60280dc2366fSVenugopal Iyer 60290dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_rx_rings; i++) { 60300dc2366fSVenugopal Iyer rx_ring = &ixgbe->rx_rings[i]; 60310dc2366fSVenugopal Iyer if (rx_ring->group_index == gindex) 60320dc2366fSVenugopal Iyer rindex--; 60330dc2366fSVenugopal Iyer if (rindex < 0) 60340dc2366fSVenugopal Iyer return (i); 60350dc2366fSVenugopal Iyer } 60360dc2366fSVenugopal Iyer 60370dc2366fSVenugopal Iyer return (-1); 60380dc2366fSVenugopal Iyer } 60390dc2366fSVenugopal Iyer 60400dc2366fSVenugopal Iyer /* 6041da14cebeSEric Cheng * Callback funtion for MAC layer to register all rings. 6042da14cebeSEric Cheng */ 6043da14cebeSEric Cheng /* ARGSUSED */ 6044da14cebeSEric Cheng void 60450dc2366fSVenugopal Iyer ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index, 6046da14cebeSEric Cheng const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 6047da14cebeSEric Cheng { 6048da14cebeSEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg; 6049da14cebeSEric Cheng mac_intr_t *mintr = &infop->mri_intr; 6050da14cebeSEric Cheng 6051da14cebeSEric Cheng switch (rtype) { 6052da14cebeSEric Cheng case MAC_RING_TYPE_RX: { 60530dc2366fSVenugopal Iyer /* 60540dc2366fSVenugopal Iyer * 'index' is the ring index within the group. 60550dc2366fSVenugopal Iyer * Need to get the global ring index by searching in groups. 60560dc2366fSVenugopal Iyer */ 60570dc2366fSVenugopal Iyer int global_ring_index = ixgbe_get_rx_ring_index( 60580dc2366fSVenugopal Iyer ixgbe, group_index, ring_index); 6059da14cebeSEric Cheng 60600dc2366fSVenugopal Iyer ASSERT(global_ring_index >= 0); 60610dc2366fSVenugopal Iyer 60620dc2366fSVenugopal Iyer ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[global_ring_index]; 6063da14cebeSEric Cheng rx_ring->ring_handle = rh; 6064da14cebeSEric Cheng 6065da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 6066da14cebeSEric Cheng infop->mri_start = ixgbe_ring_start; 6067da14cebeSEric Cheng infop->mri_stop = NULL; 6068da14cebeSEric Cheng infop->mri_poll = ixgbe_ring_rx_poll; 60690dc2366fSVenugopal Iyer infop->mri_stat = ixgbe_rx_ring_stat; 6070da14cebeSEric Cheng 6071da14cebeSEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring; 6072da14cebeSEric Cheng mintr->mi_enable = ixgbe_rx_ring_intr_enable; 6073da14cebeSEric Cheng mintr->mi_disable = ixgbe_rx_ring_intr_disable; 60740dc2366fSVenugopal Iyer if (ixgbe->intr_type & 60750dc2366fSVenugopal Iyer (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) { 60760dc2366fSVenugopal Iyer mintr->mi_ddi_handle = 60770dc2366fSVenugopal Iyer ixgbe->htable[rx_ring->intr_vector]; 60780dc2366fSVenugopal Iyer } 6079da14cebeSEric Cheng 6080da14cebeSEric Cheng break; 6081da14cebeSEric Cheng } 6082da14cebeSEric Cheng case MAC_RING_TYPE_TX: { 60830dc2366fSVenugopal Iyer ASSERT(group_index == -1); 6084da14cebeSEric Cheng ASSERT(ring_index < ixgbe->num_tx_rings); 6085da14cebeSEric Cheng 6086da14cebeSEric Cheng ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index]; 6087da14cebeSEric Cheng tx_ring->ring_handle = rh; 6088da14cebeSEric Cheng 6089da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)tx_ring; 6090da14cebeSEric Cheng infop->mri_start = NULL; 6091da14cebeSEric Cheng infop->mri_stop = NULL; 6092da14cebeSEric Cheng infop->mri_tx = ixgbe_ring_tx; 60930dc2366fSVenugopal Iyer infop->mri_stat = ixgbe_tx_ring_stat; 60940dc2366fSVenugopal Iyer if (ixgbe->intr_type & 60950dc2366fSVenugopal Iyer (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) { 60960dc2366fSVenugopal Iyer mintr->mi_ddi_handle = 60970dc2366fSVenugopal Iyer ixgbe->htable[tx_ring->intr_vector]; 60980dc2366fSVenugopal Iyer } 6099da14cebeSEric Cheng break; 6100da14cebeSEric Cheng } 6101da14cebeSEric Cheng default: 6102da14cebeSEric Cheng break; 6103da14cebeSEric Cheng } 6104da14cebeSEric Cheng } 6105da14cebeSEric Cheng 6106da14cebeSEric Cheng /* 6107da14cebeSEric Cheng * Callback funtion for MAC layer to register all groups. 6108da14cebeSEric Cheng */ 6109da14cebeSEric Cheng void 6110da14cebeSEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index, 6111da14cebeSEric Cheng mac_group_info_t *infop, mac_group_handle_t gh) 6112da14cebeSEric Cheng { 6113da14cebeSEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg; 6114da14cebeSEric Cheng 6115da14cebeSEric Cheng switch (rtype) { 6116da14cebeSEric Cheng case MAC_RING_TYPE_RX: { 6117da14cebeSEric Cheng ixgbe_rx_group_t *rx_group; 6118da14cebeSEric Cheng 6119da14cebeSEric Cheng rx_group = &ixgbe->rx_groups[index]; 6120da14cebeSEric Cheng rx_group->group_handle = gh; 6121da14cebeSEric Cheng 6122da14cebeSEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_group; 6123da14cebeSEric Cheng infop->mgi_start = NULL; 6124da14cebeSEric Cheng infop->mgi_stop = NULL; 6125da14cebeSEric Cheng infop->mgi_addmac = ixgbe_addmac; 6126da14cebeSEric Cheng infop->mgi_remmac = ixgbe_remmac; 6127da14cebeSEric Cheng infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups); 6128da14cebeSEric Cheng 6129da14cebeSEric Cheng break; 6130da14cebeSEric Cheng } 6131da14cebeSEric Cheng case MAC_RING_TYPE_TX: 6132da14cebeSEric Cheng break; 6133da14cebeSEric Cheng default: 6134da14cebeSEric Cheng break; 6135da14cebeSEric Cheng } 6136da14cebeSEric Cheng } 6137da14cebeSEric Cheng 6138da14cebeSEric Cheng /* 6139da14cebeSEric Cheng * Enable interrupt on the specificed rx ring. 6140da14cebeSEric Cheng */ 6141da14cebeSEric Cheng int 6142da14cebeSEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh) 6143da14cebeSEric Cheng { 6144da14cebeSEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh; 6145da14cebeSEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe; 6146da14cebeSEric Cheng int r_idx = rx_ring->index; 61470dc2366fSVenugopal Iyer int hw_r_idx = rx_ring->hw_index; 6148da14cebeSEric Cheng int v_idx = rx_ring->intr_vector; 6149da14cebeSEric Cheng 6150da14cebeSEric Cheng mutex_enter(&ixgbe->gen_lock); 61510dc2366fSVenugopal Iyer if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) { 61520dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock); 61530dc2366fSVenugopal Iyer /* 61540dc2366fSVenugopal Iyer * Simply return 0. 61550dc2366fSVenugopal Iyer * Interrupts are being adjusted. ixgbe_intr_adjust() 61560dc2366fSVenugopal Iyer * will eventually re-enable the interrupt when it's 61570dc2366fSVenugopal Iyer * done with the adjustment. 61580dc2366fSVenugopal Iyer */ 61590dc2366fSVenugopal Iyer return (0); 61600dc2366fSVenugopal Iyer } 6161da14cebeSEric Cheng 6162da14cebeSEric Cheng /* 6163da14cebeSEric Cheng * To enable interrupt by setting the VAL bit of given interrupt 6164da14cebeSEric Cheng * vector allocation register (IVAR). 6165da14cebeSEric Cheng */ 61660dc2366fSVenugopal Iyer ixgbe_enable_ivar(ixgbe, hw_r_idx, 0); 6167da14cebeSEric Cheng 6168da14cebeSEric Cheng BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx); 6169185c5677SPaul Guo 6170185c5677SPaul Guo /* 617119843f01SPaul Guo * Trigger a Rx interrupt on this ring 6172185c5677SPaul Guo */ 6173185c5677SPaul Guo IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx)); 6174185c5677SPaul Guo IXGBE_WRITE_FLUSH(&ixgbe->hw); 6175185c5677SPaul Guo 6176da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6177da14cebeSEric Cheng 6178da14cebeSEric Cheng return (0); 6179da14cebeSEric Cheng } 6180da14cebeSEric Cheng 6181da14cebeSEric Cheng /* 6182da14cebeSEric Cheng * Disable interrupt on the specificed rx ring. 6183da14cebeSEric Cheng */ 6184da14cebeSEric Cheng int 6185da14cebeSEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh) 6186da14cebeSEric Cheng { 6187da14cebeSEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh; 6188da14cebeSEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe; 6189da14cebeSEric Cheng int r_idx = rx_ring->index; 61900dc2366fSVenugopal Iyer int hw_r_idx = rx_ring->hw_index; 6191da14cebeSEric Cheng int v_idx = rx_ring->intr_vector; 6192da14cebeSEric Cheng 6193da14cebeSEric Cheng mutex_enter(&ixgbe->gen_lock); 61940dc2366fSVenugopal Iyer if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) { 61950dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock); 61960dc2366fSVenugopal Iyer /* 61970dc2366fSVenugopal Iyer * Simply return 0. 61980dc2366fSVenugopal Iyer * In the rare case where an interrupt is being 61990dc2366fSVenugopal Iyer * disabled while interrupts are being adjusted, 62000dc2366fSVenugopal Iyer * we don't fail the operation. No interrupts will 62010dc2366fSVenugopal Iyer * be generated while they are adjusted, and 62020dc2366fSVenugopal Iyer * ixgbe_intr_adjust() will cause the interrupts 62030dc2366fSVenugopal Iyer * to be re-enabled once it completes. Note that 62040dc2366fSVenugopal Iyer * in this case, packets may be delivered to the 62050dc2366fSVenugopal Iyer * stack via interrupts before xgbe_rx_ring_intr_enable() 62060dc2366fSVenugopal Iyer * is called again. This is acceptable since interrupt 62070dc2366fSVenugopal Iyer * adjustment is infrequent, and the stack will be 62080dc2366fSVenugopal Iyer * able to handle these packets. 62090dc2366fSVenugopal Iyer */ 62100dc2366fSVenugopal Iyer return (0); 62110dc2366fSVenugopal Iyer } 6212da14cebeSEric Cheng 6213da14cebeSEric Cheng /* 6214da14cebeSEric Cheng * To disable interrupt by clearing the VAL bit of given interrupt 6215da14cebeSEric Cheng * vector allocation register (IVAR). 6216da14cebeSEric Cheng */ 62170dc2366fSVenugopal Iyer ixgbe_disable_ivar(ixgbe, hw_r_idx, 0); 6218da14cebeSEric Cheng 6219da14cebeSEric Cheng BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx); 6220da14cebeSEric Cheng 6221da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6222da14cebeSEric Cheng 6223da14cebeSEric Cheng return (0); 6224da14cebeSEric Cheng } 6225da14cebeSEric Cheng 6226da14cebeSEric Cheng /* 6227da14cebeSEric Cheng * Add a mac address. 6228da14cebeSEric Cheng */ 6229da14cebeSEric Cheng static int 6230da14cebeSEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr) 6231da14cebeSEric Cheng { 6232da14cebeSEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg; 6233da14cebeSEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe; 62340dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw; 62350dc2366fSVenugopal Iyer int slot, i; 6236da14cebeSEric Cheng 6237da14cebeSEric Cheng mutex_enter(&ixgbe->gen_lock); 6238da14cebeSEric Cheng 6239da14cebeSEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 6240da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6241da14cebeSEric Cheng return (ECANCELED); 6242da14cebeSEric Cheng } 6243da14cebeSEric Cheng 6244da14cebeSEric Cheng if (ixgbe->unicst_avail == 0) { 6245da14cebeSEric Cheng /* no slots available */ 6246da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6247da14cebeSEric Cheng return (ENOSPC); 6248da14cebeSEric Cheng } 6249da14cebeSEric Cheng 62500dc2366fSVenugopal Iyer /* 62510dc2366fSVenugopal Iyer * The first ixgbe->num_rx_groups slots are reserved for each respective 62520dc2366fSVenugopal Iyer * group. The rest slots are shared by all groups. While adding a 62530dc2366fSVenugopal Iyer * MAC address, reserved slots are firstly checked then the shared 62540dc2366fSVenugopal Iyer * slots are searched. 62550dc2366fSVenugopal Iyer */ 62560dc2366fSVenugopal Iyer slot = -1; 62570dc2366fSVenugopal Iyer if (ixgbe->unicst_addr[rx_group->index].mac.set == 1) { 62580dc2366fSVenugopal Iyer for (i = ixgbe->num_rx_groups; i < ixgbe->unicst_total; i++) { 62590dc2366fSVenugopal Iyer if (ixgbe->unicst_addr[i].mac.set == 0) { 62600dc2366fSVenugopal Iyer slot = i; 6261da14cebeSEric Cheng break; 6262da14cebeSEric Cheng } 6263da14cebeSEric Cheng } 62640dc2366fSVenugopal Iyer } else { 62650dc2366fSVenugopal Iyer slot = rx_group->index; 62660dc2366fSVenugopal Iyer } 62670dc2366fSVenugopal Iyer 62680dc2366fSVenugopal Iyer if (slot == -1) { 62690dc2366fSVenugopal Iyer /* no slots available */ 62700dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock); 62710dc2366fSVenugopal Iyer return (ENOSPC); 62720dc2366fSVenugopal Iyer } 62730dc2366fSVenugopal Iyer 62740dc2366fSVenugopal Iyer bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL); 62750dc2366fSVenugopal Iyer (void) ixgbe_set_rar(hw, slot, ixgbe->unicst_addr[slot].mac.addr, 62760dc2366fSVenugopal Iyer rx_group->index, IXGBE_RAH_AV); 62770dc2366fSVenugopal Iyer ixgbe->unicst_addr[slot].mac.set = 1; 62780dc2366fSVenugopal Iyer ixgbe->unicst_addr[slot].mac.group_index = rx_group->index; 62790dc2366fSVenugopal Iyer ixgbe->unicst_avail--; 6280da14cebeSEric Cheng 6281da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6282da14cebeSEric Cheng 62830dc2366fSVenugopal Iyer return (0); 6284da14cebeSEric Cheng } 6285da14cebeSEric Cheng 6286da14cebeSEric Cheng /* 6287da14cebeSEric Cheng * Remove a mac address. 6288da14cebeSEric Cheng */ 6289da14cebeSEric Cheng static int 6290da14cebeSEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr) 6291da14cebeSEric Cheng { 6292da14cebeSEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg; 6293da14cebeSEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe; 62940dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw; 6295da14cebeSEric Cheng int slot; 6296da14cebeSEric Cheng 6297da14cebeSEric Cheng mutex_enter(&ixgbe->gen_lock); 6298da14cebeSEric Cheng 6299da14cebeSEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 6300da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6301da14cebeSEric Cheng return (ECANCELED); 6302da14cebeSEric Cheng } 6303da14cebeSEric Cheng 6304da14cebeSEric Cheng slot = ixgbe_unicst_find(ixgbe, mac_addr); 6305da14cebeSEric Cheng if (slot == -1) { 6306da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6307da14cebeSEric Cheng return (EINVAL); 6308da14cebeSEric Cheng } 6309da14cebeSEric Cheng 6310da14cebeSEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 0) { 6311da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6312da14cebeSEric Cheng return (EINVAL); 6313da14cebeSEric Cheng } 6314da14cebeSEric Cheng 6315da14cebeSEric Cheng bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL); 63160dc2366fSVenugopal Iyer (void) ixgbe_clear_rar(hw, slot); 6317da14cebeSEric Cheng ixgbe->unicst_addr[slot].mac.set = 0; 6318da14cebeSEric Cheng ixgbe->unicst_avail++; 6319da14cebeSEric Cheng 6320da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock); 6321da14cebeSEric Cheng 63220dc2366fSVenugopal Iyer return (0); 6323da14cebeSEric Cheng } 6324