161ae650dSJack F Vogel /****************************************************************************** 261ae650dSJack F Vogel 3b6c8f260SJack F Vogel Copyright (c) 2013-2015, Intel Corporation 461ae650dSJack F Vogel All rights reserved. 561ae650dSJack F Vogel 661ae650dSJack F Vogel Redistribution and use in source and binary forms, with or without 761ae650dSJack F Vogel modification, are permitted provided that the following conditions are met: 861ae650dSJack F Vogel 961ae650dSJack F Vogel 1. Redistributions of source code must retain the above copyright notice, 1061ae650dSJack F Vogel this list of conditions and the following disclaimer. 1161ae650dSJack F Vogel 1261ae650dSJack F Vogel 2. Redistributions in binary form must reproduce the above copyright 1361ae650dSJack F Vogel notice, this list of conditions and the following disclaimer in the 1461ae650dSJack F Vogel documentation and/or other materials provided with the distribution. 1561ae650dSJack F Vogel 1661ae650dSJack F Vogel 3. Neither the name of the Intel Corporation nor the names of its 1761ae650dSJack F Vogel contributors may be used to endorse or promote products derived from 1861ae650dSJack F Vogel this software without specific prior written permission. 1961ae650dSJack F Vogel 2061ae650dSJack F Vogel THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2161ae650dSJack F Vogel AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2261ae650dSJack F Vogel IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2361ae650dSJack F Vogel ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2461ae650dSJack F Vogel LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2561ae650dSJack F Vogel CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2661ae650dSJack F Vogel SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2761ae650dSJack F Vogel INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2861ae650dSJack F Vogel CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2961ae650dSJack F Vogel ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3061ae650dSJack F Vogel POSSIBILITY OF SUCH DAMAGE. 3161ae650dSJack F Vogel 3261ae650dSJack F Vogel ******************************************************************************/ 3361ae650dSJack F Vogel /*$FreeBSD$*/ 3461ae650dSJack F Vogel 3561ae650dSJack F Vogel #include "ixl.h" 3661ae650dSJack F Vogel #include "ixl_pf.h" 3761ae650dSJack F Vogel 38*cb6b8299SEric Joyner #ifdef IXL_IW 39*cb6b8299SEric Joyner #include "ixl_iw.h" 40*cb6b8299SEric Joyner #include "ixl_iw_int.h" 41*cb6b8299SEric Joyner #endif 42*cb6b8299SEric Joyner 434294f337SSean Bruno #ifdef PCI_IOV 444294f337SSean Bruno #include "ixl_pf_iov.h" 45dcd7b3b2SJack F Vogel #endif 46dcd7b3b2SJack F Vogel 4761ae650dSJack F Vogel /********************************************************************* 4861ae650dSJack F Vogel * Driver version 4961ae650dSJack F Vogel *********************************************************************/ 50*cb6b8299SEric Joyner char ixl_driver_version[] = "1.7.12-k"; 5161ae650dSJack F Vogel 5261ae650dSJack F Vogel /********************************************************************* 5361ae650dSJack F Vogel * PCI Device ID Table 5461ae650dSJack F Vogel * 5561ae650dSJack F Vogel * Used by probe to select devices to load on 5661ae650dSJack F Vogel * Last field stores an index into ixl_strings 5761ae650dSJack F Vogel * Last entry must be all 0s 5861ae650dSJack F Vogel * 5961ae650dSJack F Vogel * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 6061ae650dSJack F Vogel *********************************************************************/ 6161ae650dSJack F Vogel 6261ae650dSJack F Vogel static ixl_vendor_info_t ixl_vendor_info_array[] = 6361ae650dSJack F Vogel { 6461ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0}, 6561ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0}, 6661ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0}, 6761ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0}, 6861ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0}, 6961ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0}, 7061ae650dSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0}, 71be771cdaSJack F Vogel {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0}, 724294f337SSean Bruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0}, 734294f337SSean Bruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0}, 744294f337SSean Bruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0}, 754294f337SSean Bruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0}, 764294f337SSean Bruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0}, 774294f337SSean Bruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0}, 78*cb6b8299SEric Joyner {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, 0, 0, 0}, 79*cb6b8299SEric Joyner {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, 0, 0, 0}, 8061ae650dSJack F Vogel /* required last entry */ 8161ae650dSJack F Vogel {0, 0, 0, 0, 0} 8261ae650dSJack F Vogel }; 8361ae650dSJack F Vogel 8461ae650dSJack F Vogel /********************************************************************* 8561ae650dSJack F Vogel * Table of branding strings 8661ae650dSJack F Vogel *********************************************************************/ 8761ae650dSJack F Vogel 8861ae650dSJack F Vogel static char *ixl_strings[] = { 894294f337SSean Bruno "Intel(R) Ethernet Connection XL710/X722 Driver" 9061ae650dSJack F Vogel }; 9161ae650dSJack F Vogel 9261ae650dSJack F Vogel 9361ae650dSJack F Vogel /********************************************************************* 9461ae650dSJack F Vogel * Function prototypes 9561ae650dSJack F Vogel *********************************************************************/ 9661ae650dSJack F Vogel static int ixl_probe(device_t); 9761ae650dSJack F Vogel static int ixl_attach(device_t); 9861ae650dSJack F Vogel static int ixl_detach(device_t); 9961ae650dSJack F Vogel static int ixl_shutdown(device_t); 1006c426059SEric Joyner 1014294f337SSean Bruno static int ixl_save_pf_tunables(struct ixl_pf *); 1024294f337SSean Bruno static int ixl_attach_get_link_status(struct ixl_pf *); 10361ae650dSJack F Vogel 10461ae650dSJack F Vogel /********************************************************************* 10561ae650dSJack F Vogel * FreeBSD Device Interface Entry Points 10661ae650dSJack F Vogel *********************************************************************/ 10761ae650dSJack F Vogel 10861ae650dSJack F Vogel static device_method_t ixl_methods[] = { 10961ae650dSJack F Vogel /* Device interface */ 11061ae650dSJack F Vogel DEVMETHOD(device_probe, ixl_probe), 11161ae650dSJack F Vogel DEVMETHOD(device_attach, ixl_attach), 11261ae650dSJack F Vogel DEVMETHOD(device_detach, ixl_detach), 11361ae650dSJack F Vogel DEVMETHOD(device_shutdown, ixl_shutdown), 11456c2c47bSJack F Vogel #ifdef PCI_IOV 115a48d00d2SEric Joyner DEVMETHOD(pci_iov_init, ixl_iov_init), 116a48d00d2SEric Joyner DEVMETHOD(pci_iov_uninit, ixl_iov_uninit), 117a48d00d2SEric Joyner DEVMETHOD(pci_iov_add_vf, ixl_add_vf), 11856c2c47bSJack F Vogel #endif 11961ae650dSJack F Vogel {0, 0} 12061ae650dSJack F Vogel }; 12161ae650dSJack F Vogel 12261ae650dSJack F Vogel static driver_t ixl_driver = { 12361ae650dSJack F Vogel "ixl", ixl_methods, sizeof(struct ixl_pf), 12461ae650dSJack F Vogel }; 12561ae650dSJack F Vogel 12661ae650dSJack F Vogel devclass_t ixl_devclass; 12761ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 12861ae650dSJack F Vogel 129*cb6b8299SEric Joyner MODULE_VERSION(ixl, 1); 130*cb6b8299SEric Joyner 13161ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1); 13261ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1); 133*cb6b8299SEric Joyner #if defined(DEV_NETMAP) && __FreeBSD_version >= 1100000 13431830672SJack F Vogel MODULE_DEPEND(ixl, netmap, 1, 1, 1); 13531830672SJack F Vogel #endif /* DEV_NETMAP */ 13631830672SJack F Vogel 13761ae650dSJack F Vogel /* 13861ae650dSJack F Vogel ** TUNEABLE PARAMETERS: 13961ae650dSJack F Vogel */ 14061ae650dSJack F Vogel 14161ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 14261ae650dSJack F Vogel "IXL driver parameters"); 14361ae650dSJack F Vogel 14461ae650dSJack F Vogel /* 14561ae650dSJack F Vogel * MSIX should be the default for best performance, 14661ae650dSJack F Vogel * but this allows it to be forced off for testing. 14761ae650dSJack F Vogel */ 14861ae650dSJack F Vogel static int ixl_enable_msix = 1; 14961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 15061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 15161ae650dSJack F Vogel "Enable MSI-X interrupts"); 15261ae650dSJack F Vogel 15361ae650dSJack F Vogel /* 15461ae650dSJack F Vogel ** Number of descriptors per ring: 15561ae650dSJack F Vogel ** - TX and RX are the same size 15661ae650dSJack F Vogel */ 157*cb6b8299SEric Joyner static int ixl_ring_size = IXL_DEFAULT_RING; 1584294f337SSean Bruno TUNABLE_INT("hw.ixl.ring_size", &ixl_ring_size); 15961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, 1604294f337SSean Bruno &ixl_ring_size, 0, "Descriptor Ring Size"); 16161ae650dSJack F Vogel 16261ae650dSJack F Vogel /* 16361ae650dSJack F Vogel ** This can be set manually, if left as 0 the 16461ae650dSJack F Vogel ** number of queues will be calculated based 16561ae650dSJack F Vogel ** on cpus and msix vectors available. 16661ae650dSJack F Vogel */ 1674294f337SSean Bruno static int ixl_max_queues = 0; 16861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 16961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 17061ae650dSJack F Vogel &ixl_max_queues, 0, "Number of Queues"); 17161ae650dSJack F Vogel 1724294f337SSean Bruno static int ixl_enable_tx_fc_filter = 1; 1734294f337SSean Bruno TUNABLE_INT("hw.ixl.enable_tx_fc_filter", 1744294f337SSean Bruno &ixl_enable_tx_fc_filter); 1754294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN, 1764294f337SSean Bruno &ixl_enable_tx_fc_filter, 0, 1774294f337SSean Bruno "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources"); 1784294f337SSean Bruno 1794294f337SSean Bruno static int ixl_core_debug_mask = 0; 1804294f337SSean Bruno TUNABLE_INT("hw.ixl.core_debug_mask", 1814294f337SSean Bruno &ixl_core_debug_mask); 1824294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN, 1834294f337SSean Bruno &ixl_core_debug_mask, 0, 1844294f337SSean Bruno "Display debug statements that are printed in non-shared code"); 1854294f337SSean Bruno 1864294f337SSean Bruno static int ixl_shared_debug_mask = 0; 1874294f337SSean Bruno TUNABLE_INT("hw.ixl.shared_debug_mask", 1884294f337SSean Bruno &ixl_shared_debug_mask); 1894294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN, 1904294f337SSean Bruno &ixl_shared_debug_mask, 0, 1914294f337SSean Bruno "Display debug statements that are printed in shared code"); 1924294f337SSean Bruno 19361ae650dSJack F Vogel /* 19461ae650dSJack F Vogel ** Controls for Interrupt Throttling 19561ae650dSJack F Vogel ** - true/false for dynamic adjustment 19661ae650dSJack F Vogel ** - default values for static ITR 19761ae650dSJack F Vogel */ 1984294f337SSean Bruno static int ixl_dynamic_rx_itr = 1; 19961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 20061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 20161ae650dSJack F Vogel &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 20261ae650dSJack F Vogel 2034294f337SSean Bruno static int ixl_dynamic_tx_itr = 1; 20461ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 20561ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 20661ae650dSJack F Vogel &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 20761ae650dSJack F Vogel 2084294f337SSean Bruno static int ixl_rx_itr = IXL_ITR_8K; 20961ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 21061ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 21161ae650dSJack F Vogel &ixl_rx_itr, 0, "RX Interrupt Rate"); 21261ae650dSJack F Vogel 2134294f337SSean Bruno static int ixl_tx_itr = IXL_ITR_4K; 21461ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 21561ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 21661ae650dSJack F Vogel &ixl_tx_itr, 0, "TX Interrupt Rate"); 21761ae650dSJack F Vogel 218*cb6b8299SEric Joyner #ifdef IXL_IW 219*cb6b8299SEric Joyner int ixl_enable_iwarp = 0; 220*cb6b8299SEric Joyner TUNABLE_INT("hw.ixl.enable_iwarp", &ixl_enable_iwarp); 221*cb6b8299SEric Joyner #endif 222*cb6b8299SEric Joyner 22331830672SJack F Vogel #ifdef DEV_NETMAP 22431830672SJack F Vogel #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ 22531830672SJack F Vogel #include <dev/netmap/if_ixl_netmap.h> 22631830672SJack F Vogel #endif /* DEV_NETMAP */ 227e5100ee2SJack F Vogel 22861ae650dSJack F Vogel /********************************************************************* 22961ae650dSJack F Vogel * Device identification routine 23061ae650dSJack F Vogel * 23161ae650dSJack F Vogel * ixl_probe determines if the driver should be loaded on 23261ae650dSJack F Vogel * the hardware based on PCI vendor/device id of the device. 23361ae650dSJack F Vogel * 23461ae650dSJack F Vogel * return BUS_PROBE_DEFAULT on success, positive on failure 23561ae650dSJack F Vogel *********************************************************************/ 23661ae650dSJack F Vogel 23761ae650dSJack F Vogel static int 23861ae650dSJack F Vogel ixl_probe(device_t dev) 23961ae650dSJack F Vogel { 24061ae650dSJack F Vogel ixl_vendor_info_t *ent; 24161ae650dSJack F Vogel 24261ae650dSJack F Vogel u16 pci_vendor_id, pci_device_id; 24361ae650dSJack F Vogel u16 pci_subvendor_id, pci_subdevice_id; 24461ae650dSJack F Vogel char device_name[256]; 24561ae650dSJack F Vogel 2461d767a8eSEric Joyner #if 0 24761ae650dSJack F Vogel INIT_DEBUGOUT("ixl_probe: begin"); 2481d767a8eSEric Joyner #endif 24961ae650dSJack F Vogel pci_vendor_id = pci_get_vendor(dev); 25061ae650dSJack F Vogel if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 25161ae650dSJack F Vogel return (ENXIO); 25261ae650dSJack F Vogel 25361ae650dSJack F Vogel pci_device_id = pci_get_device(dev); 25461ae650dSJack F Vogel pci_subvendor_id = pci_get_subvendor(dev); 25561ae650dSJack F Vogel pci_subdevice_id = pci_get_subdevice(dev); 25661ae650dSJack F Vogel 25761ae650dSJack F Vogel ent = ixl_vendor_info_array; 25861ae650dSJack F Vogel while (ent->vendor_id != 0) { 25961ae650dSJack F Vogel if ((pci_vendor_id == ent->vendor_id) && 26061ae650dSJack F Vogel (pci_device_id == ent->device_id) && 26161ae650dSJack F Vogel 26261ae650dSJack F Vogel ((pci_subvendor_id == ent->subvendor_id) || 26361ae650dSJack F Vogel (ent->subvendor_id == 0)) && 26461ae650dSJack F Vogel 26561ae650dSJack F Vogel ((pci_subdevice_id == ent->subdevice_id) || 26661ae650dSJack F Vogel (ent->subdevice_id == 0))) { 26761ae650dSJack F Vogel sprintf(device_name, "%s, Version - %s", 26861ae650dSJack F Vogel ixl_strings[ent->index], 26961ae650dSJack F Vogel ixl_driver_version); 27061ae650dSJack F Vogel device_set_desc_copy(dev, device_name); 27161ae650dSJack F Vogel return (BUS_PROBE_DEFAULT); 27261ae650dSJack F Vogel } 27361ae650dSJack F Vogel ent++; 27461ae650dSJack F Vogel } 27561ae650dSJack F Vogel return (ENXIO); 27661ae650dSJack F Vogel } 27761ae650dSJack F Vogel 2784294f337SSean Bruno static int 2794294f337SSean Bruno ixl_attach_get_link_status(struct ixl_pf *pf) 2804294f337SSean Bruno { 2814294f337SSean Bruno struct i40e_hw *hw = &pf->hw; 2824294f337SSean Bruno device_t dev = pf->dev; 2834294f337SSean Bruno int error = 0; 2844294f337SSean Bruno 2854294f337SSean Bruno if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 2864294f337SSean Bruno (hw->aq.fw_maj_ver < 4)) { 2874294f337SSean Bruno i40e_msec_delay(75); 2884294f337SSean Bruno error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); 2894294f337SSean Bruno if (error) { 2904294f337SSean Bruno device_printf(dev, "link restart failed, aq_err=%d\n", 2914294f337SSean Bruno pf->hw.aq.asq_last_status); 2924294f337SSean Bruno return error; 2934294f337SSean Bruno } 2944294f337SSean Bruno } 2954294f337SSean Bruno 2964294f337SSean Bruno /* Determine link state */ 2974294f337SSean Bruno hw->phy.get_link_info = TRUE; 2984294f337SSean Bruno i40e_get_link_status(hw, &pf->link_up); 2994294f337SSean Bruno return (0); 3004294f337SSean Bruno } 3014294f337SSean Bruno 3024294f337SSean Bruno /* 3034294f337SSean Bruno * Sanity check and save off tunable values. 3044294f337SSean Bruno */ 3054294f337SSean Bruno static int 3064294f337SSean Bruno ixl_save_pf_tunables(struct ixl_pf *pf) 3074294f337SSean Bruno { 3084294f337SSean Bruno device_t dev = pf->dev; 3094294f337SSean Bruno 3104294f337SSean Bruno /* Save tunable information */ 3114294f337SSean Bruno pf->enable_msix = ixl_enable_msix; 3124294f337SSean Bruno pf->max_queues = ixl_max_queues; 3134294f337SSean Bruno pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; 3144294f337SSean Bruno pf->dynamic_rx_itr = ixl_dynamic_rx_itr; 3154294f337SSean Bruno pf->dynamic_tx_itr = ixl_dynamic_tx_itr; 3164294f337SSean Bruno pf->dbg_mask = ixl_core_debug_mask; 3174294f337SSean Bruno pf->hw.debug_mask = ixl_shared_debug_mask; 3184294f337SSean Bruno 3194294f337SSean Bruno if (ixl_ring_size < IXL_MIN_RING 3204294f337SSean Bruno || ixl_ring_size > IXL_MAX_RING 3214294f337SSean Bruno || ixl_ring_size % IXL_RING_INCREMENT != 0) { 3224294f337SSean Bruno device_printf(dev, "Invalid ring_size value of %d set!\n", 3234294f337SSean Bruno ixl_ring_size); 3244294f337SSean Bruno device_printf(dev, "ring_size must be between %d and %d, " 3254294f337SSean Bruno "inclusive, and must be a multiple of %d\n", 3264294f337SSean Bruno IXL_MIN_RING, IXL_MAX_RING, IXL_RING_INCREMENT); 327*cb6b8299SEric Joyner device_printf(dev, "Using default value of %d instead\n", 328*cb6b8299SEric Joyner IXL_DEFAULT_RING); 329*cb6b8299SEric Joyner pf->ringsz = IXL_DEFAULT_RING; 330*cb6b8299SEric Joyner } else 331*cb6b8299SEric Joyner pf->ringsz = ixl_ring_size; 332*cb6b8299SEric Joyner 333*cb6b8299SEric Joyner if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) { 334*cb6b8299SEric Joyner device_printf(dev, "Invalid tx_itr value of %d set!\n", 335*cb6b8299SEric Joyner ixl_tx_itr); 336*cb6b8299SEric Joyner device_printf(dev, "tx_itr must be between %d and %d, " 337*cb6b8299SEric Joyner "inclusive\n", 338*cb6b8299SEric Joyner 0, IXL_MAX_ITR); 339*cb6b8299SEric Joyner device_printf(dev, "Using default value of %d instead\n", 340*cb6b8299SEric Joyner IXL_ITR_4K); 341*cb6b8299SEric Joyner pf->tx_itr = IXL_ITR_4K; 342*cb6b8299SEric Joyner } else 343*cb6b8299SEric Joyner pf->tx_itr = ixl_tx_itr; 344*cb6b8299SEric Joyner 345*cb6b8299SEric Joyner if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) { 346*cb6b8299SEric Joyner device_printf(dev, "Invalid rx_itr value of %d set!\n", 347*cb6b8299SEric Joyner ixl_rx_itr); 348*cb6b8299SEric Joyner device_printf(dev, "rx_itr must be between %d and %d, " 349*cb6b8299SEric Joyner "inclusive\n", 350*cb6b8299SEric Joyner 0, IXL_MAX_ITR); 351*cb6b8299SEric Joyner device_printf(dev, "Using default value of %d instead\n", 352*cb6b8299SEric Joyner IXL_ITR_8K); 353*cb6b8299SEric Joyner pf->rx_itr = IXL_ITR_8K; 354*cb6b8299SEric Joyner } else 355*cb6b8299SEric Joyner pf->rx_itr = ixl_rx_itr; 3564294f337SSean Bruno 3574294f337SSean Bruno return (0); 3584294f337SSean Bruno } 3594294f337SSean Bruno 36061ae650dSJack F Vogel /********************************************************************* 36161ae650dSJack F Vogel * Device initialization routine 36261ae650dSJack F Vogel * 36361ae650dSJack F Vogel * The attach entry point is called when the driver is being loaded. 36461ae650dSJack F Vogel * This routine identifies the type of hardware, allocates all resources 36561ae650dSJack F Vogel * and initializes the hardware. 36661ae650dSJack F Vogel * 36761ae650dSJack F Vogel * return 0 on success, positive on failure 36861ae650dSJack F Vogel *********************************************************************/ 36961ae650dSJack F Vogel 37061ae650dSJack F Vogel static int 37161ae650dSJack F Vogel ixl_attach(device_t dev) 37261ae650dSJack F Vogel { 37361ae650dSJack F Vogel struct ixl_pf *pf; 37461ae650dSJack F Vogel struct i40e_hw *hw; 37561ae650dSJack F Vogel struct ixl_vsi *vsi; 3764294f337SSean Bruno enum i40e_status_code status; 37761ae650dSJack F Vogel int error = 0; 37861ae650dSJack F Vogel 37961ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: begin"); 38061ae650dSJack F Vogel 38161ae650dSJack F Vogel /* Allocate, clear, and link in our primary soft structure */ 38261ae650dSJack F Vogel pf = device_get_softc(dev); 38361ae650dSJack F Vogel pf->dev = pf->osdep.dev = dev; 38461ae650dSJack F Vogel hw = &pf->hw; 38561ae650dSJack F Vogel 38661ae650dSJack F Vogel /* 38761ae650dSJack F Vogel ** Note this assumes we have a single embedded VSI, 38861ae650dSJack F Vogel ** this could be enhanced later to allocate multiple 38961ae650dSJack F Vogel */ 39061ae650dSJack F Vogel vsi = &pf->vsi; 39161ae650dSJack F Vogel vsi->dev = pf->dev; 39261ae650dSJack F Vogel 3934294f337SSean Bruno /* Save tunable values */ 3944294f337SSean Bruno error = ixl_save_pf_tunables(pf); 3954294f337SSean Bruno if (error) 3964294f337SSean Bruno return (error); 3974294f337SSean Bruno 39861ae650dSJack F Vogel /* Core Lock Init*/ 39961ae650dSJack F Vogel IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 40061ae650dSJack F Vogel 40161ae650dSJack F Vogel /* Set up the timer callout */ 40261ae650dSJack F Vogel callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 40361ae650dSJack F Vogel 40461ae650dSJack F Vogel /* Do PCI setup - map BAR0, etc */ 40561ae650dSJack F Vogel if (ixl_allocate_pci_resources(pf)) { 40661ae650dSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 40761ae650dSJack F Vogel error = ENXIO; 40861ae650dSJack F Vogel goto err_out; 40961ae650dSJack F Vogel } 41061ae650dSJack F Vogel 41161ae650dSJack F Vogel /* Establish a clean starting point */ 41261ae650dSJack F Vogel i40e_clear_hw(hw); 4134294f337SSean Bruno status = i40e_pf_reset(hw); 4144294f337SSean Bruno if (status) { 4154294f337SSean Bruno device_printf(dev, "PF reset failure %s\n", 4164294f337SSean Bruno i40e_stat_str(hw, status)); 41761ae650dSJack F Vogel error = EIO; 41861ae650dSJack F Vogel goto err_out; 41961ae650dSJack F Vogel } 42061ae650dSJack F Vogel 42161ae650dSJack F Vogel /* Initialize the shared code */ 4224294f337SSean Bruno status = i40e_init_shared_code(hw); 4234294f337SSean Bruno if (status) { 4244294f337SSean Bruno device_printf(dev, "Unable to initialize shared code, error %s\n", 4254294f337SSean Bruno i40e_stat_str(hw, status)); 42661ae650dSJack F Vogel error = EIO; 42761ae650dSJack F Vogel goto err_out; 42861ae650dSJack F Vogel } 42961ae650dSJack F Vogel 4304294f337SSean Bruno /* 4314294f337SSean Bruno * Allocate interrupts and figure out number of queues to use 4324294f337SSean Bruno * for PF interface 4334294f337SSean Bruno */ 4344294f337SSean Bruno pf->msix = ixl_init_msix(pf); 4354294f337SSean Bruno 43661ae650dSJack F Vogel /* Set up the admin queue */ 4374294f337SSean Bruno hw->aq.num_arq_entries = IXL_AQ_LEN; 4384294f337SSean Bruno hw->aq.num_asq_entries = IXL_AQ_LEN; 4394294f337SSean Bruno hw->aq.arq_buf_size = IXL_AQ_BUF_SZ; 4404294f337SSean Bruno hw->aq.asq_buf_size = IXL_AQ_BUF_SZ; 4414294f337SSean Bruno 4424294f337SSean Bruno status = i40e_init_adminq(hw); 4434294f337SSean Bruno if (status != 0 && status != I40E_ERR_FIRMWARE_API_VERSION) { 4444294f337SSean Bruno device_printf(dev, "Unable to initialize Admin Queue, error %s\n", 4454294f337SSean Bruno i40e_stat_str(hw, status)); 446fdb6f38aSEric Joyner error = EIO; 447fdb6f38aSEric Joyner goto err_out; 448fdb6f38aSEric Joyner } 4491d767a8eSEric Joyner ixl_print_nvm_version(pf); 4501d767a8eSEric Joyner 4514294f337SSean Bruno if (status == I40E_ERR_FIRMWARE_API_VERSION) { 45261ae650dSJack F Vogel device_printf(dev, "The driver for the device stopped " 45361ae650dSJack F Vogel "because the NVM image is newer than expected.\n" 45461ae650dSJack F Vogel "You must install the most recent version of " 45561ae650dSJack F Vogel "the network driver.\n"); 456fdb6f38aSEric Joyner error = EIO; 45761ae650dSJack F Vogel goto err_out; 45861ae650dSJack F Vogel } 45961ae650dSJack F Vogel 46061ae650dSJack F Vogel if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 46161ae650dSJack F Vogel hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) 46261ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 46361ae650dSJack F Vogel "a newer version of the NVM image than expected.\n" 46461ae650dSJack F Vogel "Please install the most recent version of the network driver.\n"); 46561ae650dSJack F Vogel else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 46661ae650dSJack F Vogel hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) 46761ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 46861ae650dSJack F Vogel "an older version of the NVM image than expected.\n" 46961ae650dSJack F Vogel "Please update the NVM image.\n"); 47061ae650dSJack F Vogel 47161ae650dSJack F Vogel /* Clear PXE mode */ 47261ae650dSJack F Vogel i40e_clear_pxe_mode(hw); 47361ae650dSJack F Vogel 47461ae650dSJack F Vogel /* Get capabilities from the device */ 47561ae650dSJack F Vogel error = ixl_get_hw_capabilities(pf); 47661ae650dSJack F Vogel if (error) { 47761ae650dSJack F Vogel device_printf(dev, "HW capabilities failure!\n"); 47861ae650dSJack F Vogel goto err_get_cap; 47961ae650dSJack F Vogel } 48061ae650dSJack F Vogel 48161ae650dSJack F Vogel /* Set up host memory cache */ 4824294f337SSean Bruno status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 48356c2c47bSJack F Vogel hw->func_caps.num_rx_qp, 0, 0); 4844294f337SSean Bruno if (status) { 4854294f337SSean Bruno device_printf(dev, "init_lan_hmc failed: %s\n", 4864294f337SSean Bruno i40e_stat_str(hw, status)); 48761ae650dSJack F Vogel goto err_get_cap; 48861ae650dSJack F Vogel } 48961ae650dSJack F Vogel 4904294f337SSean Bruno status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 4914294f337SSean Bruno if (status) { 4924294f337SSean Bruno device_printf(dev, "configure_lan_hmc failed: %s\n", 4934294f337SSean Bruno i40e_stat_str(hw, status)); 49461ae650dSJack F Vogel goto err_mac_hmc; 49561ae650dSJack F Vogel } 49661ae650dSJack F Vogel 4974294f337SSean Bruno /* Init queue allocation manager */ 4984294f337SSean Bruno error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp); 4994294f337SSean Bruno if (error) { 5004294f337SSean Bruno device_printf(dev, "Failed to init queue manager for PF queues, error %d\n", 5014294f337SSean Bruno error); 5024294f337SSean Bruno goto err_mac_hmc; 5034294f337SSean Bruno } 5044294f337SSean Bruno /* reserve a contiguous allocation for the PF's VSI */ 5054294f337SSean Bruno error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag); 5064294f337SSean Bruno if (error) { 5074294f337SSean Bruno device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n", 5084294f337SSean Bruno error); 5094294f337SSean Bruno goto err_mac_hmc; 5104294f337SSean Bruno } 5114294f337SSean Bruno device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n", 5124294f337SSean Bruno pf->qtag.num_allocated, pf->qtag.num_active); 5134294f337SSean Bruno 514d4683565SEric Joyner /* Disable LLDP from the firmware for certain NVM versions */ 515d4683565SEric Joyner if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || 516d4683565SEric Joyner (pf->hw.aq.fw_maj_ver < 4)) 51761ae650dSJack F Vogel i40e_aq_stop_lldp(hw, TRUE, NULL); 51861ae650dSJack F Vogel 5194294f337SSean Bruno /* Get MAC addresses from hardware */ 52061ae650dSJack F Vogel i40e_get_mac_addr(hw, hw->mac.addr); 52161ae650dSJack F Vogel error = i40e_validate_mac_addr(hw->mac.addr); 52261ae650dSJack F Vogel if (error) { 52361ae650dSJack F Vogel device_printf(dev, "validate_mac_addr failed: %d\n", error); 52461ae650dSJack F Vogel goto err_mac_hmc; 52561ae650dSJack F Vogel } 52661ae650dSJack F Vogel bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 52761ae650dSJack F Vogel i40e_get_port_mac_addr(hw, hw->mac.port_addr); 52861ae650dSJack F Vogel 5294294f337SSean Bruno /* Initialize mac filter list for VSI */ 5304294f337SSean Bruno SLIST_INIT(&vsi->ftl); 5314294f337SSean Bruno 5324294f337SSean Bruno /* Set up SW VSI and allocate queue memory and rings */ 5334294f337SSean Bruno if (ixl_setup_stations(pf)) { 53461ae650dSJack F Vogel device_printf(dev, "setup stations failed!\n"); 53561ae650dSJack F Vogel error = ENOMEM; 53661ae650dSJack F Vogel goto err_mac_hmc; 53761ae650dSJack F Vogel } 53861ae650dSJack F Vogel 5394294f337SSean Bruno /* Setup OS network interface / ifnet */ 5404294f337SSean Bruno if (ixl_setup_interface(dev, vsi)) { 5414294f337SSean Bruno device_printf(dev, "interface setup failed!\n"); 5424294f337SSean Bruno error = EIO; 543223d846dSEric Joyner goto err_late; 544223d846dSEric Joyner } 54561ae650dSJack F Vogel 54661ae650dSJack F Vogel /* Determine link state */ 5474294f337SSean Bruno if (ixl_attach_get_link_status(pf)) { 5484294f337SSean Bruno error = EINVAL; 54961ae650dSJack F Vogel goto err_late; 550e5100ee2SJack F Vogel } 55161ae650dSJack F Vogel 552b6c8f260SJack F Vogel error = ixl_switch_config(pf); 553b6c8f260SJack F Vogel if (error) { 5546c426059SEric Joyner device_printf(dev, "Initial ixl_switch_config() failed: %d\n", 5556c426059SEric Joyner error); 556a48d00d2SEric Joyner goto err_late; 557b6c8f260SJack F Vogel } 558b6c8f260SJack F Vogel 559223d846dSEric Joyner /* Limit PHY interrupts to link, autoneg, and modules failure */ 5604294f337SSean Bruno status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 561223d846dSEric Joyner NULL); 5624294f337SSean Bruno if (status) { 5634294f337SSean Bruno device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s," 5644294f337SSean Bruno " aq_err %s\n", i40e_stat_str(hw, status), 5654294f337SSean Bruno i40e_aq_str(hw, hw->aq.asq_last_status)); 566223d846dSEric Joyner goto err_late; 567223d846dSEric Joyner } 568b6c8f260SJack F Vogel 5696c426059SEric Joyner /* Get the bus configuration and set the shared code's config */ 570*cb6b8299SEric Joyner ixl_get_bus_info(pf); 57161ae650dSJack F Vogel 5726c426059SEric Joyner /* 5736c426059SEric Joyner * In MSI-X mode, initialize the Admin Queue interrupt, 5746c426059SEric Joyner * so userland tools can communicate with the adapter regardless of 5756c426059SEric Joyner * the ifnet interface's status. 5766c426059SEric Joyner */ 5776c426059SEric Joyner if (pf->msix > 1) { 5786c426059SEric Joyner error = ixl_setup_adminq_msix(pf); 5796c426059SEric Joyner if (error) { 580*cb6b8299SEric Joyner device_printf(dev, "ixl_setup_adminq_msix() error: %d\n", 5816c426059SEric Joyner error); 5826c426059SEric Joyner goto err_late; 5836c426059SEric Joyner } 5846c426059SEric Joyner error = ixl_setup_adminq_tq(pf); 5856c426059SEric Joyner if (error) { 586*cb6b8299SEric Joyner device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", 5876c426059SEric Joyner error); 5886c426059SEric Joyner goto err_late; 5896c426059SEric Joyner } 5906c426059SEric Joyner ixl_configure_intr0_msix(pf); 591*cb6b8299SEric Joyner ixl_enable_intr0(hw); 592*cb6b8299SEric Joyner 593*cb6b8299SEric Joyner error = ixl_setup_queue_msix(vsi); 594*cb6b8299SEric Joyner if (error) 595*cb6b8299SEric Joyner device_printf(dev, "ixl_setup_queue_msix() error: %d\n", 596*cb6b8299SEric Joyner error); 597*cb6b8299SEric Joyner error = ixl_setup_queue_tqs(vsi); 598*cb6b8299SEric Joyner if (error) 599*cb6b8299SEric Joyner device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", 600*cb6b8299SEric Joyner error); 601*cb6b8299SEric Joyner } else { 602*cb6b8299SEric Joyner error = ixl_setup_legacy(pf); 603*cb6b8299SEric Joyner 604*cb6b8299SEric Joyner error = ixl_setup_adminq_tq(pf); 605*cb6b8299SEric Joyner if (error) { 606*cb6b8299SEric Joyner device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", 607*cb6b8299SEric Joyner error); 608*cb6b8299SEric Joyner goto err_late; 6096c426059SEric Joyner } 610a48d00d2SEric Joyner 611*cb6b8299SEric Joyner error = ixl_setup_queue_tqs(vsi); 612*cb6b8299SEric Joyner if (error) 613*cb6b8299SEric Joyner device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", 614*cb6b8299SEric Joyner error); 615*cb6b8299SEric Joyner } 616*cb6b8299SEric Joyner 617*cb6b8299SEric Joyner if (error) { 618*cb6b8299SEric Joyner device_printf(dev, "interrupt setup error: %d\n", error); 619*cb6b8299SEric Joyner } 620*cb6b8299SEric Joyner 621*cb6b8299SEric Joyner /* Set initial advertised speed sysctl value */ 622*cb6b8299SEric Joyner ixl_get_initial_advertised_speeds(pf); 623*cb6b8299SEric Joyner 624fdb6f38aSEric Joyner /* Initialize statistics & add sysctls */ 625fdb6f38aSEric Joyner ixl_add_device_sysctls(pf); 626fdb6f38aSEric Joyner 62761ae650dSJack F Vogel ixl_pf_reset_stats(pf); 62861ae650dSJack F Vogel ixl_update_stats_counters(pf); 62961ae650dSJack F Vogel ixl_add_hw_stats(pf); 63061ae650dSJack F Vogel 63161ae650dSJack F Vogel /* Register for VLAN events */ 63261ae650dSJack F Vogel vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 63361ae650dSJack F Vogel ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 63461ae650dSJack F Vogel vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 63561ae650dSJack F Vogel ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 63661ae650dSJack F Vogel 63756c2c47bSJack F Vogel #ifdef PCI_IOV 6384294f337SSean Bruno ixl_initialize_sriov(pf); 63956c2c47bSJack F Vogel #endif 64056c2c47bSJack F Vogel 64131830672SJack F Vogel #ifdef DEV_NETMAP 64231830672SJack F Vogel ixl_netmap_attach(vsi); 64331830672SJack F Vogel #endif /* DEV_NETMAP */ 644*cb6b8299SEric Joyner 645*cb6b8299SEric Joyner #ifdef IXL_IW 646*cb6b8299SEric Joyner if (hw->func_caps.iwarp && ixl_enable_iwarp) { 647*cb6b8299SEric Joyner pf->iw_enabled = (pf->iw_msix > 0) ? true : false; 648*cb6b8299SEric Joyner if (pf->iw_enabled) { 649*cb6b8299SEric Joyner error = ixl_iw_pf_attach(pf); 650*cb6b8299SEric Joyner if (error) { 651*cb6b8299SEric Joyner device_printf(dev, 652*cb6b8299SEric Joyner "interfacing to iwarp driver failed: %d\n", 653*cb6b8299SEric Joyner error); 654*cb6b8299SEric Joyner goto err_late; 655*cb6b8299SEric Joyner } 656*cb6b8299SEric Joyner } else 657*cb6b8299SEric Joyner device_printf(dev, 658*cb6b8299SEric Joyner "iwarp disabled on this device (no msix vectors)\n"); 659*cb6b8299SEric Joyner } else { 660*cb6b8299SEric Joyner pf->iw_enabled = false; 661*cb6b8299SEric Joyner device_printf(dev, "The device is not iWARP enabled\n"); 662*cb6b8299SEric Joyner } 663*cb6b8299SEric Joyner #endif 664*cb6b8299SEric Joyner 66561ae650dSJack F Vogel INIT_DEBUGOUT("ixl_attach: end"); 66661ae650dSJack F Vogel return (0); 66761ae650dSJack F Vogel 66861ae650dSJack F Vogel err_late: 6694294f337SSean Bruno if (vsi->ifp != NULL) { 6704294f337SSean Bruno ether_ifdetach(vsi->ifp); 671e5100ee2SJack F Vogel if_free(vsi->ifp); 6724294f337SSean Bruno } 67361ae650dSJack F Vogel err_mac_hmc: 67461ae650dSJack F Vogel i40e_shutdown_lan_hmc(hw); 67561ae650dSJack F Vogel err_get_cap: 67661ae650dSJack F Vogel i40e_shutdown_adminq(hw); 67761ae650dSJack F Vogel err_out: 67861ae650dSJack F Vogel ixl_free_pci_resources(pf); 679e5100ee2SJack F Vogel ixl_free_vsi(vsi); 68061ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 68161ae650dSJack F Vogel return (error); 68261ae650dSJack F Vogel } 68361ae650dSJack F Vogel 68461ae650dSJack F Vogel /********************************************************************* 68561ae650dSJack F Vogel * Device removal routine 68661ae650dSJack F Vogel * 68761ae650dSJack F Vogel * The detach entry point is called when the driver is being removed. 68861ae650dSJack F Vogel * This routine stops the adapter and deallocates all the resources 68961ae650dSJack F Vogel * that were allocated for driver operation. 69061ae650dSJack F Vogel * 69161ae650dSJack F Vogel * return 0 on success, positive on failure 69261ae650dSJack F Vogel *********************************************************************/ 69361ae650dSJack F Vogel 69461ae650dSJack F Vogel static int 69561ae650dSJack F Vogel ixl_detach(device_t dev) 69661ae650dSJack F Vogel { 69761ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 69861ae650dSJack F Vogel struct i40e_hw *hw = &pf->hw; 69961ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 7006c426059SEric Joyner enum i40e_status_code status; 701*cb6b8299SEric Joyner #if defined(PCI_IOV) || defined(IXL_IW) 70256c2c47bSJack F Vogel int error; 70356c2c47bSJack F Vogel #endif 70461ae650dSJack F Vogel 70561ae650dSJack F Vogel INIT_DEBUGOUT("ixl_detach: begin"); 70661ae650dSJack F Vogel 70761ae650dSJack F Vogel /* Make sure VLANS are not using driver */ 70861ae650dSJack F Vogel if (vsi->ifp->if_vlantrunk != NULL) { 70961ae650dSJack F Vogel device_printf(dev, "Vlan in use, detach first\n"); 71061ae650dSJack F Vogel return (EBUSY); 71161ae650dSJack F Vogel } 71261ae650dSJack F Vogel 71356c2c47bSJack F Vogel #ifdef PCI_IOV 71456c2c47bSJack F Vogel error = pci_iov_detach(dev); 71556c2c47bSJack F Vogel if (error != 0) { 71656c2c47bSJack F Vogel device_printf(dev, "SR-IOV in use; detach first.\n"); 71756c2c47bSJack F Vogel return (error); 71856c2c47bSJack F Vogel } 71956c2c47bSJack F Vogel #endif 72056c2c47bSJack F Vogel 721b6c8f260SJack F Vogel ether_ifdetach(vsi->ifp); 722223d846dSEric Joyner if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) 72361ae650dSJack F Vogel ixl_stop(pf); 72461ae650dSJack F Vogel 72561ae650dSJack F Vogel /* Shutdown LAN HMC */ 72661ae650dSJack F Vogel status = i40e_shutdown_lan_hmc(hw); 72761ae650dSJack F Vogel if (status) 72861ae650dSJack F Vogel device_printf(dev, 72961ae650dSJack F Vogel "Shutdown LAN HMC failed with code %d\n", status); 73061ae650dSJack F Vogel 731*cb6b8299SEric Joyner /* Teardown LAN queue resources */ 732*cb6b8299SEric Joyner ixl_teardown_queue_msix(vsi); 733*cb6b8299SEric Joyner ixl_free_queue_tqs(vsi); 73461ae650dSJack F Vogel /* Shutdown admin queue */ 735*cb6b8299SEric Joyner ixl_disable_intr0(hw); 7366c426059SEric Joyner ixl_teardown_adminq_msix(pf); 737*cb6b8299SEric Joyner ixl_free_adminq_tq(pf); 73861ae650dSJack F Vogel status = i40e_shutdown_adminq(hw); 73961ae650dSJack F Vogel if (status) 74061ae650dSJack F Vogel device_printf(dev, 74161ae650dSJack F Vogel "Shutdown Admin queue failed with code %d\n", status); 74261ae650dSJack F Vogel 74361ae650dSJack F Vogel /* Unregister VLAN events */ 74461ae650dSJack F Vogel if (vsi->vlan_attach != NULL) 74561ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 74661ae650dSJack F Vogel if (vsi->vlan_detach != NULL) 74761ae650dSJack F Vogel EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 74861ae650dSJack F Vogel 74961ae650dSJack F Vogel callout_drain(&pf->timer); 750*cb6b8299SEric Joyner 751*cb6b8299SEric Joyner #ifdef IXL_IW 752*cb6b8299SEric Joyner if (ixl_enable_iwarp && pf->iw_enabled) { 753*cb6b8299SEric Joyner error = ixl_iw_pf_detach(pf); 754*cb6b8299SEric Joyner if (error == EBUSY) { 755*cb6b8299SEric Joyner device_printf(dev, "iwarp in use; stop it first.\n"); 756*cb6b8299SEric Joyner return (error); 757*cb6b8299SEric Joyner } 758*cb6b8299SEric Joyner } 759*cb6b8299SEric Joyner #endif 760*cb6b8299SEric Joyner 76131830672SJack F Vogel #ifdef DEV_NETMAP 76231830672SJack F Vogel netmap_detach(vsi->ifp); 76331830672SJack F Vogel #endif /* DEV_NETMAP */ 7644294f337SSean Bruno ixl_pf_qmgr_destroy(&pf->qmgr); 76561ae650dSJack F Vogel ixl_free_pci_resources(pf); 76661ae650dSJack F Vogel bus_generic_detach(dev); 76761ae650dSJack F Vogel if_free(vsi->ifp); 76861ae650dSJack F Vogel ixl_free_vsi(vsi); 76961ae650dSJack F Vogel IXL_PF_LOCK_DESTROY(pf); 77061ae650dSJack F Vogel return (0); 77161ae650dSJack F Vogel } 77261ae650dSJack F Vogel 77361ae650dSJack F Vogel /********************************************************************* 77461ae650dSJack F Vogel * 77561ae650dSJack F Vogel * Shutdown entry point 77661ae650dSJack F Vogel * 77761ae650dSJack F Vogel **********************************************************************/ 77861ae650dSJack F Vogel 77961ae650dSJack F Vogel static int 78061ae650dSJack F Vogel ixl_shutdown(device_t dev) 78161ae650dSJack F Vogel { 78261ae650dSJack F Vogel struct ixl_pf *pf = device_get_softc(dev); 78361ae650dSJack F Vogel ixl_stop(pf); 78461ae650dSJack F Vogel return (0); 78561ae650dSJack F Vogel } 78661ae650dSJack F Vogel 787