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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
ixgbe_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)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
ixgbe_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)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
ixgbe_quiesce(dev_info_t * devinfo)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
ixgbe_unconfigure(dev_info_t * devinfo,ixgbe_t * ixgbe)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
ixgbe_register_mac(ixgbe_t * ixgbe)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
ixgbe_identify_hardware(ixgbe_t * ixgbe)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
ixgbe_regs_map(ixgbe_t * ixgbe)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
ixgbe_init_properties(ixgbe_t * ixgbe)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
ixgbe_init_driver_settings(ixgbe_t * ixgbe)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
ixgbe_init_locks(ixgbe_t * ixgbe)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
ixgbe_destroy_locks(ixgbe_t * ixgbe)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
ixgbe_resume(dev_info_t * devinfo)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
ixgbe_suspend(dev_info_t * devinfo)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
ixgbe_init(ixgbe_t * ixgbe)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
ixgbe_chip_start(ixgbe_t * ixgbe)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
ixgbe_chip_stop(ixgbe_t * ixgbe)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
ixgbe_reset(ixgbe_t * ixgbe)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
ixgbe_tx_clean(ixgbe_t * ixgbe)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
ixgbe_tx_drain(ixgbe_t * ixgbe)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
ixgbe_rx_drain(ixgbe_t * ixgbe)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
ixgbe_start(ixgbe_t * ixgbe,boolean_t alloc_buffer)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
ixgbe_stop(ixgbe_t * ixgbe,boolean_t free_buffer)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
ixgbe_cbfunc(dev_info_t * dip,ddi_cb_action_t cbaction,void * cbarg,void * arg1,void * arg2)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
ixgbe_intr_adjust(ixgbe_t * ixgbe,ddi_cb_action_t cbaction,int count)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
ixgbe_intr_cb_register(ixgbe_t * ixgbe)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
ixgbe_alloc_rings(ixgbe_t * ixgbe)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
ixgbe_free_rings(ixgbe_t * ixgbe)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
ixgbe_alloc_rx_data(ixgbe_t * ixgbe)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
ixgbe_free_rx_data(ixgbe_t * ixgbe)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
ixgbe_setup_rings(ixgbe_t * ixgbe)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
ixgbe_setup_rx_ring(ixgbe_rx_ring_t * rx_ring)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
ixgbe_setup_rx(ixgbe_t * ixgbe)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
ixgbe_setup_tx_ring(ixgbe_tx_ring_t * tx_ring)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
ixgbe_setup_tx(ixgbe_t * ixgbe)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
ixgbe_setup_rss(ixgbe_t * ixgbe)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
ixgbe_setup_vmdq(ixgbe_t * ixgbe)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
ixgbe_setup_vmdq_rss(ixgbe_t * ixgbe)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
ixgbe_setup_rss_table(ixgbe_t * ixgbe)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
ixgbe_init_unicst(ixgbe_t * ixgbe)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
ixgbe_unicst_find(ixgbe_t * ixgbe,const uint8_t * mac_addr)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
ixgbe_multicst_add(ixgbe_t * ixgbe,const uint8_t * multiaddr)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
ixgbe_multicst_remove(ixgbe_t * ixgbe,const uint8_t * multiaddr)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
ixgbe_setup_multicst(ixgbe_t * ixgbe)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
ixgbe_setup_vmdq_rss_conf(ixgbe_t * ixgbe)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
ixgbe_get_conf(ixgbe_t * ixgbe)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
ixgbe_init_params(ixgbe_t * ixgbe)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
ixgbe_get_prop(ixgbe_t * ixgbe,char * propname,int minval,int maxval,int defval)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
ixgbe_driver_setup_link(ixgbe_t * ixgbe,boolean_t setup_hw)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
ixgbe_driver_link_check(ixgbe_t * ixgbe)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
ixgbe_sfp_check(void * arg)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
ixgbe_overtemp_check(void * arg)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
ixgbe_phy_check(void * arg)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
ixgbe_link_timer(void * arg)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
ixgbe_local_timer(void * arg)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
ixgbe_stall_check(ixgbe_t * ixgbe)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
is_valid_mac_addr(uint8_t * mac_addr)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
ixgbe_find_mac_address(ixgbe_t * ixgbe)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
ixgbe_arm_watchdog_timer(ixgbe_t * ixgbe)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
ixgbe_enable_watchdog_timer(ixgbe_t * ixgbe)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
ixgbe_disable_watchdog_timer(ixgbe_t * ixgbe)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
ixgbe_start_watchdog_timer(ixgbe_t * ixgbe)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
ixgbe_restart_watchdog_timer(ixgbe_t * ixgbe)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
ixgbe_stop_watchdog_timer(ixgbe_t * ixgbe)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
ixgbe_disable_adapter_interrupts(ixgbe_t * ixgbe)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
ixgbe_enable_adapter_interrupts(ixgbe_t * ixgbe)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
ixgbe_loopback_ioctl(ixgbe_t * ixgbe,struct iocblk * iocp,mblk_t * mp)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
ixgbe_set_loopback_mode(ixgbe_t * ixgbe,uint32_t mode)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
ixgbe_set_internal_mac_loopback(ixgbe_t * ixgbe)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
ixgbe_intr_rx_work(ixgbe_rx_ring_t * rx_ring)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
ixgbe_intr_tx_work(ixgbe_tx_ring_t * tx_ring)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
ixgbe_intr_other_work(ixgbe_t * ixgbe,uint32_t eicr)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
ixgbe_intr_legacy(void * arg1,void * arg2)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
ixgbe_intr_msi(void * arg1,void * arg2)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
ixgbe_intr_msix(void * arg1,void * arg2)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
ixgbe_alloc_intrs(ixgbe_t * ixgbe)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
ixgbe_alloc_intr_handles(ixgbe_t * ixgbe,int intr_type)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
ixgbe_add_intr_handlers(ixgbe_t * ixgbe)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
ixgbe_map_rxring_to_vector(ixgbe_t * ixgbe,int r_idx,int v_idx)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
ixgbe_map_txring_to_vector(ixgbe_t * ixgbe,int t_idx,int v_idx)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
ixgbe_setup_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,uint8_t msix_vector,int8_t cause)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
ixgbe_enable_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,int8_t cause)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
ixgbe_disable_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,int8_t cause)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
ixgbe_get_hw_rx_index(ixgbe_t * ixgbe,uint32_t sw_rx_index)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
ixgbe_map_intrs_to_vectors(ixgbe_t * ixgbe)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
ixgbe_setup_adapter_vector(ixgbe_t * ixgbe)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
ixgbe_rem_intr_handlers(ixgbe_t * ixgbe)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
ixgbe_rem_intrs(ixgbe_t * ixgbe)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
ixgbe_enable_intrs(ixgbe_t * ixgbe)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
ixgbe_disable_intrs(ixgbe_t * ixgbe)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
ixgbe_get_hw_state(ixgbe_t * ixgbe)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
ixgbe_get_driver_control(struct ixgbe_hw * hw)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
ixgbe_release_driver_control(struct ixgbe_hw * hw)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
ixgbe_atomic_reserve(uint32_t * count_p,uint32_t n)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 *
ixgbe_mc_table_itr(struct ixgbe_hw * hw,uint8_t ** upd_ptr,uint32_t * vmdq)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
ixgbe_check_acc_handle(ddi_acc_handle_t handle)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
ixgbe_check_dma_handle(ddi_dma_handle_t handle)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
ixgbe_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)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
ixgbe_fm_init(ixgbe_t * ixgbe)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
ixgbe_fm_fini(ixgbe_t * ixgbe)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
ixgbe_fm_ereport(ixgbe_t * ixgbe,char * detail)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
ixgbe_ring_start(mac_ring_driver_t rh,uint64_t mr_gen_num)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
ixgbe_get_rx_ring_index(ixgbe_t * ixgbe,int gindex,int rindex)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
ixgbe_fill_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)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
ixgbe_fill_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)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
ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)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
ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)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
ixgbe_addmac(void * arg,const uint8_t * mac_addr)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
ixgbe_remmac(void * arg,const uint8_t * mac_addr)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