19da57d7bSbt /*
29da57d7bSbt * CDDL HEADER START
39da57d7bSbt *
49da57d7bSbt * The contents of this file are subject to the terms of the
59da57d7bSbt * Common Development and Distribution License (the "License").
69da57d7bSbt * You may not use this file except in compliance with the License.
79da57d7bSbt *
819397407SSherry Moore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
919397407SSherry Moore * or http://www.opensolaris.org/os/licensing.
109da57d7bSbt * See the License for the specific language governing permissions
119da57d7bSbt * and limitations under the License.
129da57d7bSbt *
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.
159da57d7bSbt * If applicable, add the following below this CDDL HEADER, with the
169da57d7bSbt * fields enclosed by brackets "[]" replaced with your own identifying
179da57d7bSbt * information: Portions Copyright [yyyy] [name of copyright owner]
189da57d7bSbt *
199da57d7bSbt * CDDL HEADER END
209da57d7bSbt */
219da57d7bSbt
229da57d7bSbt /*
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.
2884de666eSRyan Zezeski * Copyright 2020 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.
32dc0cb1cdSDale Ghent * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
33f2fe7acaSRobert Mustacchi * Copyright 2020 Oxide Computer Company
349da57d7bSbt */
359da57d7bSbt
369da57d7bSbt #include "ixgbe_sw.h"
379da57d7bSbt
38ffd8e883SWinson Wang - Sun Microsystems - Beijing China static char ixgbe_ident[] = "Intel 10Gb Ethernet";
399da57d7bSbt
409da57d7bSbt /*
419da57d7bSbt * Local function protoypes
429da57d7bSbt */
439da57d7bSbt static int ixgbe_register_mac(ixgbe_t *);
449da57d7bSbt static int ixgbe_identify_hardware(ixgbe_t *);
459da57d7bSbt static int ixgbe_regs_map(ixgbe_t *);
469da57d7bSbt static void ixgbe_init_properties(ixgbe_t *);
479da57d7bSbt static int ixgbe_init_driver_settings(ixgbe_t *);
489da57d7bSbt static void ixgbe_init_locks(ixgbe_t *);
499da57d7bSbt static void ixgbe_destroy_locks(ixgbe_t *);
509da57d7bSbt static int ixgbe_init(ixgbe_t *);
519da57d7bSbt static int ixgbe_chip_start(ixgbe_t *);
529da57d7bSbt static void ixgbe_chip_stop(ixgbe_t *);
539da57d7bSbt static int ixgbe_reset(ixgbe_t *);
549da57d7bSbt static void ixgbe_tx_clean(ixgbe_t *);
559da57d7bSbt static boolean_t ixgbe_tx_drain(ixgbe_t *);
569da57d7bSbt static boolean_t ixgbe_rx_drain(ixgbe_t *);
579da57d7bSbt static int ixgbe_alloc_rings(ixgbe_t *);
589da57d7bSbt static void ixgbe_free_rings(ixgbe_t *);
59ea65739eSchenlu chen - Sun Microsystems - Beijing China static int ixgbe_alloc_rx_data(ixgbe_t *);
60ea65739eSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_free_rx_data(ixgbe_t *);
6184de666eSRyan Zezeski static int ixgbe_setup_rings(ixgbe_t *);
6284de666eSRyan Zezeski static int ixgbe_setup_rx(ixgbe_t *);
639da57d7bSbt static void ixgbe_setup_tx(ixgbe_t *);
649da57d7bSbt static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *);
659da57d7bSbt static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *);
669da57d7bSbt static void ixgbe_setup_rss(ixgbe_t *);
670dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq(ixgbe_t *);
680dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq_rss(ixgbe_t *);
69dc0cb1cdSDale Ghent static void ixgbe_setup_rss_table(ixgbe_t *);
709da57d7bSbt static void ixgbe_init_unicst(ixgbe_t *);
7184de666eSRyan Zezeski static int ixgbe_init_vlan(ixgbe_t *);
72da14cebeSEric Cheng static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *);
739da57d7bSbt static void ixgbe_setup_multicst(ixgbe_t *);
749da57d7bSbt static void ixgbe_get_hw_state(ixgbe_t *);
750dc2366fSVenugopal Iyer static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe);
769da57d7bSbt static void ixgbe_get_conf(ixgbe_t *);
77ea65739eSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_init_params(ixgbe_t *);
789da57d7bSbt static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int);
7962e6e1adSPaul Guo static void ixgbe_driver_link_check(ixgbe_t *);
8073cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_sfp_check(void *);
815b6dd21fSchenlu chen - Sun Microsystems - Beijing China static void ixgbe_overtemp_check(void *);
82dc0cb1cdSDale Ghent static void ixgbe_phy_check(void *);
8362e6e1adSPaul Guo static void ixgbe_link_timer(void *);
849da57d7bSbt static void ixgbe_local_timer(void *);
859da57d7bSbt static void ixgbe_arm_watchdog_timer(ixgbe_t *);
869da57d7bSbt static void ixgbe_restart_watchdog_timer(ixgbe_t *);
879da57d7bSbt static void ixgbe_disable_adapter_interrupts(ixgbe_t *);
889da57d7bSbt static void ixgbe_enable_adapter_interrupts(ixgbe_t *);
899da57d7bSbt static boolean_t is_valid_mac_addr(uint8_t *);
909da57d7bSbt static boolean_t ixgbe_stall_check(ixgbe_t *);
919da57d7bSbt static boolean_t ixgbe_set_loopback_mode(ixgbe_t *, uint32_t);
929da57d7bSbt static void ixgbe_set_internal_mac_loopback(ixgbe_t *);
939da57d7bSbt static boolean_t ixgbe_find_mac_address(ixgbe_t *);
949da57d7bSbt static int ixgbe_alloc_intrs(ixgbe_t *);
959da57d7bSbt static int ixgbe_alloc_intr_handles(ixgbe_t *, int);
969da57d7bSbt static int ixgbe_add_intr_handlers(ixgbe_t *);
979da57d7bSbt static void ixgbe_map_rxring_to_vector(ixgbe_t *, int, int);
989da57d7bSbt static void ixgbe_map_txring_to_vector(ixgbe_t *, int, int);
9973cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_setup_ivar(ixgbe_t *, uint16_t, uint8_t, int8_t);
10073cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_enable_ivar(ixgbe_t *, uint16_t, int8_t);
10173cd555cSBin Tu - Sun Microsystems - Beijing China static void ixgbe_disable_ivar(ixgbe_t *, uint16_t, int8_t);
1020dc2366fSVenugopal Iyer static uint32_t ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index);
10373cd555cSBin Tu - Sun Microsystems - Beijing China static int ixgbe_map_intrs_to_vectors(ixgbe_t *);
1049da57d7bSbt static void ixgbe_setup_adapter_vector(ixgbe_t *);
1059da57d7bSbt static void ixgbe_rem_intr_handlers(ixgbe_t *);
1069da57d7bSbt static void ixgbe_rem_intrs(ixgbe_t *);
1079da57d7bSbt static int ixgbe_enable_intrs(ixgbe_t *);
1089da57d7bSbt static int ixgbe_disable_intrs(ixgbe_t *);
1099da57d7bSbt static uint_t ixgbe_intr_legacy(void *, void *);
1109da57d7bSbt static uint_t ixgbe_intr_msi(void *, void *);
11173cd555cSBin Tu - Sun Microsystems - Beijing China static uint_t ixgbe_intr_msix(void *, void *);
1129da57d7bSbt static void ixgbe_intr_rx_work(ixgbe_rx_ring_t *);
1139da57d7bSbt static void ixgbe_intr_tx_work(ixgbe_tx_ring_t *);
11413740cb2SPaul Guo static void ixgbe_intr_other_work(ixgbe_t *, uint32_t);
1159da57d7bSbt static void ixgbe_get_driver_control(struct ixgbe_hw *);
116da14cebeSEric Cheng static int ixgbe_addmac(void *, const uint8_t *);
117da14cebeSEric Cheng static int ixgbe_remmac(void *, const uint8_t *);
11884de666eSRyan Zezeski static int ixgbe_addvlan(mac_group_driver_t, uint16_t);
11984de666eSRyan Zezeski static int ixgbe_remvlan(mac_group_driver_t, uint16_t);
1209da57d7bSbt static void ixgbe_release_driver_control(struct ixgbe_hw *);
1219da57d7bSbt
1229da57d7bSbt static int ixgbe_attach(dev_info_t *, ddi_attach_cmd_t);
1239da57d7bSbt static int ixgbe_detach(dev_info_t *, ddi_detach_cmd_t);
1249da57d7bSbt static int ixgbe_resume(dev_info_t *);
1259da57d7bSbt static int ixgbe_suspend(dev_info_t *);
1268c430e59SSaso Kiselkov static int ixgbe_quiesce(dev_info_t *);
1279da57d7bSbt static void ixgbe_unconfigure(dev_info_t *, ixgbe_t *);
1289da57d7bSbt static uint8_t *ixgbe_mc_table_itr(struct ixgbe_hw *, uint8_t **, uint32_t *);
1290dc2366fSVenugopal Iyer static int ixgbe_cbfunc(dev_info_t *, ddi_cb_action_t, void *, void *, void *);
1300dc2366fSVenugopal Iyer static int ixgbe_intr_cb_register(ixgbe_t *);
1310dc2366fSVenugopal Iyer static int ixgbe_intr_adjust(ixgbe_t *, ddi_cb_action_t, int);
1329da57d7bSbt
1339da57d7bSbt static int ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
1349da57d7bSbt const void *impl_data);
1359da57d7bSbt static void ixgbe_fm_init(ixgbe_t *);
1369da57d7bSbt static void ixgbe_fm_fini(ixgbe_t *);
137f2fe7acaSRobert Mustacchi static int ixgbe_ufm_fill_image(ddi_ufm_handle_t *, void *arg, uint_t,
138f2fe7acaSRobert Mustacchi ddi_ufm_image_t *);
139f2fe7acaSRobert Mustacchi static int ixgbe_ufm_fill_slot(ddi_ufm_handle_t *, void *, uint_t, uint_t,
140f2fe7acaSRobert Mustacchi ddi_ufm_slot_t *);
141f2fe7acaSRobert Mustacchi static int ixgbe_ufm_getcaps(ddi_ufm_handle_t *, void *, ddi_ufm_cap_t *);
142f2fe7acaSRobert Mustacchi static int ixgbe_ufm_readimg(ddi_ufm_handle_t *, void *, uint_t, uint_t,
143f2fe7acaSRobert Mustacchi uint64_t, uint64_t, void *, uint64_t *);
1449da57d7bSbt
1450dc2366fSVenugopal Iyer char *ixgbe_priv_props[] = {
1460dc2366fSVenugopal Iyer "_tx_copy_thresh",
1470dc2366fSVenugopal Iyer "_tx_recycle_thresh",
1480dc2366fSVenugopal Iyer "_tx_overload_thresh",
1490dc2366fSVenugopal Iyer "_tx_resched_thresh",
1500dc2366fSVenugopal Iyer "_rx_copy_thresh",
1510dc2366fSVenugopal Iyer "_rx_limit_per_intr",
1520dc2366fSVenugopal Iyer "_intr_throttling",
1530dc2366fSVenugopal Iyer "_adv_pause_cap",
1540dc2366fSVenugopal Iyer "_adv_asym_pause_cap",
1550dc2366fSVenugopal Iyer NULL
156ea65739eSchenlu chen - Sun Microsystems - Beijing China };
157ea65739eSchenlu chen - Sun Microsystems - Beijing China
158ea65739eSchenlu chen - Sun Microsystems - Beijing China #define IXGBE_MAX_PRIV_PROPS \
159ea65739eSchenlu chen - Sun Microsystems - Beijing China (sizeof (ixgbe_priv_props) / sizeof (mac_priv_prop_t))
160ea65739eSchenlu chen - Sun Microsystems - Beijing China
1619da57d7bSbt static struct cb_ops ixgbe_cb_ops = {
1629da57d7bSbt nulldev, /* cb_open */
1639da57d7bSbt nulldev, /* cb_close */
1649da57d7bSbt nodev, /* cb_strategy */
1659da57d7bSbt nodev, /* cb_print */
1669da57d7bSbt nodev, /* cb_dump */
1679da57d7bSbt nodev, /* cb_read */
1689da57d7bSbt nodev, /* cb_write */
1699da57d7bSbt nodev, /* cb_ioctl */
1709da57d7bSbt nodev, /* cb_devmap */
1719da57d7bSbt nodev, /* cb_mmap */
1729da57d7bSbt nodev, /* cb_segmap */
1739da57d7bSbt nochpoll, /* cb_chpoll */
1749da57d7bSbt ddi_prop_op, /* cb_prop_op */
1759da57d7bSbt NULL, /* cb_stream */
1769da57d7bSbt D_MP | D_HOTPLUG, /* cb_flag */
1779da57d7bSbt CB_REV, /* cb_rev */
1789da57d7bSbt nodev, /* cb_aread */
1799da57d7bSbt nodev /* cb_awrite */
1809da57d7bSbt };
1819da57d7bSbt
1829da57d7bSbt static struct dev_ops ixgbe_dev_ops = {
1839da57d7bSbt DEVO_REV, /* devo_rev */
1849da57d7bSbt 0, /* devo_refcnt */
1859da57d7bSbt NULL, /* devo_getinfo */
1869da57d7bSbt nulldev, /* devo_identify */
1879da57d7bSbt nulldev, /* devo_probe */
1889da57d7bSbt ixgbe_attach, /* devo_attach */
1899da57d7bSbt ixgbe_detach, /* devo_detach */
1909da57d7bSbt nodev, /* devo_reset */
1919da57d7bSbt &ixgbe_cb_ops, /* devo_cb_ops */
1929da57d7bSbt NULL, /* devo_bus_ops */
19319397407SSherry Moore ddi_power, /* devo_power */
1948c430e59SSaso Kiselkov ixgbe_quiesce, /* devo_quiesce */
1959da57d7bSbt };
1969da57d7bSbt
1979da57d7bSbt static struct modldrv ixgbe_modldrv = {
1989da57d7bSbt &mod_driverops, /* Type of module. This one is a driver */
199ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe_ident, /* Discription string */
2009da57d7bSbt &ixgbe_dev_ops /* driver ops */
2019da57d7bSbt };
2029da57d7bSbt
2039da57d7bSbt static struct modlinkage ixgbe_modlinkage = {
2049da57d7bSbt MODREV_1, &ixgbe_modldrv, NULL
2059da57d7bSbt };
2069da57d7bSbt
2079da57d7bSbt /*
2089da57d7bSbt * Access attributes for register mapping
2099da57d7bSbt */
2109da57d7bSbt ddi_device_acc_attr_t ixgbe_regs_acc_attr = {
211837c1ac4SStephen Hanson DDI_DEVICE_ATTR_V1,
2129da57d7bSbt DDI_STRUCTURE_LE_ACC,
2139da57d7bSbt DDI_STRICTORDER_ACC,
2149da57d7bSbt DDI_FLAGERR_ACC
2159da57d7bSbt };
2169da57d7bSbt
2179da57d7bSbt /*
2189da57d7bSbt * Loopback property
2199da57d7bSbt */
2209da57d7bSbt static lb_property_t lb_normal = {
2219da57d7bSbt normal, "normal", IXGBE_LB_NONE
2229da57d7bSbt };
2239da57d7bSbt
2249da57d7bSbt static lb_property_t lb_mac = {
2259da57d7bSbt internal, "MAC", IXGBE_LB_INTERNAL_MAC
2269da57d7bSbt };
2279da57d7bSbt
2281fedc51fSWinson Wang - Sun Microsystems - Beijing China static lb_property_t lb_external = {
2291fedc51fSWinson Wang - Sun Microsystems - Beijing China external, "External", IXGBE_LB_EXTERNAL
2301fedc51fSWinson Wang - Sun Microsystems - Beijing China };
2311fedc51fSWinson Wang - Sun Microsystems - Beijing China
232ea65739eSchenlu chen - Sun Microsystems - Beijing China #define IXGBE_M_CALLBACK_FLAGS \
2330dc2366fSVenugopal Iyer (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
2349da57d7bSbt
2359da57d7bSbt static mac_callbacks_t ixgbe_m_callbacks = {
2369da57d7bSbt IXGBE_M_CALLBACK_FLAGS,
2379da57d7bSbt ixgbe_m_stat,
2389da57d7bSbt ixgbe_m_start,
2399da57d7bSbt ixgbe_m_stop,
2409da57d7bSbt ixgbe_m_promisc,
2419da57d7bSbt ixgbe_m_multicst,
242da14cebeSEric Cheng NULL,
2439da57d7bSbt NULL,
2440dc2366fSVenugopal Iyer NULL,
2459da57d7bSbt ixgbe_m_ioctl,
246ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_m_getcapab,
247ea65739eSchenlu chen - Sun Microsystems - Beijing China NULL,
248ea65739eSchenlu chen - Sun Microsystems - Beijing China NULL,
249ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_m_setprop,
2500dc2366fSVenugopal Iyer ixgbe_m_getprop,
2510dc2366fSVenugopal Iyer ixgbe_m_propinfo
2529da57d7bSbt };
2539da57d7bSbt
25413740cb2SPaul Guo /*
25513740cb2SPaul Guo * Initialize capabilities of each supported adapter type
25613740cb2SPaul Guo */
25713740cb2SPaul Guo static adapter_info_t ixgbe_82598eb_cap = {
25813740cb2SPaul Guo 64, /* maximum number of rx queues */
25913740cb2SPaul Guo 1, /* minimum number of rx queues */
2600dc2366fSVenugopal Iyer 64, /* default number of rx queues */
2610dc2366fSVenugopal Iyer 16, /* maximum number of rx groups */
2620dc2366fSVenugopal Iyer 1, /* minimum number of rx groups */
2630dc2366fSVenugopal Iyer 1, /* default number of rx groups */
26413740cb2SPaul Guo 32, /* maximum number of tx queues */
26513740cb2SPaul Guo 1, /* minimum number of tx queues */
26613740cb2SPaul Guo 8, /* default number of tx queues */
2671fedc51fSWinson Wang - Sun Microsystems - Beijing China 16366, /* maximum MTU size */
268ea65739eSchenlu chen - Sun Microsystems - Beijing China 0xFFFF, /* maximum interrupt throttle rate */
269ea65739eSchenlu chen - Sun Microsystems - Beijing China 0, /* minimum interrupt throttle rate */
270ea65739eSchenlu chen - Sun Microsystems - Beijing China 200, /* default interrupt throttle rate */
27113740cb2SPaul Guo 18, /* maximum total msix vectors */
27213740cb2SPaul Guo 16, /* maximum number of ring vectors */
27313740cb2SPaul Guo 2, /* maximum number of other vectors */
27413740cb2SPaul Guo IXGBE_EICR_LSC, /* "other" interrupt types handled */
2755b6dd21fSchenlu chen - Sun Microsystems - Beijing China 0, /* "other" interrupt types enable mask */
27613740cb2SPaul Guo (IXGBE_FLAG_DCA_CAPABLE /* capability flags */
27713740cb2SPaul Guo | IXGBE_FLAG_RSS_CAPABLE
27813740cb2SPaul Guo | IXGBE_FLAG_VMDQ_CAPABLE)
27913740cb2SPaul Guo };
28013740cb2SPaul Guo
28173cd555cSBin Tu - Sun Microsystems - Beijing China static adapter_info_t ixgbe_82599eb_cap = {
28273cd555cSBin Tu - Sun Microsystems - Beijing China 128, /* maximum number of rx queues */
28373cd555cSBin Tu - Sun Microsystems - Beijing China 1, /* minimum number of rx queues */
2840dc2366fSVenugopal Iyer 128, /* default number of rx queues */
2850dc2366fSVenugopal Iyer 64, /* maximum number of rx groups */
2860dc2366fSVenugopal Iyer 1, /* minimum number of rx groups */
2870dc2366fSVenugopal Iyer 1, /* default number of rx groups */
28873cd555cSBin Tu - Sun Microsystems - Beijing China 128, /* maximum number of tx queues */
28973cd555cSBin Tu - Sun Microsystems - Beijing China 1, /* minimum number of tx queues */
29073cd555cSBin Tu - Sun Microsystems - Beijing China 8, /* default number of tx queues */
2911fedc51fSWinson Wang - Sun Microsystems - Beijing China 15500, /* maximum MTU size */
292ea65739eSchenlu chen - Sun Microsystems - Beijing China 0xFF8, /* maximum interrupt throttle rate */
293ea65739eSchenlu chen - Sun Microsystems - Beijing China 0, /* minimum interrupt throttle rate */
294ea65739eSchenlu chen - Sun Microsystems - Beijing China 200, /* default interrupt throttle rate */
29573cd555cSBin Tu - Sun Microsystems - Beijing China 64, /* maximum total msix vectors */
29673cd555cSBin Tu - Sun Microsystems - Beijing China 16, /* maximum number of ring vectors */
29773cd555cSBin Tu - Sun Microsystems - Beijing China 2, /* maximum number of other vectors */
2985b6dd21fSchenlu chen - Sun Microsystems - Beijing China (IXGBE_EICR_LSC
2995b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_EICR_GPI_SDP1
3005b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_EICR_GPI_SDP2), /* "other" interrupt types handled */
3015b6dd21fSchenlu chen - Sun Microsystems - Beijing China
3025b6dd21fSchenlu chen - Sun Microsystems - Beijing China (IXGBE_SDP1_GPIEN
3035b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_SDP2_GPIEN), /* "other" interrupt types enable mask */
3045b6dd21fSchenlu chen - Sun Microsystems - Beijing China
3055b6dd21fSchenlu chen - Sun Microsystems - Beijing China (IXGBE_FLAG_DCA_CAPABLE
30673cd555cSBin Tu - Sun Microsystems - Beijing China | IXGBE_FLAG_RSS_CAPABLE
307ffd8e883SWinson Wang - Sun Microsystems - Beijing China | IXGBE_FLAG_VMDQ_CAPABLE
3085b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_FLAG_RSC_CAPABLE
3095b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_FLAG_SFP_PLUG_CAPABLE) /* capability flags */
31073cd555cSBin Tu - Sun Microsystems - Beijing China };
31173cd555cSBin Tu - Sun Microsystems - Beijing China
31269b5a878SDan McDonald static adapter_info_t ixgbe_X540_cap = {
31369b5a878SDan McDonald 128, /* maximum number of rx queues */
31469b5a878SDan McDonald 1, /* minimum number of rx queues */
31569b5a878SDan McDonald 128, /* default number of rx queues */
31669b5a878SDan McDonald 64, /* maximum number of rx groups */
31769b5a878SDan McDonald 1, /* minimum number of rx groups */
31869b5a878SDan McDonald 1, /* default number of rx groups */
31969b5a878SDan McDonald 128, /* maximum number of tx queues */
32069b5a878SDan McDonald 1, /* minimum number of tx queues */
32169b5a878SDan McDonald 8, /* default number of tx queues */
32269b5a878SDan McDonald 15500, /* maximum MTU size */
32369b5a878SDan McDonald 0xFF8, /* maximum interrupt throttle rate */
32469b5a878SDan McDonald 0, /* minimum interrupt throttle rate */
32569b5a878SDan McDonald 200, /* default interrupt throttle rate */
32669b5a878SDan McDonald 64, /* maximum total msix vectors */
32769b5a878SDan McDonald 16, /* maximum number of ring vectors */
32869b5a878SDan McDonald 2, /* maximum number of other vectors */
32969b5a878SDan McDonald (IXGBE_EICR_LSC
330dc0cb1cdSDale Ghent | IXGBE_EICR_GPI_SDP1_X540
331dc0cb1cdSDale Ghent | IXGBE_EICR_GPI_SDP2_X540), /* "other" interrupt types handled */
33269b5a878SDan McDonald
333dc0cb1cdSDale Ghent (IXGBE_SDP1_GPIEN_X540
334dc0cb1cdSDale Ghent | IXGBE_SDP2_GPIEN_X540), /* "other" interrupt types enable mask */
33569b5a878SDan McDonald
33669b5a878SDan McDonald (IXGBE_FLAG_DCA_CAPABLE
33769b5a878SDan McDonald | IXGBE_FLAG_RSS_CAPABLE
33869b5a878SDan McDonald | IXGBE_FLAG_VMDQ_CAPABLE
33969b5a878SDan McDonald | IXGBE_FLAG_RSC_CAPABLE) /* capability flags */
34069b5a878SDan McDonald };
34169b5a878SDan McDonald
342dc0cb1cdSDale Ghent static adapter_info_t ixgbe_X550_cap = {
343dc0cb1cdSDale Ghent 128, /* maximum number of rx queues */
344dc0cb1cdSDale Ghent 1, /* minimum number of rx queues */
345dc0cb1cdSDale Ghent 128, /* default number of rx queues */
346dc0cb1cdSDale Ghent 64, /* maximum number of rx groups */
347dc0cb1cdSDale Ghent 1, /* minimum number of rx groups */
348dc0cb1cdSDale Ghent 1, /* default number of rx groups */
349dc0cb1cdSDale Ghent 128, /* maximum number of tx queues */
350dc0cb1cdSDale Ghent 1, /* minimum number of tx queues */
351dc0cb1cdSDale Ghent 8, /* default number of tx queues */
352dc0cb1cdSDale Ghent 15500, /* maximum MTU size */
353dc0cb1cdSDale Ghent 0xFF8, /* maximum interrupt throttle rate */
354dc0cb1cdSDale Ghent 0, /* minimum interrupt throttle rate */
355dc0cb1cdSDale Ghent 0x200, /* default interrupt throttle rate */
356dc0cb1cdSDale Ghent 64, /* maximum total msix vectors */
357dc0cb1cdSDale Ghent 16, /* maximum number of ring vectors */
358dc0cb1cdSDale Ghent 2, /* maximum number of other vectors */
359dc0cb1cdSDale Ghent IXGBE_EICR_LSC, /* "other" interrupt types handled */
360dc0cb1cdSDale Ghent 0, /* "other" interrupt types enable mask */
361dc0cb1cdSDale Ghent (IXGBE_FLAG_RSS_CAPABLE
362dc0cb1cdSDale Ghent | IXGBE_FLAG_VMDQ_CAPABLE
363dc0cb1cdSDale Ghent | IXGBE_FLAG_RSC_CAPABLE) /* capability flags */
364dc0cb1cdSDale Ghent };
365dc0cb1cdSDale Ghent
366f2fe7acaSRobert Mustacchi static ddi_ufm_ops_t ixgbe_ufm_ops = {
367f2fe7acaSRobert Mustacchi .ddi_ufm_op_fill_image = ixgbe_ufm_fill_image,
368f2fe7acaSRobert Mustacchi .ddi_ufm_op_fill_slot = ixgbe_ufm_fill_slot,
369f2fe7acaSRobert Mustacchi .ddi_ufm_op_getcaps = ixgbe_ufm_getcaps,
370f2fe7acaSRobert Mustacchi .ddi_ufm_op_readimg = ixgbe_ufm_readimg
371f2fe7acaSRobert Mustacchi };
372f2fe7acaSRobert Mustacchi
373f2fe7acaSRobert Mustacchi
3749da57d7bSbt /*
3759da57d7bSbt * Module Initialization Functions.
3769da57d7bSbt */
3779da57d7bSbt
3789da57d7bSbt int
_init(void)3799da57d7bSbt _init(void)
3809da57d7bSbt {
3819da57d7bSbt int status;
3829da57d7bSbt
3839da57d7bSbt mac_init_ops(&ixgbe_dev_ops, MODULE_NAME);
3849da57d7bSbt
3859da57d7bSbt status = mod_install(&ixgbe_modlinkage);
3869da57d7bSbt
3879da57d7bSbt if (status != DDI_SUCCESS) {
3889da57d7bSbt mac_fini_ops(&ixgbe_dev_ops);
3899da57d7bSbt }
3909da57d7bSbt
3919da57d7bSbt return (status);
3929da57d7bSbt }
3939da57d7bSbt
3949da57d7bSbt int
_fini(void)3959da57d7bSbt _fini(void)
3969da57d7bSbt {
3979da57d7bSbt int status;
3989da57d7bSbt
3999da57d7bSbt status = mod_remove(&ixgbe_modlinkage);
4009da57d7bSbt
4019da57d7bSbt if (status == DDI_SUCCESS) {
4029da57d7bSbt mac_fini_ops(&ixgbe_dev_ops);
4039da57d7bSbt }
4049da57d7bSbt
4059da57d7bSbt return (status);
4069da57d7bSbt }
4079da57d7bSbt
4089da57d7bSbt int
_info(struct modinfo * modinfop)4099da57d7bSbt _info(struct modinfo *modinfop)
4109da57d7bSbt {
4119da57d7bSbt int status;
4129da57d7bSbt
4139da57d7bSbt status = mod_info(&ixgbe_modlinkage, modinfop);
4149da57d7bSbt
4159da57d7bSbt return (status);
4169da57d7bSbt }
4179da57d7bSbt
4189da57d7bSbt /*
4199da57d7bSbt * ixgbe_attach - Driver attach.
4209da57d7bSbt *
4219da57d7bSbt * This function is the device specific initialization entry
4229da57d7bSbt * point. This entry point is required and must be written.
4239da57d7bSbt * The DDI_ATTACH command must be provided in the attach entry
4249da57d7bSbt * point. When attach() is called with cmd set to DDI_ATTACH,
4259da57d7bSbt * all normal kernel services (such as kmem_alloc(9F)) are
4269da57d7bSbt * available for use by the driver.
4279da57d7bSbt *
4289da57d7bSbt * The attach() function will be called once for each instance
4299da57d7bSbt * of the device on the system with cmd set to DDI_ATTACH.
4309da57d7bSbt * Until attach() succeeds, the only driver entry points which
4319da57d7bSbt * may be called are open(9E) and getinfo(9E).
4329da57d7bSbt */
4339da57d7bSbt static int
ixgbe_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)4349da57d7bSbt ixgbe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
4359da57d7bSbt {
4369da57d7bSbt ixgbe_t *ixgbe;
4379da57d7bSbt struct ixgbe_osdep *osdep;
4389da57d7bSbt struct ixgbe_hw *hw;
4399da57d7bSbt int instance;
44013740cb2SPaul Guo char taskqname[32];
4419da57d7bSbt
4429da57d7bSbt /*
4439da57d7bSbt * Check the command and perform corresponding operations
4449da57d7bSbt */
4459da57d7bSbt switch (cmd) {
4469da57d7bSbt default:
4479da57d7bSbt return (DDI_FAILURE);
4489da57d7bSbt
4499da57d7bSbt case DDI_RESUME:
4509da57d7bSbt return (ixgbe_resume(devinfo));
4519da57d7bSbt
4529da57d7bSbt case DDI_ATTACH:
4539da57d7bSbt break;
4549da57d7bSbt }
4559da57d7bSbt
4569da57d7bSbt /* Get the device instance */
4579da57d7bSbt instance = ddi_get_instance(devinfo);
4589da57d7bSbt
4599da57d7bSbt /* Allocate memory for the instance data structure */
4609da57d7bSbt ixgbe = kmem_zalloc(sizeof (ixgbe_t), KM_SLEEP);
4619da57d7bSbt
4629da57d7bSbt ixgbe->dip = devinfo;
4639da57d7bSbt ixgbe->instance = instance;
4649da57d7bSbt
4659da57d7bSbt hw = &ixgbe->hw;
4669da57d7bSbt osdep = &ixgbe->osdep;
4679da57d7bSbt hw->back = osdep;
4689da57d7bSbt osdep->ixgbe = ixgbe;
4699da57d7bSbt
4709da57d7bSbt /* Attach the instance pointer to the dev_info data structure */
4719da57d7bSbt ddi_set_driver_private(devinfo, ixgbe);
4729da57d7bSbt
4739da57d7bSbt /*
474dc0cb1cdSDale Ghent * Initialize for FMA support
4759da57d7bSbt */
476c971fb7eSgg ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE,
4779da57d7bSbt 0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
4789da57d7bSbt DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
4799da57d7bSbt ixgbe_fm_init(ixgbe);
4809da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_FM_INIT;
4819da57d7bSbt
4829da57d7bSbt /*
4839da57d7bSbt * Map PCI config space registers
4849da57d7bSbt */
4859da57d7bSbt if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
4869da57d7bSbt ixgbe_error(ixgbe, "Failed to map PCI configurations");
4879da57d7bSbt goto attach_fail;
4889da57d7bSbt }
4899da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
4909da57d7bSbt
4919da57d7bSbt /*
4929da57d7bSbt * Identify the chipset family
4939da57d7bSbt */
4949da57d7bSbt if (ixgbe_identify_hardware(ixgbe) != IXGBE_SUCCESS) {
4959da57d7bSbt ixgbe_error(ixgbe, "Failed to identify hardware");
4969da57d7bSbt goto attach_fail;
4979da57d7bSbt }
4989da57d7bSbt
4999da57d7bSbt /*
5009da57d7bSbt * Map device registers
5019da57d7bSbt */
5029da57d7bSbt if (ixgbe_regs_map(ixgbe) != IXGBE_SUCCESS) {
5039da57d7bSbt ixgbe_error(ixgbe, "Failed to map device registers");
5049da57d7bSbt goto attach_fail;
5059da57d7bSbt }
5069da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_REGS_MAP;
5079da57d7bSbt
5089da57d7bSbt /*
5099da57d7bSbt * Initialize driver parameters
5109da57d7bSbt */
5119da57d7bSbt ixgbe_init_properties(ixgbe);
5129da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS;
5139da57d7bSbt
5140dc2366fSVenugopal Iyer /*
5150dc2366fSVenugopal Iyer * Register interrupt callback
5160dc2366fSVenugopal Iyer */
5170dc2366fSVenugopal Iyer if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) {
5180dc2366fSVenugopal Iyer ixgbe_error(ixgbe, "Failed to register interrupt callback");
5190dc2366fSVenugopal Iyer goto attach_fail;
5200dc2366fSVenugopal Iyer }
5210dc2366fSVenugopal Iyer
5229da57d7bSbt /*
5239da57d7bSbt * Allocate interrupts
5249da57d7bSbt */
5259da57d7bSbt if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) {
5269da57d7bSbt ixgbe_error(ixgbe, "Failed to allocate interrupts");
5279da57d7bSbt goto attach_fail;
5289da57d7bSbt }
5299da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
5309da57d7bSbt
5319da57d7bSbt /*
5329da57d7bSbt * Allocate rx/tx rings based on the ring numbers.
5339da57d7bSbt * The actual numbers of rx/tx rings are decided by the number of
5349da57d7bSbt * allocated interrupt vectors, so we should allocate the rings after
5359da57d7bSbt * interrupts are allocated.
5369da57d7bSbt */
5379da57d7bSbt if (ixgbe_alloc_rings(ixgbe) != IXGBE_SUCCESS) {
5389da57d7bSbt ixgbe_error(ixgbe, "Failed to allocate rx and tx rings");
5399da57d7bSbt goto attach_fail;
5409da57d7bSbt }
5419da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_RINGS;
5429da57d7bSbt
5439da57d7bSbt /*
5449da57d7bSbt * Map rings to interrupt vectors
5459da57d7bSbt */
54673cd555cSBin Tu - Sun Microsystems - Beijing China if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
54773cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_error(ixgbe, "Failed to map interrupts to vectors");
5489da57d7bSbt goto attach_fail;
5499da57d7bSbt }
5509da57d7bSbt
5519da57d7bSbt /*
5529da57d7bSbt * Add interrupt handlers
5539da57d7bSbt */
5549da57d7bSbt if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
5559da57d7bSbt ixgbe_error(ixgbe, "Failed to add interrupt handlers");
5569da57d7bSbt goto attach_fail;
5579da57d7bSbt }
5589da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
5599da57d7bSbt
56013740cb2SPaul Guo /*
56162e6e1adSPaul Guo * Create a taskq for sfp-change
56213740cb2SPaul Guo */
5635b6dd21fSchenlu chen - Sun Microsystems - Beijing China (void) sprintf(taskqname, "ixgbe%d_sfp_taskq", instance);
56462e6e1adSPaul Guo if ((ixgbe->sfp_taskq = ddi_taskq_create(devinfo, taskqname,
56513740cb2SPaul Guo 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
5665b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, "sfp_taskq create failed");
56713740cb2SPaul Guo goto attach_fail;
56813740cb2SPaul Guo }
56962e6e1adSPaul Guo ixgbe->attach_progress |= ATTACH_PROGRESS_SFP_TASKQ;
57013740cb2SPaul Guo
5715b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
5725b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Create a taskq for over-temp
5735b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
5745b6dd21fSchenlu chen - Sun Microsystems - Beijing China (void) sprintf(taskqname, "ixgbe%d_overtemp_taskq", instance);
5755b6dd21fSchenlu chen - Sun Microsystems - Beijing China if ((ixgbe->overtemp_taskq = ddi_taskq_create(devinfo, taskqname,
5765b6dd21fSchenlu chen - Sun Microsystems - Beijing China 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
5775b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, "overtemp_taskq create failed");
5785b6dd21fSchenlu chen - Sun Microsystems - Beijing China goto attach_fail;
5795b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
5805b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->attach_progress |= ATTACH_PROGRESS_OVERTEMP_TASKQ;
5815b6dd21fSchenlu chen - Sun Microsystems - Beijing China
582dc0cb1cdSDale Ghent /*
583dc0cb1cdSDale Ghent * Create a taskq for processing external PHY interrupts
584dc0cb1cdSDale Ghent */
585dc0cb1cdSDale Ghent (void) sprintf(taskqname, "ixgbe%d_phy_taskq", instance);
586dc0cb1cdSDale Ghent if ((ixgbe->phy_taskq = ddi_taskq_create(devinfo, taskqname,
587dc0cb1cdSDale Ghent 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
588dc0cb1cdSDale Ghent ixgbe_error(ixgbe, "phy_taskq create failed");
589dc0cb1cdSDale Ghent goto attach_fail;
590dc0cb1cdSDale Ghent }
591dc0cb1cdSDale Ghent ixgbe->attach_progress |= ATTACH_PROGRESS_PHY_TASKQ;
592dc0cb1cdSDale Ghent
5939da57d7bSbt /*
5949da57d7bSbt * Initialize driver parameters
5959da57d7bSbt */
5969da57d7bSbt if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) {
5979da57d7bSbt ixgbe_error(ixgbe, "Failed to initialize driver settings");
5989da57d7bSbt goto attach_fail;
5999da57d7bSbt }
6009da57d7bSbt
6019da57d7bSbt /*
6029da57d7bSbt * Initialize mutexes for this device.
6039da57d7bSbt * Do this before enabling the interrupt handler and
6049da57d7bSbt * register the softint to avoid the condition where
6059da57d7bSbt * interrupt handler can try using uninitialized mutex.
6069da57d7bSbt */
6079da57d7bSbt ixgbe_init_locks(ixgbe);
6089da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_LOCKS;
6099da57d7bSbt
6109da57d7bSbt /*
6119da57d7bSbt * Initialize chipset hardware
6129da57d7bSbt */
6139da57d7bSbt if (ixgbe_init(ixgbe) != IXGBE_SUCCESS) {
6149da57d7bSbt ixgbe_error(ixgbe, "Failed to initialize adapter");
6159da57d7bSbt goto attach_fail;
6169da57d7bSbt }
61762e6e1adSPaul Guo ixgbe->link_check_complete = B_FALSE;
61862e6e1adSPaul Guo ixgbe->link_check_hrtime = gethrtime() +
61962e6e1adSPaul Guo (IXGBE_LINK_UP_TIME * 100000000ULL);
6209da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_INIT;
6219da57d7bSbt
6229da57d7bSbt if (ixgbe_check_acc_handle(ixgbe->osdep.cfg_handle) != DDI_FM_OK) {
6239da57d7bSbt ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
6249da57d7bSbt goto attach_fail;
6259da57d7bSbt }
6269da57d7bSbt
627dc0cb1cdSDale Ghent /*
628dc0cb1cdSDale Ghent * Initialize adapter capabilities
629dc0cb1cdSDale Ghent */
630dc0cb1cdSDale Ghent ixgbe_init_params(ixgbe);
631dc0cb1cdSDale Ghent
6329da57d7bSbt /*
6339da57d7bSbt * Initialize statistics
6349da57d7bSbt */
6359da57d7bSbt if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) {
6369da57d7bSbt ixgbe_error(ixgbe, "Failed to initialize statistics");
6379da57d7bSbt goto attach_fail;
6389da57d7bSbt }
6399da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_STATS;
6409da57d7bSbt
6419da57d7bSbt /*
6429da57d7bSbt * Register the driver to the MAC
6439da57d7bSbt */
6449da57d7bSbt if (ixgbe_register_mac(ixgbe) != IXGBE_SUCCESS) {
6459da57d7bSbt ixgbe_error(ixgbe, "Failed to register MAC");
6469da57d7bSbt goto attach_fail;
6479da57d7bSbt }
64813740cb2SPaul Guo mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
6499da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_MAC;
6509da57d7bSbt
65162e6e1adSPaul Guo ixgbe->periodic_id = ddi_periodic_add(ixgbe_link_timer, ixgbe,
65262e6e1adSPaul Guo IXGBE_CYCLIC_PERIOD, DDI_IPL_0);
65362e6e1adSPaul Guo if (ixgbe->periodic_id == 0) {
65462e6e1adSPaul Guo ixgbe_error(ixgbe, "Failed to add the link check timer");
65562e6e1adSPaul Guo goto attach_fail;
65662e6e1adSPaul Guo }
65762e6e1adSPaul Guo ixgbe->attach_progress |= ATTACH_PROGRESS_LINK_TIMER;
65862e6e1adSPaul Guo
6599da57d7bSbt /*
6609da57d7bSbt * Now that mutex locks are initialized, and the chip is also
6619da57d7bSbt * initialized, enable interrupts.
6629da57d7bSbt */
6639da57d7bSbt if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
6649da57d7bSbt ixgbe_error(ixgbe, "Failed to enable DDI interrupts");
6659da57d7bSbt goto attach_fail;
6669da57d7bSbt }
6679da57d7bSbt ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
6689da57d7bSbt
669f2fe7acaSRobert Mustacchi if (ixgbe->hw.bus.func == 0) {
670f2fe7acaSRobert Mustacchi if (ddi_ufm_init(devinfo, DDI_UFM_CURRENT_VERSION,
671f2fe7acaSRobert Mustacchi &ixgbe_ufm_ops, &ixgbe->ixgbe_ufmh, ixgbe) != 0) {
672f2fe7acaSRobert Mustacchi ixgbe_error(ixgbe, "Failed to enable DDI UFM support");
673f2fe7acaSRobert Mustacchi goto attach_fail;
674f2fe7acaSRobert Mustacchi }
675f2fe7acaSRobert Mustacchi ixgbe->attach_progress |= ATTACH_PROGRESS_UFM;
676f2fe7acaSRobert Mustacchi ddi_ufm_update(ixgbe->ixgbe_ufmh);
677f2fe7acaSRobert Mustacchi }
678f2fe7acaSRobert Mustacchi
679dc0cb1cdSDale Ghent ixgbe_log(ixgbe, "%s", ixgbe_ident);
68062e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED);
6819da57d7bSbt
6829da57d7bSbt return (DDI_SUCCESS);
6839da57d7bSbt
6849da57d7bSbt attach_fail:
6859da57d7bSbt ixgbe_unconfigure(devinfo, ixgbe);
6869da57d7bSbt return (DDI_FAILURE);
6879da57d7bSbt }
6889da57d7bSbt
6899da57d7bSbt /*
6909da57d7bSbt * ixgbe_detach - Driver detach.
6919da57d7bSbt *
6929da57d7bSbt * The detach() function is the complement of the attach routine.
6939da57d7bSbt * If cmd is set to DDI_DETACH, detach() is used to remove the
6949da57d7bSbt * state associated with a given instance of a device node
6959da57d7bSbt * prior to the removal of that instance from the system.
6969da57d7bSbt *
6979da57d7bSbt * The detach() function will be called once for each instance
6989da57d7bSbt * of the device for which there has been a successful attach()
6999da57d7bSbt * once there are no longer any opens on the device.
7009da57d7bSbt *
7019da57d7bSbt * Interrupts routine are disabled, All memory allocated by this
7029da57d7bSbt * driver are freed.
7039da57d7bSbt */
7049da57d7bSbt static int
ixgbe_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)7059da57d7bSbt ixgbe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
7069da57d7bSbt {
7079da57d7bSbt ixgbe_t *ixgbe;
7089da57d7bSbt
7099da57d7bSbt /*
7109da57d7bSbt * Check detach command
7119da57d7bSbt */
7129da57d7bSbt switch (cmd) {
7139da57d7bSbt default:
7149da57d7bSbt return (DDI_FAILURE);
7159da57d7bSbt
7169da57d7bSbt case DDI_SUSPEND:
7179da57d7bSbt return (ixgbe_suspend(devinfo));
7189da57d7bSbt
7199da57d7bSbt case DDI_DETACH:
7209da57d7bSbt break;
7219da57d7bSbt }
7229da57d7bSbt
7239da57d7bSbt /*
7249da57d7bSbt * Get the pointer to the driver private data structure
7259da57d7bSbt */
7269da57d7bSbt ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
7279da57d7bSbt if (ixgbe == NULL)
7289da57d7bSbt return (DDI_FAILURE);
7299da57d7bSbt
7309da57d7bSbt /*
7319da57d7bSbt * If the device is still running, it needs to be stopped first.
7329da57d7bSbt * This check is necessary because under some specific circumstances,
7339da57d7bSbt * the detach routine can be called without stopping the interface
7349da57d7bSbt * first.
7359da57d7bSbt */
7369da57d7bSbt if (ixgbe->ixgbe_state & IXGBE_STARTED) {
73762e6e1adSPaul Guo atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
73862e6e1adSPaul Guo mutex_enter(&ixgbe->gen_lock);
739ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe, B_TRUE);
7409da57d7bSbt mutex_exit(&ixgbe->gen_lock);
7419da57d7bSbt /* Disable and stop the watchdog timer */
7429da57d7bSbt ixgbe_disable_watchdog_timer(ixgbe);
74362e6e1adSPaul Guo }
7449da57d7bSbt
7459da57d7bSbt /*
7469da57d7bSbt * Check if there are still rx buffers held by the upper layer.
7479da57d7bSbt * If so, fail the detach.
7489da57d7bSbt */
7499da57d7bSbt if (!ixgbe_rx_drain(ixgbe))
7509da57d7bSbt return (DDI_FAILURE);
7519da57d7bSbt
7529da57d7bSbt /*
7539da57d7bSbt * Do the remaining unconfigure routines
7549da57d7bSbt */
7559da57d7bSbt ixgbe_unconfigure(devinfo, ixgbe);
7569da57d7bSbt
7579da57d7bSbt return (DDI_SUCCESS);
7589da57d7bSbt }
7599da57d7bSbt
7608c430e59SSaso Kiselkov /*
7618c430e59SSaso Kiselkov * quiesce(9E) entry point.
7628c430e59SSaso Kiselkov *
7638c430e59SSaso Kiselkov * This function is called when the system is single-threaded at high
7648c430e59SSaso Kiselkov * PIL with preemption disabled. Therefore, this function must not be
7658c430e59SSaso Kiselkov * blocked.
7668c430e59SSaso Kiselkov *
7678c430e59SSaso Kiselkov * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
7688c430e59SSaso Kiselkov * DDI_FAILURE indicates an error condition and should almost never happen.
7698c430e59SSaso Kiselkov */
7708c430e59SSaso Kiselkov static int
ixgbe_quiesce(dev_info_t * devinfo)7718c430e59SSaso Kiselkov ixgbe_quiesce(dev_info_t *devinfo)
7728c430e59SSaso Kiselkov {
7738c430e59SSaso Kiselkov ixgbe_t *ixgbe;
7748c430e59SSaso Kiselkov struct ixgbe_hw *hw;
7758c430e59SSaso Kiselkov
7768c430e59SSaso Kiselkov ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
7778c430e59SSaso Kiselkov
7788c430e59SSaso Kiselkov if (ixgbe == NULL)
7798c430e59SSaso Kiselkov return (DDI_FAILURE);
7808c430e59SSaso Kiselkov
7818c430e59SSaso Kiselkov hw = &ixgbe->hw;
7828c430e59SSaso Kiselkov
7838c430e59SSaso Kiselkov /*
7848c430e59SSaso Kiselkov * Disable the adapter interrupts
7858c430e59SSaso Kiselkov */
7868c430e59SSaso Kiselkov ixgbe_disable_adapter_interrupts(ixgbe);
7878c430e59SSaso Kiselkov
7888c430e59SSaso Kiselkov /*
7898c430e59SSaso Kiselkov * Tell firmware driver is no longer in control
7908c430e59SSaso Kiselkov */
7918c430e59SSaso Kiselkov ixgbe_release_driver_control(hw);
7928c430e59SSaso Kiselkov
7938c430e59SSaso Kiselkov /*
7948c430e59SSaso Kiselkov * Reset the chipset
7958c430e59SSaso Kiselkov */
7968c430e59SSaso Kiselkov (void) ixgbe_reset_hw(hw);
7978c430e59SSaso Kiselkov
7988c430e59SSaso Kiselkov /*
7998c430e59SSaso Kiselkov * Reset PHY
8008c430e59SSaso Kiselkov */
8018c430e59SSaso Kiselkov (void) ixgbe_reset_phy(hw);
8028c430e59SSaso Kiselkov
8038c430e59SSaso Kiselkov return (DDI_SUCCESS);
8048c430e59SSaso Kiselkov }
8058c430e59SSaso Kiselkov
8069da57d7bSbt static void
ixgbe_unconfigure(dev_info_t * devinfo,ixgbe_t * ixgbe)8079da57d7bSbt ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe)
8089da57d7bSbt {
8099da57d7bSbt /*
8109da57d7bSbt * Disable interrupt
8119da57d7bSbt */
8129da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
8139da57d7bSbt (void) ixgbe_disable_intrs(ixgbe);
8149da57d7bSbt }
8159da57d7bSbt
81662e6e1adSPaul Guo /*
81762e6e1adSPaul Guo * remove the link check timer
81862e6e1adSPaul Guo */
81962e6e1adSPaul Guo if (ixgbe->attach_progress & ATTACH_PROGRESS_LINK_TIMER) {
82062e6e1adSPaul Guo if (ixgbe->periodic_id != NULL) {
82162e6e1adSPaul Guo ddi_periodic_delete(ixgbe->periodic_id);
82262e6e1adSPaul Guo ixgbe->periodic_id = NULL;
82362e6e1adSPaul Guo }
82462e6e1adSPaul Guo }
82562e6e1adSPaul Guo
826f2fe7acaSRobert Mustacchi /*
827f2fe7acaSRobert Mustacchi * Clean up the UFM subsystem. Note this only is set on function 0.
828f2fe7acaSRobert Mustacchi */
829f2fe7acaSRobert Mustacchi if (ixgbe->attach_progress & ATTACH_PROGRESS_UFM) {
830f2fe7acaSRobert Mustacchi ddi_ufm_fini(ixgbe->ixgbe_ufmh);
831f2fe7acaSRobert Mustacchi }
832f2fe7acaSRobert Mustacchi
8339da57d7bSbt /*
8349da57d7bSbt * Unregister MAC
8359da57d7bSbt */
8369da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_MAC) {
8379da57d7bSbt (void) mac_unregister(ixgbe->mac_hdl);
8389da57d7bSbt }
8399da57d7bSbt
8409da57d7bSbt /*
8419da57d7bSbt * Free statistics
8429da57d7bSbt */
8439da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_STATS) {
8449da57d7bSbt kstat_delete((kstat_t *)ixgbe->ixgbe_ks);
8459da57d7bSbt }
8469da57d7bSbt
8479da57d7bSbt /*
8489da57d7bSbt * Remove interrupt handlers
8499da57d7bSbt */
8509da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
8519da57d7bSbt ixgbe_rem_intr_handlers(ixgbe);
8529da57d7bSbt }
8539da57d7bSbt
85413740cb2SPaul Guo /*
85562e6e1adSPaul Guo * Remove taskq for sfp-status-change
85613740cb2SPaul Guo */
85762e6e1adSPaul Guo if (ixgbe->attach_progress & ATTACH_PROGRESS_SFP_TASKQ) {
85862e6e1adSPaul Guo ddi_taskq_destroy(ixgbe->sfp_taskq);
85913740cb2SPaul Guo }
86013740cb2SPaul Guo
8615b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
8625b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Remove taskq for over-temp
8635b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
8645b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->attach_progress & ATTACH_PROGRESS_OVERTEMP_TASKQ) {
8655b6dd21fSchenlu chen - Sun Microsystems - Beijing China ddi_taskq_destroy(ixgbe->overtemp_taskq);
8665b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
8675b6dd21fSchenlu chen - Sun Microsystems - Beijing China
868dc0cb1cdSDale Ghent /*
869dc0cb1cdSDale Ghent * Remove taskq for external PHYs
870dc0cb1cdSDale Ghent */
871dc0cb1cdSDale Ghent if (ixgbe->attach_progress & ATTACH_PROGRESS_PHY_TASKQ) {
872dc0cb1cdSDale Ghent ddi_taskq_destroy(ixgbe->phy_taskq);
873dc0cb1cdSDale Ghent }
874dc0cb1cdSDale Ghent
8759da57d7bSbt /*
8769da57d7bSbt * Remove interrupts
8779da57d7bSbt */
8789da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) {
8799da57d7bSbt ixgbe_rem_intrs(ixgbe);
8809da57d7bSbt }
8819da57d7bSbt
8820dc2366fSVenugopal Iyer /*
8830dc2366fSVenugopal Iyer * Unregister interrupt callback handler
8840dc2366fSVenugopal Iyer */
885895d6e02SRobert Mustacchi if (ixgbe->cb_hdl != NULL) {
886895d6e02SRobert Mustacchi (void) ddi_cb_unregister(ixgbe->cb_hdl);
887895d6e02SRobert Mustacchi }
8880dc2366fSVenugopal Iyer
8899da57d7bSbt /*
8909da57d7bSbt * Remove driver properties
8919da57d7bSbt */
8929da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_PROPS) {
8939da57d7bSbt (void) ddi_prop_remove_all(devinfo);
8949da57d7bSbt }
8959da57d7bSbt
8969da57d7bSbt /*
8979da57d7bSbt * Stop the chipset
8989da57d7bSbt */
8999da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_INIT) {
9009da57d7bSbt mutex_enter(&ixgbe->gen_lock);
9019da57d7bSbt ixgbe_chip_stop(ixgbe);
9029da57d7bSbt mutex_exit(&ixgbe->gen_lock);
9039da57d7bSbt }
9049da57d7bSbt
9059da57d7bSbt /*
9069da57d7bSbt * Free register handle
9079da57d7bSbt */
9089da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_REGS_MAP) {
9099da57d7bSbt if (ixgbe->osdep.reg_handle != NULL)
9109da57d7bSbt ddi_regs_map_free(&ixgbe->osdep.reg_handle);
9119da57d7bSbt }
9129da57d7bSbt
9139da57d7bSbt /*
9149da57d7bSbt * Free PCI config handle
9159da57d7bSbt */
9169da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_PCI_CONFIG) {
9179da57d7bSbt if (ixgbe->osdep.cfg_handle != NULL)
9189da57d7bSbt pci_config_teardown(&ixgbe->osdep.cfg_handle);
9199da57d7bSbt }
9209da57d7bSbt
9219da57d7bSbt /*
9229da57d7bSbt * Free locks
9239da57d7bSbt */
9249da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_LOCKS) {
9259da57d7bSbt ixgbe_destroy_locks(ixgbe);
9269da57d7bSbt }
9279da57d7bSbt
9289da57d7bSbt /*
9299da57d7bSbt * Free the rx/tx rings
9309da57d7bSbt */
9319da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_RINGS) {
9329da57d7bSbt ixgbe_free_rings(ixgbe);
9339da57d7bSbt }
9349da57d7bSbt
9359da57d7bSbt /*
9369da57d7bSbt * Unregister FMA capabilities
9379da57d7bSbt */
9389da57d7bSbt if (ixgbe->attach_progress & ATTACH_PROGRESS_FM_INIT) {
9399da57d7bSbt ixgbe_fm_fini(ixgbe);
9409da57d7bSbt }
9419da57d7bSbt
9429da57d7bSbt /*
9439da57d7bSbt * Free the driver data structure
9449da57d7bSbt */
9459da57d7bSbt kmem_free(ixgbe, sizeof (ixgbe_t));
9469da57d7bSbt
9479da57d7bSbt ddi_set_driver_private(devinfo, NULL);
9489da57d7bSbt }
9499da57d7bSbt
9509da57d7bSbt /*
9519da57d7bSbt * ixgbe_register_mac - Register the driver and its function pointers with
9529da57d7bSbt * the GLD interface.
9539da57d7bSbt */
9549da57d7bSbt static int
ixgbe_register_mac(ixgbe_t * ixgbe)9559da57d7bSbt ixgbe_register_mac(ixgbe_t *ixgbe)
9569da57d7bSbt {
9579da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
9589da57d7bSbt mac_register_t *mac;
9599da57d7bSbt int status;
9609da57d7bSbt
9619da57d7bSbt if ((mac = mac_alloc(MAC_VERSION)) == NULL)
9629da57d7bSbt return (IXGBE_FAILURE);
9639da57d7bSbt
9649da57d7bSbt mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
9659da57d7bSbt mac->m_driver = ixgbe;
9669da57d7bSbt mac->m_dip = ixgbe->dip;
9679da57d7bSbt mac->m_src_addr = hw->mac.addr;
9689da57d7bSbt mac->m_callbacks = &ixgbe_m_callbacks;
9699da57d7bSbt mac->m_min_sdu = 0;
9709da57d7bSbt mac->m_max_sdu = ixgbe->default_mtu;
9719da57d7bSbt mac->m_margin = VLAN_TAGSZ;
972ea65739eSchenlu chen - Sun Microsystems - Beijing China mac->m_priv_props = ixgbe_priv_props;
973da14cebeSEric Cheng mac->m_v12n = MAC_VIRT_LEVEL1;
9749da57d7bSbt
9759da57d7bSbt status = mac_register(mac, &ixgbe->mac_hdl);
9769da57d7bSbt
9779da57d7bSbt mac_free(mac);
9789da57d7bSbt
9799da57d7bSbt return ((status == 0) ? IXGBE_SUCCESS : IXGBE_FAILURE);
9809da57d7bSbt }
9819da57d7bSbt
9829da57d7bSbt /*
9839da57d7bSbt * ixgbe_identify_hardware - Identify the type of the chipset.
9849da57d7bSbt */
9859da57d7bSbt static int
ixgbe_identify_hardware(ixgbe_t * ixgbe)9869da57d7bSbt ixgbe_identify_hardware(ixgbe_t *ixgbe)
9879da57d7bSbt {
9889da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
9899da57d7bSbt struct ixgbe_osdep *osdep = &ixgbe->osdep;
9909da57d7bSbt
9919da57d7bSbt /*
9929da57d7bSbt * Get the device id
9939da57d7bSbt */
9949da57d7bSbt hw->vendor_id =
9959da57d7bSbt pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
9969da57d7bSbt hw->device_id =
9979da57d7bSbt pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
9989da57d7bSbt hw->revision_id =
9999da57d7bSbt pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
10009da57d7bSbt hw->subsystem_device_id =
10019da57d7bSbt pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
10029da57d7bSbt hw->subsystem_vendor_id =
10039da57d7bSbt pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
10049da57d7bSbt
100513740cb2SPaul Guo /*
100613740cb2SPaul Guo * Set the mac type of the adapter based on the device id
100713740cb2SPaul Guo */
100813740cb2SPaul Guo if (ixgbe_set_mac_type(hw) != IXGBE_SUCCESS) {
100913740cb2SPaul Guo return (IXGBE_FAILURE);
101013740cb2SPaul Guo }
101113740cb2SPaul Guo
101213740cb2SPaul Guo /*
101313740cb2SPaul Guo * Install adapter capabilities
101413740cb2SPaul Guo */
101513740cb2SPaul Guo switch (hw->mac.type) {
101613740cb2SPaul Guo case ixgbe_mac_82598EB:
101719843f01SPaul Guo IXGBE_DEBUGLOG_0(ixgbe, "identify 82598 adapter\n");
101813740cb2SPaul Guo ixgbe->capab = &ixgbe_82598eb_cap;
101913740cb2SPaul Guo
102013740cb2SPaul Guo if (ixgbe_get_media_type(hw) == ixgbe_media_type_copper) {
102113740cb2SPaul Guo ixgbe->capab->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
102213740cb2SPaul Guo ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP1;
10235b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->other_gpie |= IXGBE_SDP1_GPIEN;
102413740cb2SPaul Guo }
102573cd555cSBin Tu - Sun Microsystems - Beijing China break;
10265b6dd21fSchenlu chen - Sun Microsystems - Beijing China
102773cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
102819843f01SPaul Guo IXGBE_DEBUGLOG_0(ixgbe, "identify 82599 adapter\n");
102973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->capab = &ixgbe_82599eb_cap;
103073cd555cSBin Tu - Sun Microsystems - Beijing China
10315b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM) {
10325b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->flags |= IXGBE_FLAG_TEMP_SENSOR_CAPABLE;
10335b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->other_intr |= IXGBE_EICR_GPI_SDP0;
10345b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN;
10355b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
103613740cb2SPaul Guo break;
10375b6dd21fSchenlu chen - Sun Microsystems - Beijing China
103869b5a878SDan McDonald case ixgbe_mac_X540:
103969b5a878SDan McDonald IXGBE_DEBUGLOG_0(ixgbe, "identify X540 adapter\n");
104069b5a878SDan McDonald ixgbe->capab = &ixgbe_X540_cap;
104169b5a878SDan McDonald /*
104269b5a878SDan McDonald * For now, X540 is all set in its capab structure.
104369b5a878SDan McDonald * As other X540 variants show up, things can change here.
104469b5a878SDan McDonald */
104569b5a878SDan McDonald break;
104669b5a878SDan McDonald
1047dc0cb1cdSDale Ghent case ixgbe_mac_X550:
1048dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
104948ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
1050dc0cb1cdSDale Ghent IXGBE_DEBUGLOG_0(ixgbe, "identify X550 adapter\n");
1051dc0cb1cdSDale Ghent ixgbe->capab = &ixgbe_X550_cap;
1052dc0cb1cdSDale Ghent
105348ed61a7SRobert Mustacchi if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
105448ed61a7SRobert Mustacchi hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP ||
105548ed61a7SRobert Mustacchi hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N ||
105648ed61a7SRobert Mustacchi hw->device_id == IXGBE_DEV_ID_X550EM_A_QSFP ||
105748ed61a7SRobert Mustacchi hw->device_id == IXGBE_DEV_ID_X550EM_A_QSFP_N) {
1058dc0cb1cdSDale Ghent ixgbe->capab->flags |= IXGBE_FLAG_SFP_PLUG_CAPABLE;
105948ed61a7SRobert Mustacchi }
1060dc0cb1cdSDale Ghent
1061dc0cb1cdSDale Ghent /*
1062dc0cb1cdSDale Ghent * Link detection on X552 SFP+ and X552/X557-AT
1063dc0cb1cdSDale Ghent */
1064dc0cb1cdSDale Ghent if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
106548ed61a7SRobert Mustacchi hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP ||
106648ed61a7SRobert Mustacchi hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP_N ||
1067dc0cb1cdSDale Ghent hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
1068dc0cb1cdSDale Ghent ixgbe->capab->other_intr |=
1069dc0cb1cdSDale Ghent IXGBE_EIMS_GPI_SDP0_BY_MAC(hw);
107048ed61a7SRobert Mustacchi }
107148ed61a7SRobert Mustacchi if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
1072dc0cb1cdSDale Ghent ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN_X540;
1073dc0cb1cdSDale Ghent }
1074dc0cb1cdSDale Ghent break;
1075dc0cb1cdSDale Ghent
107613740cb2SPaul Guo default:
107719843f01SPaul Guo IXGBE_DEBUGLOG_1(ixgbe,
107813740cb2SPaul Guo "adapter not supported in ixgbe_identify_hardware(): %d\n",
107913740cb2SPaul Guo hw->mac.type);
108013740cb2SPaul Guo return (IXGBE_FAILURE);
108113740cb2SPaul Guo }
108213740cb2SPaul Guo
10839da57d7bSbt return (IXGBE_SUCCESS);
10849da57d7bSbt }
10859da57d7bSbt
10869da57d7bSbt /*
10879da57d7bSbt * ixgbe_regs_map - Map the device registers.
10889da57d7bSbt *
10899da57d7bSbt */
10909da57d7bSbt static int
ixgbe_regs_map(ixgbe_t * ixgbe)10919da57d7bSbt ixgbe_regs_map(ixgbe_t *ixgbe)
10929da57d7bSbt {
10939da57d7bSbt dev_info_t *devinfo = ixgbe->dip;
10949da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
10959da57d7bSbt struct ixgbe_osdep *osdep = &ixgbe->osdep;
10969da57d7bSbt off_t mem_size;
10979da57d7bSbt
10989da57d7bSbt /*
10999da57d7bSbt * First get the size of device registers to be mapped.
11009da57d7bSbt */
110173cd555cSBin Tu - Sun Microsystems - Beijing China if (ddi_dev_regsize(devinfo, IXGBE_ADAPTER_REGSET, &mem_size)
110273cd555cSBin Tu - Sun Microsystems - Beijing China != DDI_SUCCESS) {
11039da57d7bSbt return (IXGBE_FAILURE);
11049da57d7bSbt }
11059da57d7bSbt
11069da57d7bSbt /*
11079da57d7bSbt * Call ddi_regs_map_setup() to map registers
11089da57d7bSbt */
110973cd555cSBin Tu - Sun Microsystems - Beijing China if ((ddi_regs_map_setup(devinfo, IXGBE_ADAPTER_REGSET,
11109da57d7bSbt (caddr_t *)&hw->hw_addr, 0,
11119da57d7bSbt mem_size, &ixgbe_regs_acc_attr,
11129da57d7bSbt &osdep->reg_handle)) != DDI_SUCCESS) {
11139da57d7bSbt return (IXGBE_FAILURE);
11149da57d7bSbt }
11159da57d7bSbt
11169da57d7bSbt return (IXGBE_SUCCESS);
11179da57d7bSbt }
11189da57d7bSbt
11199da57d7bSbt /*
11209da57d7bSbt * ixgbe_init_properties - Initialize driver properties.
11219da57d7bSbt */
11229da57d7bSbt static void
ixgbe_init_properties(ixgbe_t * ixgbe)11239da57d7bSbt ixgbe_init_properties(ixgbe_t *ixgbe)
11249da57d7bSbt {
11259da57d7bSbt /*
11269da57d7bSbt * Get conf file properties, including link settings
11279da57d7bSbt * jumbo frames, ring number, descriptor number, etc.
11289da57d7bSbt */
11299da57d7bSbt ixgbe_get_conf(ixgbe);
11309da57d7bSbt }
11319da57d7bSbt
11329da57d7bSbt /*
11339da57d7bSbt * ixgbe_init_driver_settings - Initialize driver settings.
11349da57d7bSbt *
11359da57d7bSbt * The settings include hardware function pointers, bus information,
11369da57d7bSbt * rx/tx rings settings, link state, and any other parameters that
11379da57d7bSbt * need to be setup during driver initialization.
11389da57d7bSbt */
11399da57d7bSbt static int
ixgbe_init_driver_settings(ixgbe_t * ixgbe)11409da57d7bSbt ixgbe_init_driver_settings(ixgbe_t *ixgbe)
11419da57d7bSbt {
11429da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
1143da14cebeSEric Cheng dev_info_t *devinfo = ixgbe->dip;
11449da57d7bSbt ixgbe_rx_ring_t *rx_ring;
11450dc2366fSVenugopal Iyer ixgbe_rx_group_t *rx_group;
11469da57d7bSbt ixgbe_tx_ring_t *tx_ring;
11479da57d7bSbt uint32_t rx_size;
11489da57d7bSbt uint32_t tx_size;
11490dc2366fSVenugopal Iyer uint32_t ring_per_group;
11509da57d7bSbt int i;
11519da57d7bSbt
11529da57d7bSbt /*
11539da57d7bSbt * Initialize chipset specific hardware function pointers
11549da57d7bSbt */
11559da57d7bSbt if (ixgbe_init_shared_code(hw) != IXGBE_SUCCESS) {
11569da57d7bSbt return (IXGBE_FAILURE);
11579da57d7bSbt }
11589da57d7bSbt
1159da14cebeSEric Cheng /*
1160da14cebeSEric Cheng * Get the system page size
1161da14cebeSEric Cheng */
1162da14cebeSEric Cheng ixgbe->sys_page_size = ddi_ptob(devinfo, (ulong_t)1);
1163da14cebeSEric Cheng
11649da57d7bSbt /*
11659da57d7bSbt * Set rx buffer size
11669da57d7bSbt *
11679da57d7bSbt * The IP header alignment room is counted in the calculation.
11689da57d7bSbt * The rx buffer size is in unit of 1K that is required by the
11699da57d7bSbt * chipset hardware.
11709da57d7bSbt */
11719da57d7bSbt rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
11729da57d7bSbt ixgbe->rx_buf_size = ((rx_size >> 10) +
11739da57d7bSbt ((rx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
11749da57d7bSbt
11759da57d7bSbt /*
11769da57d7bSbt * Set tx buffer size
11779da57d7bSbt */
11789da57d7bSbt tx_size = ixgbe->max_frame_size;
11799da57d7bSbt ixgbe->tx_buf_size = ((tx_size >> 10) +
11809da57d7bSbt ((tx_size & (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
11819da57d7bSbt
11829da57d7bSbt /*
11830dc2366fSVenugopal Iyer * Initialize rx/tx rings/groups parameters
11849da57d7bSbt */
11850dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
11869da57d7bSbt for (i = 0; i < ixgbe->num_rx_rings; i++) {
11879da57d7bSbt rx_ring = &ixgbe->rx_rings[i];
11889da57d7bSbt rx_ring->index = i;
11899da57d7bSbt rx_ring->ixgbe = ixgbe;
11900dc2366fSVenugopal Iyer rx_ring->group_index = i / ring_per_group;
11910dc2366fSVenugopal Iyer rx_ring->hw_index = ixgbe_get_hw_rx_index(ixgbe, i);
11920dc2366fSVenugopal Iyer }
11930dc2366fSVenugopal Iyer
11940dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_rx_groups; i++) {
11950dc2366fSVenugopal Iyer rx_group = &ixgbe->rx_groups[i];
11960dc2366fSVenugopal Iyer rx_group->index = i;
11970dc2366fSVenugopal Iyer rx_group->ixgbe = ixgbe;
119884de666eSRyan Zezeski list_create(&rx_group->vlans, sizeof (ixgbe_vlan_t),
119984de666eSRyan Zezeski offsetof(ixgbe_vlan_t, ixvl_link));
12009da57d7bSbt }
12019da57d7bSbt
12029da57d7bSbt for (i = 0; i < ixgbe->num_tx_rings; i++) {
12039da57d7bSbt tx_ring = &ixgbe->tx_rings[i];
12049da57d7bSbt tx_ring->index = i;
12059da57d7bSbt tx_ring->ixgbe = ixgbe;
12069da57d7bSbt if (ixgbe->tx_head_wb_enable)
12079da57d7bSbt tx_ring->tx_recycle = ixgbe_tx_recycle_head_wb;
12089da57d7bSbt else
12099da57d7bSbt tx_ring->tx_recycle = ixgbe_tx_recycle_legacy;
12109da57d7bSbt
12119da57d7bSbt tx_ring->ring_size = ixgbe->tx_ring_size;
12129da57d7bSbt tx_ring->free_list_size = ixgbe->tx_ring_size +
12139da57d7bSbt (ixgbe->tx_ring_size >> 1);
12149da57d7bSbt }
12159da57d7bSbt
12169da57d7bSbt /*
12179da57d7bSbt * Initialize values of interrupt throttling rate
12189da57d7bSbt */
121973cd555cSBin Tu - Sun Microsystems - Beijing China for (i = 1; i < MAX_INTR_VECTOR; i++)
12209da57d7bSbt ixgbe->intr_throttling[i] = ixgbe->intr_throttling[0];
12219da57d7bSbt
12229da57d7bSbt /*
12239da57d7bSbt * The initial link state should be "unknown"
12249da57d7bSbt */
12259da57d7bSbt ixgbe->link_state = LINK_STATE_UNKNOWN;
122673cd555cSBin Tu - Sun Microsystems - Beijing China
12279da57d7bSbt return (IXGBE_SUCCESS);
12289da57d7bSbt }
12299da57d7bSbt
12309da57d7bSbt /*
12319da57d7bSbt * ixgbe_init_locks - Initialize locks.
12329da57d7bSbt */
12339da57d7bSbt static void
ixgbe_init_locks(ixgbe_t * ixgbe)12349da57d7bSbt ixgbe_init_locks(ixgbe_t *ixgbe)
12359da57d7bSbt {
12369da57d7bSbt ixgbe_rx_ring_t *rx_ring;
12379da57d7bSbt ixgbe_tx_ring_t *tx_ring;
12389da57d7bSbt int i;
12399da57d7bSbt
12409da57d7bSbt for (i = 0; i < ixgbe->num_rx_rings; i++) {
12419da57d7bSbt rx_ring = &ixgbe->rx_rings[i];
12429da57d7bSbt mutex_init(&rx_ring->rx_lock, NULL,
12439da57d7bSbt MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12449da57d7bSbt }
12459da57d7bSbt
12469da57d7bSbt for (i = 0; i < ixgbe->num_tx_rings; i++) {
12479da57d7bSbt tx_ring = &ixgbe->tx_rings[i];
12489da57d7bSbt mutex_init(&tx_ring->tx_lock, NULL,
12499da57d7bSbt MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12509da57d7bSbt mutex_init(&tx_ring->recycle_lock, NULL,
12519da57d7bSbt MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12529da57d7bSbt mutex_init(&tx_ring->tcb_head_lock, NULL,
12539da57d7bSbt MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12549da57d7bSbt mutex_init(&tx_ring->tcb_tail_lock, NULL,
12559da57d7bSbt MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12569da57d7bSbt }
12579da57d7bSbt
12589da57d7bSbt mutex_init(&ixgbe->gen_lock, NULL,
12599da57d7bSbt MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12609da57d7bSbt
12619da57d7bSbt mutex_init(&ixgbe->watchdog_lock, NULL,
12629da57d7bSbt MUTEX_DRIVER, DDI_INTR_PRI(ixgbe->intr_pri));
12639da57d7bSbt }
12649da57d7bSbt
12659da57d7bSbt /*
12669da57d7bSbt * ixgbe_destroy_locks - Destroy locks.
12679da57d7bSbt */
12689da57d7bSbt static void
ixgbe_destroy_locks(ixgbe_t * ixgbe)12699da57d7bSbt ixgbe_destroy_locks(ixgbe_t *ixgbe)
12709da57d7bSbt {
12719da57d7bSbt ixgbe_rx_ring_t *rx_ring;
12729da57d7bSbt ixgbe_tx_ring_t *tx_ring;
12739da57d7bSbt int i;
12749da57d7bSbt
12759da57d7bSbt for (i = 0; i < ixgbe->num_rx_rings; i++) {
12769da57d7bSbt rx_ring = &ixgbe->rx_rings[i];
12779da57d7bSbt mutex_destroy(&rx_ring->rx_lock);
12789da57d7bSbt }
12799da57d7bSbt
12809da57d7bSbt for (i = 0; i < ixgbe->num_tx_rings; i++) {
12819da57d7bSbt tx_ring = &ixgbe->tx_rings[i];
12829da57d7bSbt mutex_destroy(&tx_ring->tx_lock);
12839da57d7bSbt mutex_destroy(&tx_ring->recycle_lock);
12849da57d7bSbt mutex_destroy(&tx_ring->tcb_head_lock);
12859da57d7bSbt mutex_destroy(&tx_ring->tcb_tail_lock);
12869da57d7bSbt }
12879da57d7bSbt
12889da57d7bSbt mutex_destroy(&ixgbe->gen_lock);
12899da57d7bSbt mutex_destroy(&ixgbe->watchdog_lock);
12909da57d7bSbt }
12919da57d7bSbt
129237367bbaSRobert Mustacchi /*
129337367bbaSRobert Mustacchi * We need to try and determine which LED index in hardware corresponds to the
129437367bbaSRobert Mustacchi * link/activity LED. This is the one that'll be overwritten when we perform
129537367bbaSRobert Mustacchi * GLDv3 LED activity.
129637367bbaSRobert Mustacchi */
129737367bbaSRobert Mustacchi static void
ixgbe_led_init(ixgbe_t * ixgbe)129837367bbaSRobert Mustacchi ixgbe_led_init(ixgbe_t *ixgbe)
129937367bbaSRobert Mustacchi {
130037367bbaSRobert Mustacchi uint32_t reg, i;
130137367bbaSRobert Mustacchi struct ixgbe_hw *hw = &ixgbe->hw;
130237367bbaSRobert Mustacchi
130337367bbaSRobert Mustacchi reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
130437367bbaSRobert Mustacchi for (i = 0; i < 4; i++) {
130537367bbaSRobert Mustacchi if (((reg >> IXGBE_LED_MODE_SHIFT(i)) &
130637367bbaSRobert Mustacchi IXGBE_LED_MODE_MASK_BASE) == IXGBE_LED_LINK_ACTIVE) {
130737367bbaSRobert Mustacchi ixgbe->ixgbe_led_index = i;
130837367bbaSRobert Mustacchi return;
130937367bbaSRobert Mustacchi }
131037367bbaSRobert Mustacchi }
131137367bbaSRobert Mustacchi
131237367bbaSRobert Mustacchi /*
131337367bbaSRobert Mustacchi * If we couldn't determine this, we use the default for various MACs
131437367bbaSRobert Mustacchi * based on information Intel has inserted into other drivers over the
131548ed61a7SRobert Mustacchi * years.
131637367bbaSRobert Mustacchi */
131737367bbaSRobert Mustacchi switch (hw->mac.type) {
131848ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
131948ed61a7SRobert Mustacchi ixgbe->ixgbe_led_index = 0;
132048ed61a7SRobert Mustacchi break;
132137367bbaSRobert Mustacchi case ixgbe_mac_X550EM_x:
132237367bbaSRobert Mustacchi ixgbe->ixgbe_led_index = 1;
132337367bbaSRobert Mustacchi break;
132437367bbaSRobert Mustacchi default:
132537367bbaSRobert Mustacchi ixgbe->ixgbe_led_index = 2;
132637367bbaSRobert Mustacchi break;
132737367bbaSRobert Mustacchi }
132837367bbaSRobert Mustacchi }
132937367bbaSRobert Mustacchi
13309da57d7bSbt static int
ixgbe_resume(dev_info_t * devinfo)13319da57d7bSbt ixgbe_resume(dev_info_t *devinfo)
13329da57d7bSbt {
13339da57d7bSbt ixgbe_t *ixgbe;
133462e6e1adSPaul Guo int i;
13359da57d7bSbt
13369da57d7bSbt ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
13379da57d7bSbt if (ixgbe == NULL)
13389da57d7bSbt return (DDI_FAILURE);
13399da57d7bSbt
13409da57d7bSbt mutex_enter(&ixgbe->gen_lock);
13419da57d7bSbt
13429da57d7bSbt if (ixgbe->ixgbe_state & IXGBE_STARTED) {
1343ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
13449da57d7bSbt mutex_exit(&ixgbe->gen_lock);
13459da57d7bSbt return (DDI_FAILURE);
13469da57d7bSbt }
13479da57d7bSbt
13489da57d7bSbt /*
13499da57d7bSbt * Enable and start the watchdog timer
13509da57d7bSbt */
13519da57d7bSbt ixgbe_enable_watchdog_timer(ixgbe);
13529da57d7bSbt }
13539da57d7bSbt
135462e6e1adSPaul Guo atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_SUSPENDED);
135562e6e1adSPaul Guo
135662e6e1adSPaul Guo if (ixgbe->ixgbe_state & IXGBE_STARTED) {
135762e6e1adSPaul Guo for (i = 0; i < ixgbe->num_tx_rings; i++) {
135862e6e1adSPaul Guo mac_tx_ring_update(ixgbe->mac_hdl,
135962e6e1adSPaul Guo ixgbe->tx_rings[i].ring_handle);
136062e6e1adSPaul Guo }
136162e6e1adSPaul Guo }
13629da57d7bSbt
13639da57d7bSbt mutex_exit(&ixgbe->gen_lock);
13649da57d7bSbt
13659da57d7bSbt return (DDI_SUCCESS);
13669da57d7bSbt }
13679da57d7bSbt
13689da57d7bSbt static int
ixgbe_suspend(dev_info_t * devinfo)13699da57d7bSbt ixgbe_suspend(dev_info_t *devinfo)
13709da57d7bSbt {
13719da57d7bSbt ixgbe_t *ixgbe;
13729da57d7bSbt
13739da57d7bSbt ixgbe = (ixgbe_t *)ddi_get_driver_private(devinfo);
13749da57d7bSbt if (ixgbe == NULL)
13759da57d7bSbt return (DDI_FAILURE);
13769da57d7bSbt
13779da57d7bSbt mutex_enter(&ixgbe->gen_lock);
13789da57d7bSbt
137962e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_SUSPENDED);
1380ea65739eSchenlu chen - Sun Microsystems - Beijing China if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
1381ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock);
1382ea65739eSchenlu chen - Sun Microsystems - Beijing China return (DDI_SUCCESS);
1383ea65739eSchenlu chen - Sun Microsystems - Beijing China }
1384ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe, B_FALSE);
13859da57d7bSbt
13869da57d7bSbt mutex_exit(&ixgbe->gen_lock);
13879da57d7bSbt
13889da57d7bSbt /*
13899da57d7bSbt * Disable and stop the watchdog timer
13909da57d7bSbt */
13919da57d7bSbt ixgbe_disable_watchdog_timer(ixgbe);
13929da57d7bSbt
13939da57d7bSbt return (DDI_SUCCESS);
13949da57d7bSbt }
13959da57d7bSbt
13969da57d7bSbt /*
13979da57d7bSbt * ixgbe_init - Initialize the device.
13989da57d7bSbt */
13999da57d7bSbt static int
ixgbe_init(ixgbe_t * ixgbe)14009da57d7bSbt ixgbe_init(ixgbe_t *ixgbe)
14019da57d7bSbt {
14029da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
140369c76190SKeith M Wesolowski u8 pbanum[IXGBE_PBANUM_LENGTH];
1404dc0cb1cdSDale Ghent int rv;
14059da57d7bSbt
14069da57d7bSbt mutex_enter(&ixgbe->gen_lock);
14079da57d7bSbt
14089da57d7bSbt /*
1409dc0cb1cdSDale Ghent * Configure/Initialize hardware
14109da57d7bSbt */
1411dc0cb1cdSDale Ghent rv = ixgbe_init_hw(hw);
1412dc0cb1cdSDale Ghent if (rv != IXGBE_SUCCESS) {
1413dc0cb1cdSDale Ghent switch (rv) {
1414dc0cb1cdSDale Ghent
1415dc0cb1cdSDale Ghent /*
1416dc0cb1cdSDale Ghent * The first three errors are not prohibitive to us progressing
1417dc0cb1cdSDale Ghent * further, and are maily advisory in nature. In the case of a
1418dc0cb1cdSDale Ghent * SFP module not being present or not deemed supported by the
1419dc0cb1cdSDale Ghent * common code, we adivse the operator of this fact but carry on
1420dc0cb1cdSDale Ghent * instead of failing hard, as SFPs can be inserted or replaced
1421dc0cb1cdSDale Ghent * while the driver is running. In the case of a unknown error,
1422dc0cb1cdSDale Ghent * we fail-hard, logging the reason and emitting a FMA event.
1423dc0cb1cdSDale Ghent */
1424dc0cb1cdSDale Ghent case IXGBE_ERR_EEPROM_VERSION:
1425dc0cb1cdSDale Ghent ixgbe_error(ixgbe,
1426dc0cb1cdSDale Ghent "This Intel 10Gb Ethernet device is pre-release and"
1427dc0cb1cdSDale Ghent " contains outdated firmware. Please contact your"
1428dc0cb1cdSDale Ghent " hardware vendor for a replacement.");
1429dc0cb1cdSDale Ghent break;
1430dc0cb1cdSDale Ghent case IXGBE_ERR_SFP_NOT_PRESENT:
1431dc0cb1cdSDale Ghent ixgbe_error(ixgbe,
1432dc0cb1cdSDale Ghent "No SFP+ module detected on this interface. Please "
1433dc0cb1cdSDale Ghent "install a supported SFP+ module for this "
1434dc0cb1cdSDale Ghent "interface to become operational.");
1435dc0cb1cdSDale Ghent break;
1436dc0cb1cdSDale Ghent case IXGBE_ERR_SFP_NOT_SUPPORTED:
1437dc0cb1cdSDale Ghent ixgbe_error(ixgbe,
1438dc0cb1cdSDale Ghent "Unsupported SFP+ module detected. Please replace "
1439dc0cb1cdSDale Ghent "it with a supported SFP+ module per Intel "
1440dc0cb1cdSDale Ghent "documentation, or bypass this check with "
1441dc0cb1cdSDale Ghent "allow_unsupported_sfp=1 in ixgbe.conf.");
1442dc0cb1cdSDale Ghent break;
1443dc0cb1cdSDale Ghent default:
1444dc0cb1cdSDale Ghent ixgbe_error(ixgbe,
1445dc0cb1cdSDale Ghent "Failed to initialize hardware. ixgbe_init_hw "
1446dc0cb1cdSDale Ghent "returned %d", rv);
1447dc0cb1cdSDale Ghent ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
1448dc0cb1cdSDale Ghent goto init_fail;
1449dc0cb1cdSDale Ghent }
14509da57d7bSbt }
14519da57d7bSbt
14529da57d7bSbt /*
14539da57d7bSbt * Need to init eeprom before validating the checksum.
14549da57d7bSbt */
14559da57d7bSbt if (ixgbe_init_eeprom_params(hw) < 0) {
14569da57d7bSbt ixgbe_error(ixgbe,
14579da57d7bSbt "Unable to intitialize the eeprom interface.");
14589da57d7bSbt ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
14599da57d7bSbt goto init_fail;
14609da57d7bSbt }
14619da57d7bSbt
14629da57d7bSbt /*
14639da57d7bSbt * NVM validation
14649da57d7bSbt */
14659da57d7bSbt if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
14669da57d7bSbt /*
14679da57d7bSbt * Some PCI-E parts fail the first check due to
14689da57d7bSbt * the link being in sleep state. Call it again,
14699da57d7bSbt * if it fails a second time it's a real issue.
14709da57d7bSbt */
14719da57d7bSbt if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
14729da57d7bSbt ixgbe_error(ixgbe,
14739da57d7bSbt "Invalid NVM checksum. Please contact "
14749da57d7bSbt "the vendor to update the NVM.");
14759da57d7bSbt ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
14769da57d7bSbt goto init_fail;
14779da57d7bSbt }
14789da57d7bSbt }
14799da57d7bSbt
14809da57d7bSbt /*
14819da57d7bSbt * Setup default flow control thresholds - enable/disable
14829da57d7bSbt * & flow control type is controlled by ixgbe.conf
14839da57d7bSbt */
148469b5a878SDan McDonald hw->fc.high_water[0] = DEFAULT_FCRTH;
148569b5a878SDan McDonald hw->fc.low_water[0] = DEFAULT_FCRTL;
14869da57d7bSbt hw->fc.pause_time = DEFAULT_FCPAUSE;
14879da57d7bSbt hw->fc.send_xon = B_TRUE;
14889da57d7bSbt
1489dc0cb1cdSDale Ghent /*
1490dc0cb1cdSDale Ghent * Initialize flow control
1491dc0cb1cdSDale Ghent */
1492dc0cb1cdSDale Ghent (void) ixgbe_start_hw(hw);
1493dc0cb1cdSDale Ghent
14949da57d7bSbt /*
14959da57d7bSbt * Initialize link settings
14969da57d7bSbt */
14979da57d7bSbt (void) ixgbe_driver_setup_link(ixgbe, B_FALSE);
14989da57d7bSbt
14999da57d7bSbt /*
15009da57d7bSbt * Initialize the chipset hardware
15019da57d7bSbt */
15029da57d7bSbt if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
15039da57d7bSbt ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
15049da57d7bSbt goto init_fail;
15059da57d7bSbt }
15069da57d7bSbt
150769c76190SKeith M Wesolowski /*
150869c76190SKeith M Wesolowski * Read identifying information and place in devinfo.
150969c76190SKeith M Wesolowski */
151069c76190SKeith M Wesolowski pbanum[0] = '\0';
151169c76190SKeith M Wesolowski (void) ixgbe_read_pba_string(hw, pbanum, sizeof (pbanum));
151269c76190SKeith M Wesolowski if (*pbanum != '\0') {
151369c76190SKeith M Wesolowski (void) ddi_prop_update_string(DDI_DEV_T_NONE, ixgbe->dip,
151469c76190SKeith M Wesolowski "printed-board-assembly", (char *)pbanum);
151569c76190SKeith M Wesolowski }
151669c76190SKeith M Wesolowski
151737367bbaSRobert Mustacchi /*
151837367bbaSRobert Mustacchi * Determine LED index.
151937367bbaSRobert Mustacchi */
152037367bbaSRobert Mustacchi ixgbe_led_init(ixgbe);
152137367bbaSRobert Mustacchi
15229da57d7bSbt if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
15239da57d7bSbt goto init_fail;
15249da57d7bSbt }
15259da57d7bSbt
15269da57d7bSbt mutex_exit(&ixgbe->gen_lock);
15279da57d7bSbt return (IXGBE_SUCCESS);
15289da57d7bSbt
15299da57d7bSbt init_fail:
15309da57d7bSbt /*
15319da57d7bSbt * Reset PHY
15329da57d7bSbt */
15339da57d7bSbt (void) ixgbe_reset_phy(hw);
15349da57d7bSbt
15359da57d7bSbt mutex_exit(&ixgbe->gen_lock);
15369da57d7bSbt ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
15379da57d7bSbt return (IXGBE_FAILURE);
15389da57d7bSbt }
15399da57d7bSbt
15409da57d7bSbt /*
15419da57d7bSbt * ixgbe_chip_start - Initialize and start the chipset hardware.
15429da57d7bSbt */
15439da57d7bSbt static int
ixgbe_chip_start(ixgbe_t * ixgbe)15449da57d7bSbt ixgbe_chip_start(ixgbe_t *ixgbe)
15459da57d7bSbt {
15469da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
1547dc0cb1cdSDale Ghent int i;
15489da57d7bSbt
15499da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
15509da57d7bSbt
15519da57d7bSbt /*
15529da57d7bSbt * Get the mac address
15539da57d7bSbt * This function should handle SPARC case correctly.
15549da57d7bSbt */
15559da57d7bSbt if (!ixgbe_find_mac_address(ixgbe)) {
15569da57d7bSbt ixgbe_error(ixgbe, "Failed to get the mac address");
15579da57d7bSbt return (IXGBE_FAILURE);
15589da57d7bSbt }
15599da57d7bSbt
15609da57d7bSbt /*
15619da57d7bSbt * Validate the mac address
15629da57d7bSbt */
15639da57d7bSbt (void) ixgbe_init_rx_addrs(hw);
15649da57d7bSbt if (!is_valid_mac_addr(hw->mac.addr)) {
15659da57d7bSbt ixgbe_error(ixgbe, "Invalid mac address");
15669da57d7bSbt return (IXGBE_FAILURE);
15679da57d7bSbt }
15689da57d7bSbt
156919843f01SPaul Guo /*
157019843f01SPaul Guo * Re-enable relaxed ordering for performance. It is disabled
157119843f01SPaul Guo * by default in the hardware init.
157219843f01SPaul Guo */
15735b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->relax_order_enable == B_TRUE)
15745b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_enable_relaxed_ordering(hw);
157519843f01SPaul Guo
15769da57d7bSbt /*
15779da57d7bSbt * Setup adapter interrupt vectors
15789da57d7bSbt */
15799da57d7bSbt ixgbe_setup_adapter_vector(ixgbe);
15809da57d7bSbt
15819da57d7bSbt /*
15829da57d7bSbt * Initialize unicast addresses.
15839da57d7bSbt */
15849da57d7bSbt ixgbe_init_unicst(ixgbe);
15859da57d7bSbt
15869da57d7bSbt /*
15879da57d7bSbt * Setup and initialize the mctable structures.
15889da57d7bSbt */
15899da57d7bSbt ixgbe_setup_multicst(ixgbe);
15909da57d7bSbt
15919da57d7bSbt /*
15929da57d7bSbt * Set interrupt throttling rate
15939da57d7bSbt */
159473cd555cSBin Tu - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->intr_cnt; i++) {
15959da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]);
159673cd555cSBin Tu - Sun Microsystems - Beijing China }
15979da57d7bSbt
15989da57d7bSbt /*
1599dc0cb1cdSDale Ghent * Disable Wake-on-LAN
1600dc0cb1cdSDale Ghent */
1601dc0cb1cdSDale Ghent IXGBE_WRITE_REG(hw, IXGBE_WUC, 0);
1602dc0cb1cdSDale Ghent
1603dc0cb1cdSDale Ghent /*
1604dc0cb1cdSDale Ghent * Some adapters offer Energy Efficient Ethernet (EEE) support.
1605dc0cb1cdSDale Ghent * Due to issues with EEE in e1000g/igb, we disable this by default
1606dc0cb1cdSDale Ghent * as a precautionary measure.
1607dc0cb1cdSDale Ghent *
160848ed61a7SRobert Mustacchi * Currently, this is present on a number of the X550 family parts.
1609dc0cb1cdSDale Ghent */
1610dc0cb1cdSDale Ghent (void) ixgbe_setup_eee(hw, B_FALSE);
1611dc0cb1cdSDale Ghent
1612dc0cb1cdSDale Ghent /*
1613dc0cb1cdSDale Ghent * Turn on any present SFP Tx laser
1614dc0cb1cdSDale Ghent */
1615dc0cb1cdSDale Ghent ixgbe_enable_tx_laser(hw);
1616dc0cb1cdSDale Ghent
1617dc0cb1cdSDale Ghent /*
1618dc0cb1cdSDale Ghent * Power on the PHY
1619dc0cb1cdSDale Ghent */
1620dc0cb1cdSDale Ghent (void) ixgbe_set_phy_power(hw, B_TRUE);
1621dc0cb1cdSDale Ghent
1622dc0cb1cdSDale Ghent /*
1623dc0cb1cdSDale Ghent * Save the state of the PHY
16249da57d7bSbt */
16259da57d7bSbt ixgbe_get_hw_state(ixgbe);
16269da57d7bSbt
16279da57d7bSbt /*
16289da57d7bSbt * Make sure driver has control
16299da57d7bSbt */
16309da57d7bSbt ixgbe_get_driver_control(hw);
16319da57d7bSbt
16329da57d7bSbt return (IXGBE_SUCCESS);
16339da57d7bSbt }
16349da57d7bSbt
16359da57d7bSbt /*
16369da57d7bSbt * ixgbe_chip_stop - Stop the chipset hardware
16379da57d7bSbt */
16389da57d7bSbt static void
ixgbe_chip_stop(ixgbe_t * ixgbe)16399da57d7bSbt ixgbe_chip_stop(ixgbe_t *ixgbe)
16409da57d7bSbt {
16419da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
1642dc0cb1cdSDale Ghent int rv;
16439da57d7bSbt
16449da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
16459da57d7bSbt
16469da57d7bSbt /*
1647dc0cb1cdSDale Ghent * Stop interupt generation and disable Tx unit
16489da57d7bSbt */
1649dc0cb1cdSDale Ghent hw->adapter_stopped = B_FALSE;
1650dc0cb1cdSDale Ghent (void) ixgbe_stop_adapter(hw);
16519da57d7bSbt
16529da57d7bSbt /*
16539da57d7bSbt * Reset the chipset
16549da57d7bSbt */
16559da57d7bSbt (void) ixgbe_reset_hw(hw);
16569da57d7bSbt
16579da57d7bSbt /*
16589da57d7bSbt * Reset PHY
16599da57d7bSbt */
16609da57d7bSbt (void) ixgbe_reset_phy(hw);
1661dc0cb1cdSDale Ghent
1662dc0cb1cdSDale Ghent /*
1663dc0cb1cdSDale Ghent * Enter LPLU (Low Power, Link Up) mode, if available. Avoid resetting
1664dc0cb1cdSDale Ghent * the PHY while doing so. Else, just power down the PHY.
1665dc0cb1cdSDale Ghent */
1666dc0cb1cdSDale Ghent if (hw->phy.ops.enter_lplu != NULL) {
1667dc0cb1cdSDale Ghent hw->phy.reset_disable = B_TRUE;
1668dc0cb1cdSDale Ghent rv = hw->phy.ops.enter_lplu(hw);
1669dc0cb1cdSDale Ghent if (rv != IXGBE_SUCCESS)
1670dc0cb1cdSDale Ghent ixgbe_error(ixgbe, "Error while entering LPLU: %d", rv);
1671dc0cb1cdSDale Ghent hw->phy.reset_disable = B_FALSE;
1672dc0cb1cdSDale Ghent } else {
1673dc0cb1cdSDale Ghent (void) ixgbe_set_phy_power(hw, B_FALSE);
1674dc0cb1cdSDale Ghent }
1675dc0cb1cdSDale Ghent
1676dc0cb1cdSDale Ghent /*
1677dc0cb1cdSDale Ghent * Turn off any present SFP Tx laser
1678dc0cb1cdSDale Ghent * Expected for health and safety reasons
1679dc0cb1cdSDale Ghent */
1680dc0cb1cdSDale Ghent ixgbe_disable_tx_laser(hw);
1681dc0cb1cdSDale Ghent
1682dc0cb1cdSDale Ghent /*
1683dc0cb1cdSDale Ghent * Tell firmware driver is no longer in control
1684dc0cb1cdSDale Ghent */
1685dc0cb1cdSDale Ghent ixgbe_release_driver_control(hw);
1686dc0cb1cdSDale Ghent
16879da57d7bSbt }
16889da57d7bSbt
16899da57d7bSbt /*
16909da57d7bSbt * ixgbe_reset - Reset the chipset and re-start the driver.
16919da57d7bSbt *
16929da57d7bSbt * It involves stopping and re-starting the chipset,
16939da57d7bSbt * and re-configuring the rx/tx rings.
16949da57d7bSbt */
16959da57d7bSbt static int
ixgbe_reset(ixgbe_t * ixgbe)16969da57d7bSbt ixgbe_reset(ixgbe_t *ixgbe)
16979da57d7bSbt {
169862e6e1adSPaul Guo int i;
169962e6e1adSPaul Guo
1700ea65739eSchenlu chen - Sun Microsystems - Beijing China /*
1701ea65739eSchenlu chen - Sun Microsystems - Beijing China * Disable and stop the watchdog timer
1702ea65739eSchenlu chen - Sun Microsystems - Beijing China */
1703ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_disable_watchdog_timer(ixgbe);
17049da57d7bSbt
17059da57d7bSbt mutex_enter(&ixgbe->gen_lock);
17069da57d7bSbt
17079da57d7bSbt ASSERT(ixgbe->ixgbe_state & IXGBE_STARTED);
170862e6e1adSPaul Guo atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
17099da57d7bSbt
1710ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe, B_FALSE);
17119da57d7bSbt
1712ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
1713ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock);
1714ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_FAILURE);
17159da57d7bSbt }
17169da57d7bSbt
171762e6e1adSPaul Guo /*
171862e6e1adSPaul Guo * After resetting, need to recheck the link status.
171962e6e1adSPaul Guo */
172062e6e1adSPaul Guo ixgbe->link_check_complete = B_FALSE;
172162e6e1adSPaul Guo ixgbe->link_check_hrtime = gethrtime() +
172262e6e1adSPaul Guo (IXGBE_LINK_UP_TIME * 100000000ULL);
172362e6e1adSPaul Guo
172462e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED);
172562e6e1adSPaul Guo
172662e6e1adSPaul Guo if (!(ixgbe->ixgbe_state & IXGBE_SUSPENDED)) {
172762e6e1adSPaul Guo for (i = 0; i < ixgbe->num_tx_rings; i++) {
172862e6e1adSPaul Guo mac_tx_ring_update(ixgbe->mac_hdl,
172962e6e1adSPaul Guo ixgbe->tx_rings[i].ring_handle);
173062e6e1adSPaul Guo }
173162e6e1adSPaul Guo }
173262e6e1adSPaul Guo
1733ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock);
17349da57d7bSbt
17359da57d7bSbt /*
1736ea65739eSchenlu chen - Sun Microsystems - Beijing China * Enable and start the watchdog timer
17379da57d7bSbt */
1738ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_enable_watchdog_timer(ixgbe);
17399da57d7bSbt
17409da57d7bSbt return (IXGBE_SUCCESS);
17419da57d7bSbt }
17429da57d7bSbt
17439da57d7bSbt /*
17449da57d7bSbt * ixgbe_tx_clean - Clean the pending transmit packets and DMA resources.
17459da57d7bSbt */
17469da57d7bSbt static void
ixgbe_tx_clean(ixgbe_t * ixgbe)17479da57d7bSbt ixgbe_tx_clean(ixgbe_t *ixgbe)
17489da57d7bSbt {
17499da57d7bSbt ixgbe_tx_ring_t *tx_ring;
17509da57d7bSbt tx_control_block_t *tcb;
17519da57d7bSbt link_list_t pending_list;
17529da57d7bSbt uint32_t desc_num;
17539da57d7bSbt int i, j;
17549da57d7bSbt
17559da57d7bSbt LINK_LIST_INIT(&pending_list);
17569da57d7bSbt
17579da57d7bSbt for (i = 0; i < ixgbe->num_tx_rings; i++) {
17589da57d7bSbt tx_ring = &ixgbe->tx_rings[i];
17599da57d7bSbt
17609da57d7bSbt mutex_enter(&tx_ring->recycle_lock);
17619da57d7bSbt
17629da57d7bSbt /*
17639da57d7bSbt * Clean the pending tx data - the pending packets in the
17649da57d7bSbt * work_list that have no chances to be transmitted again.
17659da57d7bSbt *
17669da57d7bSbt * We must ensure the chipset is stopped or the link is down
17679da57d7bSbt * before cleaning the transmit packets.
17689da57d7bSbt */
17699da57d7bSbt desc_num = 0;
17709da57d7bSbt for (j = 0; j < tx_ring->ring_size; j++) {
17719da57d7bSbt tcb = tx_ring->work_list[j];
17729da57d7bSbt if (tcb != NULL) {
17739da57d7bSbt desc_num += tcb->desc_num;
17749da57d7bSbt
17759da57d7bSbt tx_ring->work_list[j] = NULL;
17769da57d7bSbt
17779da57d7bSbt ixgbe_free_tcb(tcb);
17789da57d7bSbt
17799da57d7bSbt LIST_PUSH_TAIL(&pending_list, &tcb->link);
17809da57d7bSbt }
17819da57d7bSbt }
17829da57d7bSbt
17839da57d7bSbt if (desc_num > 0) {
17849da57d7bSbt atomic_add_32(&tx_ring->tbd_free, desc_num);
17859da57d7bSbt ASSERT(tx_ring->tbd_free == tx_ring->ring_size);
17869da57d7bSbt
17879da57d7bSbt /*
17889da57d7bSbt * Reset the head and tail pointers of the tbd ring;
17899da57d7bSbt * Reset the writeback head if it's enable.
17909da57d7bSbt */
17919da57d7bSbt tx_ring->tbd_head = 0;
17929da57d7bSbt tx_ring->tbd_tail = 0;
17939da57d7bSbt if (ixgbe->tx_head_wb_enable)
17949da57d7bSbt *tx_ring->tbd_head_wb = 0;
17959da57d7bSbt
17969da57d7bSbt IXGBE_WRITE_REG(&ixgbe->hw,
17979da57d7bSbt IXGBE_TDH(tx_ring->index), 0);
17989da57d7bSbt IXGBE_WRITE_REG(&ixgbe->hw,
17999da57d7bSbt IXGBE_TDT(tx_ring->index), 0);
18009da57d7bSbt }
18019da57d7bSbt
18029da57d7bSbt mutex_exit(&tx_ring->recycle_lock);
18039da57d7bSbt
18049da57d7bSbt /*
18059da57d7bSbt * Add the tx control blocks in the pending list to
18069da57d7bSbt * the free list.
18079da57d7bSbt */
18089da57d7bSbt ixgbe_put_free_list(tx_ring, &pending_list);
18099da57d7bSbt }
18109da57d7bSbt }
18119da57d7bSbt
18129da57d7bSbt /*
18139da57d7bSbt * ixgbe_tx_drain - Drain the tx rings to allow pending packets to be
18149da57d7bSbt * transmitted.
18159da57d7bSbt */
18169da57d7bSbt static boolean_t
ixgbe_tx_drain(ixgbe_t * ixgbe)18179da57d7bSbt ixgbe_tx_drain(ixgbe_t *ixgbe)
18189da57d7bSbt {
18199da57d7bSbt ixgbe_tx_ring_t *tx_ring;
18209da57d7bSbt boolean_t done;
18219da57d7bSbt int i, j;
18229da57d7bSbt
18239da57d7bSbt /*
18249da57d7bSbt * Wait for a specific time to allow pending tx packets
18259da57d7bSbt * to be transmitted.
18269da57d7bSbt *
18279da57d7bSbt * Check the counter tbd_free to see if transmission is done.
18289da57d7bSbt * No lock protection is needed here.
18299da57d7bSbt *
18309da57d7bSbt * Return B_TRUE if all pending packets have been transmitted;
18319da57d7bSbt * Otherwise return B_FALSE;
18329da57d7bSbt */
18339da57d7bSbt for (i = 0; i < TX_DRAIN_TIME; i++) {
18349da57d7bSbt
18359da57d7bSbt done = B_TRUE;
18369da57d7bSbt for (j = 0; j < ixgbe->num_tx_rings; j++) {
18379da57d7bSbt tx_ring = &ixgbe->tx_rings[j];
18389da57d7bSbt done = done &&
18399da57d7bSbt (tx_ring->tbd_free == tx_ring->ring_size);
18409da57d7bSbt }
18419da57d7bSbt
18429da57d7bSbt if (done)
18439da57d7bSbt break;
18449da57d7bSbt
18459da57d7bSbt msec_delay(1);
18469da57d7bSbt }
18479da57d7bSbt
18489da57d7bSbt return (done);
18499da57d7bSbt }
18509da57d7bSbt
18519da57d7bSbt /*
18529da57d7bSbt * ixgbe_rx_drain - Wait for all rx buffers to be released by upper layer.
18539da57d7bSbt */
18549da57d7bSbt static boolean_t
ixgbe_rx_drain(ixgbe_t * ixgbe)18559da57d7bSbt ixgbe_rx_drain(ixgbe_t *ixgbe)
18569da57d7bSbt {
1857ea65739eSchenlu chen - Sun Microsystems - Beijing China boolean_t done = B_TRUE;
1858ea65739eSchenlu chen - Sun Microsystems - Beijing China int i;
18599da57d7bSbt
18609da57d7bSbt /*
18619da57d7bSbt * Polling the rx free list to check if those rx buffers held by
18629da57d7bSbt * the upper layer are released.
18639da57d7bSbt *
18649da57d7bSbt * Check the counter rcb_free to see if all pending buffers are
18659da57d7bSbt * released. No lock protection is needed here.
18669da57d7bSbt *
18679da57d7bSbt * Return B_TRUE if all pending buffers have been released;
18689da57d7bSbt * Otherwise return B_FALSE;
18699da57d7bSbt */
18709da57d7bSbt for (i = 0; i < RX_DRAIN_TIME; i++) {
1871ea65739eSchenlu chen - Sun Microsystems - Beijing China done = (ixgbe->rcb_pending == 0);
18729da57d7bSbt
18739da57d7bSbt if (done)
18749da57d7bSbt break;
18759da57d7bSbt
18769da57d7bSbt msec_delay(1);
18779da57d7bSbt }
18789da57d7bSbt
18799da57d7bSbt return (done);
18809da57d7bSbt }
18819da57d7bSbt
18829da57d7bSbt /*
18839da57d7bSbt * ixgbe_start - Start the driver/chipset.
18849da57d7bSbt */
18859da57d7bSbt int
ixgbe_start(ixgbe_t * ixgbe,boolean_t alloc_buffer)1886ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer)
18879da57d7bSbt {
1888dc0cb1cdSDale Ghent struct ixgbe_hw *hw = &ixgbe->hw;
18899da57d7bSbt int i;
18909da57d7bSbt
18919da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
18929da57d7bSbt
1893ea65739eSchenlu chen - Sun Microsystems - Beijing China if (alloc_buffer) {
1894ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_alloc_rx_data(ixgbe) != IXGBE_SUCCESS) {
1895ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe,
1896ea65739eSchenlu chen - Sun Microsystems - Beijing China "Failed to allocate software receive rings");
1897ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_FAILURE);
1898ea65739eSchenlu chen - Sun Microsystems - Beijing China }
1899ea65739eSchenlu chen - Sun Microsystems - Beijing China
1900ea65739eSchenlu chen - Sun Microsystems - Beijing China /* Allocate buffers for all the rx/tx rings */
1901ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_alloc_dma(ixgbe) != IXGBE_SUCCESS) {
1902ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe, "Failed to allocate DMA resource");
1903ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_FAILURE);
1904ea65739eSchenlu chen - Sun Microsystems - Beijing China }
1905ea65739eSchenlu chen - Sun Microsystems - Beijing China
1906ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->tx_ring_init = B_TRUE;
1907ea65739eSchenlu chen - Sun Microsystems - Beijing China } else {
1908ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->tx_ring_init = B_FALSE;
1909ea65739eSchenlu chen - Sun Microsystems - Beijing China }
1910ea65739eSchenlu chen - Sun Microsystems - Beijing China
19119da57d7bSbt for (i = 0; i < ixgbe->num_rx_rings; i++)
19129da57d7bSbt mutex_enter(&ixgbe->rx_rings[i].rx_lock);
19139da57d7bSbt for (i = 0; i < ixgbe->num_tx_rings; i++)
19149da57d7bSbt mutex_enter(&ixgbe->tx_rings[i].tx_lock);
19159da57d7bSbt
19169da57d7bSbt /*
19179da57d7bSbt * Start the chipset hardware
19189da57d7bSbt */
19199da57d7bSbt if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) {
19209da57d7bSbt ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE);
19219da57d7bSbt goto start_failure;
19229da57d7bSbt }
19239da57d7bSbt
1924dc0cb1cdSDale Ghent /*
1925dc0cb1cdSDale Ghent * Configure link now for X550
1926dc0cb1cdSDale Ghent *
1927dc0cb1cdSDale Ghent * X550 possesses a LPLU (Low-Power Link Up) mode which keeps the
1928dc0cb1cdSDale Ghent * resting state of the adapter at a 1Gb FDX speed. Prior to the X550,
1929dc0cb1cdSDale Ghent * the resting state of the link would be the maximum speed that
1930dc0cb1cdSDale Ghent * autonegotiation will allow (usually 10Gb, infrastructure allowing)
1931dc0cb1cdSDale Ghent * so we never bothered with explicitly setting the link to 10Gb as it
1932dc0cb1cdSDale Ghent * would already be at that state on driver attach. With X550, we must
1933dc0cb1cdSDale Ghent * trigger a re-negotiation of the link in order to switch from a LPLU
1934dc0cb1cdSDale Ghent * 1Gb link to 10Gb (cable and link partner permitting.)
1935dc0cb1cdSDale Ghent */
1936dc0cb1cdSDale Ghent if (hw->mac.type == ixgbe_mac_X550 ||
193748ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_a ||
1938dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X550EM_x) {
1939dc0cb1cdSDale Ghent (void) ixgbe_driver_setup_link(ixgbe, B_TRUE);
1940dc0cb1cdSDale Ghent ixgbe_get_hw_state(ixgbe);
1941dc0cb1cdSDale Ghent }
1942dc0cb1cdSDale Ghent
19439da57d7bSbt if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
19449da57d7bSbt goto start_failure;
19459da57d7bSbt }
19469da57d7bSbt
19479da57d7bSbt /*
19489da57d7bSbt * Setup the rx/tx rings
19499da57d7bSbt */
195084de666eSRyan Zezeski if (ixgbe_setup_rings(ixgbe) != IXGBE_SUCCESS)
195184de666eSRyan Zezeski goto start_failure;
19529da57d7bSbt
195362e6e1adSPaul Guo /*
195462e6e1adSPaul Guo * ixgbe_start() will be called when resetting, however if reset
19555b6dd21fSchenlu chen - Sun Microsystems - Beijing China * happens, we need to clear the ERROR, STALL and OVERTEMP flags
19565b6dd21fSchenlu chen - Sun Microsystems - Beijing China * before enabling the interrupts.
195762e6e1adSPaul Guo */
19585b6dd21fSchenlu chen - Sun Microsystems - Beijing China atomic_and_32(&ixgbe->ixgbe_state, ~(IXGBE_ERROR
19595b6dd21fSchenlu chen - Sun Microsystems - Beijing China | IXGBE_STALL| IXGBE_OVERTEMP));
196062e6e1adSPaul Guo
19619da57d7bSbt /*
19629da57d7bSbt * Enable adapter interrupts
19639da57d7bSbt * The interrupts must be enabled after the driver state is START
19649da57d7bSbt */
19659da57d7bSbt ixgbe_enable_adapter_interrupts(ixgbe);
19669da57d7bSbt
19679da57d7bSbt for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
19689da57d7bSbt mutex_exit(&ixgbe->tx_rings[i].tx_lock);
19699da57d7bSbt for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
19709da57d7bSbt mutex_exit(&ixgbe->rx_rings[i].rx_lock);
19719da57d7bSbt
19729da57d7bSbt return (IXGBE_SUCCESS);
19739da57d7bSbt
19749da57d7bSbt start_failure:
19759da57d7bSbt for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
19769da57d7bSbt mutex_exit(&ixgbe->tx_rings[i].tx_lock);
19779da57d7bSbt for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
19789da57d7bSbt mutex_exit(&ixgbe->rx_rings[i].rx_lock);
19799da57d7bSbt
19809da57d7bSbt ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
19819da57d7bSbt
19829da57d7bSbt return (IXGBE_FAILURE);
19839da57d7bSbt }
19849da57d7bSbt
19859da57d7bSbt /*
19869da57d7bSbt * ixgbe_stop - Stop the driver/chipset.
19879da57d7bSbt */
19889da57d7bSbt void
ixgbe_stop(ixgbe_t * ixgbe,boolean_t free_buffer)1989ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_stop(ixgbe_t *ixgbe, boolean_t free_buffer)
19909da57d7bSbt {
19919da57d7bSbt int i;
19929da57d7bSbt
19939da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
19949da57d7bSbt
19959da57d7bSbt /*
19969da57d7bSbt * Disable the adapter interrupts
19979da57d7bSbt */
19989da57d7bSbt ixgbe_disable_adapter_interrupts(ixgbe);
19999da57d7bSbt
20009da57d7bSbt /*
20019da57d7bSbt * Drain the pending tx packets
20029da57d7bSbt */
20039da57d7bSbt (void) ixgbe_tx_drain(ixgbe);
20049da57d7bSbt
20059da57d7bSbt for (i = 0; i < ixgbe->num_rx_rings; i++)
20069da57d7bSbt mutex_enter(&ixgbe->rx_rings[i].rx_lock);
20079da57d7bSbt for (i = 0; i < ixgbe->num_tx_rings; i++)
20089da57d7bSbt mutex_enter(&ixgbe->tx_rings[i].tx_lock);
20099da57d7bSbt
20109da57d7bSbt /*
20119da57d7bSbt * Stop the chipset hardware
20129da57d7bSbt */
20139da57d7bSbt ixgbe_chip_stop(ixgbe);
20149da57d7bSbt
20159da57d7bSbt if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
20169da57d7bSbt ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
20179da57d7bSbt }
20189da57d7bSbt
20199da57d7bSbt /*
20209da57d7bSbt * Clean the pending tx data/resources
20219da57d7bSbt */
20229da57d7bSbt ixgbe_tx_clean(ixgbe);
20239da57d7bSbt
20249da57d7bSbt for (i = ixgbe->num_tx_rings - 1; i >= 0; i--)
20259da57d7bSbt mutex_exit(&ixgbe->tx_rings[i].tx_lock);
20269da57d7bSbt for (i = ixgbe->num_rx_rings - 1; i >= 0; i--)
20279da57d7bSbt mutex_exit(&ixgbe->rx_rings[i].rx_lock);
2028ea65739eSchenlu chen - Sun Microsystems - Beijing China
2029ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->link_state == LINK_STATE_UP) {
2030ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->link_state = LINK_STATE_UNKNOWN;
2031ea65739eSchenlu chen - Sun Microsystems - Beijing China mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
2032ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2033ea65739eSchenlu chen - Sun Microsystems - Beijing China
2034ea65739eSchenlu chen - Sun Microsystems - Beijing China if (free_buffer) {
2035ea65739eSchenlu chen - Sun Microsystems - Beijing China /*
2036ea65739eSchenlu chen - Sun Microsystems - Beijing China * Release the DMA/memory resources of rx/tx rings
2037ea65739eSchenlu chen - Sun Microsystems - Beijing China */
2038ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_dma(ixgbe);
2039ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_data(ixgbe);
2040ea65739eSchenlu chen - Sun Microsystems - Beijing China }
20419da57d7bSbt }
20429da57d7bSbt
20430dc2366fSVenugopal Iyer /*
20440dc2366fSVenugopal Iyer * ixgbe_cbfunc - Driver interface for generic DDI callbacks
20450dc2366fSVenugopal Iyer */
20460dc2366fSVenugopal Iyer /* ARGSUSED */
20470dc2366fSVenugopal Iyer static int
ixgbe_cbfunc(dev_info_t * dip,ddi_cb_action_t cbaction,void * cbarg,void * arg1,void * arg2)20480dc2366fSVenugopal Iyer ixgbe_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
20490dc2366fSVenugopal Iyer void *arg1, void *arg2)
20500dc2366fSVenugopal Iyer {
20510dc2366fSVenugopal Iyer ixgbe_t *ixgbe = (ixgbe_t *)arg1;
20520dc2366fSVenugopal Iyer
20530dc2366fSVenugopal Iyer switch (cbaction) {
20540dc2366fSVenugopal Iyer /* IRM callback */
20550dc2366fSVenugopal Iyer int count;
20560dc2366fSVenugopal Iyer case DDI_CB_INTR_ADD:
20570dc2366fSVenugopal Iyer case DDI_CB_INTR_REMOVE:
20580dc2366fSVenugopal Iyer count = (int)(uintptr_t)cbarg;
20590dc2366fSVenugopal Iyer ASSERT(ixgbe->intr_type == DDI_INTR_TYPE_MSIX);
20600dc2366fSVenugopal Iyer DTRACE_PROBE2(ixgbe__irm__callback, int, count,
20610dc2366fSVenugopal Iyer int, ixgbe->intr_cnt);
20620dc2366fSVenugopal Iyer if (ixgbe_intr_adjust(ixgbe, cbaction, count) !=
20630dc2366fSVenugopal Iyer DDI_SUCCESS) {
20640dc2366fSVenugopal Iyer ixgbe_error(ixgbe,
20650dc2366fSVenugopal Iyer "IRM CB: Failed to adjust interrupts");
20660dc2366fSVenugopal Iyer goto cb_fail;
20670dc2366fSVenugopal Iyer }
20680dc2366fSVenugopal Iyer break;
20690dc2366fSVenugopal Iyer default:
20700dc2366fSVenugopal Iyer IXGBE_DEBUGLOG_1(ixgbe, "DDI CB: action 0x%x NOT supported",
20710dc2366fSVenugopal Iyer cbaction);
20720dc2366fSVenugopal Iyer return (DDI_ENOTSUP);
20730dc2366fSVenugopal Iyer }
20740dc2366fSVenugopal Iyer return (DDI_SUCCESS);
20750dc2366fSVenugopal Iyer cb_fail:
20760dc2366fSVenugopal Iyer return (DDI_FAILURE);
20770dc2366fSVenugopal Iyer }
20780dc2366fSVenugopal Iyer
20790dc2366fSVenugopal Iyer /*
20800dc2366fSVenugopal Iyer * ixgbe_intr_adjust - Adjust interrupt to respond to IRM request.
20810dc2366fSVenugopal Iyer */
20820dc2366fSVenugopal Iyer static int
ixgbe_intr_adjust(ixgbe_t * ixgbe,ddi_cb_action_t cbaction,int count)20830dc2366fSVenugopal Iyer ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count)
20840dc2366fSVenugopal Iyer {
20850dc2366fSVenugopal Iyer int i, rc, actual;
20860dc2366fSVenugopal Iyer
20870dc2366fSVenugopal Iyer if (count == 0)
20880dc2366fSVenugopal Iyer return (DDI_SUCCESS);
20890dc2366fSVenugopal Iyer
20900dc2366fSVenugopal Iyer if ((cbaction == DDI_CB_INTR_ADD &&
20910dc2366fSVenugopal Iyer ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) ||
20920dc2366fSVenugopal Iyer (cbaction == DDI_CB_INTR_REMOVE &&
20930dc2366fSVenugopal Iyer ixgbe->intr_cnt - count < ixgbe->intr_cnt_min))
20940dc2366fSVenugopal Iyer return (DDI_FAILURE);
20950dc2366fSVenugopal Iyer
20960dc2366fSVenugopal Iyer if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
20970dc2366fSVenugopal Iyer return (DDI_FAILURE);
20980dc2366fSVenugopal Iyer }
20990dc2366fSVenugopal Iyer
21000dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_rx_rings; i++)
21010dc2366fSVenugopal Iyer mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL);
21020dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_tx_rings; i++)
21030dc2366fSVenugopal Iyer mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL);
21040dc2366fSVenugopal Iyer
21050dc2366fSVenugopal Iyer mutex_enter(&ixgbe->gen_lock);
21060dc2366fSVenugopal Iyer ixgbe->ixgbe_state &= ~IXGBE_STARTED;
21070dc2366fSVenugopal Iyer ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST;
21080dc2366fSVenugopal Iyer ixgbe->ixgbe_state |= IXGBE_SUSPENDED;
21090dc2366fSVenugopal Iyer mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
21100dc2366fSVenugopal Iyer
21110dc2366fSVenugopal Iyer ixgbe_stop(ixgbe, B_FALSE);
21120dc2366fSVenugopal Iyer /*
21130dc2366fSVenugopal Iyer * Disable interrupts
21140dc2366fSVenugopal Iyer */
21150dc2366fSVenugopal Iyer if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
21160dc2366fSVenugopal Iyer rc = ixgbe_disable_intrs(ixgbe);
21170dc2366fSVenugopal Iyer ASSERT(rc == IXGBE_SUCCESS);
21180dc2366fSVenugopal Iyer }
21190dc2366fSVenugopal Iyer ixgbe->attach_progress &= ~ATTACH_PROGRESS_ENABLE_INTR;
21200dc2366fSVenugopal Iyer
21210dc2366fSVenugopal Iyer /*
21220dc2366fSVenugopal Iyer * Remove interrupt handlers
21230dc2366fSVenugopal Iyer */
21240dc2366fSVenugopal Iyer if (ixgbe->attach_progress & ATTACH_PROGRESS_ADD_INTR) {
21250dc2366fSVenugopal Iyer ixgbe_rem_intr_handlers(ixgbe);
21260dc2366fSVenugopal Iyer }
21270dc2366fSVenugopal Iyer ixgbe->attach_progress &= ~ATTACH_PROGRESS_ADD_INTR;
21280dc2366fSVenugopal Iyer
21290dc2366fSVenugopal Iyer /*
21300dc2366fSVenugopal Iyer * Clear vect_map
21310dc2366fSVenugopal Iyer */
21320dc2366fSVenugopal Iyer bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
21330dc2366fSVenugopal Iyer switch (cbaction) {
21340dc2366fSVenugopal Iyer case DDI_CB_INTR_ADD:
21350dc2366fSVenugopal Iyer rc = ddi_intr_alloc(ixgbe->dip, ixgbe->htable,
21360dc2366fSVenugopal Iyer DDI_INTR_TYPE_MSIX, ixgbe->intr_cnt, count, &actual,
21370dc2366fSVenugopal Iyer DDI_INTR_ALLOC_NORMAL);
21380dc2366fSVenugopal Iyer if (rc != DDI_SUCCESS || actual != count) {
21390dc2366fSVenugopal Iyer ixgbe_log(ixgbe, "Adjust interrupts failed."
21400dc2366fSVenugopal Iyer "return: %d, irm cb size: %d, actual: %d",
21410dc2366fSVenugopal Iyer rc, count, actual);
21420dc2366fSVenugopal Iyer goto intr_adjust_fail;
21430dc2366fSVenugopal Iyer }
21440dc2366fSVenugopal Iyer ixgbe->intr_cnt += count;
21450dc2366fSVenugopal Iyer break;
21460dc2366fSVenugopal Iyer
21470dc2366fSVenugopal Iyer case DDI_CB_INTR_REMOVE:
21480dc2366fSVenugopal Iyer for (i = ixgbe->intr_cnt - count;
21490dc2366fSVenugopal Iyer i < ixgbe->intr_cnt; i ++) {
21500dc2366fSVenugopal Iyer rc = ddi_intr_free(ixgbe->htable[i]);
21510dc2366fSVenugopal Iyer ixgbe->htable[i] = NULL;
21520dc2366fSVenugopal Iyer if (rc != DDI_SUCCESS) {
21530dc2366fSVenugopal Iyer ixgbe_log(ixgbe, "Adjust interrupts failed."
21540dc2366fSVenugopal Iyer "return: %d, irm cb size: %d, actual: %d",
21550dc2366fSVenugopal Iyer rc, count, actual);
21560dc2366fSVenugopal Iyer goto intr_adjust_fail;
21570dc2366fSVenugopal Iyer }
21580dc2366fSVenugopal Iyer }
21590dc2366fSVenugopal Iyer ixgbe->intr_cnt -= count;
21600dc2366fSVenugopal Iyer break;
21610dc2366fSVenugopal Iyer }
21620dc2366fSVenugopal Iyer
21630dc2366fSVenugopal Iyer /*
21640dc2366fSVenugopal Iyer * Get priority for first vector, assume remaining are all the same
21650dc2366fSVenugopal Iyer */
21660dc2366fSVenugopal Iyer rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
21670dc2366fSVenugopal Iyer if (rc != DDI_SUCCESS) {
21680dc2366fSVenugopal Iyer ixgbe_log(ixgbe,
21690dc2366fSVenugopal Iyer "Get interrupt priority failed: %d", rc);
21700dc2366fSVenugopal Iyer goto intr_adjust_fail;
21710dc2366fSVenugopal Iyer }
21720dc2366fSVenugopal Iyer rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
21730dc2366fSVenugopal Iyer if (rc != DDI_SUCCESS) {
21740dc2366fSVenugopal Iyer ixgbe_log(ixgbe, "Get interrupt cap failed: %d", rc);
21750dc2366fSVenugopal Iyer goto intr_adjust_fail;
21760dc2366fSVenugopal Iyer }
21770dc2366fSVenugopal Iyer ixgbe->attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
21780dc2366fSVenugopal Iyer
21790dc2366fSVenugopal Iyer /*
21800dc2366fSVenugopal Iyer * Map rings to interrupt vectors
21810dc2366fSVenugopal Iyer */
21820dc2366fSVenugopal Iyer if (ixgbe_map_intrs_to_vectors(ixgbe) != IXGBE_SUCCESS) {
21830dc2366fSVenugopal Iyer ixgbe_error(ixgbe,
21840dc2366fSVenugopal Iyer "IRM CB: Failed to map interrupts to vectors");
21850dc2366fSVenugopal Iyer goto intr_adjust_fail;
21860dc2366fSVenugopal Iyer }
21870dc2366fSVenugopal Iyer
21880dc2366fSVenugopal Iyer /*
21890dc2366fSVenugopal Iyer * Add interrupt handlers
21900dc2366fSVenugopal Iyer */
21910dc2366fSVenugopal Iyer if (ixgbe_add_intr_handlers(ixgbe) != IXGBE_SUCCESS) {
21920dc2366fSVenugopal Iyer ixgbe_error(ixgbe, "IRM CB: Failed to add interrupt handlers");
21930dc2366fSVenugopal Iyer goto intr_adjust_fail;
21940dc2366fSVenugopal Iyer }
21950dc2366fSVenugopal Iyer ixgbe->attach_progress |= ATTACH_PROGRESS_ADD_INTR;
21960dc2366fSVenugopal Iyer
21970dc2366fSVenugopal Iyer /*
21980dc2366fSVenugopal Iyer * Now that mutex locks are initialized, and the chip is also
21990dc2366fSVenugopal Iyer * initialized, enable interrupts.
22000dc2366fSVenugopal Iyer */
22010dc2366fSVenugopal Iyer if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
22020dc2366fSVenugopal Iyer ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts");
22030dc2366fSVenugopal Iyer goto intr_adjust_fail;
22040dc2366fSVenugopal Iyer }
22050dc2366fSVenugopal Iyer ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
22060dc2366fSVenugopal Iyer if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
22070dc2366fSVenugopal Iyer ixgbe_error(ixgbe, "IRM CB: Failed to start");
22080dc2366fSVenugopal Iyer goto intr_adjust_fail;
22090dc2366fSVenugopal Iyer }
22100dc2366fSVenugopal Iyer ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST;
22110dc2366fSVenugopal Iyer ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED;
22120dc2366fSVenugopal Iyer ixgbe->ixgbe_state |= IXGBE_STARTED;
22130dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock);
22140dc2366fSVenugopal Iyer
22150dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_rx_rings; i++) {
22160dc2366fSVenugopal Iyer mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle,
22170dc2366fSVenugopal Iyer ixgbe->htable[ixgbe->rx_rings[i].intr_vector]);
22180dc2366fSVenugopal Iyer }
22190dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_tx_rings; i++) {
22200dc2366fSVenugopal Iyer mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle,
22210dc2366fSVenugopal Iyer ixgbe->htable[ixgbe->tx_rings[i].intr_vector]);
22220dc2366fSVenugopal Iyer }
22230dc2366fSVenugopal Iyer
22240dc2366fSVenugopal Iyer /* Wakeup all Tx rings */
22250dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_tx_rings; i++) {
22260dc2366fSVenugopal Iyer mac_tx_ring_update(ixgbe->mac_hdl,
22270dc2366fSVenugopal Iyer ixgbe->tx_rings[i].ring_handle);
22280dc2366fSVenugopal Iyer }
22290dc2366fSVenugopal Iyer
22300dc2366fSVenugopal Iyer IXGBE_DEBUGLOG_3(ixgbe,
22310dc2366fSVenugopal Iyer "IRM CB: interrupts new value: 0x%x(0x%x:0x%x).",
22320dc2366fSVenugopal Iyer ixgbe->intr_cnt, ixgbe->intr_cnt_min, ixgbe->intr_cnt_max);
22330dc2366fSVenugopal Iyer return (DDI_SUCCESS);
22340dc2366fSVenugopal Iyer
22350dc2366fSVenugopal Iyer intr_adjust_fail:
22360dc2366fSVenugopal Iyer ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
22370dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock);
22380dc2366fSVenugopal Iyer return (DDI_FAILURE);
22390dc2366fSVenugopal Iyer }
22400dc2366fSVenugopal Iyer
22410dc2366fSVenugopal Iyer /*
22420dc2366fSVenugopal Iyer * ixgbe_intr_cb_register - Register interrupt callback function.
22430dc2366fSVenugopal Iyer */
22440dc2366fSVenugopal Iyer static int
ixgbe_intr_cb_register(ixgbe_t * ixgbe)22450dc2366fSVenugopal Iyer ixgbe_intr_cb_register(ixgbe_t *ixgbe)
22460dc2366fSVenugopal Iyer {
22470dc2366fSVenugopal Iyer if (ddi_cb_register(ixgbe->dip, DDI_CB_FLAG_INTR, ixgbe_cbfunc,
22480dc2366fSVenugopal Iyer ixgbe, NULL, &ixgbe->cb_hdl) != DDI_SUCCESS) {
22490dc2366fSVenugopal Iyer return (IXGBE_FAILURE);
22500dc2366fSVenugopal Iyer }
22510dc2366fSVenugopal Iyer IXGBE_DEBUGLOG_0(ixgbe, "Interrupt callback function registered.");
22520dc2366fSVenugopal Iyer return (IXGBE_SUCCESS);
22530dc2366fSVenugopal Iyer }
22540dc2366fSVenugopal Iyer
22559da57d7bSbt /*
22569da57d7bSbt * ixgbe_alloc_rings - Allocate memory space for rx/tx rings.
22579da57d7bSbt */
22589da57d7bSbt static int
ixgbe_alloc_rings(ixgbe_t * ixgbe)22599da57d7bSbt ixgbe_alloc_rings(ixgbe_t *ixgbe)
22609da57d7bSbt {
22619da57d7bSbt /*
22629da57d7bSbt * Allocate memory space for rx rings
22639da57d7bSbt */
22649da57d7bSbt ixgbe->rx_rings = kmem_zalloc(
22659da57d7bSbt sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings,
22669da57d7bSbt KM_NOSLEEP);
22679da57d7bSbt
22689da57d7bSbt if (ixgbe->rx_rings == NULL) {
22699da57d7bSbt return (IXGBE_FAILURE);
22709da57d7bSbt }
22719da57d7bSbt
22729da57d7bSbt /*
22739da57d7bSbt * Allocate memory space for tx rings
22749da57d7bSbt */
22759da57d7bSbt ixgbe->tx_rings = kmem_zalloc(
22769da57d7bSbt sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings,
22779da57d7bSbt KM_NOSLEEP);
22789da57d7bSbt
22799da57d7bSbt if (ixgbe->tx_rings == NULL) {
22809da57d7bSbt kmem_free(ixgbe->rx_rings,
22819da57d7bSbt sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
22829da57d7bSbt ixgbe->rx_rings = NULL;
22839da57d7bSbt return (IXGBE_FAILURE);
22849da57d7bSbt }
22859da57d7bSbt
2286da14cebeSEric Cheng /*
2287da14cebeSEric Cheng * Allocate memory space for rx ring groups
2288da14cebeSEric Cheng */
2289da14cebeSEric Cheng ixgbe->rx_groups = kmem_zalloc(
2290da14cebeSEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups,
2291da14cebeSEric Cheng KM_NOSLEEP);
2292da14cebeSEric Cheng
2293da14cebeSEric Cheng if (ixgbe->rx_groups == NULL) {
2294da14cebeSEric Cheng kmem_free(ixgbe->rx_rings,
2295da14cebeSEric Cheng sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
2296da14cebeSEric Cheng kmem_free(ixgbe->tx_rings,
2297da14cebeSEric Cheng sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
2298da14cebeSEric Cheng ixgbe->rx_rings = NULL;
2299da14cebeSEric Cheng ixgbe->tx_rings = NULL;
2300da14cebeSEric Cheng return (IXGBE_FAILURE);
2301da14cebeSEric Cheng }
2302da14cebeSEric Cheng
23039da57d7bSbt return (IXGBE_SUCCESS);
23049da57d7bSbt }
23059da57d7bSbt
23069da57d7bSbt /*
23079da57d7bSbt * ixgbe_free_rings - Free the memory space of rx/tx rings.
23089da57d7bSbt */
23099da57d7bSbt static void
ixgbe_free_rings(ixgbe_t * ixgbe)23109da57d7bSbt ixgbe_free_rings(ixgbe_t *ixgbe)
23119da57d7bSbt {
23129da57d7bSbt if (ixgbe->rx_rings != NULL) {
23139da57d7bSbt kmem_free(ixgbe->rx_rings,
23149da57d7bSbt sizeof (ixgbe_rx_ring_t) * ixgbe->num_rx_rings);
23159da57d7bSbt ixgbe->rx_rings = NULL;
23169da57d7bSbt }
23179da57d7bSbt
23189da57d7bSbt if (ixgbe->tx_rings != NULL) {
23199da57d7bSbt kmem_free(ixgbe->tx_rings,
23209da57d7bSbt sizeof (ixgbe_tx_ring_t) * ixgbe->num_tx_rings);
23219da57d7bSbt ixgbe->tx_rings = NULL;
23229da57d7bSbt }
2323da14cebeSEric Cheng
232484de666eSRyan Zezeski for (uint_t i = 0; i < ixgbe->num_rx_groups; i++) {
232584de666eSRyan Zezeski ixgbe_vlan_t *vlp;
232684de666eSRyan Zezeski ixgbe_rx_group_t *rx_group = &ixgbe->rx_groups[i];
232784de666eSRyan Zezeski
232884de666eSRyan Zezeski while ((vlp = list_remove_head(&rx_group->vlans)) != NULL)
232984de666eSRyan Zezeski kmem_free(vlp, sizeof (ixgbe_vlan_t));
233084de666eSRyan Zezeski
233184de666eSRyan Zezeski list_destroy(&rx_group->vlans);
233284de666eSRyan Zezeski }
233384de666eSRyan Zezeski
2334da14cebeSEric Cheng if (ixgbe->rx_groups != NULL) {
2335da14cebeSEric Cheng kmem_free(ixgbe->rx_groups,
2336da14cebeSEric Cheng sizeof (ixgbe_rx_group_t) * ixgbe->num_rx_groups);
2337da14cebeSEric Cheng ixgbe->rx_groups = NULL;
2338da14cebeSEric Cheng }
23399da57d7bSbt }
23409da57d7bSbt
2341ea65739eSchenlu chen - Sun Microsystems - Beijing China static int
ixgbe_alloc_rx_data(ixgbe_t * ixgbe)2342ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_alloc_rx_data(ixgbe_t *ixgbe)
2343ea65739eSchenlu chen - Sun Microsystems - Beijing China {
2344ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_rx_ring_t *rx_ring;
2345ea65739eSchenlu chen - Sun Microsystems - Beijing China int i;
2346ea65739eSchenlu chen - Sun Microsystems - Beijing China
2347ea65739eSchenlu chen - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->num_rx_rings; i++) {
2348ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_ring = &ixgbe->rx_rings[i];
2349ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe_alloc_rx_ring_data(rx_ring) != IXGBE_SUCCESS)
2350ea65739eSchenlu chen - Sun Microsystems - Beijing China goto alloc_rx_rings_failure;
2351ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2352ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_SUCCESS);
2353ea65739eSchenlu chen - Sun Microsystems - Beijing China
2354ea65739eSchenlu chen - Sun Microsystems - Beijing China alloc_rx_rings_failure:
2355ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_data(ixgbe);
2356ea65739eSchenlu chen - Sun Microsystems - Beijing China return (IXGBE_FAILURE);
2357ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2358ea65739eSchenlu chen - Sun Microsystems - Beijing China
2359ea65739eSchenlu chen - Sun Microsystems - Beijing China static void
ixgbe_free_rx_data(ixgbe_t * ixgbe)2360ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_data(ixgbe_t *ixgbe)
2361ea65739eSchenlu chen - Sun Microsystems - Beijing China {
2362ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_rx_ring_t *rx_ring;
2363ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_rx_data_t *rx_data;
2364ea65739eSchenlu chen - Sun Microsystems - Beijing China int i;
2365ea65739eSchenlu chen - Sun Microsystems - Beijing China
2366ea65739eSchenlu chen - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->num_rx_rings; i++) {
2367ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_ring = &ixgbe->rx_rings[i];
2368ea65739eSchenlu chen - Sun Microsystems - Beijing China
2369ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_enter(&ixgbe->rx_pending_lock);
2370ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_data = rx_ring->rx_data;
2371ea65739eSchenlu chen - Sun Microsystems - Beijing China
2372ea65739eSchenlu chen - Sun Microsystems - Beijing China if (rx_data != NULL) {
2373ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_data->flag |= IXGBE_RX_STOPPED;
2374ea65739eSchenlu chen - Sun Microsystems - Beijing China
2375ea65739eSchenlu chen - Sun Microsystems - Beijing China if (rx_data->rcb_pending == 0) {
2376ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_free_rx_ring_data(rx_data);
2377ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_ring->rx_data = NULL;
2378ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2379ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2380ea65739eSchenlu chen - Sun Microsystems - Beijing China
2381ea65739eSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->rx_pending_lock);
2382ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2383ea65739eSchenlu chen - Sun Microsystems - Beijing China }
2384ea65739eSchenlu chen - Sun Microsystems - Beijing China
23859da57d7bSbt /*
23869da57d7bSbt * ixgbe_setup_rings - Setup rx/tx rings.
23879da57d7bSbt */
238884de666eSRyan Zezeski static int
ixgbe_setup_rings(ixgbe_t * ixgbe)23899da57d7bSbt ixgbe_setup_rings(ixgbe_t *ixgbe)
23909da57d7bSbt {
23919da57d7bSbt /*
23929da57d7bSbt * Setup the rx/tx rings, including the following:
23939da57d7bSbt *
23949da57d7bSbt * 1. Setup the descriptor ring and the control block buffers;
23959da57d7bSbt * 2. Initialize necessary registers for receive/transmit;
23969da57d7bSbt * 3. Initialize software pointers/parameters for receive/transmit;
23979da57d7bSbt */
239884de666eSRyan Zezeski if (ixgbe_setup_rx(ixgbe) != IXGBE_SUCCESS)
239984de666eSRyan Zezeski return (IXGBE_FAILURE);
24009da57d7bSbt
24019da57d7bSbt ixgbe_setup_tx(ixgbe);
240284de666eSRyan Zezeski
240384de666eSRyan Zezeski return (IXGBE_SUCCESS);
24049da57d7bSbt }
24059da57d7bSbt
24069da57d7bSbt static void
ixgbe_setup_rx_ring(ixgbe_rx_ring_t * rx_ring)24079da57d7bSbt ixgbe_setup_rx_ring(ixgbe_rx_ring_t *rx_ring)
24089da57d7bSbt {
24099da57d7bSbt ixgbe_t *ixgbe = rx_ring->ixgbe;
2410ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_rx_data_t *rx_data = rx_ring->rx_data;
24119da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
24129da57d7bSbt rx_control_block_t *rcb;
24139da57d7bSbt union ixgbe_adv_rx_desc *rbd;
24149da57d7bSbt uint32_t size;
24159da57d7bSbt uint32_t buf_low;
24169da57d7bSbt uint32_t buf_high;
24179da57d7bSbt uint32_t reg_val;
24189da57d7bSbt int i;
24199da57d7bSbt
24209da57d7bSbt ASSERT(mutex_owned(&rx_ring->rx_lock));
24219da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
24229da57d7bSbt
24239da57d7bSbt for (i = 0; i < ixgbe->rx_ring_size; i++) {
2424ea65739eSchenlu chen - Sun Microsystems - Beijing China rcb = rx_data->work_list[i];
2425ea65739eSchenlu chen - Sun Microsystems - Beijing China rbd = &rx_data->rbd_ring[i];
24269da57d7bSbt
24279da57d7bSbt rbd->read.pkt_addr = rcb->rx_buf.dma_address;
2428afac708dSToomas Soome rbd->read.hdr_addr = 0;
24299da57d7bSbt }
24309da57d7bSbt
24319da57d7bSbt /*
24329da57d7bSbt * Initialize the length register
24339da57d7bSbt */
2434ea65739eSchenlu chen - Sun Microsystems - Beijing China size = rx_data->ring_size * sizeof (union ixgbe_adv_rx_desc);
24350dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rx_ring->hw_index), size);
24369da57d7bSbt
24379da57d7bSbt /*
24389da57d7bSbt * Initialize the base address registers
24399da57d7bSbt */
2440ea65739eSchenlu chen - Sun Microsystems - Beijing China buf_low = (uint32_t)rx_data->rbd_area.dma_address;
2441ea65739eSchenlu chen - Sun Microsystems - Beijing China buf_high = (uint32_t)(rx_data->rbd_area.dma_address >> 32);
24420dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rx_ring->hw_index), buf_high);
24430dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rx_ring->hw_index), buf_low);
24449da57d7bSbt
24459da57d7bSbt /*
24469da57d7bSbt * Setup head & tail pointers
24479da57d7bSbt */
24480dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->hw_index),
24490dc2366fSVenugopal Iyer rx_data->ring_size - 1);
24500dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDH(rx_ring->hw_index), 0);
24519da57d7bSbt
2452ea65739eSchenlu chen - Sun Microsystems - Beijing China rx_data->rbd_next = 0;
2453ffd8e883SWinson Wang - Sun Microsystems - Beijing China rx_data->lro_first = 0;
24549da57d7bSbt
24559da57d7bSbt /*
24569da57d7bSbt * Setup the Receive Descriptor Control Register (RXDCTL)
24579da57d7bSbt * PTHRESH=32 descriptors (half the internal cache)
24589da57d7bSbt * HTHRESH=0 descriptors (to minimize latency on fetch)
24599da57d7bSbt * WTHRESH defaults to 1 (writeback each descriptor)
24609da57d7bSbt */
24610dc2366fSVenugopal Iyer reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index));
24629da57d7bSbt reg_val |= IXGBE_RXDCTL_ENABLE; /* enable queue */
246373cd555cSBin Tu - Sun Microsystems - Beijing China
2464dc0cb1cdSDale Ghent /* Not a valid value for 82599, X540 or X550 */
246569b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82598EB) {
246673cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= 0x0020; /* pthresh */
246773cd555cSBin Tu - Sun Microsystems - Beijing China }
24680dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val);
24699da57d7bSbt
247069b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82599EB ||
2471dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X540 ||
2472dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X550 ||
247348ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_x ||
247448ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_a) {
247573cd555cSBin Tu - Sun Microsystems - Beijing China reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
247673cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS);
247773cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
247873cd555cSBin Tu - Sun Microsystems - Beijing China }
247973cd555cSBin Tu - Sun Microsystems - Beijing China
24809da57d7bSbt /*
24819da57d7bSbt * Setup the Split and Replication Receive Control Register.
24829da57d7bSbt * Set the rx buffer size and the advanced descriptor type.
24839da57d7bSbt */
24849da57d7bSbt reg_val = (ixgbe->rx_buf_size >> IXGBE_SRRCTL_BSIZEPKT_SHIFT) |
24859da57d7bSbt IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
248673cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= IXGBE_SRRCTL_DROP_EN;
24870dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rx_ring->hw_index), reg_val);
24889da57d7bSbt }
24899da57d7bSbt
249084de666eSRyan Zezeski static int
ixgbe_setup_rx(ixgbe_t * ixgbe)24919da57d7bSbt ixgbe_setup_rx(ixgbe_t *ixgbe)
24929da57d7bSbt {
24939da57d7bSbt ixgbe_rx_ring_t *rx_ring;
24949da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
24959da57d7bSbt uint32_t reg_val;
2496168e1ed4SRyan Zezeski uint32_t i;
24970dc2366fSVenugopal Iyer uint32_t psrtype_rss_bit;
24989da57d7bSbt
2499dc0cb1cdSDale Ghent /*
2500dc0cb1cdSDale Ghent * Ensure that Rx is disabled while setting up
2501dc0cb1cdSDale Ghent * the Rx unit and Rx descriptor ring(s)
2502dc0cb1cdSDale Ghent */
2503dc0cb1cdSDale Ghent ixgbe_disable_rx(hw);
2504dc0cb1cdSDale Ghent
250573cd555cSBin Tu - Sun Microsystems - Beijing China /* PSRTYPE must be configured for 82599 */
25060dc2366fSVenugopal Iyer if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ &&
25070dc2366fSVenugopal Iyer ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) {
25080dc2366fSVenugopal Iyer reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
25090dc2366fSVenugopal Iyer IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
25100dc2366fSVenugopal Iyer reg_val |= IXGBE_PSRTYPE_L2HDR;
25110dc2366fSVenugopal Iyer reg_val |= 0x80000000;
25120dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), reg_val);
25130dc2366fSVenugopal Iyer } else {
25140dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups > 32) {
25150dc2366fSVenugopal Iyer psrtype_rss_bit = 0x20000000;
25160dc2366fSVenugopal Iyer } else {
25170dc2366fSVenugopal Iyer psrtype_rss_bit = 0x40000000;
25180dc2366fSVenugopal Iyer }
25190dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->capab->max_rx_grp_num; i++) {
25200dc2366fSVenugopal Iyer reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR |
25210dc2366fSVenugopal Iyer IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
25220dc2366fSVenugopal Iyer reg_val |= IXGBE_PSRTYPE_L2HDR;
25230dc2366fSVenugopal Iyer reg_val |= psrtype_rss_bit;
25240dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val);
25250dc2366fSVenugopal Iyer }
25260dc2366fSVenugopal Iyer }
252773cd555cSBin Tu - Sun Microsystems - Beijing China
25289da57d7bSbt /*
2529dc0cb1cdSDale Ghent * Set filter control in FCTRL to determine types of packets are passed
2530dc0cb1cdSDale Ghent * up to the driver.
2531dc0cb1cdSDale Ghent * - Pass broadcast packets.
2532dc0cb1cdSDale Ghent * - Do not pass flow control pause frames (82598-specific)
25339da57d7bSbt */
25349da57d7bSbt reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
2535dc0cb1cdSDale Ghent reg_val |= IXGBE_FCTRL_BAM; /* Broadcast Accept Mode */
2536dc0cb1cdSDale Ghent if (hw->mac.type == ixgbe_mac_82598EB) {
2537dc0cb1cdSDale Ghent reg_val |= IXGBE_FCTRL_DPF; /* Discard Pause Frames */
2538dc0cb1cdSDale Ghent }
25399da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val);
25409da57d7bSbt
25410dc2366fSVenugopal Iyer /*
25420dc2366fSVenugopal Iyer * Hardware checksum settings
25430dc2366fSVenugopal Iyer */
25440dc2366fSVenugopal Iyer if (ixgbe->rx_hcksum_enable) {
2545dc0cb1cdSDale Ghent reg_val = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
2546dc0cb1cdSDale Ghent reg_val |= IXGBE_RXCSUM_IPPCSE; /* IP checksum */
25470dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val);
25480dc2366fSVenugopal Iyer }
25490dc2366fSVenugopal Iyer
25500dc2366fSVenugopal Iyer /*
25510dc2366fSVenugopal Iyer * Setup VMDq and RSS for multiple receive queues
25520dc2366fSVenugopal Iyer */
25530dc2366fSVenugopal Iyer switch (ixgbe->classify_mode) {
25540dc2366fSVenugopal Iyer case IXGBE_CLASSIFY_RSS:
25550dc2366fSVenugopal Iyer /*
25560dc2366fSVenugopal Iyer * One group, only RSS is needed when more than
25570dc2366fSVenugopal Iyer * one ring enabled.
25580dc2366fSVenugopal Iyer */
25590dc2366fSVenugopal Iyer ixgbe_setup_rss(ixgbe);
25600dc2366fSVenugopal Iyer break;
25610dc2366fSVenugopal Iyer
25620dc2366fSVenugopal Iyer case IXGBE_CLASSIFY_VMDQ:
25630dc2366fSVenugopal Iyer /*
25640dc2366fSVenugopal Iyer * Multiple groups, each group has one ring,
25650dc2366fSVenugopal Iyer * only VMDq is needed.
25660dc2366fSVenugopal Iyer */
25670dc2366fSVenugopal Iyer ixgbe_setup_vmdq(ixgbe);
25680dc2366fSVenugopal Iyer break;
25690dc2366fSVenugopal Iyer
25700dc2366fSVenugopal Iyer case IXGBE_CLASSIFY_VMDQ_RSS:
25710dc2366fSVenugopal Iyer /*
25720dc2366fSVenugopal Iyer * Multiple groups and multiple rings, both
25730dc2366fSVenugopal Iyer * VMDq and RSS are needed.
25740dc2366fSVenugopal Iyer */
25750dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss(ixgbe);
25760dc2366fSVenugopal Iyer break;
25770dc2366fSVenugopal Iyer
25780dc2366fSVenugopal Iyer default:
25790dc2366fSVenugopal Iyer break;
25800dc2366fSVenugopal Iyer }
25810dc2366fSVenugopal Iyer
258284de666eSRyan Zezeski /*
258384de666eSRyan Zezeski * Initialize VLAN SW and HW state if VLAN filtering is
258484de666eSRyan Zezeski * enabled.
258584de666eSRyan Zezeski */
258684de666eSRyan Zezeski if (ixgbe->vlft_enabled) {
258784de666eSRyan Zezeski if (ixgbe_init_vlan(ixgbe) != IXGBE_SUCCESS)
258884de666eSRyan Zezeski return (IXGBE_FAILURE);
258984de666eSRyan Zezeski }
259084de666eSRyan Zezeski
25919da57d7bSbt /*
25929da57d7bSbt * Enable the receive unit. This must be done after filter
2593dc0cb1cdSDale Ghent * control is set in FCTRL. On 82598, we disable the descriptor monitor.
2594dc0cb1cdSDale Ghent * 82598 is the only adapter which defines this RXCTRL option.
25959da57d7bSbt */
2596dc0cb1cdSDale Ghent reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
2597dc0cb1cdSDale Ghent if (hw->mac.type == ixgbe_mac_82598EB)
2598dc0cb1cdSDale Ghent reg_val |= IXGBE_RXCTRL_DMBYPS; /* descriptor monitor bypass */
2599dc0cb1cdSDale Ghent reg_val |= IXGBE_RXCTRL_RXEN;
2600dc0cb1cdSDale Ghent (void) ixgbe_enable_rx_dma(hw, reg_val);
26019da57d7bSbt
26029da57d7bSbt /*
26039da57d7bSbt * ixgbe_setup_rx_ring must be called after configuring RXCTRL
26049da57d7bSbt */
26059da57d7bSbt for (i = 0; i < ixgbe->num_rx_rings; i++) {
26069da57d7bSbt rx_ring = &ixgbe->rx_rings[i];
26079da57d7bSbt ixgbe_setup_rx_ring(rx_ring);
26089da57d7bSbt }
26099da57d7bSbt
2610da14cebeSEric Cheng /*
2611168e1ed4SRyan Zezeski * The 82598 controller gives us the RNBC (Receive No Buffer
2612168e1ed4SRyan Zezeski * Count) register to determine the number of frames dropped
2613168e1ed4SRyan Zezeski * due to no available descriptors on the destination queue.
2614168e1ed4SRyan Zezeski * However, this register was removed starting with 82599 and
2615168e1ed4SRyan Zezeski * it was replaced with the RQSMR/QPRDC registers. The nice
2616168e1ed4SRyan Zezeski * thing about the new registers is that they allow you to map
2617168e1ed4SRyan Zezeski * groups of queues to specific stat registers. The bad thing
2618168e1ed4SRyan Zezeski * is there are only 16 slots in the stat registers, so this
2619168e1ed4SRyan Zezeski * won't work when we have 32 Rx groups. Instead, we map all
2620168e1ed4SRyan Zezeski * queues to the zero slot of the stat registers, giving us a
2621168e1ed4SRyan Zezeski * global counter at QPRDC[0] (with the equivalent semantics
2622168e1ed4SRyan Zezeski * of RNBC). Perhaps future controllers will have more slots
2623168e1ed4SRyan Zezeski * and we can implement per-group counters.
2624da14cebeSEric Cheng */
2625da14cebeSEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) {
2626168e1ed4SRyan Zezeski uint32_t index = ixgbe->rx_rings[i].hw_index;
2627168e1ed4SRyan Zezeski IXGBE_WRITE_REG(hw, IXGBE_RQSMR(index >> 2), 0);
2628da14cebeSEric Cheng }
2629da14cebeSEric Cheng
26309da57d7bSbt /*
263173cd555cSBin Tu - Sun Microsystems - Beijing China * The Max Frame Size in MHADD/MAXFRS will be internally increased
263273cd555cSBin Tu - Sun Microsystems - Beijing China * by four bytes if the packet has a VLAN field, so includes MTU,
263373cd555cSBin Tu - Sun Microsystems - Beijing China * ethernet header and frame check sequence.
263473cd555cSBin Tu - Sun Microsystems - Beijing China * Register is MAXFRS in 82599.
26359da57d7bSbt */
2636dc0cb1cdSDale Ghent reg_val = IXGBE_READ_REG(hw, IXGBE_MHADD);
2637dc0cb1cdSDale Ghent reg_val &= ~IXGBE_MHADD_MFS_MASK;
2638dc0cb1cdSDale Ghent reg_val |= (ixgbe->default_mtu + sizeof (struct ether_header)
26399da57d7bSbt + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT;
26409da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val);
26419da57d7bSbt
26429da57d7bSbt /*
26439da57d7bSbt * Setup Jumbo Frame enable bit
26449da57d7bSbt */
2645dc0cb1cdSDale Ghent reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2646dc0cb1cdSDale Ghent if (ixgbe->default_mtu > ETHERMTU)
26479da57d7bSbt reg_val |= IXGBE_HLREG0_JUMBOEN;
2648dc0cb1cdSDale Ghent else
2649dc0cb1cdSDale Ghent reg_val &= ~IXGBE_HLREG0_JUMBOEN;
2650dc0cb1cdSDale Ghent IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
26511878b971SVenugopal Iyer
26521878b971SVenugopal Iyer /*
26531878b971SVenugopal Iyer * Setup RSC for multiple receive queues.
26541878b971SVenugopal Iyer */
26551878b971SVenugopal Iyer if (ixgbe->lro_enable) {
26561878b971SVenugopal Iyer for (i = 0; i < ixgbe->num_rx_rings; i++) {
26571878b971SVenugopal Iyer /*
26581878b971SVenugopal Iyer * Make sure rx_buf_size * MAXDESC not greater
26591878b971SVenugopal Iyer * than 65535.
26601878b971SVenugopal Iyer * Intel recommends 4 for MAXDESC field value.
26611878b971SVenugopal Iyer */
26621878b971SVenugopal Iyer reg_val = IXGBE_READ_REG(hw, IXGBE_RSCCTL(i));
26631878b971SVenugopal Iyer reg_val |= IXGBE_RSCCTL_RSCEN;
26641878b971SVenugopal Iyer if (ixgbe->rx_buf_size == IXGBE_PKG_BUF_16k)
26651878b971SVenugopal Iyer reg_val |= IXGBE_RSCCTL_MAXDESC_1;
26661878b971SVenugopal Iyer else
26671878b971SVenugopal Iyer reg_val |= IXGBE_RSCCTL_MAXDESC_4;
26681878b971SVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(i), reg_val);
26691878b971SVenugopal Iyer }
26701878b971SVenugopal Iyer
26711878b971SVenugopal Iyer reg_val = IXGBE_READ_REG(hw, IXGBE_RSCDBU);
26721878b971SVenugopal Iyer reg_val |= IXGBE_RSCDBU_RSCACKDIS;
26731878b971SVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, reg_val);
26741878b971SVenugopal Iyer
26751878b971SVenugopal Iyer reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
26761878b971SVenugopal Iyer reg_val |= IXGBE_RDRXCTL_RSCACKC;
267719843f01SPaul Guo reg_val |= IXGBE_RDRXCTL_FCOE_WRFIX;
26781878b971SVenugopal Iyer reg_val &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
26791878b971SVenugopal Iyer
26801878b971SVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val);
26811878b971SVenugopal Iyer }
268284de666eSRyan Zezeski
268384de666eSRyan Zezeski return (IXGBE_SUCCESS);
26849da57d7bSbt }
26859da57d7bSbt
26869da57d7bSbt static void
ixgbe_setup_tx_ring(ixgbe_tx_ring_t * tx_ring)26879da57d7bSbt ixgbe_setup_tx_ring(ixgbe_tx_ring_t *tx_ring)
26889da57d7bSbt {
26899da57d7bSbt ixgbe_t *ixgbe = tx_ring->ixgbe;
26909da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
26919da57d7bSbt uint32_t size;
26929da57d7bSbt uint32_t buf_low;
26939da57d7bSbt uint32_t buf_high;
26949da57d7bSbt uint32_t reg_val;
26959da57d7bSbt
26969da57d7bSbt ASSERT(mutex_owned(&tx_ring->tx_lock));
26979da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
26989da57d7bSbt
26999da57d7bSbt /*
27009da57d7bSbt * Initialize the length register
27019da57d7bSbt */
27029da57d7bSbt size = tx_ring->ring_size * sizeof (union ixgbe_adv_tx_desc);
27039da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_TDLEN(tx_ring->index), size);
27049da57d7bSbt
27059da57d7bSbt /*
27069da57d7bSbt * Initialize the base address registers
27079da57d7bSbt */
27089da57d7bSbt buf_low = (uint32_t)tx_ring->tbd_area.dma_address;
27099da57d7bSbt buf_high = (uint32_t)(tx_ring->tbd_area.dma_address >> 32);
27109da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_TDBAL(tx_ring->index), buf_low);
27119da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_TDBAH(tx_ring->index), buf_high);
27129da57d7bSbt
27139da57d7bSbt /*
27149da57d7bSbt * Setup head & tail pointers
27159da57d7bSbt */
27169da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_TDH(tx_ring->index), 0);
27179da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_TDT(tx_ring->index), 0);
27189da57d7bSbt
27199da57d7bSbt /*
27209da57d7bSbt * Setup head write-back
27219da57d7bSbt */
27229da57d7bSbt if (ixgbe->tx_head_wb_enable) {
27239da57d7bSbt /*
27249da57d7bSbt * The memory of the head write-back is allocated using
27259da57d7bSbt * the extra tbd beyond the tail of the tbd ring.
27269da57d7bSbt */
27279da57d7bSbt tx_ring->tbd_head_wb = (uint32_t *)
27289da57d7bSbt ((uintptr_t)tx_ring->tbd_area.address + size);
27299da57d7bSbt *tx_ring->tbd_head_wb = 0;
27309da57d7bSbt
27319da57d7bSbt buf_low = (uint32_t)
27329da57d7bSbt (tx_ring->tbd_area.dma_address + size);
27339da57d7bSbt buf_high = (uint32_t)
27349da57d7bSbt ((tx_ring->tbd_area.dma_address + size) >> 32);
27359da57d7bSbt
27369da57d7bSbt /* Set the head write-back enable bit */
27379da57d7bSbt buf_low |= IXGBE_TDWBAL_HEAD_WB_ENABLE;
27389da57d7bSbt
27399da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(tx_ring->index), buf_low);
27409da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(tx_ring->index), buf_high);
27419da57d7bSbt
27429da57d7bSbt /*
27439da57d7bSbt * Turn off relaxed ordering for head write back or it will
27449da57d7bSbt * cause problems with the tx recycling
27459da57d7bSbt */
274669b5a878SDan McDonald
274769b5a878SDan McDonald reg_val = (hw->mac.type == ixgbe_mac_82598EB) ?
274869b5a878SDan McDonald IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(tx_ring->index)) :
274969b5a878SDan McDonald IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(tx_ring->index));
275069b5a878SDan McDonald reg_val &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN;
275169b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82598EB) {
275269b5a878SDan McDonald IXGBE_WRITE_REG(hw,
275369b5a878SDan McDonald IXGBE_DCA_TXCTRL(tx_ring->index), reg_val);
275469b5a878SDan McDonald } else {
275569b5a878SDan McDonald IXGBE_WRITE_REG(hw,
275669b5a878SDan McDonald IXGBE_DCA_TXCTRL_82599(tx_ring->index), reg_val);
275769b5a878SDan McDonald }
27589da57d7bSbt } else {
27599da57d7bSbt tx_ring->tbd_head_wb = NULL;
27609da57d7bSbt }
27619da57d7bSbt
27629da57d7bSbt tx_ring->tbd_head = 0;
27639da57d7bSbt tx_ring->tbd_tail = 0;
27649da57d7bSbt tx_ring->tbd_free = tx_ring->ring_size;
27659da57d7bSbt
2766ea65739eSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->tx_ring_init == B_TRUE) {
27679da57d7bSbt tx_ring->tcb_head = 0;
27689da57d7bSbt tx_ring->tcb_tail = 0;
27699da57d7bSbt tx_ring->tcb_free = tx_ring->free_list_size;
27709da57d7bSbt }
27719da57d7bSbt
27729da57d7bSbt /*
2773f27d3025Sgg * Initialize the s/w context structure
27749da57d7bSbt */
2775f27d3025Sgg bzero(&tx_ring->tx_context, sizeof (ixgbe_tx_context_t));
27769da57d7bSbt }
27779da57d7bSbt
27789da57d7bSbt static void
ixgbe_setup_tx(ixgbe_t * ixgbe)27799da57d7bSbt ixgbe_setup_tx(ixgbe_t *ixgbe)
27809da57d7bSbt {
2781c971fb7eSgg struct ixgbe_hw *hw = &ixgbe->hw;
27829da57d7bSbt ixgbe_tx_ring_t *tx_ring;
2783c971fb7eSgg uint32_t reg_val;
27849da57d7bSbt int i;
27859da57d7bSbt
27869da57d7bSbt for (i = 0; i < ixgbe->num_tx_rings; i++) {
27879da57d7bSbt tx_ring = &ixgbe->tx_rings[i];
27889da57d7bSbt ixgbe_setup_tx_ring(tx_ring);
27899da57d7bSbt }
2790c971fb7eSgg
2791da14cebeSEric Cheng /*
2792168e1ed4SRyan Zezeski * Setup the per-ring statistics mapping. We map all Tx queues
2793168e1ed4SRyan Zezeski * to slot 0 to stay consistent with Rx.
2794da14cebeSEric Cheng */
2795da14cebeSEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) {
27965b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) {
27975b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
2798168e1ed4SRyan Zezeski IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), 0);
27995b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
28005b6dd21fSchenlu chen - Sun Microsystems - Beijing China
28015b6dd21fSchenlu chen - Sun Microsystems - Beijing China default:
2802168e1ed4SRyan Zezeski IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), 0);
28035b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
280473cd555cSBin Tu - Sun Microsystems - Beijing China }
28055b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
2806da14cebeSEric Cheng
2807c971fb7eSgg /*
2808c971fb7eSgg * Enable CRC appending and TX padding (for short tx frames)
2809c971fb7eSgg */
2810c971fb7eSgg reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0);
2811c971fb7eSgg reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN;
2812c971fb7eSgg IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val);
281373cd555cSBin Tu - Sun Microsystems - Beijing China
281473cd555cSBin Tu - Sun Microsystems - Beijing China /*
2815dc0cb1cdSDale Ghent * enable DMA for 82599, X540 and X550 parts
281673cd555cSBin Tu - Sun Microsystems - Beijing China */
281769b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82599EB ||
2818dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X540 ||
2819dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X550 ||
282048ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_x ||
282148ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_a) {
282269b5a878SDan McDonald /* DMATXCTL.TE must be set after all Tx config is complete */
282373cd555cSBin Tu - Sun Microsystems - Beijing China reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
282473cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= IXGBE_DMATXCTL_TE;
282573cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val);
282669b5a878SDan McDonald
282769b5a878SDan McDonald /* Disable arbiter to set MTQC */
282869b5a878SDan McDonald reg_val = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
282969b5a878SDan McDonald reg_val |= IXGBE_RTTDCS_ARBDIS;
283069b5a878SDan McDonald IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg_val);
283169b5a878SDan McDonald IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
283269b5a878SDan McDonald reg_val &= ~IXGBE_RTTDCS_ARBDIS;
283369b5a878SDan McDonald IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg_val);
283473cd555cSBin Tu - Sun Microsystems - Beijing China }
283573cd555cSBin Tu - Sun Microsystems - Beijing China
283673cd555cSBin Tu - Sun Microsystems - Beijing China /*
283773cd555cSBin Tu - Sun Microsystems - Beijing China * Enabling tx queues ..
283873cd555cSBin Tu - Sun Microsystems - Beijing China * For 82599 must be done after DMATXCTL.TE is set
283973cd555cSBin Tu - Sun Microsystems - Beijing China */
284073cd555cSBin Tu - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->num_tx_rings; i++) {
284173cd555cSBin Tu - Sun Microsystems - Beijing China tx_ring = &ixgbe->tx_rings[i];
284273cd555cSBin Tu - Sun Microsystems - Beijing China reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->index));
284373cd555cSBin Tu - Sun Microsystems - Beijing China reg_val |= IXGBE_TXDCTL_ENABLE;
284473cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->index), reg_val);
284573cd555cSBin Tu - Sun Microsystems - Beijing China }
28469da57d7bSbt }
28479da57d7bSbt
28489da57d7bSbt /*
28499da57d7bSbt * ixgbe_setup_rss - Setup receive-side scaling feature.
28509da57d7bSbt */
28519da57d7bSbt static void
ixgbe_setup_rss(ixgbe_t * ixgbe)28529da57d7bSbt ixgbe_setup_rss(ixgbe_t *ixgbe)
28539da57d7bSbt {
28549da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
2855dc0cb1cdSDale Ghent uint32_t mrqc;
28569da57d7bSbt
28579da57d7bSbt /*
2858dc0cb1cdSDale Ghent * Initialize RETA/ERETA table
28599da57d7bSbt */
2860dc0cb1cdSDale Ghent ixgbe_setup_rss_table(ixgbe);
28619da57d7bSbt
28629da57d7bSbt /*
2863c971fb7eSgg * Enable RSS & perform hash on these packet types
28649da57d7bSbt */
28659da57d7bSbt mrqc = IXGBE_MRQC_RSSEN |
28669da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV4 |
28679da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
28689da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
28699da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
28709da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV6_EX |
28719da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV6 |
28729da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
28739da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
28749da57d7bSbt IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
28759da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
28769da57d7bSbt }
28779da57d7bSbt
28780dc2366fSVenugopal Iyer /*
28790dc2366fSVenugopal Iyer * ixgbe_setup_vmdq - Setup MAC classification feature
28800dc2366fSVenugopal Iyer */
28810dc2366fSVenugopal Iyer static void
ixgbe_setup_vmdq(ixgbe_t * ixgbe)28820dc2366fSVenugopal Iyer ixgbe_setup_vmdq(ixgbe_t *ixgbe)
28830dc2366fSVenugopal Iyer {
28840dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw;
288584de666eSRyan Zezeski uint32_t vmdctl, i, vtctl, vlnctl;
28860dc2366fSVenugopal Iyer
28870dc2366fSVenugopal Iyer /*
28880dc2366fSVenugopal Iyer * Setup the VMDq Control register, enable VMDq based on
28890dc2366fSVenugopal Iyer * packet destination MAC address:
28900dc2366fSVenugopal Iyer */
28910dc2366fSVenugopal Iyer switch (hw->mac.type) {
28920dc2366fSVenugopal Iyer case ixgbe_mac_82598EB:
28930dc2366fSVenugopal Iyer /*
28940dc2366fSVenugopal Iyer * VMDq Enable = 1;
28950dc2366fSVenugopal Iyer * VMDq Filter = 0; MAC filtering
28960dc2366fSVenugopal Iyer * Default VMDq output index = 0;
28970dc2366fSVenugopal Iyer */
28980dc2366fSVenugopal Iyer vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
28990dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
29000dc2366fSVenugopal Iyer break;
29010dc2366fSVenugopal Iyer
29020dc2366fSVenugopal Iyer case ixgbe_mac_82599EB:
290369b5a878SDan McDonald case ixgbe_mac_X540:
2904dc0cb1cdSDale Ghent case ixgbe_mac_X550:
2905dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
290648ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
29070dc2366fSVenugopal Iyer /*
29080dc2366fSVenugopal Iyer * Enable VMDq-only.
29090dc2366fSVenugopal Iyer */
29100dc2366fSVenugopal Iyer vmdctl = IXGBE_MRQC_VMDQEN;
29110dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl);
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
29180dc2366fSVenugopal Iyer /*
29190dc2366fSVenugopal Iyer * Enable Virtualization and Replication.
29200dc2366fSVenugopal Iyer */
292184de666eSRyan Zezeski vtctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
292284de666eSRyan Zezeski ixgbe->rx_def_group = vtctl & IXGBE_VT_CTL_POOL_MASK;
292384de666eSRyan Zezeski vtctl |= IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
29240dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
29250dc2366fSVenugopal Iyer
292684de666eSRyan Zezeski /*
292784de666eSRyan Zezeski * Enable VLAN filtering and switching (VFTA and VLVF).
292884de666eSRyan Zezeski */
292984de666eSRyan Zezeski vlnctl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
293084de666eSRyan Zezeski vlnctl |= IXGBE_VLNCTRL_VFE;
293184de666eSRyan Zezeski IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctl);
293284de666eSRyan Zezeski ixgbe->vlft_enabled = B_TRUE;
293384de666eSRyan Zezeski
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 break;
29400dc2366fSVenugopal Iyer
29410dc2366fSVenugopal Iyer default:
29420dc2366fSVenugopal Iyer break;
29430dc2366fSVenugopal Iyer }
29440dc2366fSVenugopal Iyer }
29450dc2366fSVenugopal Iyer
29460dc2366fSVenugopal Iyer /*
29470dc2366fSVenugopal Iyer * ixgbe_setup_vmdq_rss - Setup both vmdq feature and rss feature.
29480dc2366fSVenugopal Iyer */
29490dc2366fSVenugopal Iyer static void
ixgbe_setup_vmdq_rss(ixgbe_t * ixgbe)29500dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe)
29510dc2366fSVenugopal Iyer {
29520dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw;
2953dc0cb1cdSDale Ghent uint32_t i, mrqc;
295484de666eSRyan Zezeski uint32_t vtctl, vmdctl, vlnctl;
29550dc2366fSVenugopal Iyer
29560dc2366fSVenugopal Iyer /*
2957dc0cb1cdSDale Ghent * Initialize RETA/ERETA table
29580dc2366fSVenugopal Iyer */
2959dc0cb1cdSDale Ghent ixgbe_setup_rss_table(ixgbe);
29600dc2366fSVenugopal Iyer
29610dc2366fSVenugopal Iyer /*
29620dc2366fSVenugopal Iyer * Enable and setup RSS and VMDq
29630dc2366fSVenugopal Iyer */
29640dc2366fSVenugopal Iyer switch (hw->mac.type) {
29650dc2366fSVenugopal Iyer case ixgbe_mac_82598EB:
29660dc2366fSVenugopal Iyer /*
29670dc2366fSVenugopal Iyer * Enable RSS & Setup RSS Hash functions
29680dc2366fSVenugopal Iyer */
29690dc2366fSVenugopal Iyer mrqc = IXGBE_MRQC_RSSEN |
29700dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4 |
29710dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
29720dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
29730dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
29740dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX |
29750dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6 |
29760dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
29770dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
29780dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
29790dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
29800dc2366fSVenugopal Iyer
29810dc2366fSVenugopal Iyer /*
29820dc2366fSVenugopal Iyer * Enable and Setup VMDq
29830dc2366fSVenugopal Iyer * VMDq Filter = 0; MAC filtering
29840dc2366fSVenugopal Iyer * Default VMDq output index = 0;
29850dc2366fSVenugopal Iyer */
29860dc2366fSVenugopal Iyer vmdctl = IXGBE_VMD_CTL_VMDQ_EN;
29870dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl);
29880dc2366fSVenugopal Iyer break;
29890dc2366fSVenugopal Iyer
29900dc2366fSVenugopal Iyer case ixgbe_mac_82599EB:
299169b5a878SDan McDonald case ixgbe_mac_X540:
2992dc0cb1cdSDale Ghent case ixgbe_mac_X550:
2993dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
299448ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
29950dc2366fSVenugopal Iyer /*
29960dc2366fSVenugopal Iyer * Enable RSS & Setup RSS Hash functions
29970dc2366fSVenugopal Iyer */
29980dc2366fSVenugopal Iyer mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 |
29990dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
30000dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV4_UDP |
30010dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP |
30020dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX |
30030dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6 |
30040dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_TCP |
30050dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_UDP |
30060dc2366fSVenugopal Iyer IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
30070dc2366fSVenugopal Iyer
30080dc2366fSVenugopal Iyer /*
30090dc2366fSVenugopal Iyer * Enable VMDq+RSS.
30100dc2366fSVenugopal Iyer */
30110dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups > 32) {
30120dc2366fSVenugopal Iyer mrqc = mrqc | IXGBE_MRQC_VMDQRSS64EN;
30130dc2366fSVenugopal Iyer } else {
30140dc2366fSVenugopal Iyer mrqc = mrqc | IXGBE_MRQC_VMDQRSS32EN;
30150dc2366fSVenugopal Iyer }
30160dc2366fSVenugopal Iyer
30170dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
30180dc2366fSVenugopal Iyer
30190dc2366fSVenugopal Iyer for (i = 0; i < hw->mac.num_rar_entries; i++) {
30200dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(i), 0);
30210dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(i), 0);
30220dc2366fSVenugopal Iyer }
30230dc2366fSVenugopal Iyer break;
30240dc2366fSVenugopal Iyer
30250dc2366fSVenugopal Iyer default:
30260dc2366fSVenugopal Iyer break;
30270dc2366fSVenugopal Iyer
30280dc2366fSVenugopal Iyer }
30290dc2366fSVenugopal Iyer
303069b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82599EB ||
3031dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X540 ||
3032dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X550 ||
303348ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_x ||
303448ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_a) {
30350dc2366fSVenugopal Iyer /*
30360dc2366fSVenugopal Iyer * Enable Virtualization and Replication.
30370dc2366fSVenugopal Iyer */
303884de666eSRyan Zezeski vtctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
303984de666eSRyan Zezeski ixgbe->rx_def_group = vtctl & IXGBE_VT_CTL_POOL_MASK;
304084de666eSRyan Zezeski vtctl |= IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
30410dc2366fSVenugopal Iyer vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN;
30420dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
30430dc2366fSVenugopal Iyer
304484de666eSRyan Zezeski /*
304584de666eSRyan Zezeski * Enable VLAN filtering and switching (VFTA and VLVF).
304684de666eSRyan Zezeski */
304784de666eSRyan Zezeski vlnctl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
304884de666eSRyan Zezeski vlnctl |= IXGBE_VLNCTRL_VFE;
304984de666eSRyan Zezeski IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctl);
305084de666eSRyan Zezeski ixgbe->vlft_enabled = B_TRUE;
305184de666eSRyan Zezeski
30520dc2366fSVenugopal Iyer /*
30530dc2366fSVenugopal Iyer * Enable receiving packets to all VFs
30540dc2366fSVenugopal Iyer */
30550dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), IXGBE_VFRE_ENABLE_ALL);
30560dc2366fSVenugopal Iyer IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL);
30570dc2366fSVenugopal Iyer }
30580dc2366fSVenugopal Iyer }
30590dc2366fSVenugopal Iyer
3060dc0cb1cdSDale Ghent /*
3061dc0cb1cdSDale Ghent * ixgbe_setup_rss_table - Setup RSS table
3062dc0cb1cdSDale Ghent */
3063dc0cb1cdSDale Ghent static void
ixgbe_setup_rss_table(ixgbe_t * ixgbe)3064dc0cb1cdSDale Ghent ixgbe_setup_rss_table(ixgbe_t *ixgbe)
3065dc0cb1cdSDale Ghent {
3066dc0cb1cdSDale Ghent struct ixgbe_hw *hw = &ixgbe->hw;
3067dc0cb1cdSDale Ghent uint32_t i, j;
3068dc0cb1cdSDale Ghent uint32_t random;
3069dc0cb1cdSDale Ghent uint32_t reta;
3070dc0cb1cdSDale Ghent uint32_t ring_per_group;
3071dc0cb1cdSDale Ghent uint32_t ring;
3072dc0cb1cdSDale Ghent uint32_t table_size;
3073dc0cb1cdSDale Ghent uint32_t index_mult;
3074dc0cb1cdSDale Ghent uint32_t rxcsum;
3075dc0cb1cdSDale Ghent
3076dc0cb1cdSDale Ghent /*
3077dc0cb1cdSDale Ghent * Set multiplier for RETA setup and table size based on MAC type.
3078dc0cb1cdSDale Ghent * RETA table sizes vary by model:
3079dc0cb1cdSDale Ghent *
3080dc0cb1cdSDale Ghent * 82598, 82599, X540: 128 table entries.
3081dc0cb1cdSDale Ghent * X550: 512 table entries.
3082dc0cb1cdSDale Ghent */
3083dc0cb1cdSDale Ghent index_mult = 0x1;
3084dc0cb1cdSDale Ghent table_size = 128;
3085dc0cb1cdSDale Ghent switch (ixgbe->hw.mac.type) {
3086dc0cb1cdSDale Ghent case ixgbe_mac_82598EB:
3087dc0cb1cdSDale Ghent index_mult = 0x11;
3088dc0cb1cdSDale Ghent break;
3089dc0cb1cdSDale Ghent case ixgbe_mac_X550:
3090dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
309148ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
3092dc0cb1cdSDale Ghent table_size = 512;
3093dc0cb1cdSDale Ghent break;
3094dc0cb1cdSDale Ghent default:
3095dc0cb1cdSDale Ghent break;
3096dc0cb1cdSDale Ghent }
3097dc0cb1cdSDale Ghent
3098dc0cb1cdSDale Ghent /*
3099dc0cb1cdSDale Ghent * Fill out RSS redirection table. The configuation of the indices is
3100dc0cb1cdSDale Ghent * hardware-dependent.
3101dc0cb1cdSDale Ghent *
3102dc0cb1cdSDale Ghent * 82598: 8 bits wide containing two 4 bit RSS indices
3103dc0cb1cdSDale Ghent * 82599, X540: 8 bits wide containing one 4 bit RSS index
3104dc0cb1cdSDale Ghent * X550: 8 bits wide containing one 6 bit RSS index
3105dc0cb1cdSDale Ghent */
3106dc0cb1cdSDale Ghent reta = 0;
3107dc0cb1cdSDale Ghent ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
3108dc0cb1cdSDale Ghent
3109dc0cb1cdSDale Ghent for (i = 0, j = 0; i < table_size; i++, j++) {
3110dc0cb1cdSDale Ghent if (j == ring_per_group) j = 0;
3111dc0cb1cdSDale Ghent
3112dc0cb1cdSDale Ghent /*
3113dc0cb1cdSDale Ghent * The low 8 bits are for hash value (n+0);
3114dc0cb1cdSDale Ghent * The next 8 bits are for hash value (n+1), etc.
3115dc0cb1cdSDale Ghent */
3116dc0cb1cdSDale Ghent ring = (j * index_mult);
3117dc0cb1cdSDale Ghent reta = reta >> 8;
3118dc0cb1cdSDale Ghent reta = reta | (((uint32_t)ring) << 24);
3119dc0cb1cdSDale Ghent
3120483bfec1SToomas Soome if ((i & 3) == 3) {
3121dc0cb1cdSDale Ghent /*
3122dc0cb1cdSDale Ghent * The first 128 table entries are programmed into the
3123dc0cb1cdSDale Ghent * RETA register, with any beyond that (eg; on X550)
3124dc0cb1cdSDale Ghent * into ERETA.
3125dc0cb1cdSDale Ghent */
3126dc0cb1cdSDale Ghent if (i < 128)
3127dc0cb1cdSDale Ghent IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
3128dc0cb1cdSDale Ghent else
3129dc0cb1cdSDale Ghent IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32),
3130dc0cb1cdSDale Ghent reta);
3131dc0cb1cdSDale Ghent reta = 0;
3132483bfec1SToomas Soome }
3133dc0cb1cdSDale Ghent }
3134dc0cb1cdSDale Ghent
3135dc0cb1cdSDale Ghent /*
3136dc0cb1cdSDale Ghent * Fill out hash function seeds with a random constant
3137dc0cb1cdSDale Ghent */
3138dc0cb1cdSDale Ghent for (i = 0; i < 10; i++) {
3139dc0cb1cdSDale Ghent (void) random_get_pseudo_bytes((uint8_t *)&random,
3140dc0cb1cdSDale Ghent sizeof (uint32_t));
3141dc0cb1cdSDale Ghent IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random);
3142dc0cb1cdSDale Ghent }
3143dc0cb1cdSDale Ghent
3144dc0cb1cdSDale Ghent /*
3145dc0cb1cdSDale Ghent * Disable Packet Checksum to enable RSS for multiple receive queues.
3146dc0cb1cdSDale Ghent * It is an adapter hardware limitation that Packet Checksum is
3147dc0cb1cdSDale Ghent * mutually exclusive with RSS.
3148dc0cb1cdSDale Ghent */
3149dc0cb1cdSDale Ghent rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
3150dc0cb1cdSDale Ghent rxcsum |= IXGBE_RXCSUM_PCSD;
3151dc0cb1cdSDale Ghent rxcsum &= ~IXGBE_RXCSUM_IPPCSE;
3152dc0cb1cdSDale Ghent IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
3153dc0cb1cdSDale Ghent }
3154dc0cb1cdSDale Ghent
31559da57d7bSbt /*
31569da57d7bSbt * ixgbe_init_unicst - Initialize the unicast addresses.
31579da57d7bSbt */
31589da57d7bSbt static void
ixgbe_init_unicst(ixgbe_t * ixgbe)31599da57d7bSbt ixgbe_init_unicst(ixgbe_t *ixgbe)
31609da57d7bSbt {
31619da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
3162da14cebeSEric Cheng uint8_t *mac_addr;
31639da57d7bSbt int slot;
31649da57d7bSbt /*
31659da57d7bSbt * Here we should consider two situations:
31669da57d7bSbt *
3167da14cebeSEric Cheng * 1. Chipset is initialized at the first time,
3168da14cebeSEric Cheng * Clear all the multiple unicast addresses.
31699da57d7bSbt *
31709da57d7bSbt * 2. Chipset is reset
31719da57d7bSbt * Recover the multiple unicast addresses from the
31729da57d7bSbt * software data structure to the RAR registers.
31739da57d7bSbt */
31749da57d7bSbt if (!ixgbe->unicst_init) {
31759da57d7bSbt /*
31769da57d7bSbt * Initialize the multiple unicast addresses
31779da57d7bSbt */
31780dc2366fSVenugopal Iyer ixgbe->unicst_total = hw->mac.num_rar_entries;
3179da14cebeSEric Cheng ixgbe->unicst_avail = ixgbe->unicst_total;
3180da14cebeSEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3181da14cebeSEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr;
3182da14cebeSEric Cheng bzero(mac_addr, ETHERADDRL);
3183afac708dSToomas Soome (void) ixgbe_set_rar(hw, slot, mac_addr, 0, 0);
31849da57d7bSbt ixgbe->unicst_addr[slot].mac.set = 0;
3185da14cebeSEric Cheng }
31869da57d7bSbt ixgbe->unicst_init = B_TRUE;
31879da57d7bSbt } else {
31889da57d7bSbt /* Re-configure the RAR registers */
3189da14cebeSEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3190da14cebeSEric Cheng mac_addr = ixgbe->unicst_addr[slot].mac.addr;
3191da14cebeSEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 1) {
3192da14cebeSEric Cheng (void) ixgbe_set_rar(hw, slot, mac_addr,
31930dc2366fSVenugopal Iyer ixgbe->unicst_addr[slot].mac.group_index,
31940dc2366fSVenugopal Iyer IXGBE_RAH_AV);
3195da14cebeSEric Cheng } else {
3196da14cebeSEric Cheng bzero(mac_addr, ETHERADDRL);
3197afac708dSToomas Soome (void) ixgbe_set_rar(hw, slot, mac_addr, 0, 0);
3198da14cebeSEric Cheng }
3199da14cebeSEric Cheng }
32009da57d7bSbt }
32019da57d7bSbt }
3202da14cebeSEric Cheng
3203da14cebeSEric Cheng /*
3204da14cebeSEric Cheng * ixgbe_unicst_find - Find the slot for the specified unicast address
3205da14cebeSEric Cheng */
3206da14cebeSEric Cheng int
ixgbe_unicst_find(ixgbe_t * ixgbe,const uint8_t * mac_addr)3207da14cebeSEric Cheng ixgbe_unicst_find(ixgbe_t *ixgbe, const uint8_t *mac_addr)
3208da14cebeSEric Cheng {
3209da14cebeSEric Cheng int slot;
3210da14cebeSEric Cheng
3211da14cebeSEric Cheng ASSERT(mutex_owned(&ixgbe->gen_lock));
3212da14cebeSEric Cheng
3213da14cebeSEric Cheng for (slot = 0; slot < ixgbe->unicst_total; slot++) {
3214da14cebeSEric Cheng if (bcmp(ixgbe->unicst_addr[slot].mac.addr,
3215da14cebeSEric Cheng mac_addr, ETHERADDRL) == 0)
3216da14cebeSEric Cheng return (slot);
3217da14cebeSEric Cheng }
3218da14cebeSEric Cheng
3219da14cebeSEric Cheng return (-1);
3220da14cebeSEric Cheng }
3221da14cebeSEric Cheng
322284de666eSRyan Zezeski /*
322384de666eSRyan Zezeski * Restore the HW state to match the SW state during restart.
322484de666eSRyan Zezeski */
322584de666eSRyan Zezeski static int
ixgbe_init_vlan(ixgbe_t * ixgbe)322684de666eSRyan Zezeski ixgbe_init_vlan(ixgbe_t *ixgbe)
322784de666eSRyan Zezeski {
322884de666eSRyan Zezeski /*
322984de666eSRyan Zezeski * The device is starting for the first time; there is nothing
323084de666eSRyan Zezeski * to do.
323184de666eSRyan Zezeski */
323284de666eSRyan Zezeski if (!ixgbe->vlft_init) {
323384de666eSRyan Zezeski ixgbe->vlft_init = B_TRUE;
323484de666eSRyan Zezeski return (IXGBE_SUCCESS);
323584de666eSRyan Zezeski }
323684de666eSRyan Zezeski
323784de666eSRyan Zezeski for (uint_t i = 0; i < ixgbe->num_rx_groups; i++) {
323884de666eSRyan Zezeski int ret;
323984de666eSRyan Zezeski boolean_t vlvf_bypass;
324084de666eSRyan Zezeski ixgbe_rx_group_t *rxg = &ixgbe->rx_groups[i];
324184de666eSRyan Zezeski struct ixgbe_hw *hw = &ixgbe->hw;
324284de666eSRyan Zezeski
324384de666eSRyan Zezeski if (rxg->aupe) {
324484de666eSRyan Zezeski uint32_t vml2flt;
324584de666eSRyan Zezeski
324684de666eSRyan Zezeski vml2flt = IXGBE_READ_REG(hw, IXGBE_VMOLR(rxg->index));
324784de666eSRyan Zezeski vml2flt |= IXGBE_VMOLR_AUPE;
324884de666eSRyan Zezeski IXGBE_WRITE_REG(hw, IXGBE_VMOLR(rxg->index), vml2flt);
324984de666eSRyan Zezeski }
325084de666eSRyan Zezeski
325184de666eSRyan Zezeski vlvf_bypass = (rxg->index == ixgbe->rx_def_group);
325284de666eSRyan Zezeski for (ixgbe_vlan_t *vlp = list_head(&rxg->vlans); vlp != NULL;
325384de666eSRyan Zezeski vlp = list_next(&rxg->vlans, vlp)) {
325484de666eSRyan Zezeski ret = ixgbe_set_vfta(hw, vlp->ixvl_vid, rxg->index,
325584de666eSRyan Zezeski B_TRUE, vlvf_bypass);
325684de666eSRyan Zezeski
325784de666eSRyan Zezeski if (ret != IXGBE_SUCCESS) {
325884de666eSRyan Zezeski ixgbe_error(ixgbe, "Failed to program VFTA"
325984de666eSRyan Zezeski " for group %u, VID: %u, ret: %d.",
326084de666eSRyan Zezeski rxg->index, vlp->ixvl_vid, ret);
326184de666eSRyan Zezeski return (IXGBE_FAILURE);
326284de666eSRyan Zezeski }
326384de666eSRyan Zezeski }
326484de666eSRyan Zezeski }
326584de666eSRyan Zezeski
326684de666eSRyan Zezeski return (IXGBE_SUCCESS);
326784de666eSRyan Zezeski }
326884de666eSRyan Zezeski
32699da57d7bSbt /*
32709da57d7bSbt * ixgbe_multicst_add - Add a multicst address.
32719da57d7bSbt */
32729da57d7bSbt int
ixgbe_multicst_add(ixgbe_t * ixgbe,const uint8_t * multiaddr)32739da57d7bSbt ixgbe_multicst_add(ixgbe_t *ixgbe, const uint8_t *multiaddr)
32749da57d7bSbt {
32759da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
32769da57d7bSbt
32779da57d7bSbt if ((multiaddr[0] & 01) == 0) {
32789da57d7bSbt return (EINVAL);
32799da57d7bSbt }
32809da57d7bSbt
32819da57d7bSbt if (ixgbe->mcast_count >= MAX_NUM_MULTICAST_ADDRESSES) {
32829da57d7bSbt return (ENOENT);
32839da57d7bSbt }
32849da57d7bSbt
32859da57d7bSbt bcopy(multiaddr,
32869da57d7bSbt &ixgbe->mcast_table[ixgbe->mcast_count], ETHERADDRL);
32879da57d7bSbt ixgbe->mcast_count++;
32889da57d7bSbt
32899da57d7bSbt /*
32909da57d7bSbt * Update the multicast table in the hardware
32919da57d7bSbt */
32929da57d7bSbt ixgbe_setup_multicst(ixgbe);
32939da57d7bSbt
32949da57d7bSbt if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
32959da57d7bSbt ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
32969da57d7bSbt return (EIO);
32979da57d7bSbt }
32989da57d7bSbt
32999da57d7bSbt return (0);
33009da57d7bSbt }
33019da57d7bSbt
33029da57d7bSbt /*
33039da57d7bSbt * ixgbe_multicst_remove - Remove a multicst address.
33049da57d7bSbt */
33059da57d7bSbt int
ixgbe_multicst_remove(ixgbe_t * ixgbe,const uint8_t * multiaddr)33069da57d7bSbt ixgbe_multicst_remove(ixgbe_t *ixgbe, const uint8_t *multiaddr)
33079da57d7bSbt {
33089da57d7bSbt int i;
33099da57d7bSbt
33109da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
33119da57d7bSbt
33129da57d7bSbt for (i = 0; i < ixgbe->mcast_count; i++) {
33139da57d7bSbt if (bcmp(multiaddr, &ixgbe->mcast_table[i],
33149da57d7bSbt ETHERADDRL) == 0) {
33159da57d7bSbt for (i++; i < ixgbe->mcast_count; i++) {
33169da57d7bSbt ixgbe->mcast_table[i - 1] =
33179da57d7bSbt ixgbe->mcast_table[i];
33189da57d7bSbt }
33199da57d7bSbt ixgbe->mcast_count--;
33209da57d7bSbt break;
33219da57d7bSbt }
33229da57d7bSbt }
33239da57d7bSbt
33249da57d7bSbt /*
33259da57d7bSbt * Update the multicast table in the hardware
33269da57d7bSbt */
33279da57d7bSbt ixgbe_setup_multicst(ixgbe);
33289da57d7bSbt
33299da57d7bSbt if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
33309da57d7bSbt ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
33319da57d7bSbt return (EIO);
33329da57d7bSbt }
33339da57d7bSbt
33349da57d7bSbt return (0);
33359da57d7bSbt }
33369da57d7bSbt
33379da57d7bSbt /*
33389da57d7bSbt * ixgbe_setup_multicast - Setup multicast data structures.
33399da57d7bSbt *
33409da57d7bSbt * This routine initializes all of the multicast related structures
33419da57d7bSbt * and save them in the hardware registers.
33429da57d7bSbt */
33439da57d7bSbt static void
ixgbe_setup_multicst(ixgbe_t * ixgbe)33449da57d7bSbt ixgbe_setup_multicst(ixgbe_t *ixgbe)
33459da57d7bSbt {
33469da57d7bSbt uint8_t *mc_addr_list;
33479da57d7bSbt uint32_t mc_addr_count;
33489da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
33499da57d7bSbt
33509da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
33519da57d7bSbt
33529da57d7bSbt ASSERT(ixgbe->mcast_count <= MAX_NUM_MULTICAST_ADDRESSES);
33539da57d7bSbt
33549da57d7bSbt mc_addr_list = (uint8_t *)ixgbe->mcast_table;
33559da57d7bSbt mc_addr_count = ixgbe->mcast_count;
33569da57d7bSbt
33579da57d7bSbt /*
33589da57d7bSbt * Update the multicast addresses to the MTA registers
33599da57d7bSbt */
33609da57d7bSbt (void) ixgbe_update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
336169b5a878SDan McDonald ixgbe_mc_table_itr, TRUE);
33629da57d7bSbt }
33639da57d7bSbt
33640dc2366fSVenugopal Iyer /*
33650dc2366fSVenugopal Iyer * ixgbe_setup_vmdq_rss_conf - Configure vmdq and rss (number and mode).
33660dc2366fSVenugopal Iyer *
33670dc2366fSVenugopal Iyer * Configure the rx classification mode (vmdq & rss) and vmdq & rss numbers.
33680dc2366fSVenugopal Iyer * Different chipsets may have different allowed configuration of vmdq and rss.
33690dc2366fSVenugopal Iyer */
33700dc2366fSVenugopal Iyer static void
ixgbe_setup_vmdq_rss_conf(ixgbe_t * ixgbe)33710dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe)
33720dc2366fSVenugopal Iyer {
33730dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw;
33740dc2366fSVenugopal Iyer uint32_t ring_per_group;
33750dc2366fSVenugopal Iyer
33760dc2366fSVenugopal Iyer switch (hw->mac.type) {
33770dc2366fSVenugopal Iyer case ixgbe_mac_82598EB:
33780dc2366fSVenugopal Iyer /*
33790dc2366fSVenugopal Iyer * 82598 supports the following combination:
33800dc2366fSVenugopal Iyer * vmdq no. x rss no.
33810dc2366fSVenugopal Iyer * [5..16] x 1
33820dc2366fSVenugopal Iyer * [1..4] x [1..16]
33830dc2366fSVenugopal Iyer * However 8 rss queue per pool (vmdq) is sufficient for
33840dc2366fSVenugopal Iyer * most cases.
33850dc2366fSVenugopal Iyer */
33860dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
33870dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups > 4) {
33880dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups;
33890dc2366fSVenugopal Iyer } else {
33900dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups *
33910dc2366fSVenugopal Iyer min(8, ring_per_group);
33920dc2366fSVenugopal Iyer }
33930dc2366fSVenugopal Iyer
33940dc2366fSVenugopal Iyer break;
33950dc2366fSVenugopal Iyer
33960dc2366fSVenugopal Iyer case ixgbe_mac_82599EB:
339769b5a878SDan McDonald case ixgbe_mac_X540:
3398dc0cb1cdSDale Ghent case ixgbe_mac_X550:
3399dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
340048ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
34010dc2366fSVenugopal Iyer /*
34020dc2366fSVenugopal Iyer * 82599 supports the following combination:
34030dc2366fSVenugopal Iyer * vmdq no. x rss no.
34040dc2366fSVenugopal Iyer * [33..64] x [1..2]
34050dc2366fSVenugopal Iyer * [2..32] x [1..4]
34060dc2366fSVenugopal Iyer * 1 x [1..16]
34070dc2366fSVenugopal Iyer * However 8 rss queue per pool (vmdq) is sufficient for
34080dc2366fSVenugopal Iyer * most cases.
340969b5a878SDan McDonald *
3410dc0cb1cdSDale Ghent * For now, treat X540 and X550 like the 82599.
34110dc2366fSVenugopal Iyer */
34120dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
34130dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups == 1) {
34140dc2366fSVenugopal Iyer ixgbe->num_rx_rings = min(8, ring_per_group);
34150dc2366fSVenugopal Iyer } else if (ixgbe->num_rx_groups <= 32) {
34160dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups *
34170dc2366fSVenugopal Iyer min(4, ring_per_group);
34180dc2366fSVenugopal Iyer } else if (ixgbe->num_rx_groups <= 64) {
34190dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups *
34200dc2366fSVenugopal Iyer min(2, ring_per_group);
34210dc2366fSVenugopal Iyer }
34220dc2366fSVenugopal Iyer break;
34230dc2366fSVenugopal Iyer
34240dc2366fSVenugopal Iyer default:
34250dc2366fSVenugopal Iyer break;
34260dc2366fSVenugopal Iyer }
34270dc2366fSVenugopal Iyer
34280dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
34290dc2366fSVenugopal Iyer
34300dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups == 1 && ring_per_group == 1) {
34310dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
34320dc2366fSVenugopal Iyer } else if (ixgbe->num_rx_groups != 1 && ring_per_group == 1) {
34330dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ;
34340dc2366fSVenugopal Iyer } else if (ixgbe->num_rx_groups != 1 && ring_per_group != 1) {
34350dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_VMDQ_RSS;
34360dc2366fSVenugopal Iyer } else {
34370dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_RSS;
34380dc2366fSVenugopal Iyer }
34390dc2366fSVenugopal Iyer
344019843f01SPaul Guo IXGBE_DEBUGLOG_2(ixgbe, "rx group number:%d, rx ring number:%d",
34410dc2366fSVenugopal Iyer ixgbe->num_rx_groups, ixgbe->num_rx_rings);
34420dc2366fSVenugopal Iyer }
34430dc2366fSVenugopal Iyer
34449da57d7bSbt /*
34459da57d7bSbt * ixgbe_get_conf - Get driver configurations set in driver.conf.
34469da57d7bSbt *
34479da57d7bSbt * This routine gets user-configured values out of the configuration
34489da57d7bSbt * file ixgbe.conf.
34499da57d7bSbt *
34509da57d7bSbt * For each configurable value, there is a minimum, a maximum, and a
34519da57d7bSbt * default.
34529da57d7bSbt * If user does not configure a value, use the default.
34539da57d7bSbt * If user configures below the minimum, use the minumum.
34549da57d7bSbt * If user configures above the maximum, use the maxumum.
34559da57d7bSbt */
34569da57d7bSbt static void
ixgbe_get_conf(ixgbe_t * ixgbe)34579da57d7bSbt ixgbe_get_conf(ixgbe_t *ixgbe)
34589da57d7bSbt {
34599da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
34609da57d7bSbt uint32_t flow_control;
34619da57d7bSbt
34629da57d7bSbt /*
34639da57d7bSbt * ixgbe driver supports the following user configurations:
34649da57d7bSbt *
34659da57d7bSbt * Jumbo frame configuration:
34669da57d7bSbt * default_mtu
34679da57d7bSbt *
34689da57d7bSbt * Ethernet flow control configuration:
34699da57d7bSbt * flow_control
34709da57d7bSbt *
34719da57d7bSbt * Multiple rings configurations:
34729da57d7bSbt * tx_queue_number
34739da57d7bSbt * tx_ring_size
34749da57d7bSbt * rx_queue_number
34759da57d7bSbt * rx_ring_size
34769da57d7bSbt *
34779da57d7bSbt * Call ixgbe_get_prop() to get the value for a specific
34789da57d7bSbt * configuration parameter.
34799da57d7bSbt */
34809da57d7bSbt
34819da57d7bSbt /*
34829da57d7bSbt * Jumbo frame configuration - max_frame_size controls host buffer
34839da57d7bSbt * allocation, so includes MTU, ethernet header, vlan tag and
34849da57d7bSbt * frame check sequence.
34859da57d7bSbt */
34869da57d7bSbt ixgbe->default_mtu = ixgbe_get_prop(ixgbe, PROP_DEFAULT_MTU,
34871fedc51fSWinson Wang - Sun Microsystems - Beijing China MIN_MTU, ixgbe->capab->max_mtu, DEFAULT_MTU);
34889da57d7bSbt
34899da57d7bSbt ixgbe->max_frame_size = ixgbe->default_mtu +
34909da57d7bSbt sizeof (struct ether_vlan_header) + ETHERFCSL;
34919da57d7bSbt
34929da57d7bSbt /*
34939da57d7bSbt * Ethernet flow control configuration
34949da57d7bSbt */
34959da57d7bSbt flow_control = ixgbe_get_prop(ixgbe, PROP_FLOW_CONTROL,
3496da14cebeSEric Cheng ixgbe_fc_none, 3, ixgbe_fc_none);
34979da57d7bSbt if (flow_control == 3)
34989da57d7bSbt flow_control = ixgbe_fc_default;
34999da57d7bSbt
350073cd555cSBin Tu - Sun Microsystems - Beijing China /*
350173cd555cSBin Tu - Sun Microsystems - Beijing China * fc.requested mode is what the user requests. After autoneg,
350273cd555cSBin Tu - Sun Microsystems - Beijing China * fc.current_mode will be the flow_control mode that was negotiated.
350373cd555cSBin Tu - Sun Microsystems - Beijing China */
350473cd555cSBin Tu - Sun Microsystems - Beijing China hw->fc.requested_mode = flow_control;
35059da57d7bSbt
35069da57d7bSbt /*
35079da57d7bSbt * Multiple rings configurations
35089da57d7bSbt */
35099da57d7bSbt ixgbe->num_tx_rings = ixgbe_get_prop(ixgbe, PROP_TX_QUEUE_NUM,
351013740cb2SPaul Guo ixgbe->capab->min_tx_que_num,
351113740cb2SPaul Guo ixgbe->capab->max_tx_que_num,
351213740cb2SPaul Guo ixgbe->capab->def_tx_que_num);
35139da57d7bSbt ixgbe->tx_ring_size = ixgbe_get_prop(ixgbe, PROP_TX_RING_SIZE,
35149da57d7bSbt MIN_TX_RING_SIZE, MAX_TX_RING_SIZE, DEFAULT_TX_RING_SIZE);
35159da57d7bSbt
35169da57d7bSbt ixgbe->num_rx_rings = ixgbe_get_prop(ixgbe, PROP_RX_QUEUE_NUM,
351713740cb2SPaul Guo ixgbe->capab->min_rx_que_num,
351813740cb2SPaul Guo ixgbe->capab->max_rx_que_num,
351913740cb2SPaul Guo ixgbe->capab->def_rx_que_num);
35209da57d7bSbt ixgbe->rx_ring_size = ixgbe_get_prop(ixgbe, PROP_RX_RING_SIZE,
35219da57d7bSbt MIN_RX_RING_SIZE, MAX_RX_RING_SIZE, DEFAULT_RX_RING_SIZE);
35229da57d7bSbt
3523da14cebeSEric Cheng /*
3524da14cebeSEric Cheng * Multiple groups configuration
3525da14cebeSEric Cheng */
3526da14cebeSEric Cheng ixgbe->num_rx_groups = ixgbe_get_prop(ixgbe, PROP_RX_GROUP_NUM,
35270dc2366fSVenugopal Iyer ixgbe->capab->min_rx_grp_num, ixgbe->capab->max_rx_grp_num,
35280dc2366fSVenugopal Iyer ixgbe->capab->def_rx_grp_num);
3529da14cebeSEric Cheng
3530da14cebeSEric Cheng ixgbe->mr_enable = ixgbe_get_prop(ixgbe, PROP_MR_ENABLE,
3531da14cebeSEric Cheng 0, 1, DEFAULT_MR_ENABLE);
3532da14cebeSEric Cheng
3533da14cebeSEric Cheng if (ixgbe->mr_enable == B_FALSE) {
3534da14cebeSEric Cheng ixgbe->num_tx_rings = 1;
3535da14cebeSEric Cheng ixgbe->num_rx_rings = 1;
3536da14cebeSEric Cheng ixgbe->num_rx_groups = 1;
35370dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
35380dc2366fSVenugopal Iyer } else {
35390dc2366fSVenugopal Iyer ixgbe->num_rx_rings = ixgbe->num_rx_groups *
35400dc2366fSVenugopal Iyer max(ixgbe->num_rx_rings / ixgbe->num_rx_groups, 1);
35410dc2366fSVenugopal Iyer /*
35420dc2366fSVenugopal Iyer * The combination of num_rx_rings and num_rx_groups
35430dc2366fSVenugopal Iyer * may be not supported by h/w. We need to adjust
35440dc2366fSVenugopal Iyer * them to appropriate values.
35450dc2366fSVenugopal Iyer */
35460dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss_conf(ixgbe);
3547da14cebeSEric Cheng }
3548da14cebeSEric Cheng
35499da57d7bSbt /*
35509da57d7bSbt * Tunable used to force an interrupt type. The only use is
35519da57d7bSbt * for testing of the lesser interrupt types.
35529da57d7bSbt * 0 = don't force interrupt type
3553da14cebeSEric Cheng * 1 = force interrupt type MSI-X
35549da57d7bSbt * 2 = force interrupt type MSI
35559da57d7bSbt * 3 = force interrupt type Legacy
35569da57d7bSbt */
35579da57d7bSbt ixgbe->intr_force = ixgbe_get_prop(ixgbe, PROP_INTR_FORCE,
35589da57d7bSbt IXGBE_INTR_NONE, IXGBE_INTR_LEGACY, IXGBE_INTR_NONE);
35599da57d7bSbt
35609da57d7bSbt ixgbe->tx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_TX_HCKSUM_ENABLE,
3561c971fb7eSgg 0, 1, DEFAULT_TX_HCKSUM_ENABLE);
35629da57d7bSbt ixgbe->rx_hcksum_enable = ixgbe_get_prop(ixgbe, PROP_RX_HCKSUM_ENABLE,
3563c971fb7eSgg 0, 1, DEFAULT_RX_HCKSUM_ENABLE);
35649da57d7bSbt ixgbe->lso_enable = ixgbe_get_prop(ixgbe, PROP_LSO_ENABLE,
3565c971fb7eSgg 0, 1, DEFAULT_LSO_ENABLE);
3566ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe->lro_enable = ixgbe_get_prop(ixgbe, PROP_LRO_ENABLE,
3567ffd8e883SWinson Wang - Sun Microsystems - Beijing China 0, 1, DEFAULT_LRO_ENABLE);
35689da57d7bSbt ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE,
3569c971fb7eSgg 0, 1, DEFAULT_TX_HEAD_WB_ENABLE);
35705b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->relax_order_enable = ixgbe_get_prop(ixgbe,
35715b6dd21fSchenlu chen - Sun Microsystems - Beijing China PROP_RELAX_ORDER_ENABLE, 0, 1, DEFAULT_RELAX_ORDER_ENABLE);
3572c971fb7eSgg
3573dc0cb1cdSDale Ghent /* Head Write Back not recommended for 82599, X540 and X550 */
357469b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82599EB ||
3575dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X540 ||
3576dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X550 ||
357748ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_x ||
357848ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_a) {
357973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->tx_head_wb_enable = B_FALSE;
358073cd555cSBin Tu - Sun Microsystems - Beijing China }
358173cd555cSBin Tu - Sun Microsystems - Beijing China
3582c971fb7eSgg /*
3583c971fb7eSgg * ixgbe LSO needs the tx h/w checksum support.
3584c971fb7eSgg * LSO will be disabled if tx h/w checksum is not
3585c971fb7eSgg * enabled.
3586c971fb7eSgg */
3587c971fb7eSgg if (ixgbe->tx_hcksum_enable == B_FALSE) {
3588c971fb7eSgg ixgbe->lso_enable = B_FALSE;
3589c971fb7eSgg }
35909da57d7bSbt
3591ffd8e883SWinson Wang - Sun Microsystems - Beijing China /*
3592ffd8e883SWinson Wang - Sun Microsystems - Beijing China * ixgbe LRO needs the rx h/w checksum support.
3593ffd8e883SWinson Wang - Sun Microsystems - Beijing China * LRO will be disabled if rx h/w checksum is not
3594ffd8e883SWinson Wang - Sun Microsystems - Beijing China * enabled.
3595ffd8e883SWinson Wang - Sun Microsystems - Beijing China */
3596ffd8e883SWinson Wang - Sun Microsystems - Beijing China if (ixgbe->rx_hcksum_enable == B_FALSE) {
3597ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe->lro_enable = B_FALSE;
3598ffd8e883SWinson Wang - Sun Microsystems - Beijing China }
3599ffd8e883SWinson Wang - Sun Microsystems - Beijing China
3600ffd8e883SWinson Wang - Sun Microsystems - Beijing China /*
3601dc0cb1cdSDale Ghent * ixgbe LRO only supported by 82599, X540 and X550
3602ffd8e883SWinson Wang - Sun Microsystems - Beijing China */
360369b5a878SDan McDonald if (hw->mac.type == ixgbe_mac_82598EB) {
3604ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe->lro_enable = B_FALSE;
3605ffd8e883SWinson Wang - Sun Microsystems - Beijing China }
36069da57d7bSbt ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD,
36079da57d7bSbt MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD,
36089da57d7bSbt DEFAULT_TX_COPY_THRESHOLD);
36099da57d7bSbt ixgbe->tx_recycle_thresh = ixgbe_get_prop(ixgbe,
36109da57d7bSbt PROP_TX_RECYCLE_THRESHOLD, MIN_TX_RECYCLE_THRESHOLD,
36119da57d7bSbt MAX_TX_RECYCLE_THRESHOLD, DEFAULT_TX_RECYCLE_THRESHOLD);
36129da57d7bSbt ixgbe->tx_overload_thresh = ixgbe_get_prop(ixgbe,
36139da57d7bSbt PROP_TX_OVERLOAD_THRESHOLD, MIN_TX_OVERLOAD_THRESHOLD,
36149da57d7bSbt MAX_TX_OVERLOAD_THRESHOLD, DEFAULT_TX_OVERLOAD_THRESHOLD);
36159da57d7bSbt ixgbe->tx_resched_thresh = ixgbe_get_prop(ixgbe,
36169da57d7bSbt PROP_TX_RESCHED_THRESHOLD, MIN_TX_RESCHED_THRESHOLD,
36179da57d7bSbt MAX_TX_RESCHED_THRESHOLD, DEFAULT_TX_RESCHED_THRESHOLD);
36189da57d7bSbt
36199da57d7bSbt ixgbe->rx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_RX_COPY_THRESHOLD,
36209da57d7bSbt MIN_RX_COPY_THRESHOLD, MAX_RX_COPY_THRESHOLD,
36219da57d7bSbt DEFAULT_RX_COPY_THRESHOLD);
36229da57d7bSbt ixgbe->rx_limit_per_intr = ixgbe_get_prop(ixgbe, PROP_RX_LIMIT_PER_INTR,
36239da57d7bSbt MIN_RX_LIMIT_PER_INTR, MAX_RX_LIMIT_PER_INTR,
36249da57d7bSbt DEFAULT_RX_LIMIT_PER_INTR);
36259da57d7bSbt
3626ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING,
3627ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->min_intr_throttle,
3628ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->max_intr_throttle,
3629ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->capab->def_intr_throttle);
363073cd555cSBin Tu - Sun Microsystems - Beijing China /*
3631dc0cb1cdSDale Ghent * 82599, X540 and X550 require the interrupt throttling rate is
3632dc0cb1cdSDale Ghent * a multiple of 8. This is enforced by the register definiton.
363373cd555cSBin Tu - Sun Microsystems - Beijing China */
3634dc0cb1cdSDale Ghent if (hw->mac.type == ixgbe_mac_82599EB ||
3635dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X540 ||
3636dc0cb1cdSDale Ghent hw->mac.type == ixgbe_mac_X550 ||
363748ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_x ||
363848ed61a7SRobert Mustacchi hw->mac.type == ixgbe_mac_X550EM_a)
3639ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8;
364043fab1a9SSaso Kiselkov
364143fab1a9SSaso Kiselkov hw->allow_unsupported_sfp = ixgbe_get_prop(ixgbe,
364243fab1a9SSaso Kiselkov PROP_ALLOW_UNSUPPORTED_SFP, 0, 1, DEFAULT_ALLOW_UNSUPPORTED_SFP);
3643ea65739eSchenlu chen - Sun Microsystems - Beijing China }
3644185c5677SPaul Guo
3645ea65739eSchenlu chen - Sun Microsystems - Beijing China static void
ixgbe_init_params(ixgbe_t * ixgbe)3646ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_init_params(ixgbe_t *ixgbe)
3647ea65739eSchenlu chen - Sun Microsystems - Beijing China {
3648dc0cb1cdSDale Ghent struct ixgbe_hw *hw = &ixgbe->hw;
3649dc0cb1cdSDale Ghent ixgbe_link_speed speeds_supported = 0;
3650dc0cb1cdSDale Ghent boolean_t negotiate;
3651dc0cb1cdSDale Ghent
3652dc0cb1cdSDale Ghent /*
3653dc0cb1cdSDale Ghent * Get a list of speeds the adapter supports. If the hw struct hasn't
3654dc0cb1cdSDale Ghent * been populated with this information yet, retrieve it from the
3655dc0cb1cdSDale Ghent * adapter and save it to our own variable.
3656dc0cb1cdSDale Ghent *
3657dc0cb1cdSDale Ghent * On certain adapters, such as ones which use SFPs, the contents of
3658dc0cb1cdSDale Ghent * hw->phy.speeds_supported (and hw->phy.autoneg_advertised) are not
3659dc0cb1cdSDale Ghent * updated, so we must rely on calling ixgbe_get_link_capabilities()
3660dc0cb1cdSDale Ghent * in order to ascertain the speeds which we are capable of supporting,
3661dc0cb1cdSDale Ghent * and in the case of SFP-equipped adapters, which speed we are
3662dc0cb1cdSDale Ghent * advertising. If ixgbe_get_link_capabilities() fails for some reason,
3663dc0cb1cdSDale Ghent * we'll go with a default list of speeds as a last resort.
3664dc0cb1cdSDale Ghent */
3665dc0cb1cdSDale Ghent speeds_supported = hw->phy.speeds_supported;
3666dc0cb1cdSDale Ghent
3667dc0cb1cdSDale Ghent if (speeds_supported == 0) {
3668dc0cb1cdSDale Ghent if (ixgbe_get_link_capabilities(hw, &speeds_supported,
3669dc0cb1cdSDale Ghent &negotiate) != IXGBE_SUCCESS) {
3670dc0cb1cdSDale Ghent if (hw->mac.type == ixgbe_mac_82598EB) {
3671dc0cb1cdSDale Ghent speeds_supported =
3672dc0cb1cdSDale Ghent IXGBE_LINK_SPEED_82598_AUTONEG;
3673dc0cb1cdSDale Ghent } else {
3674dc0cb1cdSDale Ghent speeds_supported =
3675dc0cb1cdSDale Ghent IXGBE_LINK_SPEED_82599_AUTONEG;
3676dc0cb1cdSDale Ghent }
3677dc0cb1cdSDale Ghent }
3678dc0cb1cdSDale Ghent }
3679dc0cb1cdSDale Ghent ixgbe->speeds_supported = speeds_supported;
3680dc0cb1cdSDale Ghent
3681dc0cb1cdSDale Ghent /*
3682dc0cb1cdSDale Ghent * By default, all supported speeds are enabled and advertised.
3683dc0cb1cdSDale Ghent */
3684dc0cb1cdSDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_10GB_FULL) {
3685dc0cb1cdSDale Ghent ixgbe->param_en_10000fdx_cap = 1;
3686dc0cb1cdSDale Ghent ixgbe->param_adv_10000fdx_cap = 1;
3687dc0cb1cdSDale Ghent } else {
3688dc0cb1cdSDale Ghent ixgbe->param_en_10000fdx_cap = 0;
3689dc0cb1cdSDale Ghent ixgbe->param_adv_10000fdx_cap = 0;
3690dc0cb1cdSDale Ghent }
3691dc0cb1cdSDale Ghent
3692dc0cb1cdSDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_5GB_FULL) {
3693dc0cb1cdSDale Ghent ixgbe->param_en_5000fdx_cap = 1;
3694dc0cb1cdSDale Ghent ixgbe->param_adv_5000fdx_cap = 1;
3695dc0cb1cdSDale Ghent } else {
3696dc0cb1cdSDale Ghent ixgbe->param_en_5000fdx_cap = 0;
3697dc0cb1cdSDale Ghent ixgbe->param_adv_5000fdx_cap = 0;
3698dc0cb1cdSDale Ghent }
3699dc0cb1cdSDale Ghent
3700dc0cb1cdSDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_2_5GB_FULL) {
3701dc0cb1cdSDale Ghent ixgbe->param_en_2500fdx_cap = 1;
3702dc0cb1cdSDale Ghent ixgbe->param_adv_2500fdx_cap = 1;
3703dc0cb1cdSDale Ghent } else {
3704dc0cb1cdSDale Ghent ixgbe->param_en_2500fdx_cap = 0;
3705dc0cb1cdSDale Ghent ixgbe->param_adv_2500fdx_cap = 0;
3706dc0cb1cdSDale Ghent }
3707dc0cb1cdSDale Ghent
3708dc0cb1cdSDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_1GB_FULL) {
3709dc0cb1cdSDale Ghent ixgbe->param_en_1000fdx_cap = 1;
3710dc0cb1cdSDale Ghent ixgbe->param_adv_1000fdx_cap = 1;
3711dc0cb1cdSDale Ghent } else {
3712dc0cb1cdSDale Ghent ixgbe->param_en_1000fdx_cap = 0;
3713dc0cb1cdSDale Ghent ixgbe->param_adv_1000fdx_cap = 0;
3714dc0cb1cdSDale Ghent }
3715dc0cb1cdSDale Ghent
3716dc0cb1cdSDale Ghent if (speeds_supported & IXGBE_LINK_SPEED_100_FULL) {
3717dc0cb1cdSDale Ghent ixgbe->param_en_100fdx_cap = 1;
3718dc0cb1cdSDale Ghent ixgbe->param_adv_100fdx_cap = 1;
3719dc0cb1cdSDale Ghent } else {
3720dc0cb1cdSDale Ghent ixgbe->param_en_100fdx_cap = 0;
3721dc0cb1cdSDale Ghent ixgbe->param_adv_100fdx_cap = 0;
3722dc0cb1cdSDale Ghent }
3723ea65739eSchenlu chen - Sun Microsystems - Beijing China
3724ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_pause_cap = 1;
3725ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_asym_pause_cap = 1;
3726ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_rem_fault = 0;
3727ea65739eSchenlu chen - Sun Microsystems - Beijing China
3728ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_autoneg_cap = 1;
3729ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_pause_cap = 1;
3730ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_asym_pause_cap = 1;
3731ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_adv_rem_fault = 0;
3732ea65739eSchenlu chen - Sun Microsystems - Beijing China
3733ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_10000fdx_cap = 0;
3734dc0cb1cdSDale Ghent ixgbe->param_lp_5000fdx_cap = 0;
3735dc0cb1cdSDale Ghent ixgbe->param_lp_2500fdx_cap = 0;
3736ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_1000fdx_cap = 0;
3737ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_100fdx_cap = 0;
3738ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_autoneg_cap = 0;
3739ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_pause_cap = 0;
3740ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_asym_pause_cap = 0;
3741ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe->param_lp_rem_fault = 0;
37429da57d7bSbt }
37439da57d7bSbt
37449da57d7bSbt /*
37459da57d7bSbt * ixgbe_get_prop - Get a property value out of the configuration file
37469da57d7bSbt * ixgbe.conf.
37479da57d7bSbt *
37489da57d7bSbt * Caller provides the name of the property, a default value, a minimum
37499da57d7bSbt * value, and a maximum value.
37509da57d7bSbt *
37519da57d7bSbt * Return configured value of the property, with default, minimum and
37529da57d7bSbt * maximum properly applied.
37539da57d7bSbt */
37549da57d7bSbt static int
ixgbe_get_prop(ixgbe_t * ixgbe,char * propname,int minval,int maxval,int defval)37559da57d7bSbt ixgbe_get_prop(ixgbe_t *ixgbe,
37569da57d7bSbt char *propname, /* name of the property */
37579da57d7bSbt int minval, /* minimum acceptable value */
37589da57d7bSbt int maxval, /* maximim acceptable value */
37599da57d7bSbt int defval) /* default value */
37609da57d7bSbt {
37619da57d7bSbt int value;
37629da57d7bSbt
37639da57d7bSbt /*
37649da57d7bSbt * Call ddi_prop_get_int() to read the conf settings
37659da57d7bSbt */
37669da57d7bSbt value = ddi_prop_get_int(DDI_DEV_T_ANY, ixgbe->dip,
37679da57d7bSbt DDI_PROP_DONTPASS, propname, defval);
37689da57d7bSbt if (value > maxval)
37699da57d7bSbt value = maxval;
37709da57d7bSbt
37719da57d7bSbt if (value < minval)
37729da57d7bSbt value = minval;
37739da57d7bSbt
37749da57d7bSbt return (value);
37759da57d7bSbt }
37769da57d7bSbt
37779da57d7bSbt /*
37789da57d7bSbt * ixgbe_driver_setup_link - Using the link properties to setup the link.
37799da57d7bSbt */
37809da57d7bSbt int
ixgbe_driver_setup_link(ixgbe_t * ixgbe,boolean_t setup_hw)37819da57d7bSbt ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw)
37829da57d7bSbt {
3783dc0cb1cdSDale Ghent struct ixgbe_hw *hw = &ixgbe->hw;
3784dc0cb1cdSDale Ghent ixgbe_link_speed advertised = 0;
37859da57d7bSbt
37863cfa0eb9Schenlu chen - Sun Microsystems - Beijing China /*
3787dc0cb1cdSDale Ghent * Assemble a list of enabled speeds to auto-negotiate with.
37883cfa0eb9Schenlu chen - Sun Microsystems - Beijing China */
3789dc0cb1cdSDale Ghent if (ixgbe->param_en_10000fdx_cap == 1)
3790dc0cb1cdSDale Ghent advertised |= IXGBE_LINK_SPEED_10GB_FULL;
3791dc0cb1cdSDale Ghent
3792dc0cb1cdSDale Ghent if (ixgbe->param_en_5000fdx_cap == 1)
3793dc0cb1cdSDale Ghent advertised |= IXGBE_LINK_SPEED_5GB_FULL;
3794dc0cb1cdSDale Ghent
3795dc0cb1cdSDale Ghent if (ixgbe->param_en_2500fdx_cap == 1)
3796dc0cb1cdSDale Ghent advertised |= IXGBE_LINK_SPEED_2_5GB_FULL;
37979da57d7bSbt
3798dc0cb1cdSDale Ghent if (ixgbe->param_en_1000fdx_cap == 1)
3799dc0cb1cdSDale Ghent advertised |= IXGBE_LINK_SPEED_1GB_FULL;
38009da57d7bSbt
3801dc0cb1cdSDale Ghent if (ixgbe->param_en_100fdx_cap == 1)
3802dc0cb1cdSDale Ghent advertised |= IXGBE_LINK_SPEED_100_FULL;
38039da57d7bSbt
3804dc0cb1cdSDale Ghent /*
3805dc0cb1cdSDale Ghent * As a last resort, autoneg with a default list of speeds.
3806dc0cb1cdSDale Ghent */
3807dc0cb1cdSDale Ghent if (ixgbe->param_adv_autoneg_cap == 1 && advertised == 0) {
3808dc0cb1cdSDale Ghent ixgbe_notice(ixgbe, "Invalid link settings. Setting link "
3809dc0cb1cdSDale Ghent "to autonegotiate with full capabilities.");
38109da57d7bSbt
3811dc0cb1cdSDale Ghent if (hw->mac.type == ixgbe_mac_82598EB)
3812dc0cb1cdSDale Ghent advertised = IXGBE_LINK_SPEED_82598_AUTONEG;
3813dc0cb1cdSDale Ghent else
3814dc0cb1cdSDale Ghent advertised = IXGBE_LINK_SPEED_82599_AUTONEG;
38159da57d7bSbt }
38169da57d7bSbt
38179da57d7bSbt if (setup_hw) {
3818dc0cb1cdSDale Ghent if (ixgbe_setup_link(&ixgbe->hw, advertised,
3819dc0cb1cdSDale Ghent ixgbe->param_adv_autoneg_cap) != IXGBE_SUCCESS) {
382073cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_notice(ixgbe, "Setup link failed on this "
382173cd555cSBin Tu - Sun Microsystems - Beijing China "device.");
38229da57d7bSbt return (IXGBE_FAILURE);
382373cd555cSBin Tu - Sun Microsystems - Beijing China }
38249da57d7bSbt }
38259da57d7bSbt
38269da57d7bSbt return (IXGBE_SUCCESS);
38279da57d7bSbt }
38289da57d7bSbt
38299da57d7bSbt /*
383062e6e1adSPaul Guo * ixgbe_driver_link_check - Link status processing.
383162e6e1adSPaul Guo *
383262e6e1adSPaul Guo * This function can be called in both kernel context and interrupt context
38339da57d7bSbt */
383413740cb2SPaul Guo static void
ixgbe_driver_link_check(ixgbe_t * ixgbe)383562e6e1adSPaul Guo ixgbe_driver_link_check(ixgbe_t *ixgbe)
38369da57d7bSbt {
38379da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
38389da57d7bSbt ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN;
38399da57d7bSbt boolean_t link_up = B_FALSE;
38409da57d7bSbt boolean_t link_changed = B_FALSE;
38419da57d7bSbt
384262e6e1adSPaul Guo ASSERT(mutex_owned(&ixgbe->gen_lock));
38439da57d7bSbt
3844dc0cb1cdSDale Ghent (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
38459da57d7bSbt if (link_up) {
384662e6e1adSPaul Guo ixgbe->link_check_complete = B_TRUE;
384762e6e1adSPaul Guo
384873cd555cSBin Tu - Sun Microsystems - Beijing China /* Link is up, enable flow control settings */
384969b5a878SDan McDonald (void) ixgbe_fc_enable(hw);
385073cd555cSBin Tu - Sun Microsystems - Beijing China
38519da57d7bSbt /*
38529da57d7bSbt * The Link is up, check whether it was marked as down earlier
38539da57d7bSbt */
38549da57d7bSbt if (ixgbe->link_state != LINK_STATE_UP) {
38559da57d7bSbt switch (speed) {
385673cd555cSBin Tu - Sun Microsystems - Beijing China case IXGBE_LINK_SPEED_10GB_FULL:
385773cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->link_speed = SPEED_10GB;
385873cd555cSBin Tu - Sun Microsystems - Beijing China break;
3859dc0cb1cdSDale Ghent case IXGBE_LINK_SPEED_5GB_FULL:
3860dc0cb1cdSDale Ghent ixgbe->link_speed = SPEED_5GB;
3861dc0cb1cdSDale Ghent break;
3862dc0cb1cdSDale Ghent case IXGBE_LINK_SPEED_2_5GB_FULL:
3863dc0cb1cdSDale Ghent ixgbe->link_speed = SPEED_2_5GB;
3864dc0cb1cdSDale Ghent break;
386573cd555cSBin Tu - Sun Microsystems - Beijing China case IXGBE_LINK_SPEED_1GB_FULL:
386673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->link_speed = SPEED_1GB;
386773cd555cSBin Tu - Sun Microsystems - Beijing China break;
386873cd555cSBin Tu - Sun Microsystems - Beijing China case IXGBE_LINK_SPEED_100_FULL:
386973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->link_speed = SPEED_100;
38709da57d7bSbt }
38719da57d7bSbt ixgbe->link_duplex = LINK_DUPLEX_FULL;
38729da57d7bSbt ixgbe->link_state = LINK_STATE_UP;
38739da57d7bSbt link_changed = B_TRUE;
38749da57d7bSbt }
38759da57d7bSbt } else {
387662e6e1adSPaul Guo if (ixgbe->link_check_complete == B_TRUE ||
387762e6e1adSPaul Guo (ixgbe->link_check_complete == B_FALSE &&
387862e6e1adSPaul Guo gethrtime() >= ixgbe->link_check_hrtime)) {
387962e6e1adSPaul Guo /*
388062e6e1adSPaul Guo * The link is really down
388162e6e1adSPaul Guo */
388262e6e1adSPaul Guo ixgbe->link_check_complete = B_TRUE;
38839da57d7bSbt
388462e6e1adSPaul Guo if (ixgbe->link_state != LINK_STATE_DOWN) {
388562e6e1adSPaul Guo ixgbe->link_speed = 0;
388662e6e1adSPaul Guo ixgbe->link_duplex = LINK_DUPLEX_UNKNOWN;
388762e6e1adSPaul Guo ixgbe->link_state = LINK_STATE_DOWN;
388862e6e1adSPaul Guo link_changed = B_TRUE;
388962e6e1adSPaul Guo }
38909da57d7bSbt }
38919da57d7bSbt }
38929da57d7bSbt
389362e6e1adSPaul Guo /*
389462e6e1adSPaul Guo * If we are in an interrupt context, need to re-enable the
389562e6e1adSPaul Guo * interrupt, which was automasked
389662e6e1adSPaul Guo */
389762e6e1adSPaul Guo if (servicing_interrupt() != 0) {
389862e6e1adSPaul Guo ixgbe->eims |= IXGBE_EICR_LSC;
389962e6e1adSPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
390062e6e1adSPaul Guo }
390113740cb2SPaul Guo
390213740cb2SPaul Guo if (link_changed) {
390313740cb2SPaul Guo mac_link_update(ixgbe->mac_hdl, ixgbe->link_state);
390413740cb2SPaul Guo }
39059da57d7bSbt }
39069da57d7bSbt
390773cd555cSBin Tu - Sun Microsystems - Beijing China /*
390873cd555cSBin Tu - Sun Microsystems - Beijing China * ixgbe_sfp_check - sfp module processing done in taskq only for 82599.
390973cd555cSBin Tu - Sun Microsystems - Beijing China */
391073cd555cSBin Tu - Sun Microsystems - Beijing China static void
ixgbe_sfp_check(void * arg)391173cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_sfp_check(void *arg)
391273cd555cSBin Tu - Sun Microsystems - Beijing China {
391373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_t *ixgbe = (ixgbe_t *)arg;
391473cd555cSBin Tu - Sun Microsystems - Beijing China uint32_t eicr = ixgbe->eicr;
391573cd555cSBin Tu - Sun Microsystems - Beijing China struct ixgbe_hw *hw = &ixgbe->hw;
391673cd555cSBin Tu - Sun Microsystems - Beijing China
391762e6e1adSPaul Guo mutex_enter(&ixgbe->gen_lock);
391845d3dd98SRobert Mustacchi (void) hw->phy.ops.identify_sfp(hw);
3919dc0cb1cdSDale Ghent if (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) {
392073cd555cSBin Tu - Sun Microsystems - Beijing China /* clear the interrupt */
3921dc0cb1cdSDale Ghent IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
392273cd555cSBin Tu - Sun Microsystems - Beijing China
392373cd555cSBin Tu - Sun Microsystems - Beijing China /* if link up, do multispeed fiber setup */
39243cfa0eb9Schenlu chen - Sun Microsystems - Beijing China (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
3925dc0cb1cdSDale Ghent B_TRUE);
392673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_driver_link_check(ixgbe);
39275b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_get_hw_state(ixgbe);
3928dc0cb1cdSDale Ghent } else if (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)) {
392973cd555cSBin Tu - Sun Microsystems - Beijing China /* clear the interrupt */
3930dc0cb1cdSDale Ghent IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2_BY_MAC(hw));
393173cd555cSBin Tu - Sun Microsystems - Beijing China
393273cd555cSBin Tu - Sun Microsystems - Beijing China /* if link up, do sfp module setup */
393373cd555cSBin Tu - Sun Microsystems - Beijing China (void) hw->mac.ops.setup_sfp(hw);
393473cd555cSBin Tu - Sun Microsystems - Beijing China
393573cd555cSBin Tu - Sun Microsystems - Beijing China /* do multispeed fiber setup */
39363cfa0eb9Schenlu chen - Sun Microsystems - Beijing China (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG,
3937dc0cb1cdSDale Ghent B_TRUE);
393873cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_driver_link_check(ixgbe);
39395b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_get_hw_state(ixgbe);
394073cd555cSBin Tu - Sun Microsystems - Beijing China }
394162e6e1adSPaul Guo mutex_exit(&ixgbe->gen_lock);
39425b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39435b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
39445b6dd21fSchenlu chen - Sun Microsystems - Beijing China * We need to fully re-check the link later.
39455b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
39465b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->link_check_complete = B_FALSE;
39475b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->link_check_hrtime = gethrtime() +
39485b6dd21fSchenlu chen - Sun Microsystems - Beijing China (IXGBE_LINK_UP_TIME * 100000000ULL);
39495b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
39505b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39515b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
39525b6dd21fSchenlu chen - Sun Microsystems - Beijing China * ixgbe_overtemp_check - overtemp module processing done in taskq
39535b6dd21fSchenlu chen - Sun Microsystems - Beijing China *
39545b6dd21fSchenlu chen - Sun Microsystems - Beijing China * This routine will only be called on adapters with temperature sensor.
39555b6dd21fSchenlu chen - Sun Microsystems - Beijing China * The indication of over-temperature can be either SDP0 interrupt or the link
39565b6dd21fSchenlu chen - Sun Microsystems - Beijing China * status change interrupt.
39575b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
39585b6dd21fSchenlu chen - Sun Microsystems - Beijing China static void
ixgbe_overtemp_check(void * arg)39595b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_overtemp_check(void *arg)
39605b6dd21fSchenlu chen - Sun Microsystems - Beijing China {
39615b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_t *ixgbe = (ixgbe_t *)arg;
39625b6dd21fSchenlu chen - Sun Microsystems - Beijing China struct ixgbe_hw *hw = &ixgbe->hw;
39635b6dd21fSchenlu chen - Sun Microsystems - Beijing China uint32_t eicr = ixgbe->eicr;
39645b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_link_speed speed;
39655b6dd21fSchenlu chen - Sun Microsystems - Beijing China boolean_t link_up;
39665b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39675b6dd21fSchenlu chen - Sun Microsystems - Beijing China mutex_enter(&ixgbe->gen_lock);
39685b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39695b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* make sure we know current state of link */
3970dc0cb1cdSDale Ghent (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
39715b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39725b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* check over-temp condition */
3973dc0cb1cdSDale Ghent if (((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) && (!link_up)) ||
39745b6dd21fSchenlu chen - Sun Microsystems - Beijing China (eicr & IXGBE_EICR_LSC)) {
39755b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) {
39765b6dd21fSchenlu chen - Sun Microsystems - Beijing China atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
39775b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39785b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
39795b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Disable the adapter interrupts
39805b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
39815b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_disable_adapter_interrupts(ixgbe);
39825b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39835b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
39845b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Disable Rx/Tx units
39855b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
39865b6dd21fSchenlu chen - Sun Microsystems - Beijing China (void) ixgbe_stop_adapter(hw);
39875b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39885b6dd21fSchenlu chen - Sun Microsystems - Beijing China ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
39895b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe,
39905b6dd21fSchenlu chen - Sun Microsystems - Beijing China "Problem: Network adapter has been stopped "
39915b6dd21fSchenlu chen - Sun Microsystems - Beijing China "because it has overheated");
39925b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe,
39935b6dd21fSchenlu chen - Sun Microsystems - Beijing China "Action: Restart the computer. "
39945b6dd21fSchenlu chen - Sun Microsystems - Beijing China "If the problem persists, power off the system "
39955b6dd21fSchenlu chen - Sun Microsystems - Beijing China "and replace the adapter");
39965b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
39975b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
39985b6dd21fSchenlu chen - Sun Microsystems - Beijing China
39995b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* write to clear the interrupt */
40005b6dd21fSchenlu chen - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
40015b6dd21fSchenlu chen - Sun Microsystems - Beijing China
40025b6dd21fSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock);
400362e6e1adSPaul Guo }
400462e6e1adSPaul Guo
4005dc0cb1cdSDale Ghent /*
4006dc0cb1cdSDale Ghent * ixgbe_phy_check - taskq to process interrupts from an external PHY
4007dc0cb1cdSDale Ghent *
4008dc0cb1cdSDale Ghent * This routine will only be called on adapters with external PHYs
4009dc0cb1cdSDale Ghent * (such as X550) that may be trying to raise our attention to some event.
4010dc0cb1cdSDale Ghent * Currently, this is limited to claiming PHY overtemperature and link status
4011dc0cb1cdSDale Ghent * change (LSC) events, however this may expand to include other things in
4012dc0cb1cdSDale Ghent * future adapters.
4013dc0cb1cdSDale Ghent */
4014dc0cb1cdSDale Ghent static void
ixgbe_phy_check(void * arg)4015dc0cb1cdSDale Ghent ixgbe_phy_check(void *arg)
4016dc0cb1cdSDale Ghent {
4017dc0cb1cdSDale Ghent ixgbe_t *ixgbe = (ixgbe_t *)arg;
4018dc0cb1cdSDale Ghent struct ixgbe_hw *hw = &ixgbe->hw;
4019dc0cb1cdSDale Ghent int rv;
4020dc0cb1cdSDale Ghent
4021dc0cb1cdSDale Ghent mutex_enter(&ixgbe->gen_lock);
4022dc0cb1cdSDale Ghent
4023dc0cb1cdSDale Ghent /*
4024dc0cb1cdSDale Ghent * X550 baseT PHY overtemp and LSC events are handled here.
4025dc0cb1cdSDale Ghent *
4026dc0cb1cdSDale Ghent * If an overtemp event occurs, it will be reflected in the
4027dc0cb1cdSDale Ghent * return value of phy.ops.handle_lasi() and the common code will
4028dc0cb1cdSDale Ghent * automatically power off the baseT PHY. This is our cue to trigger
4029dc0cb1cdSDale Ghent * an FMA event.
4030dc0cb1cdSDale Ghent *
4031dc0cb1cdSDale Ghent * If a link status change event occurs, phy.ops.handle_lasi() will
4032dc0cb1cdSDale Ghent * automatically initiate a link setup between the integrated KR PHY
4033dc0cb1cdSDale Ghent * and the external X557 PHY to ensure that the link speed between
4034dc0cb1cdSDale Ghent * them matches the link speed of the baseT link.
4035dc0cb1cdSDale Ghent */
4036dc0cb1cdSDale Ghent rv = ixgbe_handle_lasi(hw);
4037dc0cb1cdSDale Ghent
4038dc0cb1cdSDale Ghent if (rv == IXGBE_ERR_OVERTEMP) {
4039dc0cb1cdSDale Ghent atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
4040dc0cb1cdSDale Ghent
4041dc0cb1cdSDale Ghent /*
4042dc0cb1cdSDale Ghent * Disable the adapter interrupts
4043dc0cb1cdSDale Ghent */
4044dc0cb1cdSDale Ghent ixgbe_disable_adapter_interrupts(ixgbe);
4045dc0cb1cdSDale Ghent
4046dc0cb1cdSDale Ghent /*
4047dc0cb1cdSDale Ghent * Disable Rx/Tx units
4048dc0cb1cdSDale Ghent */
4049dc0cb1cdSDale Ghent (void) ixgbe_stop_adapter(hw);
4050dc0cb1cdSDale Ghent
4051dc0cb1cdSDale Ghent ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
4052dc0cb1cdSDale Ghent ixgbe_error(ixgbe,
4053dc0cb1cdSDale Ghent "Problem: Network adapter has been stopped due to a "
4054dc0cb1cdSDale Ghent "overtemperature event being detected.");
4055dc0cb1cdSDale Ghent ixgbe_error(ixgbe,
4056dc0cb1cdSDale Ghent "Action: Shut down or restart the computer. If the issue "
4057dc0cb1cdSDale Ghent "persists, please take action in accordance with the "
4058dc0cb1cdSDale Ghent "recommendations from your system vendor.");
4059dc0cb1cdSDale Ghent }
4060dc0cb1cdSDale Ghent
4061dc0cb1cdSDale Ghent mutex_exit(&ixgbe->gen_lock);
4062dc0cb1cdSDale Ghent }
4063dc0cb1cdSDale Ghent
406462e6e1adSPaul Guo /*
406562e6e1adSPaul Guo * ixgbe_link_timer - timer for link status detection
406662e6e1adSPaul Guo */
406762e6e1adSPaul Guo static void
ixgbe_link_timer(void * arg)406862e6e1adSPaul Guo ixgbe_link_timer(void *arg)
406962e6e1adSPaul Guo {
407062e6e1adSPaul Guo ixgbe_t *ixgbe = (ixgbe_t *)arg;
407162e6e1adSPaul Guo
407262e6e1adSPaul Guo mutex_enter(&ixgbe->gen_lock);
407362e6e1adSPaul Guo ixgbe_driver_link_check(ixgbe);
407462e6e1adSPaul Guo mutex_exit(&ixgbe->gen_lock);
407573cd555cSBin Tu - Sun Microsystems - Beijing China }
407673cd555cSBin Tu - Sun Microsystems - Beijing China
40779da57d7bSbt /*
40789da57d7bSbt * ixgbe_local_timer - Driver watchdog function.
40799da57d7bSbt *
408062e6e1adSPaul Guo * This function will handle the transmit stall check and other routines.
40819da57d7bSbt */
40829da57d7bSbt static void
ixgbe_local_timer(void * arg)40839da57d7bSbt ixgbe_local_timer(void *arg)
40849da57d7bSbt {
40859da57d7bSbt ixgbe_t *ixgbe = (ixgbe_t *)arg;
40869da57d7bSbt
40875b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->ixgbe_state & IXGBE_OVERTEMP)
40885b6dd21fSchenlu chen - Sun Microsystems - Beijing China goto out;
40895b6dd21fSchenlu chen - Sun Microsystems - Beijing China
409062e6e1adSPaul Guo if (ixgbe->ixgbe_state & IXGBE_ERROR) {
409162e6e1adSPaul Guo ixgbe->reset_count++;
409262e6e1adSPaul Guo if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
409362e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
40945b6dd21fSchenlu chen - Sun Microsystems - Beijing China goto out;
409562e6e1adSPaul Guo }
409662e6e1adSPaul Guo
40979da57d7bSbt if (ixgbe_stall_check(ixgbe)) {
409862e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STALL);
409973cd555cSBin Tu - Sun Microsystems - Beijing China ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
410062e6e1adSPaul Guo
41019da57d7bSbt ixgbe->reset_count++;
41029da57d7bSbt if (ixgbe_reset(ixgbe) == IXGBE_SUCCESS)
41039da57d7bSbt ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_RESTORED);
41049da57d7bSbt }
4105ffd8e883SWinson Wang - Sun Microsystems - Beijing China
41065b6dd21fSchenlu chen - Sun Microsystems - Beijing China out:
4107ffd8e883SWinson Wang - Sun Microsystems - Beijing China ixgbe_restart_watchdog_timer(ixgbe);
41089da57d7bSbt }
41099da57d7bSbt
41109da57d7bSbt /*
41119da57d7bSbt * ixgbe_stall_check - Check for transmit stall.
41129da57d7bSbt *
41139da57d7bSbt * This function checks if the adapter is stalled (in transmit).
41149da57d7bSbt *
41159da57d7bSbt * It is called each time the watchdog timeout is invoked.
41169da57d7bSbt * If the transmit descriptor reclaim continuously fails,
41179da57d7bSbt * the watchdog value will increment by 1. If the watchdog
41189da57d7bSbt * value exceeds the threshold, the ixgbe is assumed to
41199da57d7bSbt * have stalled and need to be reset.
41209da57d7bSbt */
41219da57d7bSbt static boolean_t
ixgbe_stall_check(ixgbe_t * ixgbe)41229da57d7bSbt ixgbe_stall_check(ixgbe_t *ixgbe)
41239da57d7bSbt {
41249da57d7bSbt ixgbe_tx_ring_t *tx_ring;
41259da57d7bSbt boolean_t result;
41269da57d7bSbt int i;
41279da57d7bSbt
41289da57d7bSbt if (ixgbe->link_state != LINK_STATE_UP)
41299da57d7bSbt return (B_FALSE);
41309da57d7bSbt
41319da57d7bSbt /*
41329da57d7bSbt * If any tx ring is stalled, we'll reset the chipset
41339da57d7bSbt */
41349da57d7bSbt result = B_FALSE;
41359da57d7bSbt for (i = 0; i < ixgbe->num_tx_rings; i++) {
41369da57d7bSbt tx_ring = &ixgbe->tx_rings[i];
4137ea65739eSchenlu chen - Sun Microsystems - Beijing China if (tx_ring->tbd_free <= ixgbe->tx_recycle_thresh) {
4138185c5677SPaul Guo tx_ring->tx_recycle(tx_ring);
4139185c5677SPaul Guo }
41409da57d7bSbt
41419da57d7bSbt if (tx_ring->recycle_fail > 0)
41429da57d7bSbt tx_ring->stall_watchdog++;
41439da57d7bSbt else
41449da57d7bSbt tx_ring->stall_watchdog = 0;
41459da57d7bSbt
41469da57d7bSbt if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) {
41479da57d7bSbt result = B_TRUE;
41489da57d7bSbt break;
41499da57d7bSbt }
41509da57d7bSbt }
41519da57d7bSbt
41529da57d7bSbt if (result) {
41539da57d7bSbt tx_ring->stall_watchdog = 0;
41549da57d7bSbt tx_ring->recycle_fail = 0;
41559da57d7bSbt }
41569da57d7bSbt
41579da57d7bSbt return (result);
41589da57d7bSbt }
41599da57d7bSbt
41609da57d7bSbt
41619da57d7bSbt /*
41629da57d7bSbt * is_valid_mac_addr - Check if the mac address is valid.
41639da57d7bSbt */
41649da57d7bSbt static boolean_t
is_valid_mac_addr(uint8_t * mac_addr)41659da57d7bSbt is_valid_mac_addr(uint8_t *mac_addr)
41669da57d7bSbt {
41679da57d7bSbt const uint8_t addr_test1[6] = { 0, 0, 0, 0, 0, 0 };
41689da57d7bSbt const uint8_t addr_test2[6] =
41699da57d7bSbt { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
41709da57d7bSbt
41719da57d7bSbt if (!(bcmp(addr_test1, mac_addr, ETHERADDRL)) ||
41729da57d7bSbt !(bcmp(addr_test2, mac_addr, ETHERADDRL)))
41739da57d7bSbt return (B_FALSE);
41749da57d7bSbt
41759da57d7bSbt return (B_TRUE);
41769da57d7bSbt }
41779da57d7bSbt
41789da57d7bSbt static boolean_t
ixgbe_find_mac_address(ixgbe_t * ixgbe)41799da57d7bSbt ixgbe_find_mac_address(ixgbe_t *ixgbe)
41809da57d7bSbt {
41819da57d7bSbt #ifdef __sparc
41829da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
41839da57d7bSbt uchar_t *bytes;
41849da57d7bSbt struct ether_addr sysaddr;
41859da57d7bSbt uint_t nelts;
41869da57d7bSbt int err;
41879da57d7bSbt boolean_t found = B_FALSE;
41889da57d7bSbt
41899da57d7bSbt /*
41909da57d7bSbt * The "vendor's factory-set address" may already have
41919da57d7bSbt * been extracted from the chip, but if the property
41929da57d7bSbt * "local-mac-address" is set we use that instead.
41939da57d7bSbt *
41949da57d7bSbt * We check whether it looks like an array of 6
41959da57d7bSbt * bytes (which it should, if OBP set it). If we can't
41969da57d7bSbt * make sense of it this way, we'll ignore it.
41979da57d7bSbt */
41989da57d7bSbt err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
41999da57d7bSbt DDI_PROP_DONTPASS, "local-mac-address", &bytes, &nelts);
42009da57d7bSbt if (err == DDI_PROP_SUCCESS) {
42019da57d7bSbt if (nelts == ETHERADDRL) {
42029da57d7bSbt while (nelts--)
42039da57d7bSbt hw->mac.addr[nelts] = bytes[nelts];
42049da57d7bSbt found = B_TRUE;
42059da57d7bSbt }
42069da57d7bSbt ddi_prop_free(bytes);
42079da57d7bSbt }
42089da57d7bSbt
42099da57d7bSbt /*
42109da57d7bSbt * Look up the OBP property "local-mac-address?". If the user has set
42119da57d7bSbt * 'local-mac-address? = false', use "the system address" instead.
42129da57d7bSbt */
42139da57d7bSbt if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, 0,
42149da57d7bSbt "local-mac-address?", &bytes, &nelts) == DDI_PROP_SUCCESS) {
42159da57d7bSbt if (strncmp("false", (caddr_t)bytes, (size_t)nelts) == 0) {
42169da57d7bSbt if (localetheraddr(NULL, &sysaddr) != 0) {
42179da57d7bSbt bcopy(&sysaddr, hw->mac.addr, ETHERADDRL);
42189da57d7bSbt found = B_TRUE;
42199da57d7bSbt }
42209da57d7bSbt }
42219da57d7bSbt ddi_prop_free(bytes);
42229da57d7bSbt }
42239da57d7bSbt
42249da57d7bSbt /*
42259da57d7bSbt * Finally(!), if there's a valid "mac-address" property (created
42269da57d7bSbt * if we netbooted from this interface), we must use this instead
42279da57d7bSbt * of any of the above to ensure that the NFS/install server doesn't
4228dc0cb1cdSDale Ghent * get confused by the address changing as illumos takes over!
42299da57d7bSbt */
42309da57d7bSbt err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip,
42319da57d7bSbt DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts);
42329da57d7bSbt if (err == DDI_PROP_SUCCESS) {
42339da57d7bSbt if (nelts == ETHERADDRL) {
42349da57d7bSbt while (nelts--)
42359da57d7bSbt hw->mac.addr[nelts] = bytes[nelts];
42369da57d7bSbt found = B_TRUE;
42379da57d7bSbt }
42389da57d7bSbt ddi_prop_free(bytes);
42399da57d7bSbt }
42409da57d7bSbt
42419da57d7bSbt if (found) {
42429da57d7bSbt bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
42439da57d7bSbt return (B_TRUE);
42449da57d7bSbt }
42459da57d7bSbt #else
42469da57d7bSbt _NOTE(ARGUNUSED(ixgbe));
42479da57d7bSbt #endif
42489da57d7bSbt
42499da57d7bSbt return (B_TRUE);
42509da57d7bSbt }
42519da57d7bSbt
42529da57d7bSbt #pragma inline(ixgbe_arm_watchdog_timer)
42539da57d7bSbt static void
ixgbe_arm_watchdog_timer(ixgbe_t * ixgbe)42549da57d7bSbt ixgbe_arm_watchdog_timer(ixgbe_t *ixgbe)
42559da57d7bSbt {
42569da57d7bSbt /*
42579da57d7bSbt * Fire a watchdog timer
42589da57d7bSbt */
42599da57d7bSbt ixgbe->watchdog_tid =
42609da57d7bSbt timeout(ixgbe_local_timer,
42619da57d7bSbt (void *)ixgbe, 1 * drv_usectohz(1000000));
42629da57d7bSbt
42639da57d7bSbt }
42649da57d7bSbt
42659da57d7bSbt /*
42669da57d7bSbt * ixgbe_enable_watchdog_timer - Enable and start the driver watchdog timer.
42679da57d7bSbt */
42689da57d7bSbt void
ixgbe_enable_watchdog_timer(ixgbe_t * ixgbe)42699da57d7bSbt ixgbe_enable_watchdog_timer(ixgbe_t *ixgbe)
42709da57d7bSbt {
42719da57d7bSbt mutex_enter(&ixgbe->watchdog_lock);
42729da57d7bSbt
42739da57d7bSbt if (!ixgbe->watchdog_enable) {
42749da57d7bSbt ixgbe->watchdog_enable = B_TRUE;
42759da57d7bSbt ixgbe->watchdog_start = B_TRUE;
42769da57d7bSbt ixgbe_arm_watchdog_timer(ixgbe);
42779da57d7bSbt }
42789da57d7bSbt
42799da57d7bSbt mutex_exit(&ixgbe->watchdog_lock);
42809da57d7bSbt }
42819da57d7bSbt
42829da57d7bSbt /*
42839da57d7bSbt * ixgbe_disable_watchdog_timer - Disable and stop the driver watchdog timer.
42849da57d7bSbt */
42859da57d7bSbt void
ixgbe_disable_watchdog_timer(ixgbe_t * ixgbe)42869da57d7bSbt ixgbe_disable_watchdog_timer(ixgbe_t *ixgbe)
42879da57d7bSbt {
42889da57d7bSbt timeout_id_t tid;
42899da57d7bSbt
42909da57d7bSbt mutex_enter(&ixgbe->watchdog_lock);
42919da57d7bSbt
42929da57d7bSbt ixgbe->watchdog_enable = B_FALSE;
42939da57d7bSbt ixgbe->watchdog_start = B_FALSE;
42949da57d7bSbt tid = ixgbe->watchdog_tid;
42959da57d7bSbt ixgbe->watchdog_tid = 0;
42969da57d7bSbt
42979da57d7bSbt mutex_exit(&ixgbe->watchdog_lock);
42989da57d7bSbt
42999da57d7bSbt if (tid != 0)
43009da57d7bSbt (void) untimeout(tid);
43019da57d7bSbt }
43029da57d7bSbt
43039da57d7bSbt /*
43049da57d7bSbt * ixgbe_start_watchdog_timer - Start the driver watchdog timer.
43059da57d7bSbt */
430613740cb2SPaul Guo void
ixgbe_start_watchdog_timer(ixgbe_t * ixgbe)43079da57d7bSbt ixgbe_start_watchdog_timer(ixgbe_t *ixgbe)
43089da57d7bSbt {
43099da57d7bSbt mutex_enter(&ixgbe->watchdog_lock);
43109da57d7bSbt
43119da57d7bSbt if (ixgbe->watchdog_enable) {
43129da57d7bSbt if (!ixgbe->watchdog_start) {
43139da57d7bSbt ixgbe->watchdog_start = B_TRUE;
43149da57d7bSbt ixgbe_arm_watchdog_timer(ixgbe);
43159da57d7bSbt }
43169da57d7bSbt }
43179da57d7bSbt
43189da57d7bSbt mutex_exit(&ixgbe->watchdog_lock);
43199da57d7bSbt }
43209da57d7bSbt
43219da57d7bSbt /*
43229da57d7bSbt * ixgbe_restart_watchdog_timer - Restart the driver watchdog timer.
43239da57d7bSbt */
43249da57d7bSbt static void
ixgbe_restart_watchdog_timer(ixgbe_t * ixgbe)43259da57d7bSbt ixgbe_restart_watchdog_timer(ixgbe_t *ixgbe)
43269da57d7bSbt {
43279da57d7bSbt mutex_enter(&ixgbe->watchdog_lock);
43289da57d7bSbt
43299da57d7bSbt if (ixgbe->watchdog_start)
43309da57d7bSbt ixgbe_arm_watchdog_timer(ixgbe);
43319da57d7bSbt
43329da57d7bSbt mutex_exit(&ixgbe->watchdog_lock);
43339da57d7bSbt }
43349da57d7bSbt
43359da57d7bSbt /*
43369da57d7bSbt * ixgbe_stop_watchdog_timer - Stop the driver watchdog timer.
43379da57d7bSbt */
433813740cb2SPaul Guo void
ixgbe_stop_watchdog_timer(ixgbe_t * ixgbe)43399da57d7bSbt ixgbe_stop_watchdog_timer(ixgbe_t *ixgbe)
43409da57d7bSbt {
43419da57d7bSbt timeout_id_t tid;
43429da57d7bSbt
43439da57d7bSbt mutex_enter(&ixgbe->watchdog_lock);
43449da57d7bSbt
43459da57d7bSbt ixgbe->watchdog_start = B_FALSE;
43469da57d7bSbt tid = ixgbe->watchdog_tid;
43479da57d7bSbt ixgbe->watchdog_tid = 0;
43489da57d7bSbt
43499da57d7bSbt mutex_exit(&ixgbe->watchdog_lock);
43509da57d7bSbt
43519da57d7bSbt if (tid != 0)
43529da57d7bSbt (void) untimeout(tid);
43539da57d7bSbt }
43549da57d7bSbt
43559da57d7bSbt /*
43569da57d7bSbt * ixgbe_disable_adapter_interrupts - Disable all adapter interrupts.
43579da57d7bSbt */
43589da57d7bSbt static void
ixgbe_disable_adapter_interrupts(ixgbe_t * ixgbe)43599da57d7bSbt ixgbe_disable_adapter_interrupts(ixgbe_t *ixgbe)
43609da57d7bSbt {
43619da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
43629da57d7bSbt
43639da57d7bSbt /*
43649da57d7bSbt * mask all interrupts off
43659da57d7bSbt */
43669da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_EIMC, 0xffffffff);
43679da57d7bSbt
43689da57d7bSbt /*
43699da57d7bSbt * for MSI-X, also disable autoclear
43709da57d7bSbt */
43719da57d7bSbt if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
43729da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_EIAC, 0x0);
43739da57d7bSbt }
43749da57d7bSbt
43759da57d7bSbt IXGBE_WRITE_FLUSH(hw);
43769da57d7bSbt }
43779da57d7bSbt
43789da57d7bSbt /*
43799da57d7bSbt * ixgbe_enable_adapter_interrupts - Enable all hardware interrupts.
43809da57d7bSbt */
43819da57d7bSbt static void
ixgbe_enable_adapter_interrupts(ixgbe_t * ixgbe)43829da57d7bSbt ixgbe_enable_adapter_interrupts(ixgbe_t *ixgbe)
43839da57d7bSbt {
43849da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
438513740cb2SPaul Guo uint32_t eiac, eiam;
438613740cb2SPaul Guo uint32_t gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
438713740cb2SPaul Guo
438813740cb2SPaul Guo /* interrupt types to enable */
438913740cb2SPaul Guo ixgbe->eims = IXGBE_EIMS_ENABLE_MASK; /* shared code default */
439013740cb2SPaul Guo ixgbe->eims &= ~IXGBE_EIMS_TCP_TIMER; /* minus tcp timer */
439113740cb2SPaul Guo ixgbe->eims |= ixgbe->capab->other_intr; /* "other" interrupt types */
43929da57d7bSbt
439313740cb2SPaul Guo /* enable automask on "other" causes that this adapter can generate */
439413740cb2SPaul Guo eiam = ixgbe->capab->other_intr;
43959da57d7bSbt
43969da57d7bSbt /*
43979da57d7bSbt * msi-x mode
43989da57d7bSbt */
43999da57d7bSbt if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX) {
44009da57d7bSbt /* enable autoclear but not on bits 29:20 */
440113740cb2SPaul Guo eiac = (ixgbe->eims & ~IXGBE_OTHER_INTR);
44029da57d7bSbt
44039da57d7bSbt /* general purpose interrupt enable */
440413740cb2SPaul Guo gpie |= (IXGBE_GPIE_MSIX_MODE
440513740cb2SPaul Guo | IXGBE_GPIE_PBA_SUPPORT
440613740cb2SPaul Guo | IXGBE_GPIE_OCD
440713740cb2SPaul Guo | IXGBE_GPIE_EIAME);
44089da57d7bSbt /*
44099da57d7bSbt * non-msi-x mode
44109da57d7bSbt */
44119da57d7bSbt } else {
44129da57d7bSbt
44139da57d7bSbt /* disable autoclear, leave gpie at default */
44149da57d7bSbt eiac = 0;
441513740cb2SPaul Guo
441673cd555cSBin Tu - Sun Microsystems - Beijing China /*
441773cd555cSBin Tu - Sun Microsystems - Beijing China * General purpose interrupt enable.
4418dc0cb1cdSDale Ghent * For 82599, X540 and X550, extended interrupt
4419dc0cb1cdSDale Ghent * automask enable only in MSI or MSI-X mode
442073cd555cSBin Tu - Sun Microsystems - Beijing China */
442169b5a878SDan McDonald if ((hw->mac.type == ixgbe_mac_82598EB) ||
442273cd555cSBin Tu - Sun Microsystems - Beijing China (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) {
442373cd555cSBin Tu - Sun Microsystems - Beijing China gpie |= IXGBE_GPIE_EIAME;
442473cd555cSBin Tu - Sun Microsystems - Beijing China }
442573cd555cSBin Tu - Sun Microsystems - Beijing China }
44265b6dd21fSchenlu chen - Sun Microsystems - Beijing China
44275b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* Enable specific "other" interrupt types */
44285b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) {
44295b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
44305b6dd21fSchenlu chen - Sun Microsystems - Beijing China gpie |= ixgbe->capab->other_gpie;
44315b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
44325b6dd21fSchenlu chen - Sun Microsystems - Beijing China
44335b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
443469b5a878SDan McDonald case ixgbe_mac_X540:
4435dc0cb1cdSDale Ghent case ixgbe_mac_X550:
4436dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
443748ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
44385b6dd21fSchenlu chen - Sun Microsystems - Beijing China gpie |= ixgbe->capab->other_gpie;
44395b6dd21fSchenlu chen - Sun Microsystems - Beijing China
44405b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* Enable RSC Delay 8us when LRO enabled */
44415b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (ixgbe->lro_enable) {
44425b6dd21fSchenlu chen - Sun Microsystems - Beijing China gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT);
44435b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
44445b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
44455b6dd21fSchenlu chen - Sun Microsystems - Beijing China
44465b6dd21fSchenlu chen - Sun Microsystems - Beijing China default:
44475b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
4448ffd8e883SWinson Wang - Sun Microsystems - Beijing China }
44495b6dd21fSchenlu chen - Sun Microsystems - Beijing China
445013740cb2SPaul Guo /* write to interrupt control registers */
445113740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
44529da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_EIAC, eiac);
445313740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIAM, eiam);
44549da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
44559da57d7bSbt IXGBE_WRITE_FLUSH(hw);
44569da57d7bSbt }
44579da57d7bSbt
44589da57d7bSbt /*
44599da57d7bSbt * ixgbe_loopback_ioctl - Loopback support.
44609da57d7bSbt */
44619da57d7bSbt enum ioc_reply
ixgbe_loopback_ioctl(ixgbe_t * ixgbe,struct iocblk * iocp,mblk_t * mp)44629da57d7bSbt ixgbe_loopback_ioctl(ixgbe_t *ixgbe, struct iocblk *iocp, mblk_t *mp)
44639da57d7bSbt {
44649da57d7bSbt lb_info_sz_t *lbsp;
44659da57d7bSbt lb_property_t *lbpp;
44669da57d7bSbt uint32_t *lbmp;
44679da57d7bSbt uint32_t size;
44689da57d7bSbt uint32_t value;
44699da57d7bSbt
44709da57d7bSbt if (mp->b_cont == NULL)
44719da57d7bSbt return (IOC_INVAL);
44729da57d7bSbt
44739da57d7bSbt switch (iocp->ioc_cmd) {
44749da57d7bSbt default:
44759da57d7bSbt return (IOC_INVAL);
44769da57d7bSbt
44779da57d7bSbt case LB_GET_INFO_SIZE:
44789da57d7bSbt size = sizeof (lb_info_sz_t);
44799da57d7bSbt if (iocp->ioc_count != size)
44809da57d7bSbt return (IOC_INVAL);
44819da57d7bSbt
44829da57d7bSbt value = sizeof (lb_normal);
44839da57d7bSbt value += sizeof (lb_mac);
44841fedc51fSWinson Wang - Sun Microsystems - Beijing China value += sizeof (lb_external);
44859da57d7bSbt
44869da57d7bSbt lbsp = (lb_info_sz_t *)(uintptr_t)mp->b_cont->b_rptr;
44879da57d7bSbt *lbsp = value;
44889da57d7bSbt break;
44899da57d7bSbt
44909da57d7bSbt case LB_GET_INFO:
44919da57d7bSbt value = sizeof (lb_normal);
44929da57d7bSbt value += sizeof (lb_mac);
44931fedc51fSWinson Wang - Sun Microsystems - Beijing China value += sizeof (lb_external);
44949da57d7bSbt
44959da57d7bSbt size = value;
44969da57d7bSbt if (iocp->ioc_count != size)
44979da57d7bSbt return (IOC_INVAL);
44989da57d7bSbt
44999da57d7bSbt value = 0;
45009da57d7bSbt lbpp = (lb_property_t *)(uintptr_t)mp->b_cont->b_rptr;
45019da57d7bSbt
45029da57d7bSbt lbpp[value++] = lb_normal;
45039da57d7bSbt lbpp[value++] = lb_mac;
45041fedc51fSWinson Wang - Sun Microsystems - Beijing China lbpp[value++] = lb_external;
45059da57d7bSbt break;
45069da57d7bSbt
45079da57d7bSbt case LB_GET_MODE:
45089da57d7bSbt size = sizeof (uint32_t);
45099da57d7bSbt if (iocp->ioc_count != size)
45109da57d7bSbt return (IOC_INVAL);
45119da57d7bSbt
45129da57d7bSbt lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
45139da57d7bSbt *lbmp = ixgbe->loopback_mode;
45149da57d7bSbt break;
45159da57d7bSbt
45169da57d7bSbt case LB_SET_MODE:
45179da57d7bSbt size = 0;
45189da57d7bSbt if (iocp->ioc_count != sizeof (uint32_t))
45199da57d7bSbt return (IOC_INVAL);
45209da57d7bSbt
45219da57d7bSbt lbmp = (uint32_t *)(uintptr_t)mp->b_cont->b_rptr;
45229da57d7bSbt if (!ixgbe_set_loopback_mode(ixgbe, *lbmp))
45239da57d7bSbt return (IOC_INVAL);
45249da57d7bSbt break;
45259da57d7bSbt }
45269da57d7bSbt
45279da57d7bSbt iocp->ioc_count = size;
45289da57d7bSbt iocp->ioc_error = 0;
45299da57d7bSbt
45309da57d7bSbt if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
45319da57d7bSbt ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
45329da57d7bSbt return (IOC_INVAL);
45339da57d7bSbt }
45349da57d7bSbt
45359da57d7bSbt return (IOC_REPLY);
45369da57d7bSbt }
45379da57d7bSbt
45389da57d7bSbt /*
45399da57d7bSbt * ixgbe_set_loopback_mode - Setup loopback based on the loopback mode.
45409da57d7bSbt */
45419da57d7bSbt static boolean_t
ixgbe_set_loopback_mode(ixgbe_t * ixgbe,uint32_t mode)45429da57d7bSbt ixgbe_set_loopback_mode(ixgbe_t *ixgbe, uint32_t mode)
45439da57d7bSbt {
45449da57d7bSbt if (mode == ixgbe->loopback_mode)
45459da57d7bSbt return (B_TRUE);
45469da57d7bSbt
45479da57d7bSbt ixgbe->loopback_mode = mode;
45489da57d7bSbt
45499da57d7bSbt if (mode == IXGBE_LB_NONE) {
45509da57d7bSbt /*
45519da57d7bSbt * Reset the chip
45529da57d7bSbt */
45539da57d7bSbt (void) ixgbe_reset(ixgbe);
45549da57d7bSbt return (B_TRUE);
45559da57d7bSbt }
45569da57d7bSbt
45579da57d7bSbt mutex_enter(&ixgbe->gen_lock);
45589da57d7bSbt
45599da57d7bSbt switch (mode) {
45609da57d7bSbt default:
45619da57d7bSbt mutex_exit(&ixgbe->gen_lock);
45629da57d7bSbt return (B_FALSE);
45639da57d7bSbt
45641fedc51fSWinson Wang - Sun Microsystems - Beijing China case IXGBE_LB_EXTERNAL:
45651fedc51fSWinson Wang - Sun Microsystems - Beijing China break;
45661fedc51fSWinson Wang - Sun Microsystems - Beijing China
45679da57d7bSbt case IXGBE_LB_INTERNAL_MAC:
45689da57d7bSbt ixgbe_set_internal_mac_loopback(ixgbe);
45699da57d7bSbt break;
45709da57d7bSbt }
45719da57d7bSbt
45729da57d7bSbt mutex_exit(&ixgbe->gen_lock);
45739da57d7bSbt
45749da57d7bSbt return (B_TRUE);
45759da57d7bSbt }
45769da57d7bSbt
45779da57d7bSbt /*
45789da57d7bSbt * ixgbe_set_internal_mac_loopback - Set the internal MAC loopback mode.
45799da57d7bSbt */
45809da57d7bSbt static void
ixgbe_set_internal_mac_loopback(ixgbe_t * ixgbe)45819da57d7bSbt ixgbe_set_internal_mac_loopback(ixgbe_t *ixgbe)
45829da57d7bSbt {
45839da57d7bSbt struct ixgbe_hw *hw;
45849da57d7bSbt uint32_t reg;
45859da57d7bSbt uint8_t atlas;
45869da57d7bSbt
45879da57d7bSbt hw = &ixgbe->hw;
45889da57d7bSbt
45899da57d7bSbt /*
45909da57d7bSbt * Setup MAC loopback
45919da57d7bSbt */
45929da57d7bSbt reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_HLREG0);
45939da57d7bSbt reg |= IXGBE_HLREG0_LPBK;
45949da57d7bSbt IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_HLREG0, reg);
45959da57d7bSbt
45969da57d7bSbt reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
45979da57d7bSbt reg &= ~IXGBE_AUTOC_LMS_MASK;
45989da57d7bSbt IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
45999da57d7bSbt
46009da57d7bSbt /*
46019da57d7bSbt * Disable Atlas Tx lanes to keep packets in loopback and not on wire
46029da57d7bSbt */
46035b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) {
46045b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
46059da57d7bSbt (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
46069da57d7bSbt &atlas);
46079da57d7bSbt atlas |= IXGBE_ATLAS_PDN_TX_REG_EN;
46089da57d7bSbt (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_LPBK,
46099da57d7bSbt atlas);
46109da57d7bSbt
46119da57d7bSbt (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
46129da57d7bSbt &atlas);
46139da57d7bSbt atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
46149da57d7bSbt (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_10G,
46159da57d7bSbt atlas);
46169da57d7bSbt
46179da57d7bSbt (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
46189da57d7bSbt &atlas);
46199da57d7bSbt atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
46209da57d7bSbt (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_1G,
46219da57d7bSbt atlas);
46229da57d7bSbt
46239da57d7bSbt (void) ixgbe_read_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
46249da57d7bSbt &atlas);
46259da57d7bSbt atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
46269da57d7bSbt (void) ixgbe_write_analog_reg8(&ixgbe->hw, IXGBE_ATLAS_PDN_AN,
46279da57d7bSbt atlas);
46285b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
46295b6dd21fSchenlu chen - Sun Microsystems - Beijing China
46305b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
463169b5a878SDan McDonald case ixgbe_mac_X540:
4632dc0cb1cdSDale Ghent case ixgbe_mac_X550:
4633dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
463448ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
463500f1c25aSchenlu chen - Sun Microsystems - Beijing China reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC);
463600f1c25aSchenlu chen - Sun Microsystems - Beijing China reg |= (IXGBE_AUTOC_FLU |
463700f1c25aSchenlu chen - Sun Microsystems - Beijing China IXGBE_AUTOC_10G_KX4);
463800f1c25aSchenlu chen - Sun Microsystems - Beijing China IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg);
463900f1c25aSchenlu chen - Sun Microsystems - Beijing China
464000f1c25aSchenlu chen - Sun Microsystems - Beijing China (void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL,
4641dc0cb1cdSDale Ghent B_FALSE);
46425b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
46435b6dd21fSchenlu chen - Sun Microsystems - Beijing China
46445b6dd21fSchenlu chen - Sun Microsystems - Beijing China default:
46455b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
46469da57d7bSbt }
46479da57d7bSbt }
46489da57d7bSbt
46499da57d7bSbt #pragma inline(ixgbe_intr_rx_work)
46509da57d7bSbt /*
46519da57d7bSbt * ixgbe_intr_rx_work - RX processing of ISR.
46529da57d7bSbt */
46539da57d7bSbt static void
ixgbe_intr_rx_work(ixgbe_rx_ring_t * rx_ring)46549da57d7bSbt ixgbe_intr_rx_work(ixgbe_rx_ring_t *rx_ring)
46559da57d7bSbt {
46569da57d7bSbt mblk_t *mp;
46579da57d7bSbt
46589da57d7bSbt mutex_enter(&rx_ring->rx_lock);
46599da57d7bSbt
4660da14cebeSEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
46619da57d7bSbt mutex_exit(&rx_ring->rx_lock);
46629da57d7bSbt
46639da57d7bSbt if (mp != NULL)
4664da14cebeSEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
4665da14cebeSEric Cheng rx_ring->ring_gen_num);
46669da57d7bSbt }
46679da57d7bSbt
46689da57d7bSbt #pragma inline(ixgbe_intr_tx_work)
46699da57d7bSbt /*
46709da57d7bSbt * ixgbe_intr_tx_work - TX processing of ISR.
46719da57d7bSbt */
46729da57d7bSbt static void
ixgbe_intr_tx_work(ixgbe_tx_ring_t * tx_ring)46739da57d7bSbt ixgbe_intr_tx_work(ixgbe_tx_ring_t *tx_ring)
46749da57d7bSbt {
4675ea65739eSchenlu chen - Sun Microsystems - Beijing China ixgbe_t *ixgbe = tx_ring->ixgbe;
4676ea65739eSchenlu chen - Sun Microsystems - Beijing China
46779da57d7bSbt /*
46789da57d7bSbt * Recycle the tx descriptors
46799da57d7bSbt */
46809da57d7bSbt tx_ring->tx_recycle(tx_ring);
46819da57d7bSbt
46829da57d7bSbt /*
46839da57d7bSbt * Schedule the re-transmit
46849da57d7bSbt */
46859da57d7bSbt if (tx_ring->reschedule &&
4686ea65739eSchenlu chen - Sun Microsystems - Beijing China (tx_ring->tbd_free >= ixgbe->tx_resched_thresh)) {
46879da57d7bSbt tx_ring->reschedule = B_FALSE;
4688da14cebeSEric Cheng mac_tx_ring_update(tx_ring->ixgbe->mac_hdl,
4689da14cebeSEric Cheng tx_ring->ring_handle);
4690a9bfd41dSRyan Zezeski tx_ring->stat_reschedule++;
46919da57d7bSbt }
46929da57d7bSbt }
46939da57d7bSbt
46949da57d7bSbt #pragma inline(ixgbe_intr_other_work)
46959da57d7bSbt /*
469613740cb2SPaul Guo * ixgbe_intr_other_work - Process interrupt types other than tx/rx
46979da57d7bSbt */
46989da57d7bSbt static void
ixgbe_intr_other_work(ixgbe_t * ixgbe,uint32_t eicr)469913740cb2SPaul Guo ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr)
47009da57d7bSbt {
4701dc0cb1cdSDale Ghent struct ixgbe_hw *hw = &ixgbe->hw;
4702dc0cb1cdSDale Ghent
470362e6e1adSPaul Guo ASSERT(mutex_owned(&ixgbe->gen_lock));
470462e6e1adSPaul Guo
47059da57d7bSbt /*
470662e6e1adSPaul Guo * handle link status change
47079da57d7bSbt */
470813740cb2SPaul Guo if (eicr & IXGBE_EICR_LSC) {
470962e6e1adSPaul Guo ixgbe_driver_link_check(ixgbe);
47105b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_get_hw_state(ixgbe);
471113740cb2SPaul Guo }
47129da57d7bSbt
47139da57d7bSbt /*
471413740cb2SPaul Guo * check for fan failure on adapters with fans
47159da57d7bSbt */
471613740cb2SPaul Guo if ((ixgbe->capab->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
471713740cb2SPaul Guo (eicr & IXGBE_EICR_GPI_SDP1)) {
47185b6dd21fSchenlu chen - Sun Microsystems - Beijing China atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP);
47199da57d7bSbt
47205b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
47215b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Disable the adapter interrupts
47225b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
47235b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_disable_adapter_interrupts(ixgbe);
47245b6dd21fSchenlu chen - Sun Microsystems - Beijing China
47255b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
47265b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Disable Rx/Tx units
47275b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
47285b6dd21fSchenlu chen - Sun Microsystems - Beijing China (void) ixgbe_stop_adapter(&ixgbe->hw);
47295b6dd21fSchenlu chen - Sun Microsystems - Beijing China
47305b6dd21fSchenlu chen - Sun Microsystems - Beijing China ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST);
47315b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe,
47325b6dd21fSchenlu chen - Sun Microsystems - Beijing China "Problem: Network adapter has been stopped "
47335b6dd21fSchenlu chen - Sun Microsystems - Beijing China "because the fan has stopped.\n");
47345b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_error(ixgbe,
47355b6dd21fSchenlu chen - Sun Microsystems - Beijing China "Action: Replace the adapter.\n");
47365b6dd21fSchenlu chen - Sun Microsystems - Beijing China
47375b6dd21fSchenlu chen - Sun Microsystems - Beijing China /* re-enable the interrupt, which was automasked */
47385b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->eims |= IXGBE_EICR_GPI_SDP1;
473973cd555cSBin Tu - Sun Microsystems - Beijing China }
47409da57d7bSbt
474173cd555cSBin Tu - Sun Microsystems - Beijing China /*
47425b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Do SFP check for adapters with hot-plug capability
474373cd555cSBin Tu - Sun Microsystems - Beijing China */
47445b6dd21fSchenlu chen - Sun Microsystems - Beijing China if ((ixgbe->capab->flags & IXGBE_FLAG_SFP_PLUG_CAPABLE) &&
4745dc0cb1cdSDale Ghent ((eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) ||
4746dc0cb1cdSDale Ghent (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)))) {
47475b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->eicr = eicr;
474862e6e1adSPaul Guo if ((ddi_taskq_dispatch(ixgbe->sfp_taskq,
474973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_sfp_check, (void *)ixgbe,
475073cd555cSBin Tu - Sun Microsystems - Beijing China DDI_NOSLEEP)) != DDI_SUCCESS) {
4751185c5677SPaul Guo ixgbe_log(ixgbe, "No memory available to dispatch "
4752185c5677SPaul Guo "taskq for SFP check");
475373cd555cSBin Tu - Sun Microsystems - Beijing China }
47545b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
475562e6e1adSPaul Guo
47565b6dd21fSchenlu chen - Sun Microsystems - Beijing China /*
47575b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Do over-temperature check for adapters with temp sensor
47585b6dd21fSchenlu chen - Sun Microsystems - Beijing China */
47595b6dd21fSchenlu chen - Sun Microsystems - Beijing China if ((ixgbe->capab->flags & IXGBE_FLAG_TEMP_SENSOR_CAPABLE) &&
4760dc0cb1cdSDale Ghent ((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) ||
4761dc0cb1cdSDale Ghent (eicr & IXGBE_EICR_LSC))) {
47625b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->eicr = eicr;
47635b6dd21fSchenlu chen - Sun Microsystems - Beijing China if ((ddi_taskq_dispatch(ixgbe->overtemp_taskq,
47645b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_overtemp_check, (void *)ixgbe,
47655b6dd21fSchenlu chen - Sun Microsystems - Beijing China DDI_NOSLEEP)) != DDI_SUCCESS) {
47665b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_log(ixgbe, "No memory available to dispatch "
47675b6dd21fSchenlu chen - Sun Microsystems - Beijing China "taskq for overtemp check");
47685b6dd21fSchenlu chen - Sun Microsystems - Beijing China }
476913740cb2SPaul Guo }
4770dc0cb1cdSDale Ghent
4771dc0cb1cdSDale Ghent /*
4772dc0cb1cdSDale Ghent * Process an external PHY interrupt
4773dc0cb1cdSDale Ghent */
4774dc0cb1cdSDale Ghent if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T &&
4775dc0cb1cdSDale Ghent (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
4776dc0cb1cdSDale Ghent ixgbe->eicr = eicr;
4777dc0cb1cdSDale Ghent if ((ddi_taskq_dispatch(ixgbe->phy_taskq,
4778dc0cb1cdSDale Ghent ixgbe_phy_check, (void *)ixgbe,
4779dc0cb1cdSDale Ghent DDI_NOSLEEP)) != DDI_SUCCESS) {
4780dc0cb1cdSDale Ghent ixgbe_log(ixgbe, "No memory available to dispatch "
4781dc0cb1cdSDale Ghent "taskq for PHY check");
4782dc0cb1cdSDale Ghent }
4783dc0cb1cdSDale Ghent }
47849da57d7bSbt }
47859da57d7bSbt
47869da57d7bSbt /*
47879da57d7bSbt * ixgbe_intr_legacy - Interrupt handler for legacy interrupts.
47889da57d7bSbt */
47899da57d7bSbt static uint_t
ixgbe_intr_legacy(void * arg1,void * arg2)47909da57d7bSbt ixgbe_intr_legacy(void *arg1, void *arg2)
47919da57d7bSbt {
47929da57d7bSbt ixgbe_t *ixgbe = (ixgbe_t *)arg1;
47939da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
47949da57d7bSbt ixgbe_tx_ring_t *tx_ring;
4795da14cebeSEric Cheng ixgbe_rx_ring_t *rx_ring;
47969da57d7bSbt uint32_t eicr;
47979da57d7bSbt mblk_t *mp;
47989da57d7bSbt boolean_t tx_reschedule;
47999da57d7bSbt uint_t result;
48009da57d7bSbt
480113740cb2SPaul Guo _NOTE(ARGUNUSED(arg2));
48029da57d7bSbt
48039da57d7bSbt mutex_enter(&ixgbe->gen_lock);
48049da57d7bSbt if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
48059da57d7bSbt mutex_exit(&ixgbe->gen_lock);
48069da57d7bSbt return (DDI_INTR_UNCLAIMED);
48079da57d7bSbt }
48089da57d7bSbt
48099da57d7bSbt mp = NULL;
48109da57d7bSbt tx_reschedule = B_FALSE;
48119da57d7bSbt
48129da57d7bSbt /*
48139da57d7bSbt * Any bit set in eicr: claim this interrupt
48149da57d7bSbt */
48159da57d7bSbt eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
481662e6e1adSPaul Guo
481762e6e1adSPaul Guo if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
481819843f01SPaul Guo mutex_exit(&ixgbe->gen_lock);
481962e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
482062e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
482162e6e1adSPaul Guo return (DDI_INTR_CLAIMED);
482262e6e1adSPaul Guo }
482362e6e1adSPaul Guo
48249da57d7bSbt if (eicr) {
48259da57d7bSbt /*
48269da57d7bSbt * For legacy interrupt, we have only one interrupt,
48279da57d7bSbt * so we have only one rx ring and one tx ring enabled.
48289da57d7bSbt */
48299da57d7bSbt ASSERT(ixgbe->num_rx_rings == 1);
48309da57d7bSbt ASSERT(ixgbe->num_tx_rings == 1);
48319da57d7bSbt
48329da57d7bSbt /*
4833da14cebeSEric Cheng * For legacy interrupt, rx rings[0] will use RTxQ[0].
48349da57d7bSbt */
4835da14cebeSEric Cheng if (eicr & 0x1) {
483673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eimc |= IXGBE_EICR_RTX_QUEUE;
483773cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
483873cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
48399da57d7bSbt /*
48409da57d7bSbt * Clean the rx descriptors
48419da57d7bSbt */
4842da14cebeSEric Cheng rx_ring = &ixgbe->rx_rings[0];
4843da14cebeSEric Cheng mp = ixgbe_ring_rx(rx_ring, IXGBE_POLL_NULL);
4844da14cebeSEric Cheng }
48459da57d7bSbt
4846da14cebeSEric Cheng /*
4847da14cebeSEric Cheng * For legacy interrupt, tx rings[0] will use RTxQ[1].
4848da14cebeSEric Cheng */
4849da14cebeSEric Cheng if (eicr & 0x2) {
48509da57d7bSbt /*
48519da57d7bSbt * Recycle the tx descriptors
48529da57d7bSbt */
48539da57d7bSbt tx_ring = &ixgbe->tx_rings[0];
48549da57d7bSbt tx_ring->tx_recycle(tx_ring);
48559da57d7bSbt
48569da57d7bSbt /*
48579da57d7bSbt * Schedule the re-transmit
48589da57d7bSbt */
48599da57d7bSbt tx_reschedule = (tx_ring->reschedule &&
4860ea65739eSchenlu chen - Sun Microsystems - Beijing China (tx_ring->tbd_free >= ixgbe->tx_resched_thresh));
48619da57d7bSbt }
48629da57d7bSbt
486313740cb2SPaul Guo /* any interrupt type other than tx/rx */
486413740cb2SPaul Guo if (eicr & ixgbe->capab->other_intr) {
48655b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) {
48665b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
486773cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
48685b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
48695b6dd21fSchenlu chen - Sun Microsystems - Beijing China
48705b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
487169b5a878SDan McDonald case ixgbe_mac_X540:
4872dc0cb1cdSDale Ghent case ixgbe_mac_X550:
4873dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
487448ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
487573cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eimc = IXGBE_82599_OTHER_INTR;
487673cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
48775b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
48785b6dd21fSchenlu chen - Sun Microsystems - Beijing China
48795b6dd21fSchenlu chen - Sun Microsystems - Beijing China default:
48805b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
488173cd555cSBin Tu - Sun Microsystems - Beijing China }
488213740cb2SPaul Guo ixgbe_intr_other_work(ixgbe, eicr);
488373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
48849da57d7bSbt }
48859da57d7bSbt
488613740cb2SPaul Guo mutex_exit(&ixgbe->gen_lock);
488713740cb2SPaul Guo
48889da57d7bSbt result = DDI_INTR_CLAIMED;
48899da57d7bSbt } else {
489013740cb2SPaul Guo mutex_exit(&ixgbe->gen_lock);
489113740cb2SPaul Guo
48929da57d7bSbt /*
48939da57d7bSbt * No interrupt cause bits set: don't claim this interrupt.
48949da57d7bSbt */
48959da57d7bSbt result = DDI_INTR_UNCLAIMED;
48969da57d7bSbt }
48979da57d7bSbt
489813740cb2SPaul Guo /* re-enable the interrupts which were automasked */
489913740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
49009da57d7bSbt
49019da57d7bSbt /*
49029da57d7bSbt * Do the following work outside of the gen_lock
49039da57d7bSbt */
490473cd555cSBin Tu - Sun Microsystems - Beijing China if (mp != NULL) {
4905da14cebeSEric Cheng mac_rx_ring(rx_ring->ixgbe->mac_hdl, rx_ring->ring_handle, mp,
4906da14cebeSEric Cheng rx_ring->ring_gen_num);
490773cd555cSBin Tu - Sun Microsystems - Beijing China }
49089da57d7bSbt
49099da57d7bSbt if (tx_reschedule) {
49109da57d7bSbt tx_ring->reschedule = B_FALSE;
4911da14cebeSEric Cheng mac_tx_ring_update(ixgbe->mac_hdl, tx_ring->ring_handle);
4912a9bfd41dSRyan Zezeski tx_ring->stat_reschedule++;
49139da57d7bSbt }
49149da57d7bSbt
49159da57d7bSbt return (result);
49169da57d7bSbt }
49179da57d7bSbt
49189da57d7bSbt /*
49199da57d7bSbt * ixgbe_intr_msi - Interrupt handler for MSI.
49209da57d7bSbt */
49219da57d7bSbt static uint_t
ixgbe_intr_msi(void * arg1,void * arg2)49229da57d7bSbt ixgbe_intr_msi(void *arg1, void *arg2)
49239da57d7bSbt {
49249da57d7bSbt ixgbe_t *ixgbe = (ixgbe_t *)arg1;
49259da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
49269da57d7bSbt uint32_t eicr;
49279da57d7bSbt
492813740cb2SPaul Guo _NOTE(ARGUNUSED(arg2));
492913740cb2SPaul Guo
49309da57d7bSbt eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
49319da57d7bSbt
493262e6e1adSPaul Guo if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
493362e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
493462e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
493562e6e1adSPaul Guo return (DDI_INTR_CLAIMED);
493662e6e1adSPaul Guo }
493762e6e1adSPaul Guo
49389da57d7bSbt /*
49399da57d7bSbt * For MSI interrupt, we have only one vector,
49409da57d7bSbt * so we have only one rx ring and one tx ring enabled.
49419da57d7bSbt */
49429da57d7bSbt ASSERT(ixgbe->num_rx_rings == 1);
49439da57d7bSbt ASSERT(ixgbe->num_tx_rings == 1);
49449da57d7bSbt
49459da57d7bSbt /*
4946da14cebeSEric Cheng * For MSI interrupt, rx rings[0] will use RTxQ[0].
49479da57d7bSbt */
4948da14cebeSEric Cheng if (eicr & 0x1) {
49499da57d7bSbt ixgbe_intr_rx_work(&ixgbe->rx_rings[0]);
4950da14cebeSEric Cheng }
4951da14cebeSEric Cheng
4952da14cebeSEric Cheng /*
4953da14cebeSEric Cheng * For MSI interrupt, tx rings[0] will use RTxQ[1].
4954da14cebeSEric Cheng */
4955da14cebeSEric Cheng if (eicr & 0x2) {
49569da57d7bSbt ixgbe_intr_tx_work(&ixgbe->tx_rings[0]);
49579da57d7bSbt }
49589da57d7bSbt
495913740cb2SPaul Guo /* any interrupt type other than tx/rx */
496013740cb2SPaul Guo if (eicr & ixgbe->capab->other_intr) {
496113740cb2SPaul Guo mutex_enter(&ixgbe->gen_lock);
49625b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) {
49635b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
496473cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
49655b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
49665b6dd21fSchenlu chen - Sun Microsystems - Beijing China
49675b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
496869b5a878SDan McDonald case ixgbe_mac_X540:
4969dc0cb1cdSDale Ghent case ixgbe_mac_X550:
4970dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
497148ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
497273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eimc = IXGBE_82599_OTHER_INTR;
497373cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc);
49745b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
49755b6dd21fSchenlu chen - Sun Microsystems - Beijing China
49765b6dd21fSchenlu chen - Sun Microsystems - Beijing China default:
49775b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
497873cd555cSBin Tu - Sun Microsystems - Beijing China }
497913740cb2SPaul Guo ixgbe_intr_other_work(ixgbe, eicr);
498073cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
498113740cb2SPaul Guo mutex_exit(&ixgbe->gen_lock);
49829da57d7bSbt }
49839da57d7bSbt
498413740cb2SPaul Guo /* re-enable the interrupts which were automasked */
498513740cb2SPaul Guo IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
498613740cb2SPaul Guo
49879da57d7bSbt return (DDI_INTR_CLAIMED);
49889da57d7bSbt }
49899da57d7bSbt
49909da57d7bSbt /*
499173cd555cSBin Tu - Sun Microsystems - Beijing China * ixgbe_intr_msix - Interrupt handler for MSI-X.
49929da57d7bSbt */
49939da57d7bSbt static uint_t
ixgbe_intr_msix(void * arg1,void * arg2)499473cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_msix(void *arg1, void *arg2)
49959da57d7bSbt {
499673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_vector_t *vect = (ixgbe_intr_vector_t *)arg1;
4997da14cebeSEric Cheng ixgbe_t *ixgbe = vect->ixgbe;
499873cd555cSBin Tu - Sun Microsystems - Beijing China struct ixgbe_hw *hw = &ixgbe->hw;
499973cd555cSBin Tu - Sun Microsystems - Beijing China uint32_t eicr;
5000da14cebeSEric Cheng int r_idx = 0;
50019da57d7bSbt
500213740cb2SPaul Guo _NOTE(ARGUNUSED(arg2));
500313740cb2SPaul Guo
50049da57d7bSbt /*
5005da14cebeSEric Cheng * Clean each rx ring that has its bit set in the map
50069da57d7bSbt */
50079da57d7bSbt r_idx = bt_getlowbit(vect->rx_map, 0, (ixgbe->num_rx_rings - 1));
50089da57d7bSbt while (r_idx >= 0) {
50099da57d7bSbt ixgbe_intr_rx_work(&ixgbe->rx_rings[r_idx]);
50109da57d7bSbt r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
50119da57d7bSbt (ixgbe->num_rx_rings - 1));
50129da57d7bSbt }
50139da57d7bSbt
5014da14cebeSEric Cheng /*
5015da14cebeSEric Cheng * Clean each tx ring that has its bit set in the map
5016da14cebeSEric Cheng */
5017da14cebeSEric Cheng r_idx = bt_getlowbit(vect->tx_map, 0, (ixgbe->num_tx_rings - 1));
5018da14cebeSEric Cheng while (r_idx >= 0) {
5019da14cebeSEric Cheng ixgbe_intr_tx_work(&ixgbe->tx_rings[r_idx]);
5020da14cebeSEric Cheng r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
5021da14cebeSEric Cheng (ixgbe->num_tx_rings - 1));
5022da14cebeSEric Cheng }
5023da14cebeSEric Cheng
50249da57d7bSbt
50259da57d7bSbt /*
502673cd555cSBin Tu - Sun Microsystems - Beijing China * Clean other interrupt (link change) that has its bit set in the map
50279da57d7bSbt */
502873cd555cSBin Tu - Sun Microsystems - Beijing China if (BT_TEST(vect->other_map, 0) == 1) {
502973cd555cSBin Tu - Sun Microsystems - Beijing China eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
50309da57d7bSbt
503162e6e1adSPaul Guo if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) !=
503262e6e1adSPaul Guo DDI_FM_OK) {
503362e6e1adSPaul Guo ddi_fm_service_impact(ixgbe->dip,
503462e6e1adSPaul Guo DDI_SERVICE_DEGRADED);
503562e6e1adSPaul Guo atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
503662e6e1adSPaul Guo return (DDI_INTR_CLAIMED);
503762e6e1adSPaul Guo }
503862e6e1adSPaul Guo
503973cd555cSBin Tu - Sun Microsystems - Beijing China /*
50405b6dd21fSchenlu chen - Sun Microsystems - Beijing China * Check "other" cause bits: any interrupt type other than tx/rx
504173cd555cSBin Tu - Sun Microsystems - Beijing China */
504273cd555cSBin Tu - Sun Microsystems - Beijing China if (eicr & ixgbe->capab->other_intr) {
50435b6dd21fSchenlu chen - Sun Microsystems - Beijing China mutex_enter(&ixgbe->gen_lock);
50445b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) {
50455b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
504673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR);
504773cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_other_work(ixgbe, eicr);
50485b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
50495b6dd21fSchenlu chen - Sun Microsystems - Beijing China
50505b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
505169b5a878SDan McDonald case ixgbe_mac_X540:
5052dc0cb1cdSDale Ghent case ixgbe_mac_X550:
5053dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
505448ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
50555b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->eims |= IXGBE_EICR_RTX_QUEUE;
50565b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe_intr_other_work(ixgbe, eicr);
50575b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
50585b6dd21fSchenlu chen - Sun Microsystems - Beijing China
50595b6dd21fSchenlu chen - Sun Microsystems - Beijing China default:
50605b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
506173cd555cSBin Tu - Sun Microsystems - Beijing China }
50625b6dd21fSchenlu chen - Sun Microsystems - Beijing China mutex_exit(&ixgbe->gen_lock);
506373cd555cSBin Tu - Sun Microsystems - Beijing China }
506473cd555cSBin Tu - Sun Microsystems - Beijing China
506573cd555cSBin Tu - Sun Microsystems - Beijing China /* re-enable the interrupts which were automasked */
506673cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_EIMS, ixgbe->eims);
506773cd555cSBin Tu - Sun Microsystems - Beijing China }
506813740cb2SPaul Guo
50699da57d7bSbt return (DDI_INTR_CLAIMED);
50709da57d7bSbt }
50719da57d7bSbt
50729da57d7bSbt /*
50739da57d7bSbt * ixgbe_alloc_intrs - Allocate interrupts for the driver.
50749da57d7bSbt *
50759da57d7bSbt * Normal sequence is to try MSI-X; if not sucessful, try MSI;
50769da57d7bSbt * if not successful, try Legacy.
50779da57d7bSbt * ixgbe->intr_force can be used to force sequence to start with
50789da57d7bSbt * any of the 3 types.
50799da57d7bSbt * If MSI-X is not used, number of tx/rx rings is forced to 1.
50809da57d7bSbt */
50819da57d7bSbt static int
ixgbe_alloc_intrs(ixgbe_t * ixgbe)50829da57d7bSbt ixgbe_alloc_intrs(ixgbe_t *ixgbe)
50839da57d7bSbt {
50849da57d7bSbt dev_info_t *devinfo;
50859da57d7bSbt int intr_types;
50869da57d7bSbt int rc;
50879da57d7bSbt
50889da57d7bSbt devinfo = ixgbe->dip;
50899da57d7bSbt
50909da57d7bSbt /*
50919da57d7bSbt * Get supported interrupt types
50929da57d7bSbt */
50939da57d7bSbt rc = ddi_intr_get_supported_types(devinfo, &intr_types);
50949da57d7bSbt
50959da57d7bSbt if (rc != DDI_SUCCESS) {
50969da57d7bSbt ixgbe_log(ixgbe,
50979da57d7bSbt "Get supported interrupt types failed: %d", rc);
50989da57d7bSbt return (IXGBE_FAILURE);
50999da57d7bSbt }
51009da57d7bSbt IXGBE_DEBUGLOG_1(ixgbe, "Supported interrupt types: %x", intr_types);
51019da57d7bSbt
51029da57d7bSbt ixgbe->intr_type = 0;
51039da57d7bSbt
51049da57d7bSbt /*
51059da57d7bSbt * Install MSI-X interrupts
51069da57d7bSbt */
51079da57d7bSbt if ((intr_types & DDI_INTR_TYPE_MSIX) &&
51089da57d7bSbt (ixgbe->intr_force <= IXGBE_INTR_MSIX)) {
51099da57d7bSbt rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSIX);
51109da57d7bSbt if (rc == IXGBE_SUCCESS)
51119da57d7bSbt return (IXGBE_SUCCESS);
51129da57d7bSbt
51139da57d7bSbt ixgbe_log(ixgbe,
51149da57d7bSbt "Allocate MSI-X failed, trying MSI interrupts...");
51159da57d7bSbt }
51169da57d7bSbt
51179da57d7bSbt /*
5118da14cebeSEric Cheng * MSI-X not used, force rings and groups to 1
51199da57d7bSbt */
51209da57d7bSbt ixgbe->num_rx_rings = 1;
5121da14cebeSEric Cheng ixgbe->num_rx_groups = 1;
51229da57d7bSbt ixgbe->num_tx_rings = 1;
51230dc2366fSVenugopal Iyer ixgbe->classify_mode = IXGBE_CLASSIFY_NONE;
51249da57d7bSbt ixgbe_log(ixgbe,
5125da14cebeSEric Cheng "MSI-X not used, force rings and groups number to 1");
51269da57d7bSbt
51279da57d7bSbt /*
51289da57d7bSbt * Install MSI interrupts
51299da57d7bSbt */
51309da57d7bSbt if ((intr_types & DDI_INTR_TYPE_MSI) &&
51319da57d7bSbt (ixgbe->intr_force <= IXGBE_INTR_MSI)) {
51329da57d7bSbt rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_MSI);
51339da57d7bSbt if (rc == IXGBE_SUCCESS)
51349da57d7bSbt return (IXGBE_SUCCESS);
51359da57d7bSbt
51369da57d7bSbt ixgbe_log(ixgbe,
51379da57d7bSbt "Allocate MSI failed, trying Legacy interrupts...");
51389da57d7bSbt }
51399da57d7bSbt
51409da57d7bSbt /*
51419da57d7bSbt * Install legacy interrupts
51429da57d7bSbt */
51439da57d7bSbt if (intr_types & DDI_INTR_TYPE_FIXED) {
5144dc0cb1cdSDale Ghent /*
5145dc0cb1cdSDale Ghent * Disallow legacy interrupts for X550. X550 has a silicon
5146dc0cb1cdSDale Ghent * bug which prevents Shared Legacy interrupts from working.
5147dc0cb1cdSDale Ghent * For details, please reference:
5148dc0cb1cdSDale Ghent *
5149dc0cb1cdSDale Ghent * Intel Ethernet Controller X550 Specification Update rev. 2.1
5150dc0cb1cdSDale Ghent * May 2016, erratum 22: PCIe Interrupt Status Bit
5151dc0cb1cdSDale Ghent */
5152dc0cb1cdSDale Ghent if (ixgbe->hw.mac.type == ixgbe_mac_X550 ||
5153dc0cb1cdSDale Ghent ixgbe->hw.mac.type == ixgbe_mac_X550EM_x ||
515448ed61a7SRobert Mustacchi ixgbe->hw.mac.type == ixgbe_mac_X550EM_a ||
5155dc0cb1cdSDale Ghent ixgbe->hw.mac.type == ixgbe_mac_X550_vf ||
515648ed61a7SRobert Mustacchi ixgbe->hw.mac.type == ixgbe_mac_X550EM_x_vf ||
515748ed61a7SRobert Mustacchi ixgbe->hw.mac.type == ixgbe_mac_X550EM_a_vf) {
5158dc0cb1cdSDale Ghent ixgbe_log(ixgbe,
5159dc0cb1cdSDale Ghent "Legacy interrupts are not supported on this "
5160dc0cb1cdSDale Ghent "adapter. Please use MSI or MSI-X instead.");
5161dc0cb1cdSDale Ghent return (IXGBE_FAILURE);
5162dc0cb1cdSDale Ghent }
51639da57d7bSbt rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED);
51649da57d7bSbt if (rc == IXGBE_SUCCESS)
51659da57d7bSbt return (IXGBE_SUCCESS);
51669da57d7bSbt
51679da57d7bSbt ixgbe_log(ixgbe,
51689da57d7bSbt "Allocate Legacy interrupts failed");
51699da57d7bSbt }
51709da57d7bSbt
51719da57d7bSbt /*
51729da57d7bSbt * If none of the 3 types succeeded, return failure
51739da57d7bSbt */
51749da57d7bSbt return (IXGBE_FAILURE);
51759da57d7bSbt }
51769da57d7bSbt
51779da57d7bSbt /*
51789da57d7bSbt * ixgbe_alloc_intr_handles - Allocate interrupt handles.
51799da57d7bSbt *
51809da57d7bSbt * For legacy and MSI, only 1 handle is needed. For MSI-X,
51819da57d7bSbt * if fewer than 2 handles are available, return failure.
5182da14cebeSEric Cheng * Upon success, this maps the vectors to rx and tx rings for
5183da14cebeSEric Cheng * interrupts.
51849da57d7bSbt */
51859da57d7bSbt static int
ixgbe_alloc_intr_handles(ixgbe_t * ixgbe,int intr_type)51869da57d7bSbt ixgbe_alloc_intr_handles(ixgbe_t *ixgbe, int intr_type)
51879da57d7bSbt {
51889da57d7bSbt dev_info_t *devinfo;
51890dc2366fSVenugopal Iyer int request, count, actual;
5190da14cebeSEric Cheng int minimum;
51919da57d7bSbt int rc;
51920dc2366fSVenugopal Iyer uint32_t ring_per_group;
51939da57d7bSbt
51949da57d7bSbt devinfo = ixgbe->dip;
51959da57d7bSbt
51969da57d7bSbt switch (intr_type) {
51979da57d7bSbt case DDI_INTR_TYPE_FIXED:
51989da57d7bSbt request = 1; /* Request 1 legacy interrupt handle */
51999da57d7bSbt minimum = 1;
52009da57d7bSbt IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: legacy");
52019da57d7bSbt break;
52029da57d7bSbt
52039da57d7bSbt case DDI_INTR_TYPE_MSI:
52049da57d7bSbt request = 1; /* Request 1 MSI interrupt handle */
52059da57d7bSbt minimum = 1;
52069da57d7bSbt IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI");
52079da57d7bSbt break;
52089da57d7bSbt
52099da57d7bSbt case DDI_INTR_TYPE_MSIX:
52109da57d7bSbt /*
52119da57d7bSbt * Best number of vectors for the adapter is
52120dc2366fSVenugopal Iyer * (# rx rings + # tx rings), however we will
52130dc2366fSVenugopal Iyer * limit the request number.
52149da57d7bSbt */
52150dc2366fSVenugopal Iyer request = min(16, ixgbe->num_rx_rings + ixgbe->num_tx_rings);
521673cd555cSBin Tu - Sun Microsystems - Beijing China if (request > ixgbe->capab->max_ring_vect)
521773cd555cSBin Tu - Sun Microsystems - Beijing China request = ixgbe->capab->max_ring_vect;
52180dc2366fSVenugopal Iyer minimum = 1;
52199da57d7bSbt IXGBE_DEBUGLOG_0(ixgbe, "interrupt type: MSI-X");
52209da57d7bSbt break;
52219da57d7bSbt
52229da57d7bSbt default:
52239da57d7bSbt ixgbe_log(ixgbe,
52249da57d7bSbt "invalid call to ixgbe_alloc_intr_handles(): %d\n",
52259da57d7bSbt intr_type);
52269da57d7bSbt return (IXGBE_FAILURE);
52279da57d7bSbt }
52289da57d7bSbt IXGBE_DEBUGLOG_2(ixgbe, "interrupt handles requested: %d minimum: %d",
52299da57d7bSbt request, minimum);
52309da57d7bSbt
52319da57d7bSbt /*
52329da57d7bSbt * Get number of supported interrupts
52339da57d7bSbt */
52349da57d7bSbt rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
52359da57d7bSbt if ((rc != DDI_SUCCESS) || (count < minimum)) {
52369da57d7bSbt ixgbe_log(ixgbe,
52379da57d7bSbt "Get interrupt number failed. Return: %d, count: %d",
52389da57d7bSbt rc, count);
52399da57d7bSbt return (IXGBE_FAILURE);
52409da57d7bSbt }
52419da57d7bSbt IXGBE_DEBUGLOG_1(ixgbe, "interrupts supported: %d", count);
52429da57d7bSbt
52439da57d7bSbt actual = 0;
52449da57d7bSbt ixgbe->intr_cnt = 0;
52450dc2366fSVenugopal Iyer ixgbe->intr_cnt_max = 0;
52460dc2366fSVenugopal Iyer ixgbe->intr_cnt_min = 0;
52479da57d7bSbt
52489da57d7bSbt /*
52499da57d7bSbt * Allocate an array of interrupt handles
52509da57d7bSbt */
52519da57d7bSbt ixgbe->intr_size = request * sizeof (ddi_intr_handle_t);
52529da57d7bSbt ixgbe->htable = kmem_alloc(ixgbe->intr_size, KM_SLEEP);
52539da57d7bSbt
52549da57d7bSbt rc = ddi_intr_alloc(devinfo, ixgbe->htable, intr_type, 0,
52559da57d7bSbt request, &actual, DDI_INTR_ALLOC_NORMAL);
52569da57d7bSbt if (rc != DDI_SUCCESS) {
52579da57d7bSbt ixgbe_log(ixgbe, "Allocate interrupts failed. "
52589da57d7bSbt "return: %d, request: %d, actual: %d",
52599da57d7bSbt rc, request, actual);
52609da57d7bSbt goto alloc_handle_fail;
52619da57d7bSbt }
52629da57d7bSbt IXGBE_DEBUGLOG_1(ixgbe, "interrupts actually allocated: %d", actual);
52639da57d7bSbt
52640dc2366fSVenugopal Iyer /*
52650dc2366fSVenugopal Iyer * upper/lower limit of interrupts
52660dc2366fSVenugopal Iyer */
52679da57d7bSbt ixgbe->intr_cnt = actual;
52680dc2366fSVenugopal Iyer ixgbe->intr_cnt_max = request;
52690dc2366fSVenugopal Iyer ixgbe->intr_cnt_min = minimum;
52700dc2366fSVenugopal Iyer
52710dc2366fSVenugopal Iyer /*
52720dc2366fSVenugopal Iyer * rss number per group should not exceed the rx interrupt number,
52730dc2366fSVenugopal Iyer * else need to adjust rx ring number.
52740dc2366fSVenugopal Iyer */
52750dc2366fSVenugopal Iyer ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
52760dc2366fSVenugopal Iyer ASSERT((ixgbe->num_rx_rings % ixgbe->num_rx_groups) == 0);
52775b6dd21fSchenlu chen - Sun Microsystems - Beijing China if (actual < ring_per_group) {
52785b6dd21fSchenlu chen - Sun Microsystems - Beijing China ixgbe->num_rx_rings = ixgbe->num_rx_groups * actual;
52790dc2366fSVenugopal Iyer ixgbe_setup_vmdq_rss_conf(ixgbe);
52800dc2366fSVenugopal Iyer }
52819da57d7bSbt
52829da57d7bSbt /*
5283da14cebeSEric Cheng * Now we know the actual number of vectors. Here we map the vector
5284da14cebeSEric Cheng * to other, rx rings and tx ring.
52859da57d7bSbt */
52869da57d7bSbt if (actual < minimum) {
52879da57d7bSbt ixgbe_log(ixgbe, "Insufficient interrupt handles available: %d",
52889da57d7bSbt actual);
52899da57d7bSbt goto alloc_handle_fail;
52909da57d7bSbt }
52919da57d7bSbt
52929da57d7bSbt /*
52939da57d7bSbt * Get priority for first vector, assume remaining are all the same
52949da57d7bSbt */
52959da57d7bSbt rc = ddi_intr_get_pri(ixgbe->htable[0], &ixgbe->intr_pri);
52969da57d7bSbt if (rc != DDI_SUCCESS) {
52979da57d7bSbt ixgbe_log(ixgbe,
52989da57d7bSbt "Get interrupt priority failed: %d", rc);
52999da57d7bSbt goto alloc_handle_fail;
53009da57d7bSbt }
53019da57d7bSbt
53029da57d7bSbt rc = ddi_intr_get_cap(ixgbe->htable[0], &ixgbe->intr_cap);
53039da57d7bSbt if (rc != DDI_SUCCESS) {
53049da57d7bSbt ixgbe_log(ixgbe,
53059da57d7bSbt "Get interrupt cap failed: %d", rc);
53069da57d7bSbt goto alloc_handle_fail;
53079da57d7bSbt }
53089da57d7bSbt
53099da57d7bSbt ixgbe->intr_type = intr_type;
53109da57d7bSbt
53119da57d7bSbt return (IXGBE_SUCCESS);
53129da57d7bSbt
53139da57d7bSbt alloc_handle_fail:
53149da57d7bSbt ixgbe_rem_intrs(ixgbe);
53159da57d7bSbt
53169da57d7bSbt return (IXGBE_FAILURE);
53179da57d7bSbt }
53189da57d7bSbt
53199da57d7bSbt /*
53209da57d7bSbt * ixgbe_add_intr_handlers - Add interrupt handlers based on the interrupt type.
53219da57d7bSbt *
53229da57d7bSbt * Before adding the interrupt handlers, the interrupt vectors have
53239da57d7bSbt * been allocated, and the rx/tx rings have also been allocated.
53249da57d7bSbt */
53259da57d7bSbt static int
ixgbe_add_intr_handlers(ixgbe_t * ixgbe)53269da57d7bSbt ixgbe_add_intr_handlers(ixgbe_t *ixgbe)
53279da57d7bSbt {
5328da14cebeSEric Cheng int vector = 0;
53299da57d7bSbt int rc;
53309da57d7bSbt
53319da57d7bSbt switch (ixgbe->intr_type) {
53329da57d7bSbt case DDI_INTR_TYPE_MSIX:
53339da57d7bSbt /*
533473cd555cSBin Tu - Sun Microsystems - Beijing China * Add interrupt handler for all vectors
53359da57d7bSbt */
533673cd555cSBin Tu - Sun Microsystems - Beijing China for (vector = 0; vector < ixgbe->intr_cnt; vector++) {
53379da57d7bSbt /*
53389da57d7bSbt * install pointer to vect_map[vector]
53399da57d7bSbt */
53409da57d7bSbt rc = ddi_intr_add_handler(ixgbe->htable[vector],
534173cd555cSBin Tu - Sun Microsystems - Beijing China (ddi_intr_handler_t *)ixgbe_intr_msix,
53429da57d7bSbt (void *)&ixgbe->vect_map[vector], NULL);
53439da57d7bSbt
53449da57d7bSbt if (rc != DDI_SUCCESS) {
53459da57d7bSbt ixgbe_log(ixgbe,
534619843f01SPaul Guo "Add interrupt handler failed. "
5347da14cebeSEric Cheng "return: %d, vector: %d", rc, vector);
53489da57d7bSbt for (vector--; vector >= 0; vector--) {
53499da57d7bSbt (void) ddi_intr_remove_handler(
53509da57d7bSbt ixgbe->htable[vector]);
53519da57d7bSbt }
53529da57d7bSbt return (IXGBE_FAILURE);
53539da57d7bSbt }
5354da14cebeSEric Cheng }
53559da57d7bSbt
53569da57d7bSbt break;
53579da57d7bSbt
53589da57d7bSbt case DDI_INTR_TYPE_MSI:
53599da57d7bSbt /*
53609da57d7bSbt * Add interrupt handlers for the only vector
53619da57d7bSbt */
53629da57d7bSbt rc = ddi_intr_add_handler(ixgbe->htable[vector],
53639da57d7bSbt (ddi_intr_handler_t *)ixgbe_intr_msi,
53649da57d7bSbt (void *)ixgbe, NULL);
53659da57d7bSbt
53669da57d7bSbt if (rc != DDI_SUCCESS) {
53679da57d7bSbt ixgbe_log(ixgbe,
53689da57d7bSbt "Add MSI interrupt handler failed: %d", rc);
53699da57d7bSbt return (IXGBE_FAILURE);
53709da57d7bSbt }
53719da57d7bSbt
53729da57d7bSbt break;
53739da57d7bSbt
53749da57d7bSbt case DDI_INTR_TYPE_FIXED:
53759da57d7bSbt /*
53769da57d7bSbt * Add interrupt handlers for the only vector
53779da57d7bSbt */
53789da57d7bSbt rc = ddi_intr_add_handler(ixgbe->htable[vector],
53799da57d7bSbt (ddi_intr_handler_t *)ixgbe_intr_legacy,
53809da57d7bSbt (void *)ixgbe, NULL);
53819da57d7bSbt
53829da57d7bSbt if (rc != DDI_SUCCESS) {
53839da57d7bSbt ixgbe_log(ixgbe,
53849da57d7bSbt "Add legacy interrupt handler failed: %d", rc);
53859da57d7bSbt return (IXGBE_FAILURE);
53869da57d7bSbt }
53879da57d7bSbt
53889da57d7bSbt break;
53899da57d7bSbt
53909da57d7bSbt default:
53919da57d7bSbt return (IXGBE_FAILURE);
53929da57d7bSbt }
53939da57d7bSbt
53949da57d7bSbt return (IXGBE_SUCCESS);
53959da57d7bSbt }
53969da57d7bSbt
53979da57d7bSbt #pragma inline(ixgbe_map_rxring_to_vector)
53989da57d7bSbt /*
53999da57d7bSbt * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector.
54009da57d7bSbt */
54019da57d7bSbt static void
ixgbe_map_rxring_to_vector(ixgbe_t * ixgbe,int r_idx,int v_idx)54029da57d7bSbt ixgbe_map_rxring_to_vector(ixgbe_t *ixgbe, int r_idx, int v_idx)
54039da57d7bSbt {
54049da57d7bSbt /*
54059da57d7bSbt * Set bit in map
54069da57d7bSbt */
54079da57d7bSbt BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
54089da57d7bSbt
54099da57d7bSbt /*
54109da57d7bSbt * Count bits set
54119da57d7bSbt */
54129da57d7bSbt ixgbe->vect_map[v_idx].rxr_cnt++;
54139da57d7bSbt
54149da57d7bSbt /*
54159da57d7bSbt * Remember bit position
54169da57d7bSbt */
5417da14cebeSEric Cheng ixgbe->rx_rings[r_idx].intr_vector = v_idx;
54189da57d7bSbt ixgbe->rx_rings[r_idx].vect_bit = 1 << v_idx;
54199da57d7bSbt }
54209da57d7bSbt
54219da57d7bSbt #pragma inline(ixgbe_map_txring_to_vector)
54229da57d7bSbt /*
54239da57d7bSbt * ixgbe_map_txring_to_vector - Map given tx ring to given interrupt vector.
54249da57d7bSbt */
54259da57d7bSbt static void
ixgbe_map_txring_to_vector(ixgbe_t * ixgbe,int t_idx,int v_idx)54269da57d7bSbt ixgbe_map_txring_to_vector(ixgbe_t *ixgbe, int t_idx, int v_idx)
54279da57d7bSbt {
54289da57d7bSbt /*
54299da57d7bSbt * Set bit in map
54309da57d7bSbt */
54319da57d7bSbt BT_SET(ixgbe->vect_map[v_idx].tx_map, t_idx);
54329da57d7bSbt
54339da57d7bSbt /*
54349da57d7bSbt * Count bits set
54359da57d7bSbt */
54369da57d7bSbt ixgbe->vect_map[v_idx].txr_cnt++;
54379da57d7bSbt
54389da57d7bSbt /*
54399da57d7bSbt * Remember bit position
54409da57d7bSbt */
5441da14cebeSEric Cheng ixgbe->tx_rings[t_idx].intr_vector = v_idx;
54429da57d7bSbt ixgbe->tx_rings[t_idx].vect_bit = 1 << v_idx;
54439da57d7bSbt }
54449da57d7bSbt
54459da57d7bSbt /*
5446da14cebeSEric Cheng * ixgbe_setup_ivar - Set the given entry in the given interrupt vector
54479da57d7bSbt * allocation register (IVAR).
544873cd555cSBin Tu - Sun Microsystems - Beijing China * cause:
544973cd555cSBin Tu - Sun Microsystems - Beijing China * -1 : other cause
545073cd555cSBin Tu - Sun Microsystems - Beijing China * 0 : rx
545173cd555cSBin Tu - Sun Microsystems - Beijing China * 1 : tx
54529da57d7bSbt */
54539da57d7bSbt static void
ixgbe_setup_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,uint8_t msix_vector,int8_t cause)545473cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, uint8_t msix_vector,
545573cd555cSBin Tu - Sun Microsystems - Beijing China int8_t cause)
54569da57d7bSbt {
54579da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
54589da57d7bSbt u32 ivar, index;
54599da57d7bSbt
546073cd555cSBin Tu - Sun Microsystems - Beijing China switch (hw->mac.type) {
546173cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
546273cd555cSBin Tu - Sun Microsystems - Beijing China msix_vector |= IXGBE_IVAR_ALLOC_VAL;
546373cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) {
546473cd555cSBin Tu - Sun Microsystems - Beijing China cause = 0;
546573cd555cSBin Tu - Sun Microsystems - Beijing China }
546673cd555cSBin Tu - Sun Microsystems - Beijing China index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
546773cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
546873cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(0xFF << (8 * (intr_alloc_entry & 0x3)));
546973cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (msix_vector << (8 * (intr_alloc_entry & 0x3)));
547073cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
547173cd555cSBin Tu - Sun Microsystems - Beijing China break;
54725b6dd21fSchenlu chen - Sun Microsystems - Beijing China
547373cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
547469b5a878SDan McDonald case ixgbe_mac_X540:
5475dc0cb1cdSDale Ghent case ixgbe_mac_X550:
5476dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
547748ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
547873cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) {
547973cd555cSBin Tu - Sun Microsystems - Beijing China /* other causes */
548073cd555cSBin Tu - Sun Microsystems - Beijing China msix_vector |= IXGBE_IVAR_ALLOC_VAL;
548173cd555cSBin Tu - Sun Microsystems - Beijing China index = (intr_alloc_entry & 1) * 8;
548273cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
548373cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(0xFF << index);
548473cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (msix_vector << index);
548573cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
548673cd555cSBin Tu - Sun Microsystems - Beijing China } else {
548773cd555cSBin Tu - Sun Microsystems - Beijing China /* tx or rx causes */
548873cd555cSBin Tu - Sun Microsystems - Beijing China msix_vector |= IXGBE_IVAR_ALLOC_VAL;
548973cd555cSBin Tu - Sun Microsystems - Beijing China index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
549073cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw,
549173cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_IVAR(intr_alloc_entry >> 1));
549273cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(0xFF << index);
549373cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (msix_vector << index);
549473cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
549573cd555cSBin Tu - Sun Microsystems - Beijing China ivar);
549673cd555cSBin Tu - Sun Microsystems - Beijing China }
549773cd555cSBin Tu - Sun Microsystems - Beijing China break;
54985b6dd21fSchenlu chen - Sun Microsystems - Beijing China
549973cd555cSBin Tu - Sun Microsystems - Beijing China default:
550073cd555cSBin Tu - Sun Microsystems - Beijing China break;
550173cd555cSBin Tu - Sun Microsystems - Beijing China }
5502da14cebeSEric Cheng }
5503da14cebeSEric Cheng
5504da14cebeSEric Cheng /*
5505da14cebeSEric Cheng * ixgbe_enable_ivar - Enable the given entry by setting the VAL bit of
5506da14cebeSEric Cheng * given interrupt vector allocation register (IVAR).
550773cd555cSBin Tu - Sun Microsystems - Beijing China * cause:
550873cd555cSBin Tu - Sun Microsystems - Beijing China * -1 : other cause
550973cd555cSBin Tu - Sun Microsystems - Beijing China * 0 : rx
551073cd555cSBin Tu - Sun Microsystems - Beijing China * 1 : tx
5511da14cebeSEric Cheng */
5512da14cebeSEric Cheng static void
ixgbe_enable_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,int8_t cause)551373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_enable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
5514da14cebeSEric Cheng {
5515da14cebeSEric Cheng struct ixgbe_hw *hw = &ixgbe->hw;
5516da14cebeSEric Cheng u32 ivar, index;
5517da14cebeSEric Cheng
551873cd555cSBin Tu - Sun Microsystems - Beijing China switch (hw->mac.type) {
551973cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
552073cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) {
552173cd555cSBin Tu - Sun Microsystems - Beijing China cause = 0;
552273cd555cSBin Tu - Sun Microsystems - Beijing China }
552373cd555cSBin Tu - Sun Microsystems - Beijing China index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
552473cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
552573cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (IXGBE_IVAR_ALLOC_VAL << (8 *
552673cd555cSBin Tu - Sun Microsystems - Beijing China (intr_alloc_entry & 0x3)));
552773cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
552873cd555cSBin Tu - Sun Microsystems - Beijing China break;
55295b6dd21fSchenlu chen - Sun Microsystems - Beijing China
553073cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
553169b5a878SDan McDonald case ixgbe_mac_X540:
5532dc0cb1cdSDale Ghent case ixgbe_mac_X550:
5533dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
553448ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
553573cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) {
553673cd555cSBin Tu - Sun Microsystems - Beijing China /* other causes */
553773cd555cSBin Tu - Sun Microsystems - Beijing China index = (intr_alloc_entry & 1) * 8;
553873cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
553973cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
554073cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
554173cd555cSBin Tu - Sun Microsystems - Beijing China } else {
554273cd555cSBin Tu - Sun Microsystems - Beijing China /* tx or rx causes */
554373cd555cSBin Tu - Sun Microsystems - Beijing China index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
554473cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw,
554573cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_IVAR(intr_alloc_entry >> 1));
554673cd555cSBin Tu - Sun Microsystems - Beijing China ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
554773cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
554873cd555cSBin Tu - Sun Microsystems - Beijing China ivar);
554973cd555cSBin Tu - Sun Microsystems - Beijing China }
555073cd555cSBin Tu - Sun Microsystems - Beijing China break;
55515b6dd21fSchenlu chen - Sun Microsystems - Beijing China
555273cd555cSBin Tu - Sun Microsystems - Beijing China default:
555373cd555cSBin Tu - Sun Microsystems - Beijing China break;
555473cd555cSBin Tu - Sun Microsystems - Beijing China }
5555da14cebeSEric Cheng }
5556da14cebeSEric Cheng
5557da14cebeSEric Cheng /*
555873cd555cSBin Tu - Sun Microsystems - Beijing China * ixgbe_disable_ivar - Disble the given entry by clearing the VAL bit of
5559da14cebeSEric Cheng * given interrupt vector allocation register (IVAR).
556073cd555cSBin Tu - Sun Microsystems - Beijing China * cause:
556173cd555cSBin Tu - Sun Microsystems - Beijing China * -1 : other cause
556273cd555cSBin Tu - Sun Microsystems - Beijing China * 0 : rx
556373cd555cSBin Tu - Sun Microsystems - Beijing China * 1 : tx
5564da14cebeSEric Cheng */
5565da14cebeSEric Cheng static void
ixgbe_disable_ivar(ixgbe_t * ixgbe,uint16_t intr_alloc_entry,int8_t cause)556673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_disable_ivar(ixgbe_t *ixgbe, uint16_t intr_alloc_entry, int8_t cause)
5567da14cebeSEric Cheng {
5568da14cebeSEric Cheng struct ixgbe_hw *hw = &ixgbe->hw;
5569da14cebeSEric Cheng u32 ivar, index;
5570da14cebeSEric Cheng
557173cd555cSBin Tu - Sun Microsystems - Beijing China switch (hw->mac.type) {
557273cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
557373cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) {
557473cd555cSBin Tu - Sun Microsystems - Beijing China cause = 0;
557573cd555cSBin Tu - Sun Microsystems - Beijing China }
557673cd555cSBin Tu - Sun Microsystems - Beijing China index = (((cause * 64) + intr_alloc_entry) >> 2) & 0x1F;
557773cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
557873cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(IXGBE_IVAR_ALLOC_VAL<< (8 *
557973cd555cSBin Tu - Sun Microsystems - Beijing China (intr_alloc_entry & 0x3)));
558073cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
558173cd555cSBin Tu - Sun Microsystems - Beijing China break;
55825b6dd21fSchenlu chen - Sun Microsystems - Beijing China
558373cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
558469b5a878SDan McDonald case ixgbe_mac_X540:
5585dc0cb1cdSDale Ghent case ixgbe_mac_X550:
5586dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
558748ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
558873cd555cSBin Tu - Sun Microsystems - Beijing China if (cause == -1) {
558973cd555cSBin Tu - Sun Microsystems - Beijing China /* other causes */
559073cd555cSBin Tu - Sun Microsystems - Beijing China index = (intr_alloc_entry & 1) * 8;
559173cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
559273cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
559373cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar);
559473cd555cSBin Tu - Sun Microsystems - Beijing China } else {
559573cd555cSBin Tu - Sun Microsystems - Beijing China /* tx or rx causes */
559673cd555cSBin Tu - Sun Microsystems - Beijing China index = ((16 * (intr_alloc_entry & 1)) + (8 * cause));
559773cd555cSBin Tu - Sun Microsystems - Beijing China ivar = IXGBE_READ_REG(hw,
559873cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_IVAR(intr_alloc_entry >> 1));
559973cd555cSBin Tu - Sun Microsystems - Beijing China ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
560073cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(intr_alloc_entry >> 1),
560173cd555cSBin Tu - Sun Microsystems - Beijing China ivar);
560273cd555cSBin Tu - Sun Microsystems - Beijing China }
560373cd555cSBin Tu - Sun Microsystems - Beijing China break;
56045b6dd21fSchenlu chen - Sun Microsystems - Beijing China
560573cd555cSBin Tu - Sun Microsystems - Beijing China default:
560673cd555cSBin Tu - Sun Microsystems - Beijing China break;
560773cd555cSBin Tu - Sun Microsystems - Beijing China }
56089da57d7bSbt }
56099da57d7bSbt
56100dc2366fSVenugopal Iyer /*
56110dc2366fSVenugopal Iyer * Convert the rx ring index driver maintained to the rx ring index
56120dc2366fSVenugopal Iyer * in h/w.
56130dc2366fSVenugopal Iyer */
56140dc2366fSVenugopal Iyer static uint32_t
ixgbe_get_hw_rx_index(ixgbe_t * ixgbe,uint32_t sw_rx_index)56150dc2366fSVenugopal Iyer ixgbe_get_hw_rx_index(ixgbe_t *ixgbe, uint32_t sw_rx_index)
56160dc2366fSVenugopal Iyer {
56170dc2366fSVenugopal Iyer
56180dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw;
56190dc2366fSVenugopal Iyer uint32_t rx_ring_per_group, hw_rx_index;
56200dc2366fSVenugopal Iyer
56210dc2366fSVenugopal Iyer if (ixgbe->classify_mode == IXGBE_CLASSIFY_RSS ||
56220dc2366fSVenugopal Iyer ixgbe->classify_mode == IXGBE_CLASSIFY_NONE) {
56230dc2366fSVenugopal Iyer return (sw_rx_index);
56240dc2366fSVenugopal Iyer } else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ) {
56255b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) {
56265b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
56270dc2366fSVenugopal Iyer return (sw_rx_index);
56285b6dd21fSchenlu chen - Sun Microsystems - Beijing China
56295b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
563069b5a878SDan McDonald case ixgbe_mac_X540:
5631dc0cb1cdSDale Ghent case ixgbe_mac_X550:
5632dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
563348ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
56340dc2366fSVenugopal Iyer return (sw_rx_index * 2);
56355b6dd21fSchenlu chen - Sun Microsystems - Beijing China
56365b6dd21fSchenlu chen - Sun Microsystems - Beijing China default:
56375b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
56380dc2366fSVenugopal Iyer }
56390dc2366fSVenugopal Iyer } else if (ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) {
56400dc2366fSVenugopal Iyer rx_ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups;
56410dc2366fSVenugopal Iyer
56425b6dd21fSchenlu chen - Sun Microsystems - Beijing China switch (hw->mac.type) {
56435b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
56440dc2366fSVenugopal Iyer hw_rx_index = (sw_rx_index / rx_ring_per_group) *
56450dc2366fSVenugopal Iyer 16 + (sw_rx_index % rx_ring_per_group);
56460dc2366fSVenugopal Iyer return (hw_rx_index);
56475b6dd21fSchenlu chen - Sun Microsystems - Beijing China
56485b6dd21fSchenlu chen - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
564969b5a878SDan McDonald case ixgbe_mac_X540:
5650dc0cb1cdSDale Ghent case ixgbe_mac_X550:
5651dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
565248ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
56530dc2366fSVenugopal Iyer if (ixgbe->num_rx_groups > 32) {
56540dc2366fSVenugopal Iyer hw_rx_index = (sw_rx_index /
56550dc2366fSVenugopal Iyer rx_ring_per_group) * 2 +
56560dc2366fSVenugopal Iyer (sw_rx_index % rx_ring_per_group);
56570dc2366fSVenugopal Iyer } else {
56580dc2366fSVenugopal Iyer hw_rx_index = (sw_rx_index /
56590dc2366fSVenugopal Iyer rx_ring_per_group) * 4 +
56600dc2366fSVenugopal Iyer (sw_rx_index % rx_ring_per_group);
56610dc2366fSVenugopal Iyer }
56620dc2366fSVenugopal Iyer return (hw_rx_index);
56635b6dd21fSchenlu chen - Sun Microsystems - Beijing China
56645b6dd21fSchenlu chen - Sun Microsystems - Beijing China default:
56655b6dd21fSchenlu chen - Sun Microsystems - Beijing China break;
56660dc2366fSVenugopal Iyer }
56670dc2366fSVenugopal Iyer }
56680dc2366fSVenugopal Iyer
56690dc2366fSVenugopal Iyer /*
56700dc2366fSVenugopal Iyer * Should never reach. Just to make compiler happy.
56710dc2366fSVenugopal Iyer */
56720dc2366fSVenugopal Iyer return (sw_rx_index);
56730dc2366fSVenugopal Iyer }
56740dc2366fSVenugopal Iyer
56759da57d7bSbt /*
567673cd555cSBin Tu - Sun Microsystems - Beijing China * ixgbe_map_intrs_to_vectors - Map different interrupts to MSI-X vectors.
56779da57d7bSbt *
567873cd555cSBin Tu - Sun Microsystems - Beijing China * For MSI-X, here will map rx interrupt, tx interrupt and other interrupt
567973cd555cSBin Tu - Sun Microsystems - Beijing China * to vector[0 - (intr_cnt -1)].
56809da57d7bSbt */
56819da57d7bSbt static int
ixgbe_map_intrs_to_vectors(ixgbe_t * ixgbe)568273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_map_intrs_to_vectors(ixgbe_t *ixgbe)
56839da57d7bSbt {
56849da57d7bSbt int i, vector = 0;
56859da57d7bSbt
56869da57d7bSbt /* initialize vector map */
56879da57d7bSbt bzero(&ixgbe->vect_map, sizeof (ixgbe->vect_map));
568873cd555cSBin Tu - Sun Microsystems - Beijing China for (i = 0; i < ixgbe->intr_cnt; i++) {
568973cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->vect_map[i].ixgbe = ixgbe;
569073cd555cSBin Tu - Sun Microsystems - Beijing China }
56919da57d7bSbt
56929da57d7bSbt /*
5693da14cebeSEric Cheng * non-MSI-X case is very simple: rx rings[0] on RTxQ[0],
5694da14cebeSEric Cheng * tx rings[0] on RTxQ[1].
56959da57d7bSbt */
56969da57d7bSbt if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
56979da57d7bSbt ixgbe_map_rxring_to_vector(ixgbe, 0, 0);
5698da14cebeSEric Cheng ixgbe_map_txring_to_vector(ixgbe, 0, 1);
56999da57d7bSbt return (IXGBE_SUCCESS);
57009da57d7bSbt }
57019da57d7bSbt
57029da57d7bSbt /*
570373cd555cSBin Tu - Sun Microsystems - Beijing China * Interrupts/vectors mapping for MSI-X
57049da57d7bSbt */
57059da57d7bSbt
57069da57d7bSbt /*
570773cd555cSBin Tu - Sun Microsystems - Beijing China * Map other interrupt to vector 0,
570873cd555cSBin Tu - Sun Microsystems - Beijing China * Set bit in map and count the bits set.
570973cd555cSBin Tu - Sun Microsystems - Beijing China */
571073cd555cSBin Tu - Sun Microsystems - Beijing China BT_SET(ixgbe->vect_map[vector].other_map, 0);
571173cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe->vect_map[vector].other_cnt++;
571273cd555cSBin Tu - Sun Microsystems - Beijing China
571373cd555cSBin Tu - Sun Microsystems - Beijing China /*
571473cd555cSBin Tu - Sun Microsystems - Beijing China * Map rx ring interrupts to vectors
57159da57d7bSbt */
5716da14cebeSEric Cheng for (i = 0; i < ixgbe->num_rx_rings; i++) {
5717da14cebeSEric Cheng ixgbe_map_rxring_to_vector(ixgbe, i, vector);
571873cd555cSBin Tu - Sun Microsystems - Beijing China vector = (vector +1) % ixgbe->intr_cnt;
5719da14cebeSEric Cheng }
57209da57d7bSbt
57219da57d7bSbt /*
572273cd555cSBin Tu - Sun Microsystems - Beijing China * Map tx ring interrupts to vectors
57239da57d7bSbt */
5724da14cebeSEric Cheng for (i = 0; i < ixgbe->num_tx_rings; i++) {
5725da14cebeSEric Cheng ixgbe_map_txring_to_vector(ixgbe, i, vector);
572673cd555cSBin Tu - Sun Microsystems - Beijing China vector = (vector +1) % ixgbe->intr_cnt;
57279da57d7bSbt }
57289da57d7bSbt
57299da57d7bSbt return (IXGBE_SUCCESS);
57309da57d7bSbt }
57319da57d7bSbt
57329da57d7bSbt /*
57339da57d7bSbt * ixgbe_setup_adapter_vector - Setup the adapter interrupt vector(s).
57349da57d7bSbt *
5735da14cebeSEric Cheng * This relies on ring/vector mapping already set up in the
57369da57d7bSbt * vect_map[] structures
57379da57d7bSbt */
57389da57d7bSbt static void
ixgbe_setup_adapter_vector(ixgbe_t * ixgbe)57399da57d7bSbt ixgbe_setup_adapter_vector(ixgbe_t *ixgbe)
57409da57d7bSbt {
57419da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
574273cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_intr_vector_t *vect; /* vector bitmap */
5743da14cebeSEric Cheng int r_idx; /* ring index */
5744da14cebeSEric Cheng int v_idx; /* vector index */
57450dc2366fSVenugopal Iyer uint32_t hw_index;
57469da57d7bSbt
57479da57d7bSbt /*
57489da57d7bSbt * Clear any previous entries
57499da57d7bSbt */
575073cd555cSBin Tu - Sun Microsystems - Beijing China switch (hw->mac.type) {
575173cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82598EB:
575273cd555cSBin Tu - Sun Microsystems - Beijing China for (v_idx = 0; v_idx < 25; v_idx++)
575373cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
575473cd555cSBin Tu - Sun Microsystems - Beijing China break;
57555b6dd21fSchenlu chen - Sun Microsystems - Beijing China
575673cd555cSBin Tu - Sun Microsystems - Beijing China case ixgbe_mac_82599EB:
575769b5a878SDan McDonald case ixgbe_mac_X540:
5758dc0cb1cdSDale Ghent case ixgbe_mac_X550:
5759dc0cb1cdSDale Ghent case ixgbe_mac_X550EM_x:
576048ed61a7SRobert Mustacchi case ixgbe_mac_X550EM_a:
576173cd555cSBin Tu - Sun Microsystems - Beijing China for (v_idx = 0; v_idx < 64; v_idx++)
576273cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0);
576373cd555cSBin Tu - Sun Microsystems - Beijing China IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0);
576473cd555cSBin Tu - Sun Microsystems - Beijing China break;
57655b6dd21fSchenlu chen - Sun Microsystems - Beijing China
576673cd555cSBin Tu - Sun Microsystems - Beijing China default:
576773cd555cSBin Tu - Sun Microsystems - Beijing China break;
576873cd555cSBin Tu - Sun Microsystems - Beijing China }
57699da57d7bSbt
57709da57d7bSbt /*
5771da14cebeSEric Cheng * For non MSI-X interrupt, rx rings[0] will use RTxQ[0], and
5772da14cebeSEric Cheng * tx rings[0] will use RTxQ[1].
5773da14cebeSEric Cheng */
5774da14cebeSEric Cheng if (ixgbe->intr_type != DDI_INTR_TYPE_MSIX) {
577573cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe, 0, 0, 0);
577673cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe, 0, 1, 1);
5777da14cebeSEric Cheng return;
5778da14cebeSEric Cheng }
5779da14cebeSEric Cheng
5780da14cebeSEric Cheng /*
578173cd555cSBin Tu - Sun Microsystems - Beijing China * For MSI-X interrupt, "Other" is always on vector[0].
57829da57d7bSbt */
578373cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe, IXGBE_IVAR_OTHER_CAUSES_INDEX, 0, -1);
57849da57d7bSbt
57859da57d7bSbt /*
57869da57d7bSbt * For each interrupt vector, populate the IVAR table
57879da57d7bSbt */
57889da57d7bSbt for (v_idx = 0; v_idx < ixgbe->intr_cnt; v_idx++) {
57899da57d7bSbt vect = &ixgbe->vect_map[v_idx];
57909da57d7bSbt
57919da57d7bSbt /*
57929da57d7bSbt * For each rx ring bit set
57939da57d7bSbt */
57949da57d7bSbt r_idx = bt_getlowbit(vect->rx_map, 0,
57959da57d7bSbt (ixgbe->num_rx_rings - 1));
57969da57d7bSbt
57979da57d7bSbt while (r_idx >= 0) {
57980dc2366fSVenugopal Iyer hw_index = ixgbe->rx_rings[r_idx].hw_index;
57990dc2366fSVenugopal Iyer ixgbe_setup_ivar(ixgbe, hw_index, v_idx, 0);
58009da57d7bSbt r_idx = bt_getlowbit(vect->rx_map, (r_idx + 1),
58019da57d7bSbt (ixgbe->num_rx_rings - 1));
58029da57d7bSbt }
58039da57d7bSbt
58049da57d7bSbt /*
58059da57d7bSbt * For each tx ring bit set
58069da57d7bSbt */
58079da57d7bSbt r_idx = bt_getlowbit(vect->tx_map, 0,
58089da57d7bSbt (ixgbe->num_tx_rings - 1));
58099da57d7bSbt
58109da57d7bSbt while (r_idx >= 0) {
581173cd555cSBin Tu - Sun Microsystems - Beijing China ixgbe_setup_ivar(ixgbe, r_idx, v_idx, 1);
58129da57d7bSbt r_idx = bt_getlowbit(vect->tx_map, (r_idx + 1),
58139da57d7bSbt (ixgbe->num_tx_rings - 1));
58149da57d7bSbt }
58159da57d7bSbt }
58169da57d7bSbt }
58179da57d7bSbt
58189da57d7bSbt /*
58199da57d7bSbt * ixgbe_rem_intr_handlers - Remove the interrupt handlers.
58209da57d7bSbt */
58219da57d7bSbt static void
ixgbe_rem_intr_handlers(ixgbe_t * ixgbe)58229da57d7bSbt ixgbe_rem_intr_handlers(ixgbe_t *ixgbe)
58239da57d7bSbt {
58249da57d7bSbt int i;
58259da57d7bSbt int rc;
58269da57d7bSbt
58279da57d7bSbt for (i = 0; i < ixgbe->intr_cnt; i++) {
58289da57d7bSbt rc = ddi_intr_remove_handler(ixgbe->htable[i]);
58299da57d7bSbt if (rc != DDI_SUCCESS) {
58309da57d7bSbt IXGBE_DEBUGLOG_1(ixgbe,
58319da57d7bSbt "Remove intr handler failed: %d", rc);
58329da57d7bSbt }
58339da57d7bSbt }
58349da57d7bSbt }
58359da57d7bSbt
58369da57d7bSbt /*
58379da57d7bSbt * ixgbe_rem_intrs - Remove the allocated interrupts.
58389da57d7bSbt */
58399da57d7bSbt static void
ixgbe_rem_intrs(ixgbe_t * ixgbe)58409da57d7bSbt ixgbe_rem_intrs(ixgbe_t *ixgbe)
58419da57d7bSbt {
58429da57d7bSbt int i;
58439da57d7bSbt int rc;
58449da57d7bSbt
58459da57d7bSbt for (i = 0; i < ixgbe->intr_cnt; i++) {
58469da57d7bSbt rc = ddi_intr_free(ixgbe->htable[i]);
58479da57d7bSbt if (rc != DDI_SUCCESS) {
58489da57d7bSbt IXGBE_DEBUGLOG_1(ixgbe,
58499da57d7bSbt "Free intr failed: %d", rc);
58509da57d7bSbt }
58519da57d7bSbt }
58529da57d7bSbt
58539da57d7bSbt kmem_free(ixgbe->htable, ixgbe->intr_size);
58549da57d7bSbt ixgbe->htable = NULL;
58559da57d7bSbt }
58569da57d7bSbt
58579da57d7bSbt /*
58589da57d7bSbt * ixgbe_enable_intrs - Enable all the ddi interrupts.
58599da57d7bSbt */
58609da57d7bSbt static int
ixgbe_enable_intrs(ixgbe_t * ixgbe)58619da57d7bSbt ixgbe_enable_intrs(ixgbe_t *ixgbe)
58629da57d7bSbt {
58639da57d7bSbt int i;
58649da57d7bSbt int rc;
58659da57d7bSbt
58669da57d7bSbt /*
58679da57d7bSbt * Enable interrupts
58689da57d7bSbt */
58699da57d7bSbt if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
58709da57d7bSbt /*
58719da57d7bSbt * Call ddi_intr_block_enable() for MSI
58729da57d7bSbt */
58739da57d7bSbt rc = ddi_intr_block_enable(ixgbe->htable, ixgbe->intr_cnt);
58749da57d7bSbt if (rc != DDI_SUCCESS) {
58759da57d7bSbt ixgbe_log(ixgbe,
58769da57d7bSbt "Enable block intr failed: %d", rc);
58779da57d7bSbt return (IXGBE_FAILURE);
58789da57d7bSbt }
58799da57d7bSbt } else {
58809da57d7bSbt /*
58819da57d7bSbt * Call ddi_intr_enable() for Legacy/MSI non block enable
58829da57d7bSbt */
58839da57d7bSbt for (i = 0; i < ixgbe->intr_cnt; i++) {
58849da57d7bSbt rc = ddi_intr_enable(ixgbe->htable[i]);
58859da57d7bSbt if (rc != DDI_SUCCESS) {
58869da57d7bSbt ixgbe_log(ixgbe,
58879da57d7bSbt "Enable intr failed: %d", rc);
58889da57d7bSbt return (IXGBE_FAILURE);
58899da57d7bSbt }
58909da57d7bSbt }
58919da57d7bSbt }
58929da57d7bSbt
58939da57d7bSbt return (IXGBE_SUCCESS);
58949da57d7bSbt }
58959da57d7bSbt
58969da57d7bSbt /*
58979da57d7bSbt * ixgbe_disable_intrs - Disable all the interrupts.
58989da57d7bSbt */
58999da57d7bSbt static int
ixgbe_disable_intrs(ixgbe_t * ixgbe)59009da57d7bSbt ixgbe_disable_intrs(ixgbe_t *ixgbe)
59019da57d7bSbt {
59029da57d7bSbt int i;
59039da57d7bSbt int rc;
59049da57d7bSbt
59059da57d7bSbt /*
59069da57d7bSbt * Disable all interrupts
59079da57d7bSbt */
59089da57d7bSbt if (ixgbe->intr_cap & DDI_INTR_FLAG_BLOCK) {
59099da57d7bSbt rc = ddi_intr_block_disable(ixgbe->htable, ixgbe->intr_cnt);
59109da57d7bSbt if (rc != DDI_SUCCESS) {
59119da57d7bSbt ixgbe_log(ixgbe,
59129da57d7bSbt "Disable block intr failed: %d", rc);
59139da57d7bSbt return (IXGBE_FAILURE);
59149da57d7bSbt }
59159da57d7bSbt } else {
59169da57d7bSbt for (i = 0; i < ixgbe->intr_cnt; i++) {
59179da57d7bSbt rc = ddi_intr_disable(ixgbe->htable[i]);
59189da57d7bSbt if (rc != DDI_SUCCESS) {
59199da57d7bSbt ixgbe_log(ixgbe,
59209da57d7bSbt "Disable intr failed: %d", rc);
59219da57d7bSbt return (IXGBE_FAILURE);
59229da57d7bSbt }
59239da57d7bSbt }
59249da57d7bSbt }
59259da57d7bSbt
59269da57d7bSbt return (IXGBE_SUCCESS);
59279da57d7bSbt }
59289da57d7bSbt
59299da57d7bSbt /*
59309da57d7bSbt * ixgbe_get_hw_state - Get and save parameters related to adapter hardware.
59319da57d7bSbt */
59329da57d7bSbt static void
ixgbe_get_hw_state(ixgbe_t * ixgbe)59339da57d7bSbt ixgbe_get_hw_state(ixgbe_t *ixgbe)
59349da57d7bSbt {
59359da57d7bSbt struct ixgbe_hw *hw = &ixgbe->hw;
5936dc0cb1cdSDale Ghent ixgbe_link_speed speed = 0;
593713740cb2SPaul Guo boolean_t link_up = B_FALSE;
59389da57d7bSbt uint32_t pcs1g_anlp = 0;
59399da57d7bSbt
59409da57d7bSbt ASSERT(mutex_owned(&ixgbe->gen_lock));
59419da57d7bSbt ixgbe->param_lp_1000fdx_cap = 0;
59429da57d7bSbt ixgbe->param_lp_100fdx_cap = 0;
59439da57d7bSbt
594413740cb2SPaul Guo /* check for link, don't wait */
5945dc0cb1cdSDale Ghent (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
5946*633c5e5cSRobert Mustacchi ixgbe->phys_supported = ixgbe_get_supported_physical_layer(hw);
59475b6dd21fSchenlu chen - Sun Microsystems - Beijing China
5948dc0cb1cdSDale Ghent /*
5949dc0cb1cdSDale Ghent * Update the observed Link Partner's capabilities. Not all adapters
5950dc0cb1cdSDale Ghent * can provide full information on the LP's capable speeds, so we
5951dc0cb1cdSDale Ghent * provide what we can.
5952dc0cb1cdSDale Ghent */
595313740cb2SPaul Guo if (link_up) {
59549da57d7bSbt pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
59559da57d7bSbt
59569da57d7bSbt ixgbe->param_lp_1000fdx_cap =
59579da57d7bSbt (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
59589da57d7bSbt ixgbe->param_lp_100fdx_cap =
59599da57d7bSbt (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0;
59609da57d7bSbt }
59619da57d7bSbt
5962dc0cb1cdSDale Ghent /*
5963dc0cb1cdSDale Ghent * Update GLD's notion of the adapter's currently advertised speeds.
5964dc0cb1cdSDale Ghent * Since the common code doesn't always record the current autonegotiate
5965dc0cb1cdSDale Ghent * settings in the phy struct for all parts (specifically, adapters with
5966dc0cb1cdSDale Ghent * SFPs) we first test to see if it is 0, and if so, we fall back to
5967dc0cb1cdSDale Ghent * using the adapter's speed capabilities which we saved during instance
5968dc0cb1cdSDale Ghent * init in ixgbe_init_params().
5969dc0cb1cdSDale Ghent *
5970dc0cb1cdSDale Ghent * Adapters with SFPs will always be shown as advertising all of their
5971dc0cb1cdSDale Ghent * supported speeds, and adapters with baseT PHYs (where the phy struct
5972dc0cb1cdSDale Ghent * is maintained by the common code) will always have a factual view of
5973dc0cb1cdSDale Ghent * their currently-advertised speeds. In the case of SFPs, this is
5974dc0cb1cdSDale Ghent * acceptable as we default to advertising all speeds that the adapter
5975dc0cb1cdSDale Ghent * claims to support, and those properties are immutable; unlike on
5976dc0cb1cdSDale Ghent * baseT (copper) PHYs, where speeds can be enabled or disabled at will.
5977dc0cb1cdSDale Ghent */
5978dc0cb1cdSDale Ghent speed = hw->phy.autoneg_advertised;
5979dc0cb1cdSDale Ghent if (speed == 0)
5980dc0cb1cdSDale Ghent speed = ixgbe->speeds_supported;
5981dc0cb1cdSDale Ghent
5982dc0cb1cdSDale Ghent ixgbe->param_adv_10000fdx_cap =
5983dc0cb1cdSDale Ghent (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 1 : 0;
5984dc0cb1cdSDale Ghent ixgbe->param_adv_5000fdx_cap =
5985dc0cb1cdSDale Ghent (speed & IXGBE_LINK_SPEED_5GB_FULL) ? 1 : 0;
5986dc0cb1cdSDale Ghent ixgbe->param_adv_2500fdx_cap =
5987dc0cb1cdSDale Ghent (speed & IXGBE_LINK_SPEED_2_5GB_FULL) ? 1 : 0;
5988dc0cb1cdSDale Ghent ixgbe->param_adv_1000fdx_cap =
5989dc0cb1cdSDale Ghent (speed & IXGBE_LINK_SPEED_1GB_FULL) ? 1 : 0;
5990dc0cb1cdSDale Ghent ixgbe->param_adv_100fdx_cap =
5991dc0cb1cdSDale Ghent (speed & IXGBE_LINK_SPEED_100_FULL) ? 1 : 0;
59929da57d7bSbt }
59939da57d7bSbt
59949da57d7bSbt /*
59959da57d7bSbt * ixgbe_get_driver_control - Notify that driver is in control of device.
59969da57d7bSbt */
59979da57d7bSbt static void
ixgbe_get_driver_control(struct ixgbe_hw * hw)59989da57d7bSbt ixgbe_get_driver_control(struct ixgbe_hw *hw)
59999da57d7bSbt {
60009da57d7bSbt uint32_t ctrl_ext;
60019da57d7bSbt
60029da57d7bSbt /*
60039da57d7bSbt * Notify firmware that driver is in control of device
60049da57d7bSbt */
60059da57d7bSbt ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
60069da57d7bSbt ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
60079da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
60089da57d7bSbt }
60099da57d7bSbt
60109da57d7bSbt /*
60119da57d7bSbt * ixgbe_release_driver_control - Notify that driver is no longer in control
60129da57d7bSbt * of device.
60139da57d7bSbt */
60149da57d7bSbt static void
ixgbe_release_driver_control(struct ixgbe_hw * hw)60159da57d7bSbt ixgbe_release_driver_control(struct ixgbe_hw *hw)
60169da57d7bSbt {
60179da57d7bSbt uint32_t ctrl_ext;
60189da57d7bSbt
60199da57d7bSbt /*
60209da57d7bSbt * Notify firmware that driver is no longer in control of device
60219da57d7bSbt */
60229da57d7bSbt ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
60239da57d7bSbt ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD;
60249da57d7bSbt IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
60259da57d7bSbt }
60269da57d7bSbt
60279da57d7bSbt /*
60289da57d7bSbt * ixgbe_atomic_reserve - Atomic decrease operation.
60299da57d7bSbt */
60309da57d7bSbt int
ixgbe_atomic_reserve(uint32_t * count_p,uint32_t n)60319da57d7bSbt ixgbe_atomic_reserve(uint32_t *count_p, uint32_t n)
60329da57d7bSbt {
60339da57d7bSbt uint32_t oldval;
60349da57d7bSbt uint32_t newval;
60359da57d7bSbt
60369da57d7bSbt /*
60379da57d7bSbt * ATOMICALLY
60389da57d7bSbt */
60399da57d7bSbt do {
60409da57d7bSbt oldval = *count_p;
60419da57d7bSbt if (oldval < n)
60429da57d7bSbt return (-1);
60439da57d7bSbt newval = oldval - n;
60449da57d7bSbt } while (atomic_cas_32(count_p, oldval, newval) != oldval);
60459da57d7bSbt
60469da57d7bSbt return (newval);
60479da57d7bSbt }
60489da57d7bSbt
60499da57d7bSbt /*
60509da57d7bSbt * ixgbe_mc_table_itr - Traverse the entries in the multicast table.
60519da57d7bSbt */
60529da57d7bSbt static uint8_t *
ixgbe_mc_table_itr(struct ixgbe_hw * hw,uint8_t ** upd_ptr,uint32_t * vmdq)60539da57d7bSbt ixgbe_mc_table_itr(struct ixgbe_hw *hw, uint8_t **upd_ptr, uint32_t *vmdq)
60549da57d7bSbt {
60559da57d7bSbt uint8_t *addr = *upd_ptr;
60569da57d7bSbt uint8_t *new_ptr;
60579da57d7bSbt
605813740cb2SPaul Guo _NOTE(ARGUNUSED(hw));
605913740cb2SPaul Guo _NOTE(ARGUNUSED(vmdq));
606013740cb2SPaul Guo
60619da57d7bSbt new_ptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS;
60629da57d7bSbt *upd_ptr = new_ptr;
60639da57d7bSbt return (addr);
60649da57d7bSbt }
60659da57d7bSbt
60669da57d7bSbt /*
60679da57d7bSbt * FMA support
60689da57d7bSbt */
60699da57d7bSbt int
ixgbe_check_acc_handle(ddi_acc_handle_t handle)60709da57d7bSbt ixgbe_check_acc_handle(ddi_acc_handle_t handle)
60719da57d7bSbt {
60729da57d7bSbt ddi_fm_error_t de;
60739da57d7bSbt
60749da57d7bSbt ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
60759da57d7bSbt ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
60769da57d7bSbt return (de.fme_status);
60779da57d7bSbt }
60789da57d7bSbt
60799da57d7bSbt int
ixgbe_check_dma_handle(ddi_dma_handle_t handle)60809da57d7bSbt ixgbe_check_dma_handle(ddi_dma_handle_t handle)
60819da57d7bSbt {
60829da57d7bSbt ddi_fm_error_t de;
60839da57d7bSbt
60849da57d7bSbt ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
60859da57d7bSbt return (de.fme_status);
60869da57d7bSbt }
60879da57d7bSbt
60889da57d7bSbt /*
60899da57d7bSbt * ixgbe_fm_error_cb - The IO fault service error handling callback function.
60909da57d7bSbt */
60919da57d7bSbt static int
ixgbe_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)60929da57d7bSbt ixgbe_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
60939da57d7bSbt {
60949da57d7bSbt _NOTE(ARGUNUSED(impl_data));
60959da57d7bSbt /*
60969da57d7bSbt * as the driver can always deal with an error in any dma or
60979da57d7bSbt * access handle, we can just return the fme_status value.
60989da57d7bSbt */
60999da57d7bSbt pci_ereport_post(dip, err, NULL);
61009da57d7bSbt return (err->fme_status);
61019da57d7bSbt }
61029da57d7bSbt
61039da57d7bSbt static void
ixgbe_fm_init(ixgbe_t * ixgbe)61049da57d7bSbt ixgbe_fm_init(ixgbe_t *ixgbe)
61059da57d7bSbt {
61069da57d7bSbt ddi_iblock_cookie_t iblk;
6107837c1ac4SStephen Hanson int fma_dma_flag;
61089da57d7bSbt
61099da57d7bSbt /*
61109da57d7bSbt * Only register with IO Fault Services if we have some capability
61119da57d7bSbt */
61129da57d7bSbt if (ixgbe->fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
61139da57d7bSbt ixgbe_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
61149da57d7bSbt } else {
61159da57d7bSbt ixgbe_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
61169da57d7bSbt }
61179da57d7bSbt
61189da57d7bSbt if (ixgbe->fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
61199da57d7bSbt fma_dma_flag = 1;
61209da57d7bSbt } else {
61219da57d7bSbt fma_dma_flag = 0;
61229da57d7bSbt }
61239da57d7bSbt
6124837c1ac4SStephen Hanson ixgbe_set_fma_flags(fma_dma_flag);
61259da57d7bSbt
61269da57d7bSbt if (ixgbe->fm_capabilities) {
61279da57d7bSbt
61289da57d7bSbt /*
61299da57d7bSbt * Register capabilities with IO Fault Services
61309da57d7bSbt */
61319da57d7bSbt ddi_fm_init(ixgbe->dip, &ixgbe->fm_capabilities, &iblk);
61329da57d7bSbt
61339da57d7bSbt /*
61349da57d7bSbt * Initialize pci ereport capabilities if ereport capable
61359da57d7bSbt */
61369da57d7bSbt if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
61379da57d7bSbt DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
61389da57d7bSbt pci_ereport_setup(ixgbe->dip);
61399da57d7bSbt
61409da57d7bSbt /*
61419da57d7bSbt * Register error callback if error callback capable
61429da57d7bSbt */
61439da57d7bSbt if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
61449da57d7bSbt ddi_fm_handler_register(ixgbe->dip,
61459da57d7bSbt ixgbe_fm_error_cb, (void*) ixgbe);
61469da57d7bSbt }
61479da57d7bSbt }
61489da57d7bSbt
61499da57d7bSbt static void
ixgbe_fm_fini(ixgbe_t * ixgbe)61509da57d7bSbt ixgbe_fm_fini(ixgbe_t *ixgbe)
61519da57d7bSbt {
61529da57d7bSbt /*
61539da57d7bSbt * Only unregister FMA capabilities if they are registered
61549da57d7bSbt */
61559da57d7bSbt if (ixgbe->fm_capabilities) {
61569da57d7bSbt
61579da57d7bSbt /*
61589da57d7bSbt * Release any resources allocated by pci_ereport_setup()
61599da57d7bSbt */
61609da57d7bSbt if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities) ||
61619da57d7bSbt DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
61629da57d7bSbt pci_ereport_teardown(ixgbe->dip);
61639da57d7bSbt
61649da57d7bSbt /*
61659da57d7bSbt * Un-register error callback if error callback capable
61669da57d7bSbt */
61679da57d7bSbt if (DDI_FM_ERRCB_CAP(ixgbe->fm_capabilities))
61689da57d7bSbt ddi_fm_handler_unregister(ixgbe->dip);
61699da57d7bSbt
61709da57d7bSbt /*
61719da57d7bSbt * Unregister from IO Fault Service
61729da57d7bSbt */
61739da57d7bSbt ddi_fm_fini(ixgbe->dip);
61749da57d7bSbt }
61759da57d7bSbt }
61769da57d7bSbt
61779da57d7bSbt void
ixgbe_fm_ereport(ixgbe_t * ixgbe,char * detail)61789da57d7bSbt ixgbe_fm_ereport(ixgbe_t *ixgbe, char *detail)
61799da57d7bSbt {
61809da57d7bSbt uint64_t ena;
61819da57d7bSbt char buf[FM_MAX_CLASS];
61829da57d7bSbt
61839da57d7bSbt (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
61849da57d7bSbt ena = fm_ena_generate(0, FM_ENA_FMT1);
61859da57d7bSbt if (DDI_FM_EREPORT_CAP(ixgbe->fm_capabilities)) {
61869da57d7bSbt ddi_fm_ereport_post(ixgbe->dip, buf, ena, DDI_NOSLEEP,
61879da57d7bSbt FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
61889da57d7bSbt }
61899da57d7bSbt }
6190da14cebeSEric Cheng
6191da14cebeSEric Cheng static int
ixgbe_ring_start(mac_ring_driver_t rh,uint64_t mr_gen_num)6192da14cebeSEric Cheng ixgbe_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
6193da14cebeSEric Cheng {
6194da14cebeSEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)rh;
6195da14cebeSEric Cheng
6196da14cebeSEric Cheng mutex_enter(&rx_ring->rx_lock);
6197da14cebeSEric Cheng rx_ring->ring_gen_num = mr_gen_num;
6198da14cebeSEric Cheng mutex_exit(&rx_ring->rx_lock);
6199da14cebeSEric Cheng return (0);
6200da14cebeSEric Cheng }
6201da14cebeSEric Cheng
62020dc2366fSVenugopal Iyer /*
62030dc2366fSVenugopal Iyer * Get the global ring index by a ring index within a group.
62040dc2366fSVenugopal Iyer */
62050dc2366fSVenugopal Iyer static int
ixgbe_get_rx_ring_index(ixgbe_t * ixgbe,int gindex,int rindex)62060dc2366fSVenugopal Iyer ixgbe_get_rx_ring_index(ixgbe_t *ixgbe, int gindex, int rindex)
62070dc2366fSVenugopal Iyer {
62080dc2366fSVenugopal Iyer ixgbe_rx_ring_t *rx_ring;
62090dc2366fSVenugopal Iyer int i;
62100dc2366fSVenugopal Iyer
62110dc2366fSVenugopal Iyer for (i = 0; i < ixgbe->num_rx_rings; i++) {
62120dc2366fSVenugopal Iyer rx_ring = &ixgbe->rx_rings[i];
62130dc2366fSVenugopal Iyer if (rx_ring->group_index == gindex)
62140dc2366fSVenugopal Iyer rindex--;
62150dc2366fSVenugopal Iyer if (rindex < 0)
62160dc2366fSVenugopal Iyer return (i);
62170dc2366fSVenugopal Iyer }
62180dc2366fSVenugopal Iyer
62190dc2366fSVenugopal Iyer return (-1);
62200dc2366fSVenugopal Iyer }
62210dc2366fSVenugopal Iyer
6222da14cebeSEric Cheng /*
6223da14cebeSEric Cheng * Callback funtion for MAC layer to register all rings.
6224da14cebeSEric Cheng */
6225da14cebeSEric Cheng /* ARGSUSED */
6226da14cebeSEric 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)62270dc2366fSVenugopal Iyer ixgbe_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index,
6228da14cebeSEric Cheng const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
6229da14cebeSEric Cheng {
6230da14cebeSEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg;
6231da14cebeSEric Cheng mac_intr_t *mintr = &infop->mri_intr;
6232da14cebeSEric Cheng
6233da14cebeSEric Cheng switch (rtype) {
6234da14cebeSEric Cheng case MAC_RING_TYPE_RX: {
62350dc2366fSVenugopal Iyer /*
62360dc2366fSVenugopal Iyer * 'index' is the ring index within the group.
62370dc2366fSVenugopal Iyer * Need to get the global ring index by searching in groups.
62380dc2366fSVenugopal Iyer */
62390dc2366fSVenugopal Iyer int global_ring_index = ixgbe_get_rx_ring_index(
62400dc2366fSVenugopal Iyer ixgbe, group_index, ring_index);
6241da14cebeSEric Cheng
62420dc2366fSVenugopal Iyer ASSERT(global_ring_index >= 0);
62430dc2366fSVenugopal Iyer
62440dc2366fSVenugopal Iyer ixgbe_rx_ring_t *rx_ring = &ixgbe->rx_rings[global_ring_index];
6245da14cebeSEric Cheng rx_ring->ring_handle = rh;
6246da14cebeSEric Cheng
6247da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring;
6248da14cebeSEric Cheng infop->mri_start = ixgbe_ring_start;
6249da14cebeSEric Cheng infop->mri_stop = NULL;
6250da14cebeSEric Cheng infop->mri_poll = ixgbe_ring_rx_poll;
62510dc2366fSVenugopal Iyer infop->mri_stat = ixgbe_rx_ring_stat;
6252da14cebeSEric Cheng
6253da14cebeSEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring;
6254da14cebeSEric Cheng mintr->mi_enable = ixgbe_rx_ring_intr_enable;
6255da14cebeSEric Cheng mintr->mi_disable = ixgbe_rx_ring_intr_disable;
62560dc2366fSVenugopal Iyer if (ixgbe->intr_type &
62570dc2366fSVenugopal Iyer (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
62580dc2366fSVenugopal Iyer mintr->mi_ddi_handle =
62590dc2366fSVenugopal Iyer ixgbe->htable[rx_ring->intr_vector];
62600dc2366fSVenugopal Iyer }
6261da14cebeSEric Cheng
6262da14cebeSEric Cheng break;
6263da14cebeSEric Cheng }
6264da14cebeSEric Cheng case MAC_RING_TYPE_TX: {
62650dc2366fSVenugopal Iyer ASSERT(group_index == -1);
6266da14cebeSEric Cheng ASSERT(ring_index < ixgbe->num_tx_rings);
6267da14cebeSEric Cheng
6268da14cebeSEric Cheng ixgbe_tx_ring_t *tx_ring = &ixgbe->tx_rings[ring_index];
6269da14cebeSEric Cheng tx_ring->ring_handle = rh;
6270da14cebeSEric Cheng
6271da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)tx_ring;
6272da14cebeSEric Cheng infop->mri_start = NULL;
6273da14cebeSEric Cheng infop->mri_stop = NULL;
6274da14cebeSEric Cheng infop->mri_tx = ixgbe_ring_tx;
62750dc2366fSVenugopal Iyer infop->mri_stat = ixgbe_tx_ring_stat;
62760dc2366fSVenugopal Iyer if (ixgbe->intr_type &
62770dc2366fSVenugopal Iyer (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) {
62780dc2366fSVenugopal Iyer mintr->mi_ddi_handle =
62790dc2366fSVenugopal Iyer ixgbe->htable[tx_ring->intr_vector];
62800dc2366fSVenugopal Iyer }
6281da14cebeSEric Cheng break;
6282da14cebeSEric Cheng }
6283da14cebeSEric Cheng default:
6284da14cebeSEric Cheng break;
6285da14cebeSEric Cheng }
6286da14cebeSEric Cheng }
6287da14cebeSEric Cheng
6288da14cebeSEric Cheng /*
6289da14cebeSEric Cheng * Callback funtion for MAC layer to register all groups.
6290da14cebeSEric Cheng */
6291da14cebeSEric 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)6292da14cebeSEric Cheng ixgbe_fill_group(void *arg, mac_ring_type_t rtype, const int index,
6293da14cebeSEric Cheng mac_group_info_t *infop, mac_group_handle_t gh)
6294da14cebeSEric Cheng {
6295da14cebeSEric Cheng ixgbe_t *ixgbe = (ixgbe_t *)arg;
629684de666eSRyan Zezeski struct ixgbe_hw *hw = &ixgbe->hw;
6297da14cebeSEric Cheng
6298da14cebeSEric Cheng switch (rtype) {
6299da14cebeSEric Cheng case MAC_RING_TYPE_RX: {
6300da14cebeSEric Cheng ixgbe_rx_group_t *rx_group;
6301da14cebeSEric Cheng
6302da14cebeSEric Cheng rx_group = &ixgbe->rx_groups[index];
6303da14cebeSEric Cheng rx_group->group_handle = gh;
6304da14cebeSEric Cheng
6305da14cebeSEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_group;
6306da14cebeSEric Cheng infop->mgi_start = NULL;
6307da14cebeSEric Cheng infop->mgi_stop = NULL;
6308da14cebeSEric Cheng infop->mgi_addmac = ixgbe_addmac;
6309da14cebeSEric Cheng infop->mgi_remmac = ixgbe_remmac;
631084de666eSRyan Zezeski
631184de666eSRyan Zezeski if ((ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ ||
631284de666eSRyan Zezeski ixgbe->classify_mode == IXGBE_CLASSIFY_VMDQ_RSS) &&
631384de666eSRyan Zezeski (hw->mac.type == ixgbe_mac_82599EB ||
631484de666eSRyan Zezeski hw->mac.type == ixgbe_mac_X540 ||
631584de666eSRyan Zezeski hw->mac.type == ixgbe_mac_X550 ||
631684de666eSRyan Zezeski hw->mac.type == ixgbe_mac_X550EM_x)) {
631784de666eSRyan Zezeski infop->mgi_addvlan = ixgbe_addvlan;
631884de666eSRyan Zezeski infop->mgi_remvlan = ixgbe_remvlan;
631984de666eSRyan Zezeski } else {
632084de666eSRyan Zezeski infop->mgi_addvlan = NULL;
632184de666eSRyan Zezeski infop->mgi_remvlan = NULL;
632284de666eSRyan Zezeski }
632384de666eSRyan Zezeski
6324da14cebeSEric Cheng infop->mgi_count = (ixgbe->num_rx_rings / ixgbe->num_rx_groups);
6325da14cebeSEric Cheng
6326da14cebeSEric Cheng break;
6327da14cebeSEric Cheng }
6328da14cebeSEric Cheng case MAC_RING_TYPE_TX:
6329da14cebeSEric Cheng break;
6330da14cebeSEric Cheng default:
6331da14cebeSEric Cheng break;
6332da14cebeSEric Cheng }
6333da14cebeSEric Cheng }
6334da14cebeSEric Cheng
6335da14cebeSEric Cheng /*
6336da14cebeSEric Cheng * Enable interrupt on the specificed rx ring.
6337da14cebeSEric Cheng */
6338da14cebeSEric Cheng int
ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)6339da14cebeSEric Cheng ixgbe_rx_ring_intr_enable(mac_intr_handle_t intrh)
6340da14cebeSEric Cheng {
6341da14cebeSEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
6342da14cebeSEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe;
6343da14cebeSEric Cheng int r_idx = rx_ring->index;
63440dc2366fSVenugopal Iyer int hw_r_idx = rx_ring->hw_index;
6345da14cebeSEric Cheng int v_idx = rx_ring->intr_vector;
6346da14cebeSEric Cheng
6347da14cebeSEric Cheng mutex_enter(&ixgbe->gen_lock);
63480dc2366fSVenugopal Iyer if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
63490dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock);
63500dc2366fSVenugopal Iyer /*
63510dc2366fSVenugopal Iyer * Simply return 0.
63520dc2366fSVenugopal Iyer * Interrupts are being adjusted. ixgbe_intr_adjust()
63530dc2366fSVenugopal Iyer * will eventually re-enable the interrupt when it's
63540dc2366fSVenugopal Iyer * done with the adjustment.
63550dc2366fSVenugopal Iyer */
63560dc2366fSVenugopal Iyer return (0);
63570dc2366fSVenugopal Iyer }
6358da14cebeSEric Cheng
6359da14cebeSEric Cheng /*
6360da14cebeSEric Cheng * To enable interrupt by setting the VAL bit of given interrupt
6361da14cebeSEric Cheng * vector allocation register (IVAR).
6362da14cebeSEric Cheng */
63630dc2366fSVenugopal Iyer ixgbe_enable_ivar(ixgbe, hw_r_idx, 0);
6364da14cebeSEric Cheng
6365da14cebeSEric Cheng BT_SET(ixgbe->vect_map[v_idx].rx_map, r_idx);
6366185c5677SPaul Guo
6367185c5677SPaul Guo /*
636819843f01SPaul Guo * Trigger a Rx interrupt on this ring
6369185c5677SPaul Guo */
6370185c5677SPaul Guo IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_EICS, (1 << v_idx));
6371185c5677SPaul Guo IXGBE_WRITE_FLUSH(&ixgbe->hw);
6372185c5677SPaul Guo
6373da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6374da14cebeSEric Cheng
6375da14cebeSEric Cheng return (0);
6376da14cebeSEric Cheng }
6377da14cebeSEric Cheng
6378da14cebeSEric Cheng /*
6379da14cebeSEric Cheng * Disable interrupt on the specificed rx ring.
6380da14cebeSEric Cheng */
6381da14cebeSEric Cheng int
ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)6382da14cebeSEric Cheng ixgbe_rx_ring_intr_disable(mac_intr_handle_t intrh)
6383da14cebeSEric Cheng {
6384da14cebeSEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)intrh;
6385da14cebeSEric Cheng ixgbe_t *ixgbe = rx_ring->ixgbe;
6386da14cebeSEric Cheng int r_idx = rx_ring->index;
63870dc2366fSVenugopal Iyer int hw_r_idx = rx_ring->hw_index;
6388da14cebeSEric Cheng int v_idx = rx_ring->intr_vector;
6389da14cebeSEric Cheng
6390da14cebeSEric Cheng mutex_enter(&ixgbe->gen_lock);
63910dc2366fSVenugopal Iyer if (ixgbe->ixgbe_state & IXGBE_INTR_ADJUST) {
63920dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock);
63930dc2366fSVenugopal Iyer /*
63940dc2366fSVenugopal Iyer * Simply return 0.
63950dc2366fSVenugopal Iyer * In the rare case where an interrupt is being
63960dc2366fSVenugopal Iyer * disabled while interrupts are being adjusted,
63970dc2366fSVenugopal Iyer * we don't fail the operation. No interrupts will
63980dc2366fSVenugopal Iyer * be generated while they are adjusted, and
63990dc2366fSVenugopal Iyer * ixgbe_intr_adjust() will cause the interrupts
64000dc2366fSVenugopal Iyer * to be re-enabled once it completes. Note that
64010dc2366fSVenugopal Iyer * in this case, packets may be delivered to the
64020dc2366fSVenugopal Iyer * stack via interrupts before xgbe_rx_ring_intr_enable()
64030dc2366fSVenugopal Iyer * is called again. This is acceptable since interrupt
64040dc2366fSVenugopal Iyer * adjustment is infrequent, and the stack will be
64050dc2366fSVenugopal Iyer * able to handle these packets.
64060dc2366fSVenugopal Iyer */
64070dc2366fSVenugopal Iyer return (0);
64080dc2366fSVenugopal Iyer }
6409da14cebeSEric Cheng
6410da14cebeSEric Cheng /*
6411da14cebeSEric Cheng * To disable interrupt by clearing the VAL bit of given interrupt
6412da14cebeSEric Cheng * vector allocation register (IVAR).
6413da14cebeSEric Cheng */
64140dc2366fSVenugopal Iyer ixgbe_disable_ivar(ixgbe, hw_r_idx, 0);
6415da14cebeSEric Cheng
6416da14cebeSEric Cheng BT_CLEAR(ixgbe->vect_map[v_idx].rx_map, r_idx);
6417da14cebeSEric Cheng
6418da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6419da14cebeSEric Cheng
6420da14cebeSEric Cheng return (0);
6421da14cebeSEric Cheng }
6422da14cebeSEric Cheng
642384de666eSRyan Zezeski static ixgbe_vlan_t *
ixgbe_find_vlan(ixgbe_rx_group_t * rx_group,uint16_t vid)642484de666eSRyan Zezeski ixgbe_find_vlan(ixgbe_rx_group_t *rx_group, uint16_t vid)
642584de666eSRyan Zezeski {
642684de666eSRyan Zezeski for (ixgbe_vlan_t *vlp = list_head(&rx_group->vlans); vlp != NULL;
642784de666eSRyan Zezeski vlp = list_next(&rx_group->vlans, vlp)) {
642884de666eSRyan Zezeski if (vlp->ixvl_vid == vid)
642984de666eSRyan Zezeski return (vlp);
643084de666eSRyan Zezeski }
643184de666eSRyan Zezeski
643284de666eSRyan Zezeski return (NULL);
643384de666eSRyan Zezeski }
643484de666eSRyan Zezeski
643584de666eSRyan Zezeski /*
643684de666eSRyan Zezeski * Attempt to use a VLAN HW filter for this group. If the group is
643784de666eSRyan Zezeski * interested in untagged packets then set AUPE only. If the group is
643884de666eSRyan Zezeski * the default then only set the VFTA. Leave the VLVF slots open for
643984de666eSRyan Zezeski * reserved groups to guarantee their use of HW filtering.
644084de666eSRyan Zezeski */
644184de666eSRyan Zezeski static int
ixgbe_addvlan(mac_group_driver_t gdriver,uint16_t vid)644284de666eSRyan Zezeski ixgbe_addvlan(mac_group_driver_t gdriver, uint16_t vid)
644384de666eSRyan Zezeski {
644484de666eSRyan Zezeski ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)gdriver;
644584de666eSRyan Zezeski ixgbe_t *ixgbe = rx_group->ixgbe;
644684de666eSRyan Zezeski struct ixgbe_hw *hw = &ixgbe->hw;
644784de666eSRyan Zezeski ixgbe_vlan_t *vlp;
644884de666eSRyan Zezeski int ret;
644984de666eSRyan Zezeski boolean_t is_def_grp;
645084de666eSRyan Zezeski
645184de666eSRyan Zezeski mutex_enter(&ixgbe->gen_lock);
645284de666eSRyan Zezeski
645384de666eSRyan Zezeski if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
645484de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
645584de666eSRyan Zezeski return (ECANCELED);
645684de666eSRyan Zezeski }
645784de666eSRyan Zezeski
645884de666eSRyan Zezeski /*
645984de666eSRyan Zezeski * Let's be sure VLAN filtering is enabled.
646084de666eSRyan Zezeski */
646184de666eSRyan Zezeski VERIFY3B(ixgbe->vlft_enabled, ==, B_TRUE);
646284de666eSRyan Zezeski is_def_grp = (rx_group->index == ixgbe->rx_def_group);
646384de666eSRyan Zezeski
646484de666eSRyan Zezeski /*
646584de666eSRyan Zezeski * VLAN filtering is enabled but we want to receive untagged
646684de666eSRyan Zezeski * traffic on this group -- set the AUPE bit on the group and
646784de666eSRyan Zezeski * leave the VLAN tables alone.
646884de666eSRyan Zezeski */
646984de666eSRyan Zezeski if (vid == MAC_VLAN_UNTAGGED) {
647084de666eSRyan Zezeski /*
647184de666eSRyan Zezeski * We never enable AUPE on the default group; it is
647284de666eSRyan Zezeski * redundant. Untagged traffic which passes L2
647384de666eSRyan Zezeski * filtering is delivered to the default group if no
647484de666eSRyan Zezeski * other group is interested.
647584de666eSRyan Zezeski */
647684de666eSRyan Zezeski if (!is_def_grp) {
647784de666eSRyan Zezeski uint32_t vml2flt;
647884de666eSRyan Zezeski
647984de666eSRyan Zezeski vml2flt = IXGBE_READ_REG(hw,
648084de666eSRyan Zezeski IXGBE_VMOLR(rx_group->index));
648184de666eSRyan Zezeski vml2flt |= IXGBE_VMOLR_AUPE;
648284de666eSRyan Zezeski IXGBE_WRITE_REG(hw, IXGBE_VMOLR(rx_group->index),
648384de666eSRyan Zezeski vml2flt);
648484de666eSRyan Zezeski rx_group->aupe = B_TRUE;
648584de666eSRyan Zezeski }
648684de666eSRyan Zezeski
648784de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
648884de666eSRyan Zezeski return (0);
648984de666eSRyan Zezeski }
649084de666eSRyan Zezeski
649184de666eSRyan Zezeski vlp = ixgbe_find_vlan(rx_group, vid);
649284de666eSRyan Zezeski if (vlp != NULL) {
649384de666eSRyan Zezeski /* Only the default group supports multiple clients. */
649484de666eSRyan Zezeski VERIFY3B(is_def_grp, ==, B_TRUE);
649584de666eSRyan Zezeski vlp->ixvl_refs++;
649684de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
649784de666eSRyan Zezeski return (0);
649884de666eSRyan Zezeski }
649984de666eSRyan Zezeski
650084de666eSRyan Zezeski /*
650184de666eSRyan Zezeski * The default group doesn't require a VLVF entry, only a VFTA
650284de666eSRyan Zezeski * entry. All traffic passing L2 filtering (MPSAR + VFTA) is
650384de666eSRyan Zezeski * delivered to the default group if no other group is
650484de666eSRyan Zezeski * interested. The fourth argument, vlvf_bypass, tells the
650584de666eSRyan Zezeski * ixgbe common code to avoid using a VLVF slot if one isn't
650684de666eSRyan Zezeski * already allocated to this VLAN.
650784de666eSRyan Zezeski *
650884de666eSRyan Zezeski * This logic is meant to reserve VLVF slots for use by
650984de666eSRyan Zezeski * reserved groups: guaranteeing their use of HW filtering.
651084de666eSRyan Zezeski */
651184de666eSRyan Zezeski ret = ixgbe_set_vfta(hw, vid, rx_group->index, B_TRUE, is_def_grp);
651284de666eSRyan Zezeski
651384de666eSRyan Zezeski if (ret == IXGBE_SUCCESS) {
651484de666eSRyan Zezeski vlp = kmem_zalloc(sizeof (ixgbe_vlan_t), KM_SLEEP);
651584de666eSRyan Zezeski vlp->ixvl_vid = vid;
651684de666eSRyan Zezeski vlp->ixvl_refs = 1;
651784de666eSRyan Zezeski list_insert_tail(&rx_group->vlans, vlp);
651884de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
651984de666eSRyan Zezeski return (0);
652084de666eSRyan Zezeski }
652184de666eSRyan Zezeski
652284de666eSRyan Zezeski /*
652384de666eSRyan Zezeski * We should actually never return ENOSPC because we've set
652484de666eSRyan Zezeski * things up so that every reserved group is guaranteed to
652584de666eSRyan Zezeski * have a VLVF slot.
652684de666eSRyan Zezeski */
652784de666eSRyan Zezeski if (ret == IXGBE_ERR_PARAM)
652884de666eSRyan Zezeski ret = EINVAL;
652984de666eSRyan Zezeski else if (ret == IXGBE_ERR_NO_SPACE)
653084de666eSRyan Zezeski ret = ENOSPC;
653184de666eSRyan Zezeski else
653284de666eSRyan Zezeski ret = EIO;
653384de666eSRyan Zezeski
653484de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
653584de666eSRyan Zezeski return (ret);
653684de666eSRyan Zezeski }
653784de666eSRyan Zezeski
653884de666eSRyan Zezeski /*
653984de666eSRyan Zezeski * Attempt to remove the VLAN HW filter associated with this group. If
654084de666eSRyan Zezeski * we are removing a HW filter for the default group then we know only
654184de666eSRyan Zezeski * the VFTA was set (VLVF is reserved for non-default/reserved
654284de666eSRyan Zezeski * groups). If the group wishes to stop receiving untagged traffic
654384de666eSRyan Zezeski * then clear the AUPE but leave the VLAN filters alone.
654484de666eSRyan Zezeski */
654584de666eSRyan Zezeski static int
ixgbe_remvlan(mac_group_driver_t gdriver,uint16_t vid)654684de666eSRyan Zezeski ixgbe_remvlan(mac_group_driver_t gdriver, uint16_t vid)
654784de666eSRyan Zezeski {
654884de666eSRyan Zezeski ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)gdriver;
654984de666eSRyan Zezeski ixgbe_t *ixgbe = rx_group->ixgbe;
655084de666eSRyan Zezeski struct ixgbe_hw *hw = &ixgbe->hw;
655184de666eSRyan Zezeski int ret;
655284de666eSRyan Zezeski ixgbe_vlan_t *vlp;
655384de666eSRyan Zezeski boolean_t is_def_grp;
655484de666eSRyan Zezeski
655584de666eSRyan Zezeski mutex_enter(&ixgbe->gen_lock);
655684de666eSRyan Zezeski
655784de666eSRyan Zezeski if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
655884de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
655984de666eSRyan Zezeski return (ECANCELED);
656084de666eSRyan Zezeski }
656184de666eSRyan Zezeski
656284de666eSRyan Zezeski is_def_grp = (rx_group->index == ixgbe->rx_def_group);
656384de666eSRyan Zezeski
656484de666eSRyan Zezeski /* See the AUPE comment in ixgbe_addvlan(). */
656584de666eSRyan Zezeski if (vid == MAC_VLAN_UNTAGGED) {
656684de666eSRyan Zezeski if (!is_def_grp) {
656784de666eSRyan Zezeski uint32_t vml2flt;
656884de666eSRyan Zezeski
656984de666eSRyan Zezeski vml2flt = IXGBE_READ_REG(hw,
657084de666eSRyan Zezeski IXGBE_VMOLR(rx_group->index));
657184de666eSRyan Zezeski vml2flt &= ~IXGBE_VMOLR_AUPE;
657284de666eSRyan Zezeski IXGBE_WRITE_REG(hw,
657384de666eSRyan Zezeski IXGBE_VMOLR(rx_group->index), vml2flt);
657484de666eSRyan Zezeski rx_group->aupe = B_FALSE;
657584de666eSRyan Zezeski }
657684de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
657784de666eSRyan Zezeski return (0);
657884de666eSRyan Zezeski }
657984de666eSRyan Zezeski
658084de666eSRyan Zezeski vlp = ixgbe_find_vlan(rx_group, vid);
658184de666eSRyan Zezeski if (vlp == NULL) {
658284de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
658384de666eSRyan Zezeski return (ENOENT);
658484de666eSRyan Zezeski }
658584de666eSRyan Zezeski
658684de666eSRyan Zezeski /*
658784de666eSRyan Zezeski * See the comment in ixgbe_addvlan() about is_def_grp and
658884de666eSRyan Zezeski * vlvf_bypass.
658984de666eSRyan Zezeski */
659084de666eSRyan Zezeski if (vlp->ixvl_refs == 1) {
659184de666eSRyan Zezeski ret = ixgbe_set_vfta(hw, vid, rx_group->index, B_FALSE,
659284de666eSRyan Zezeski is_def_grp);
659384de666eSRyan Zezeski } else {
659484de666eSRyan Zezeski /*
659584de666eSRyan Zezeski * Only the default group can have multiple clients.
659684de666eSRyan Zezeski * If there is more than one client, leave the
659784de666eSRyan Zezeski * VFTA[vid] bit alone.
659884de666eSRyan Zezeski */
659984de666eSRyan Zezeski VERIFY3B(is_def_grp, ==, B_TRUE);
660084de666eSRyan Zezeski VERIFY3U(vlp->ixvl_refs, >, 1);
660184de666eSRyan Zezeski vlp->ixvl_refs--;
660284de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
660384de666eSRyan Zezeski return (0);
660484de666eSRyan Zezeski }
660584de666eSRyan Zezeski
660684de666eSRyan Zezeski if (ret != IXGBE_SUCCESS) {
660784de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
660884de666eSRyan Zezeski /* IXGBE_ERR_PARAM should be the only possible error here. */
660984de666eSRyan Zezeski if (ret == IXGBE_ERR_PARAM)
661084de666eSRyan Zezeski return (EINVAL);
661184de666eSRyan Zezeski else
661284de666eSRyan Zezeski return (EIO);
661384de666eSRyan Zezeski }
661484de666eSRyan Zezeski
661584de666eSRyan Zezeski VERIFY3U(vlp->ixvl_refs, ==, 1);
661684de666eSRyan Zezeski vlp->ixvl_refs = 0;
661784de666eSRyan Zezeski list_remove(&rx_group->vlans, vlp);
661884de666eSRyan Zezeski kmem_free(vlp, sizeof (ixgbe_vlan_t));
661984de666eSRyan Zezeski
662084de666eSRyan Zezeski /*
662184de666eSRyan Zezeski * Calling ixgbe_set_vfta() on a non-default group may have
662284de666eSRyan Zezeski * cleared the VFTA[vid] bit even though the default group
662384de666eSRyan Zezeski * still has clients using the vid. This happens because the
662484de666eSRyan Zezeski * ixgbe common code doesn't ref count the use of VLANs. Check
662584de666eSRyan Zezeski * for any use of vid on the default group and make sure the
662684de666eSRyan Zezeski * VFTA[vid] bit is set. This operation is idempotent: setting
662784de666eSRyan Zezeski * VFTA[vid] to true if already true won't hurt anything.
662884de666eSRyan Zezeski */
662984de666eSRyan Zezeski if (!is_def_grp) {
663084de666eSRyan Zezeski ixgbe_rx_group_t *defgrp;
663184de666eSRyan Zezeski
663284de666eSRyan Zezeski defgrp = &ixgbe->rx_groups[ixgbe->rx_def_group];
663384de666eSRyan Zezeski vlp = ixgbe_find_vlan(defgrp, vid);
663484de666eSRyan Zezeski if (vlp != NULL) {
663584de666eSRyan Zezeski /* This shouldn't fail, but if it does return EIO. */
663684de666eSRyan Zezeski ret = ixgbe_set_vfta(hw, vid, rx_group->index, B_TRUE,
663784de666eSRyan Zezeski B_TRUE);
663884de666eSRyan Zezeski if (ret != IXGBE_SUCCESS) {
663984de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
664084de666eSRyan Zezeski return (EIO);
664184de666eSRyan Zezeski }
664284de666eSRyan Zezeski }
664384de666eSRyan Zezeski }
664484de666eSRyan Zezeski
664584de666eSRyan Zezeski mutex_exit(&ixgbe->gen_lock);
664684de666eSRyan Zezeski return (0);
664784de666eSRyan Zezeski }
664884de666eSRyan Zezeski
6649da14cebeSEric Cheng /*
6650da14cebeSEric Cheng * Add a mac address.
6651da14cebeSEric Cheng */
6652da14cebeSEric Cheng static int
ixgbe_addmac(void * arg,const uint8_t * mac_addr)6653da14cebeSEric Cheng ixgbe_addmac(void *arg, const uint8_t *mac_addr)
6654da14cebeSEric Cheng {
6655da14cebeSEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
6656da14cebeSEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe;
66570dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw;
66580dc2366fSVenugopal Iyer int slot, i;
6659da14cebeSEric Cheng
6660da14cebeSEric Cheng mutex_enter(&ixgbe->gen_lock);
6661da14cebeSEric Cheng
6662da14cebeSEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
6663da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6664da14cebeSEric Cheng return (ECANCELED);
6665da14cebeSEric Cheng }
6666da14cebeSEric Cheng
6667da14cebeSEric Cheng if (ixgbe->unicst_avail == 0) {
6668da14cebeSEric Cheng /* no slots available */
6669da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6670da14cebeSEric Cheng return (ENOSPC);
6671da14cebeSEric Cheng }
6672da14cebeSEric Cheng
66730dc2366fSVenugopal Iyer /*
66740dc2366fSVenugopal Iyer * The first ixgbe->num_rx_groups slots are reserved for each respective
66750dc2366fSVenugopal Iyer * group. The rest slots are shared by all groups. While adding a
66760dc2366fSVenugopal Iyer * MAC address, reserved slots are firstly checked then the shared
66770dc2366fSVenugopal Iyer * slots are searched.
66780dc2366fSVenugopal Iyer */
66790dc2366fSVenugopal Iyer slot = -1;
66800dc2366fSVenugopal Iyer if (ixgbe->unicst_addr[rx_group->index].mac.set == 1) {
66810dc2366fSVenugopal Iyer for (i = ixgbe->num_rx_groups; i < ixgbe->unicst_total; i++) {
66820dc2366fSVenugopal Iyer if (ixgbe->unicst_addr[i].mac.set == 0) {
66830dc2366fSVenugopal Iyer slot = i;
66840dc2366fSVenugopal Iyer break;
66850dc2366fSVenugopal Iyer }
66860dc2366fSVenugopal Iyer }
66870dc2366fSVenugopal Iyer } else {
66880dc2366fSVenugopal Iyer slot = rx_group->index;
6689da14cebeSEric Cheng }
6690da14cebeSEric Cheng
66910dc2366fSVenugopal Iyer if (slot == -1) {
66920dc2366fSVenugopal Iyer /* no slots available */
66930dc2366fSVenugopal Iyer mutex_exit(&ixgbe->gen_lock);
66940dc2366fSVenugopal Iyer return (ENOSPC);
6695da14cebeSEric Cheng }
6696da14cebeSEric Cheng
66970dc2366fSVenugopal Iyer bcopy(mac_addr, ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
66980dc2366fSVenugopal Iyer (void) ixgbe_set_rar(hw, slot, ixgbe->unicst_addr[slot].mac.addr,
66990dc2366fSVenugopal Iyer rx_group->index, IXGBE_RAH_AV);
67000dc2366fSVenugopal Iyer ixgbe->unicst_addr[slot].mac.set = 1;
67010dc2366fSVenugopal Iyer ixgbe->unicst_addr[slot].mac.group_index = rx_group->index;
67020dc2366fSVenugopal Iyer ixgbe->unicst_avail--;
67030dc2366fSVenugopal Iyer
6704da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6705da14cebeSEric Cheng
67060dc2366fSVenugopal Iyer return (0);
6707da14cebeSEric Cheng }
6708da14cebeSEric Cheng
6709da14cebeSEric Cheng /*
6710da14cebeSEric Cheng * Remove a mac address.
6711da14cebeSEric Cheng */
6712da14cebeSEric Cheng static int
ixgbe_remmac(void * arg,const uint8_t * mac_addr)6713da14cebeSEric Cheng ixgbe_remmac(void *arg, const uint8_t *mac_addr)
6714da14cebeSEric Cheng {
6715da14cebeSEric Cheng ixgbe_rx_group_t *rx_group = (ixgbe_rx_group_t *)arg;
6716da14cebeSEric Cheng ixgbe_t *ixgbe = rx_group->ixgbe;
67170dc2366fSVenugopal Iyer struct ixgbe_hw *hw = &ixgbe->hw;
6718da14cebeSEric Cheng int slot;
6719da14cebeSEric Cheng
6720da14cebeSEric Cheng mutex_enter(&ixgbe->gen_lock);
6721da14cebeSEric Cheng
6722da14cebeSEric Cheng if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
6723da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6724da14cebeSEric Cheng return (ECANCELED);
6725da14cebeSEric Cheng }
6726da14cebeSEric Cheng
6727da14cebeSEric Cheng slot = ixgbe_unicst_find(ixgbe, mac_addr);
6728da14cebeSEric Cheng if (slot == -1) {
6729da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6730da14cebeSEric Cheng return (EINVAL);
6731da14cebeSEric Cheng }
6732da14cebeSEric Cheng
6733da14cebeSEric Cheng if (ixgbe->unicst_addr[slot].mac.set == 0) {
6734da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6735da14cebeSEric Cheng return (EINVAL);
6736da14cebeSEric Cheng }
6737da14cebeSEric Cheng
6738da14cebeSEric Cheng bzero(ixgbe->unicst_addr[slot].mac.addr, ETHERADDRL);
67390dc2366fSVenugopal Iyer (void) ixgbe_clear_rar(hw, slot);
67400dc2366fSVenugopal Iyer ixgbe->unicst_addr[slot].mac.set = 0;
67410dc2366fSVenugopal Iyer ixgbe->unicst_avail++;
6742da14cebeSEric Cheng
6743da14cebeSEric Cheng mutex_exit(&ixgbe->gen_lock);
6744da14cebeSEric Cheng
67450dc2366fSVenugopal Iyer return (0);
6746da14cebeSEric Cheng }
6747f2fe7acaSRobert Mustacchi
6748f2fe7acaSRobert Mustacchi static int
ixgbe_ufm_fill_image(ddi_ufm_handle_t * ufmh,void * arg,uint_t imgno,ddi_ufm_image_t * imgp)6749f2fe7acaSRobert Mustacchi ixgbe_ufm_fill_image(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
6750f2fe7acaSRobert Mustacchi ddi_ufm_image_t *imgp)
6751f2fe7acaSRobert Mustacchi {
6752f2fe7acaSRobert Mustacchi ixgbe_t *ixgbe = arg;
6753f2fe7acaSRobert Mustacchi const char *type;
6754f2fe7acaSRobert Mustacchi
6755f2fe7acaSRobert Mustacchi if (imgno != 0) {
6756f2fe7acaSRobert Mustacchi return (EINVAL);
6757f2fe7acaSRobert Mustacchi }
6758f2fe7acaSRobert Mustacchi
6759f2fe7acaSRobert Mustacchi ddi_ufm_image_set_desc(imgp, "NVM");
6760f2fe7acaSRobert Mustacchi ddi_ufm_image_set_nslots(imgp, 1);
6761f2fe7acaSRobert Mustacchi switch (ixgbe->hw.eeprom.type) {
6762f2fe7acaSRobert Mustacchi case ixgbe_eeprom_spi:
6763f2fe7acaSRobert Mustacchi type = "SPI EEPROM";
6764f2fe7acaSRobert Mustacchi break;
6765f2fe7acaSRobert Mustacchi case ixgbe_flash:
6766f2fe7acaSRobert Mustacchi type = "Flash";
6767f2fe7acaSRobert Mustacchi break;
6768f2fe7acaSRobert Mustacchi default:
6769f2fe7acaSRobert Mustacchi type = NULL;
6770f2fe7acaSRobert Mustacchi break;
6771f2fe7acaSRobert Mustacchi }
6772f2fe7acaSRobert Mustacchi
6773f2fe7acaSRobert Mustacchi if (type != NULL) {
6774f2fe7acaSRobert Mustacchi nvlist_t *nvl;
6775f2fe7acaSRobert Mustacchi
6776f2fe7acaSRobert Mustacchi nvl = fnvlist_alloc();
6777f2fe7acaSRobert Mustacchi fnvlist_add_string(nvl, "image-type", type);
6778f2fe7acaSRobert Mustacchi /*
6779f2fe7acaSRobert Mustacchi * The DDI takes ownership of the nvlist_t at this point.
6780f2fe7acaSRobert Mustacchi */
6781f2fe7acaSRobert Mustacchi ddi_ufm_image_set_misc(imgp, nvl);
6782f2fe7acaSRobert Mustacchi }
6783f2fe7acaSRobert Mustacchi
6784f2fe7acaSRobert Mustacchi return (0);
6785f2fe7acaSRobert Mustacchi }
6786f2fe7acaSRobert Mustacchi
6787f2fe7acaSRobert Mustacchi static int
ixgbe_ufm_fill_slot(ddi_ufm_handle_t * ufmh,void * arg,uint_t imgno,uint_t slotno,ddi_ufm_slot_t * slotp)6788f2fe7acaSRobert Mustacchi ixgbe_ufm_fill_slot(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
6789f2fe7acaSRobert Mustacchi uint_t slotno, ddi_ufm_slot_t *slotp)
6790f2fe7acaSRobert Mustacchi {
6791f2fe7acaSRobert Mustacchi ixgbe_t *ixgbe = arg;
6792f2fe7acaSRobert Mustacchi
6793f2fe7acaSRobert Mustacchi if (imgno != 0 || slotno != 0) {
6794f2fe7acaSRobert Mustacchi return (EINVAL);
6795f2fe7acaSRobert Mustacchi }
6796f2fe7acaSRobert Mustacchi
6797f2fe7acaSRobert Mustacchi /*
6798f2fe7acaSRobert Mustacchi * Unfortunately there is no generic versioning in the ixgbe family
6799f2fe7acaSRobert Mustacchi * eeprom parts.
6800f2fe7acaSRobert Mustacchi */
6801f2fe7acaSRobert Mustacchi ddi_ufm_slot_set_version(slotp, "unknown");
6802f2fe7acaSRobert Mustacchi ddi_ufm_slot_set_attrs(slotp, DDI_UFM_ATTR_ACTIVE |
6803f2fe7acaSRobert Mustacchi DDI_UFM_ATTR_READABLE | DDI_UFM_ATTR_WRITEABLE);
6804f2fe7acaSRobert Mustacchi ddi_ufm_slot_set_imgsize(slotp, ixgbe->hw.eeprom.word_size * 2);
6805f2fe7acaSRobert Mustacchi
6806f2fe7acaSRobert Mustacchi return (0);
6807f2fe7acaSRobert Mustacchi }
6808f2fe7acaSRobert Mustacchi
6809f2fe7acaSRobert Mustacchi static int
ixgbe_ufm_getcaps(ddi_ufm_handle_t * ufmh,void * arg,ddi_ufm_cap_t * caps)6810f2fe7acaSRobert Mustacchi ixgbe_ufm_getcaps(ddi_ufm_handle_t *ufmh, void *arg, ddi_ufm_cap_t *caps)
6811f2fe7acaSRobert Mustacchi {
6812f2fe7acaSRobert Mustacchi ixgbe_t *ixgbe = arg;
6813f2fe7acaSRobert Mustacchi
6814f2fe7acaSRobert Mustacchi *caps = 0;
6815f2fe7acaSRobert Mustacchi switch (ixgbe->hw.eeprom.type) {
6816f2fe7acaSRobert Mustacchi case ixgbe_eeprom_spi:
6817f2fe7acaSRobert Mustacchi case ixgbe_flash:
6818f2fe7acaSRobert Mustacchi *caps |= DDI_UFM_CAP_REPORT;
6819f2fe7acaSRobert Mustacchi if (ixgbe->hw.eeprom.ops.read_buffer != NULL) {
6820f2fe7acaSRobert Mustacchi *caps |= DDI_UFM_CAP_READIMG;
6821f2fe7acaSRobert Mustacchi }
6822f2fe7acaSRobert Mustacchi break;
6823f2fe7acaSRobert Mustacchi default:
6824f2fe7acaSRobert Mustacchi break;
6825f2fe7acaSRobert Mustacchi }
6826f2fe7acaSRobert Mustacchi
6827f2fe7acaSRobert Mustacchi return (0);
6828f2fe7acaSRobert Mustacchi }
6829f2fe7acaSRobert Mustacchi
6830f2fe7acaSRobert Mustacchi static int
ixgbe_ufm_readimg(ddi_ufm_handle_t * ufmh,void * arg,uint_t imgno,uint_t slotno,uint64_t len,uint64_t offset,void * buf,uint64_t * nread)6831f2fe7acaSRobert Mustacchi ixgbe_ufm_readimg(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
6832f2fe7acaSRobert Mustacchi uint_t slotno, uint64_t len, uint64_t offset, void *buf, uint64_t *nread)
6833f2fe7acaSRobert Mustacchi {
6834f2fe7acaSRobert Mustacchi int ret;
6835f2fe7acaSRobert Mustacchi uint16_t wordoff, nwords, *buf16 = buf;
6836f2fe7acaSRobert Mustacchi ixgbe_t *ixgbe = arg;
6837f2fe7acaSRobert Mustacchi uint32_t imgsize = ixgbe->hw.eeprom.word_size * 2;
6838f2fe7acaSRobert Mustacchi
6839f2fe7acaSRobert Mustacchi if (imgno != 0 || slotno != 0) {
6840f2fe7acaSRobert Mustacchi return (EINVAL);
6841f2fe7acaSRobert Mustacchi }
6842f2fe7acaSRobert Mustacchi
6843f2fe7acaSRobert Mustacchi if (len > imgsize || offset > imgsize || len + offset > imgsize) {
6844f2fe7acaSRobert Mustacchi return (EINVAL);
6845f2fe7acaSRobert Mustacchi }
6846f2fe7acaSRobert Mustacchi
6847f2fe7acaSRobert Mustacchi if (ixgbe->hw.eeprom.ops.read_buffer == NULL) {
6848f2fe7acaSRobert Mustacchi return (ENOTSUP);
6849f2fe7acaSRobert Mustacchi }
6850f2fe7acaSRobert Mustacchi
6851f2fe7acaSRobert Mustacchi /*
6852f2fe7acaSRobert Mustacchi * Hardware provides us a means to read 16-bit words. For the time
6853f2fe7acaSRobert Mustacchi * being, restrict offset and length to be 2 byte aligned. We should
6854f2fe7acaSRobert Mustacchi * probably reduce this restriction. We could probably just use a bounce
6855f2fe7acaSRobert Mustacchi * buffer.
6856f2fe7acaSRobert Mustacchi */
6857f2fe7acaSRobert Mustacchi if ((offset % 2) != 0 || (len % 2) != 0) {
6858f2fe7acaSRobert Mustacchi return (EINVAL);
6859f2fe7acaSRobert Mustacchi }
6860f2fe7acaSRobert Mustacchi
6861f2fe7acaSRobert Mustacchi wordoff = offset >> 1;
6862f2fe7acaSRobert Mustacchi nwords = len >> 1;
6863f2fe7acaSRobert Mustacchi mutex_enter(&ixgbe->gen_lock);
6864f2fe7acaSRobert Mustacchi ret = ixgbe_read_eeprom_buffer(&ixgbe->hw, wordoff, nwords, buf16);
6865f2fe7acaSRobert Mustacchi mutex_exit(&ixgbe->gen_lock);
6866f2fe7acaSRobert Mustacchi
6867f2fe7acaSRobert Mustacchi if (ret == 0) {
6868f2fe7acaSRobert Mustacchi uint16_t i;
6869f2fe7acaSRobert Mustacchi *nread = len;
6870f2fe7acaSRobert Mustacchi for (i = 0; i < nwords; i++) {
6871f2fe7acaSRobert Mustacchi buf16[i] = LE_16(buf16[i]);
6872f2fe7acaSRobert Mustacchi }
6873f2fe7acaSRobert Mustacchi } else {
6874f2fe7acaSRobert Mustacchi ret = EIO;
6875f2fe7acaSRobert Mustacchi }
6876f2fe7acaSRobert Mustacchi
6877f2fe7acaSRobert Mustacchi return (ret);
6878f2fe7acaSRobert Mustacchi }
6879