1266423Sjfv/****************************************************************************** 2266423Sjfv 3349163Serj Copyright (c) 2013-2019, Intel Corporation 4266423Sjfv All rights reserved. 5349163Serj 6266423Sjfv Redistribution and use in source and binary forms, with or without 7266423Sjfv modification, are permitted provided that the following conditions are met: 8266423Sjfv 9266423Sjfv 1. Redistributions of source code must retain the above copyright notice, 10266423Sjfv this list of conditions and the following disclaimer. 11266423Sjfv 12266423Sjfv 2. Redistributions in binary form must reproduce the above copyright 13266423Sjfv notice, this list of conditions and the following disclaimer in the 14266423Sjfv documentation and/or other materials provided with the distribution. 15266423Sjfv 16266423Sjfv 3. Neither the name of the Intel Corporation nor the names of its 17266423Sjfv contributors may be used to endorse or promote products derived from 18266423Sjfv this software without specific prior written permission. 19266423Sjfv 20266423Sjfv THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21266423Sjfv AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22266423Sjfv IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23266423Sjfv ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24266423Sjfv LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25266423Sjfv CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26266423Sjfv SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27266423Sjfv INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28266423Sjfv CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29266423Sjfv ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30266423Sjfv POSSIBILITY OF SUCH DAMAGE. 31266423Sjfv 32266423Sjfv******************************************************************************/ 33266423Sjfv/*$FreeBSD: stable/11/sys/dev/ixl/if_ixl.c 349163 2019-06-18 00:08:02Z erj $*/ 34266423Sjfv 35270346Sjfv#include "ixl.h" 36270346Sjfv#include "ixl_pf.h" 37269198Sjfv 38318357Serj#ifdef IXL_IW 39318357Serj#include "ixl_iw.h" 40318357Serj#include "ixl_iw_int.h" 41318357Serj#endif 42318357Serj 43303967Ssbruno#ifdef PCI_IOV 44303967Ssbruno#include "ixl_pf_iov.h" 45277262Sjfv#endif 46277262Sjfv 47266423Sjfv/********************************************************************* 48266423Sjfv * Driver version 49266423Sjfv *********************************************************************/ 50333343Serj#define IXL_DRIVER_VERSION_MAJOR 1 51349163Serj#define IXL_DRIVER_VERSION_MINOR 11 52333343Serj#define IXL_DRIVER_VERSION_BUILD 9 53266423Sjfv 54333343Serjchar ixl_driver_version[] = __XSTRING(IXL_DRIVER_VERSION_MAJOR) "." 55333343Serj __XSTRING(IXL_DRIVER_VERSION_MINOR) "." 56333343Serj __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k"; 57333343Serj 58266423Sjfv/********************************************************************* 59266423Sjfv * PCI Device ID Table 60266423Sjfv * 61266423Sjfv * Used by probe to select devices to load on 62270346Sjfv * Last field stores an index into ixl_strings 63266423Sjfv * Last entry must be all 0s 64266423Sjfv * 65266423Sjfv * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } 66266423Sjfv *********************************************************************/ 67266423Sjfv 68270346Sjfvstatic ixl_vendor_info_t ixl_vendor_info_array[] = 69266423Sjfv{ 70266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0}, 71266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0}, 72266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0}, 73266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0}, 74266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0}, 75266423Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0}, 76270346Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0}, 77284049Sjfv {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0}, 78303967Ssbruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0}, 79303967Ssbruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0}, 80303967Ssbruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0}, 81303967Ssbruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0}, 82303967Ssbruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0}, 83303967Ssbruno {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0}, 84318357Serj {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, 0, 0, 0}, 85318357Serj {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, 0, 0, 0}, 86349163Serj {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_BC, 0, 0, 0}, 87349163Serj {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_SFP, 0, 0, 0}, 88349163Serj {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_B, 0, 0, 0}, 89266423Sjfv /* required last entry */ 90266423Sjfv {0, 0, 0, 0, 0} 91266423Sjfv}; 92266423Sjfv 93266423Sjfv/********************************************************************* 94266423Sjfv * Table of branding strings 95266423Sjfv *********************************************************************/ 96266423Sjfv 97270346Sjfvstatic char *ixl_strings[] = { 98333343Serj "Intel(R) Ethernet Connection 700 Series PF Driver" 99266423Sjfv}; 100266423Sjfv 101266423Sjfv 102266423Sjfv/********************************************************************* 103266423Sjfv * Function prototypes 104266423Sjfv *********************************************************************/ 105270346Sjfvstatic int ixl_probe(device_t); 106270346Sjfvstatic int ixl_attach(device_t); 107270346Sjfvstatic int ixl_detach(device_t); 108270346Sjfvstatic int ixl_shutdown(device_t); 109299553Serj 110303967Ssbrunostatic int ixl_save_pf_tunables(struct ixl_pf *); 111299553Serj 112266423Sjfv/********************************************************************* 113266423Sjfv * FreeBSD Device Interface Entry Points 114266423Sjfv *********************************************************************/ 115266423Sjfv 116270346Sjfvstatic device_method_t ixl_methods[] = { 117266423Sjfv /* Device interface */ 118270346Sjfv DEVMETHOD(device_probe, ixl_probe), 119270346Sjfv DEVMETHOD(device_attach, ixl_attach), 120270346Sjfv DEVMETHOD(device_detach, ixl_detach), 121270346Sjfv DEVMETHOD(device_shutdown, ixl_shutdown), 122279858Sjfv#ifdef PCI_IOV 123299546Serj DEVMETHOD(pci_iov_init, ixl_iov_init), 124299546Serj DEVMETHOD(pci_iov_uninit, ixl_iov_uninit), 125299546Serj DEVMETHOD(pci_iov_add_vf, ixl_add_vf), 126279858Sjfv#endif 127266423Sjfv {0, 0} 128266423Sjfv}; 129266423Sjfv 130270346Sjfvstatic driver_t ixl_driver = { 131270346Sjfv "ixl", ixl_methods, sizeof(struct ixl_pf), 132266423Sjfv}; 133266423Sjfv 134270346Sjfvdevclass_t ixl_devclass; 135270346SjfvDRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 136266423Sjfv 137318357SerjMODULE_VERSION(ixl, 1); 138318357Serj 139270346SjfvMODULE_DEPEND(ixl, pci, 1, 1, 1); 140270346SjfvMODULE_DEPEND(ixl, ether, 1, 1, 1); 141318357Serj#if defined(DEV_NETMAP) && __FreeBSD_version >= 1100000 142279860SjfvMODULE_DEPEND(ixl, netmap, 1, 1, 1); 143279860Sjfv#endif /* DEV_NETMAP */ 144279860Sjfv 145266423Sjfv/* 146270346Sjfv** TUNEABLE PARAMETERS: 147270346Sjfv*/ 148270346Sjfv 149270346Sjfvstatic SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 150270346Sjfv "IXL driver parameters"); 151270346Sjfv 152270346Sjfv/* 153266423Sjfv * MSIX should be the default for best performance, 154266423Sjfv * but this allows it to be forced off for testing. 155266423Sjfv */ 156270346Sjfvstatic int ixl_enable_msix = 1; 157270346SjfvTUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); 158270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, 159270346Sjfv "Enable MSI-X interrupts"); 160266423Sjfv 161266423Sjfv/* 162333343Serj** Number of descriptors per ring 163333343Serj** - TX and RX sizes are independently configurable 164266423Sjfv*/ 165333343Serjstatic int ixl_tx_ring_size = IXL_DEFAULT_RING; 166333343SerjTUNABLE_INT("hw.ixl.tx_ring_size", &ixl_tx_ring_size); 167333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, tx_ring_size, CTLFLAG_RDTUN, 168333343Serj &ixl_tx_ring_size, 0, "TX Descriptor Ring Size"); 169266423Sjfv 170333343Serjstatic int ixl_rx_ring_size = IXL_DEFAULT_RING; 171333343SerjTUNABLE_INT("hw.ixl.rx_ring_size", &ixl_rx_ring_size); 172333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, rx_ring_size, CTLFLAG_RDTUN, 173333343Serj &ixl_rx_ring_size, 0, "RX Descriptor Ring Size"); 174333343Serj 175266423Sjfv/* 176266423Sjfv** This can be set manually, if left as 0 the 177266423Sjfv** number of queues will be calculated based 178266423Sjfv** on cpus and msix vectors available. 179266423Sjfv*/ 180303967Ssbrunostatic int ixl_max_queues = 0; 181270346SjfvTUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); 182270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, 183270346Sjfv &ixl_max_queues, 0, "Number of Queues"); 184266423Sjfv 185333343Serj/* 186333343Serj * Leave this on unless you need to send flow control 187333343Serj * frames (or other control frames) from software 188333343Serj */ 189303967Ssbrunostatic int ixl_enable_tx_fc_filter = 1; 190303967SsbrunoTUNABLE_INT("hw.ixl.enable_tx_fc_filter", 191303967Ssbruno &ixl_enable_tx_fc_filter); 192303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN, 193303967Ssbruno &ixl_enable_tx_fc_filter, 0, 194303967Ssbruno "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources"); 195303967Ssbruno 196349163Serjstatic int ixl_i2c_access_method = 0; 197349163SerjTUNABLE_INT("hw.ixl.i2c_access_method", 198349163Serj &ixl_i2c_access_method); 199349163SerjSYSCTL_INT(_hw_ixl, OID_AUTO, i2c_access_method, CTLFLAG_RDTUN, 200349163Serj &ixl_i2c_access_method, 0, 201349163Serj IXL_SYSCTL_HELP_I2C_METHOD); 202349163Serj 203333343Serj/* 204333343Serj * Different method for processing TX descriptor 205333343Serj * completion. 206333343Serj */ 207333343Serjstatic int ixl_enable_head_writeback = 1; 208333343SerjTUNABLE_INT("hw.ixl.enable_head_writeback", 209333343Serj &ixl_enable_head_writeback); 210333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, enable_head_writeback, CTLFLAG_RDTUN, 211333343Serj &ixl_enable_head_writeback, 0, 212333343Serj "For detecting last completed TX descriptor by hardware, use value written by HW instead of checking descriptors"); 213333343Serj 214303967Ssbrunostatic int ixl_core_debug_mask = 0; 215303967SsbrunoTUNABLE_INT("hw.ixl.core_debug_mask", 216303967Ssbruno &ixl_core_debug_mask); 217303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN, 218303967Ssbruno &ixl_core_debug_mask, 0, 219303967Ssbruno "Display debug statements that are printed in non-shared code"); 220303967Ssbruno 221303967Ssbrunostatic int ixl_shared_debug_mask = 0; 222303967SsbrunoTUNABLE_INT("hw.ixl.shared_debug_mask", 223303967Ssbruno &ixl_shared_debug_mask); 224303967SsbrunoSYSCTL_INT(_hw_ixl, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN, 225303967Ssbruno &ixl_shared_debug_mask, 0, 226303967Ssbruno "Display debug statements that are printed in shared code"); 227303967Ssbruno 228349163Serj 229266423Sjfv/* 230266423Sjfv** Controls for Interrupt Throttling 231266423Sjfv** - true/false for dynamic adjustment 232266423Sjfv** - default values for static ITR 233266423Sjfv*/ 234303967Ssbrunostatic int ixl_dynamic_rx_itr = 1; 235270346SjfvTUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 236270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 237270346Sjfv &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 238266423Sjfv 239303967Ssbrunostatic int ixl_dynamic_tx_itr = 1; 240270346SjfvTUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 241270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 242270346Sjfv &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 243266423Sjfv 244303967Ssbrunostatic int ixl_rx_itr = IXL_ITR_8K; 245270346SjfvTUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 246270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 247270346Sjfv &ixl_rx_itr, 0, "RX Interrupt Rate"); 248270346Sjfv 249303967Ssbrunostatic int ixl_tx_itr = IXL_ITR_4K; 250270346SjfvTUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 251270346SjfvSYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 252270346Sjfv &ixl_tx_itr, 0, "TX Interrupt Rate"); 253270346Sjfv 254318357Serj#ifdef IXL_IW 255318357Serjint ixl_enable_iwarp = 0; 256318357SerjTUNABLE_INT("hw.ixl.enable_iwarp", &ixl_enable_iwarp); 257333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, enable_iwarp, CTLFLAG_RDTUN, 258333343Serj &ixl_enable_iwarp, 0, "iWARP enabled"); 259333343Serj 260333343Serj#if __FreeBSD_version < 1100000 261333343Serjint ixl_limit_iwarp_msix = 1; 262333343Serj#else 263333343Serjint ixl_limit_iwarp_msix = IXL_IW_MAX_MSIX; 264318357Serj#endif 265333343SerjTUNABLE_INT("hw.ixl.limit_iwarp_msix", &ixl_limit_iwarp_msix); 266333343SerjSYSCTL_INT(_hw_ixl, OID_AUTO, limit_iwarp_msix, CTLFLAG_RDTUN, 267333343Serj &ixl_limit_iwarp_msix, 0, "Limit MSIX vectors assigned to iWARP"); 268333343Serj#endif 269318357Serj 270279860Sjfv#ifdef DEV_NETMAP 271279860Sjfv#define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ 272279860Sjfv#include <dev/netmap/if_ixl_netmap.h> 273279860Sjfv#endif /* DEV_NETMAP */ 274274205Sjfv 275266423Sjfv/********************************************************************* 276266423Sjfv * Device identification routine 277266423Sjfv * 278270346Sjfv * ixl_probe determines if the driver should be loaded on 279266423Sjfv * the hardware based on PCI vendor/device id of the device. 280266423Sjfv * 281266423Sjfv * return BUS_PROBE_DEFAULT on success, positive on failure 282266423Sjfv *********************************************************************/ 283266423Sjfv 284266423Sjfvstatic int 285270346Sjfvixl_probe(device_t dev) 286266423Sjfv{ 287270346Sjfv ixl_vendor_info_t *ent; 288266423Sjfv 289266423Sjfv u16 pci_vendor_id, pci_device_id; 290266423Sjfv u16 pci_subvendor_id, pci_subdevice_id; 291266423Sjfv char device_name[256]; 292266423Sjfv 293299552Serj#if 0 294270346Sjfv INIT_DEBUGOUT("ixl_probe: begin"); 295299552Serj#endif 296266423Sjfv pci_vendor_id = pci_get_vendor(dev); 297266423Sjfv if (pci_vendor_id != I40E_INTEL_VENDOR_ID) 298266423Sjfv return (ENXIO); 299266423Sjfv 300266423Sjfv pci_device_id = pci_get_device(dev); 301266423Sjfv pci_subvendor_id = pci_get_subvendor(dev); 302266423Sjfv pci_subdevice_id = pci_get_subdevice(dev); 303266423Sjfv 304270346Sjfv ent = ixl_vendor_info_array; 305266423Sjfv while (ent->vendor_id != 0) { 306266423Sjfv if ((pci_vendor_id == ent->vendor_id) && 307266423Sjfv (pci_device_id == ent->device_id) && 308266423Sjfv 309266423Sjfv ((pci_subvendor_id == ent->subvendor_id) || 310266423Sjfv (ent->subvendor_id == 0)) && 311266423Sjfv 312266423Sjfv ((pci_subdevice_id == ent->subdevice_id) || 313266423Sjfv (ent->subdevice_id == 0))) { 314266423Sjfv sprintf(device_name, "%s, Version - %s", 315270346Sjfv ixl_strings[ent->index], 316270346Sjfv ixl_driver_version); 317266423Sjfv device_set_desc_copy(dev, device_name); 318266423Sjfv return (BUS_PROBE_DEFAULT); 319266423Sjfv } 320266423Sjfv ent++; 321266423Sjfv } 322266423Sjfv return (ENXIO); 323266423Sjfv} 324266423Sjfv 325303967Ssbruno/* 326303967Ssbruno * Sanity check and save off tunable values. 327303967Ssbruno */ 328303967Ssbrunostatic int 329303967Ssbrunoixl_save_pf_tunables(struct ixl_pf *pf) 330303967Ssbruno{ 331303967Ssbruno device_t dev = pf->dev; 332303967Ssbruno 333303967Ssbruno /* Save tunable information */ 334303967Ssbruno pf->enable_msix = ixl_enable_msix; 335303967Ssbruno pf->max_queues = ixl_max_queues; 336303967Ssbruno pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; 337303967Ssbruno pf->dynamic_rx_itr = ixl_dynamic_rx_itr; 338303967Ssbruno pf->dynamic_tx_itr = ixl_dynamic_tx_itr; 339303967Ssbruno pf->dbg_mask = ixl_core_debug_mask; 340303967Ssbruno pf->hw.debug_mask = ixl_shared_debug_mask; 341333343Serj#ifdef DEV_NETMAP 342333343Serj if (ixl_enable_head_writeback == 0) 343333343Serj device_printf(dev, "Head writeback mode cannot be disabled " 344333343Serj "when netmap is enabled\n"); 345333343Serj pf->vsi.enable_head_writeback = 1; 346333343Serj#else 347333343Serj pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback); 348333343Serj#endif 349333343Serj ixl_vsi_setup_rings_size(&pf->vsi, ixl_tx_ring_size, ixl_rx_ring_size); 350303967Ssbruno 351349163Serj if (ixl_i2c_access_method > IXL_I2C_ACCESS_METHOD_TYPE_LENGTH - 1 352349163Serj || ixl_i2c_access_method < IXL_I2C_ACCESS_METHOD_BEST_AVAILABLE) 353349163Serj pf->i2c_access_method = IXL_I2C_ACCESS_METHOD_BEST_AVAILABLE; 354349163Serj else 355349163Serj pf->i2c_access_method = 356349163Serj (enum ixl_i2c_access_method_t)ixl_i2c_access_method; 357349163Serj 358318357Serj if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) { 359318357Serj device_printf(dev, "Invalid tx_itr value of %d set!\n", 360318357Serj ixl_tx_itr); 361318357Serj device_printf(dev, "tx_itr must be between %d and %d, " 362318357Serj "inclusive\n", 363318357Serj 0, IXL_MAX_ITR); 364318357Serj device_printf(dev, "Using default value of %d instead\n", 365318357Serj IXL_ITR_4K); 366318357Serj pf->tx_itr = IXL_ITR_4K; 367318357Serj } else 368318357Serj pf->tx_itr = ixl_tx_itr; 369318357Serj 370318357Serj if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) { 371318357Serj device_printf(dev, "Invalid rx_itr value of %d set!\n", 372318357Serj ixl_rx_itr); 373318357Serj device_printf(dev, "rx_itr must be between %d and %d, " 374318357Serj "inclusive\n", 375318357Serj 0, IXL_MAX_ITR); 376318357Serj device_printf(dev, "Using default value of %d instead\n", 377318357Serj IXL_ITR_8K); 378318357Serj pf->rx_itr = IXL_ITR_8K; 379318357Serj } else 380318357Serj pf->rx_itr = ixl_rx_itr; 381318357Serj 382303967Ssbruno return (0); 383303967Ssbruno} 384303967Ssbruno 385349163Serjstatic int 386349163Serjixl_attach_recovery_mode(struct ixl_pf *pf) 387349163Serj{ 388349163Serj struct ixl_vsi *vsi = &pf->vsi; 389349163Serj struct i40e_hw *hw = &pf->hw; 390349163Serj device_t dev = pf->dev; 391349163Serj int error = 0; 392349163Serj 393349163Serj device_printf(dev, "Firmware recovery mode detected. Limiting functionality. Refer to Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n"); 394349163Serj 395349163Serj atomic_set_int(&pf->state, IXL_PF_STATE_RECOVERY_MODE); 396349163Serj 397349163Serj i40e_get_mac_addr(hw, hw->mac.addr); 398349163Serj 399349163Serj pf->msix = ixl_init_msix(pf); 400349163Serj ixl_setup_stations(pf); 401349163Serj ixl_setup_interface(pf->dev, vsi); 402349163Serj 403349163Serj if (pf->msix > 1) { 404349163Serj error = ixl_setup_adminq_msix(pf); 405349163Serj if (error) { 406349163Serj device_printf(dev, "ixl_setup_adminq_msix() error: %d\n", 407349163Serj error); 408349163Serj goto recovery_err_late; 409349163Serj } 410349163Serj error = ixl_setup_adminq_tq(pf); 411349163Serj if (error) { 412349163Serj device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", 413349163Serj error); 414349163Serj goto recovery_err_late; 415349163Serj } 416349163Serj ixl_configure_intr0_msix(pf); 417349163Serj ixl_enable_intr0(hw); 418349163Serj } else { 419349163Serj error = ixl_setup_legacy(pf); 420349163Serj 421349163Serj error = ixl_setup_adminq_tq(pf); 422349163Serj if (error) { 423349163Serj device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", 424349163Serj error); 425349163Serj goto recovery_err_late; 426349163Serj } 427349163Serj } 428349163Serj 429349163Serj /* Get the bus configuration and set the shared code's config */ 430349163Serj ixl_get_bus_info(pf); 431349163Serj 432349163Serj /* Initialize statistics & add sysctls */ 433349163Serj ixl_add_device_sysctls(pf); 434349163Serj 435349163Serj /* Start the local timer */ 436349163Serj IXL_PF_LOCK(pf); 437349163Serj callout_reset(&pf->timer, hz, ixl_local_timer, pf); 438349163Serj IXL_PF_UNLOCK(pf); 439349163Serj 440349163Serjrecovery_err_late: 441349163Serj return (error); 442349163Serj} 443349163Serj 444266423Sjfv/********************************************************************* 445266423Sjfv * Device initialization routine 446266423Sjfv * 447266423Sjfv * The attach entry point is called when the driver is being loaded. 448266423Sjfv * This routine identifies the type of hardware, allocates all resources 449266423Sjfv * and initializes the hardware. 450266423Sjfv * 451266423Sjfv * return 0 on success, positive on failure 452266423Sjfv *********************************************************************/ 453266423Sjfv 454266423Sjfvstatic int 455270346Sjfvixl_attach(device_t dev) 456266423Sjfv{ 457270346Sjfv struct ixl_pf *pf; 458266423Sjfv struct i40e_hw *hw; 459299552Serj struct ixl_vsi *vsi; 460349163Serj enum i40e_get_fw_lldp_status_resp lldp_status; 461303967Ssbruno enum i40e_status_code status; 462266423Sjfv int error = 0; 463266423Sjfv 464270346Sjfv INIT_DEBUGOUT("ixl_attach: begin"); 465266423Sjfv 466266423Sjfv /* Allocate, clear, and link in our primary soft structure */ 467266423Sjfv pf = device_get_softc(dev); 468266423Sjfv pf->dev = pf->osdep.dev = dev; 469266423Sjfv hw = &pf->hw; 470266423Sjfv 471266423Sjfv /* 472266423Sjfv ** Note this assumes we have a single embedded VSI, 473266423Sjfv ** this could be enhanced later to allocate multiple 474266423Sjfv */ 475266423Sjfv vsi = &pf->vsi; 476266423Sjfv vsi->dev = pf->dev; 477333343Serj vsi->back = pf; 478266423Sjfv 479303967Ssbruno /* Save tunable values */ 480303967Ssbruno error = ixl_save_pf_tunables(pf); 481303967Ssbruno if (error) 482303967Ssbruno return (error); 483303967Ssbruno 484266423Sjfv /* Core Lock Init*/ 485270346Sjfv IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); 486266423Sjfv 487266423Sjfv /* Set up the timer callout */ 488266423Sjfv callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); 489266423Sjfv 490266423Sjfv /* Do PCI setup - map BAR0, etc */ 491270346Sjfv if (ixl_allocate_pci_resources(pf)) { 492266423Sjfv error = ENXIO; 493266423Sjfv goto err_out; 494266423Sjfv } 495266423Sjfv 496266423Sjfv /* Establish a clean starting point */ 497269198Sjfv i40e_clear_hw(hw); 498349163Serj 499349163Serj /* Don't try to reset device if it's in recovery mode */ 500349163Serj if (!ixl_fw_recovery_mode(pf)) { 501349163Serj status = i40e_pf_reset(hw); 502349163Serj if (status) { 503349163Serj device_printf(dev, "PF reset failure %s\n", 504349163Serj i40e_stat_str(hw, status)); 505349163Serj error = EIO; 506349163Serj goto err_out; 507349163Serj } 508269198Sjfv } 509266423Sjfv 510266423Sjfv /* Initialize the shared code */ 511303967Ssbruno status = i40e_init_shared_code(hw); 512303967Ssbruno if (status) { 513303967Ssbruno device_printf(dev, "Unable to initialize shared code, error %s\n", 514303967Ssbruno i40e_stat_str(hw, status)); 515266423Sjfv error = EIO; 516266423Sjfv goto err_out; 517266423Sjfv } 518266423Sjfv 519266423Sjfv /* Set up the admin queue */ 520303967Ssbruno hw->aq.num_arq_entries = IXL_AQ_LEN; 521303967Ssbruno hw->aq.num_asq_entries = IXL_AQ_LEN; 522303967Ssbruno hw->aq.arq_buf_size = IXL_AQ_BUF_SZ; 523303967Ssbruno hw->aq.asq_buf_size = IXL_AQ_BUF_SZ; 524303967Ssbruno 525303967Ssbruno status = i40e_init_adminq(hw); 526303967Ssbruno if (status != 0 && status != I40E_ERR_FIRMWARE_API_VERSION) { 527303967Ssbruno device_printf(dev, "Unable to initialize Admin Queue, error %s\n", 528303967Ssbruno i40e_stat_str(hw, status)); 529299549Serj error = EIO; 530299549Serj goto err_out; 531299549Serj } 532299552Serj ixl_print_nvm_version(pf); 533299552Serj 534303967Ssbruno if (status == I40E_ERR_FIRMWARE_API_VERSION) { 535269198Sjfv device_printf(dev, "The driver for the device stopped " 536333343Serj "because the NVM image is newer than expected.\n"); 537333343Serj device_printf(dev, "You must install the most recent version of " 538299549Serj "the network driver.\n"); 539299549Serj error = EIO; 540266423Sjfv goto err_out; 541266423Sjfv } 542266423Sjfv 543269198Sjfv if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 544333343Serj hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw)) { 545269198Sjfv device_printf(dev, "The driver for the device detected " 546333343Serj "a newer version of the NVM image than expected.\n"); 547333343Serj device_printf(dev, "Please install the most recent version " 548333343Serj "of the network driver.\n"); 549333343Serj } else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4) { 550269198Sjfv device_printf(dev, "The driver for the device detected " 551333343Serj "an older version of the NVM image than expected.\n"); 552333343Serj device_printf(dev, "Please update the NVM image.\n"); 553333343Serj } 554266423Sjfv 555349163Serj if (ixl_fw_recovery_mode(pf)) 556349163Serj return ixl_attach_recovery_mode(pf); 557349163Serj 558266423Sjfv /* Clear PXE mode */ 559266423Sjfv i40e_clear_pxe_mode(hw); 560266423Sjfv 561266423Sjfv /* Get capabilities from the device */ 562270346Sjfv error = ixl_get_hw_capabilities(pf); 563266423Sjfv if (error) { 564266423Sjfv device_printf(dev, "HW capabilities failure!\n"); 565266423Sjfv goto err_get_cap; 566266423Sjfv } 567266423Sjfv 568333343Serj /* 569333343Serj * Allocate interrupts and figure out number of queues to use 570333343Serj * for PF interface 571333343Serj */ 572333343Serj pf->msix = ixl_init_msix(pf); 573333343Serj 574266423Sjfv /* Set up host memory cache */ 575303967Ssbruno status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 576279858Sjfv hw->func_caps.num_rx_qp, 0, 0); 577303967Ssbruno if (status) { 578303967Ssbruno device_printf(dev, "init_lan_hmc failed: %s\n", 579303967Ssbruno i40e_stat_str(hw, status)); 580266423Sjfv goto err_get_cap; 581266423Sjfv } 582266423Sjfv 583303967Ssbruno status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 584303967Ssbruno if (status) { 585303967Ssbruno device_printf(dev, "configure_lan_hmc failed: %s\n", 586303967Ssbruno i40e_stat_str(hw, status)); 587303967Ssbruno goto err_mac_hmc; 588303967Ssbruno } 589303967Ssbruno 590303967Ssbruno /* Init queue allocation manager */ 591303967Ssbruno error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp); 592266423Sjfv if (error) { 593303967Ssbruno device_printf(dev, "Failed to init queue manager for PF queues, error %d\n", 594303967Ssbruno error); 595266423Sjfv goto err_mac_hmc; 596266423Sjfv } 597303967Ssbruno /* reserve a contiguous allocation for the PF's VSI */ 598303967Ssbruno error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag); 599303967Ssbruno if (error) { 600303967Ssbruno device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n", 601303967Ssbruno error); 602303967Ssbruno goto err_mac_hmc; 603303967Ssbruno } 604303967Ssbruno device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n", 605303967Ssbruno pf->qtag.num_allocated, pf->qtag.num_active); 606266423Sjfv 607349163Serj /* Disable LLDP from the firmware on XL710 for certain NVM versions */ 608349163Serj if (hw->mac.type == I40E_MAC_XL710 && 609349163Serj (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 3)) || 610349163Serj (hw->aq.fw_maj_ver < 4))) { 611349163Serj i40e_aq_stop_lldp(hw, true, false, NULL); 612333343Serj pf->state |= IXL_PF_STATE_FW_LLDP_DISABLED; 613333343Serj } 614269198Sjfv 615349163Serj /* Try enabling Energy Efficient Ethernet (EEE) mode */ 616349163Serj if(i40e_enable_eee(hw, true) == I40E_SUCCESS) 617349163Serj atomic_set_int(&pf->state, IXL_PF_STATE_EEE_ENABLED); 618349163Serj else 619349163Serj atomic_clear_int(&pf->state, IXL_PF_STATE_EEE_ENABLED); 620349163Serj 621303967Ssbruno /* Get MAC addresses from hardware */ 622266423Sjfv i40e_get_mac_addr(hw, hw->mac.addr); 623266423Sjfv error = i40e_validate_mac_addr(hw->mac.addr); 624266423Sjfv if (error) { 625266423Sjfv device_printf(dev, "validate_mac_addr failed: %d\n", error); 626266423Sjfv goto err_mac_hmc; 627266423Sjfv } 628266423Sjfv bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 629266423Sjfv i40e_get_port_mac_addr(hw, hw->mac.port_addr); 630266423Sjfv 631333343Serj /* Query device FW LLDP status */ 632349163Serj if (i40e_get_fw_lldp_status(hw, &lldp_status) == I40E_SUCCESS) { 633349163Serj if (lldp_status == I40E_GET_FW_LLDP_STATUS_DISABLED) { 634349163Serj atomic_set_int(&pf->state, 635349163Serj IXL_PF_STATE_FW_LLDP_DISABLED); 636349163Serj } else { 637349163Serj atomic_clear_int(&pf->state, 638349163Serj IXL_PF_STATE_FW_LLDP_DISABLED); 639349163Serj } 640349163Serj } 641349163Serj 642333343Serj /* Tell FW to apply DCB config on link up */ 643349163Serj i40e_aq_set_dcb_parameters(hw, true, NULL); 644333343Serj 645303967Ssbruno /* Set up SW VSI and allocate queue memory and rings */ 646303967Ssbruno if (ixl_setup_stations(pf)) { 647266423Sjfv device_printf(dev, "setup stations failed!\n"); 648266423Sjfv error = ENOMEM; 649266423Sjfv goto err_mac_hmc; 650266423Sjfv } 651266423Sjfv 652299547Serj /* Setup OS network interface / ifnet */ 653303967Ssbruno if (ixl_setup_interface(dev, vsi)) { 654274205Sjfv device_printf(dev, "interface setup failed!\n"); 655274205Sjfv error = EIO; 656266423Sjfv goto err_late; 657274205Sjfv } 658266423Sjfv 659303967Ssbruno /* Determine link state */ 660303967Ssbruno if (ixl_attach_get_link_status(pf)) { 661303967Ssbruno error = EINVAL; 662303967Ssbruno goto err_late; 663303967Ssbruno } 664303967Ssbruno 665279033Sjfv error = ixl_switch_config(pf); 666279033Sjfv if (error) { 667299553Serj device_printf(dev, "Initial ixl_switch_config() failed: %d\n", 668299553Serj error); 669299546Serj goto err_late; 670279033Sjfv } 671279033Sjfv 672299547Serj /* Limit PHY interrupts to link, autoneg, and modules failure */ 673303967Ssbruno status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 674299547Serj NULL); 675303967Ssbruno if (status) { 676303967Ssbruno device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s," 677303967Ssbruno " aq_err %s\n", i40e_stat_str(hw, status), 678303967Ssbruno i40e_aq_str(hw, hw->aq.asq_last_status)); 679299547Serj goto err_late; 680299547Serj } 681279033Sjfv 682299553Serj /* Get the bus configuration and set the shared code's config */ 683318357Serj ixl_get_bus_info(pf); 684266423Sjfv 685299553Serj /* 686299553Serj * In MSI-X mode, initialize the Admin Queue interrupt, 687299553Serj * so userland tools can communicate with the adapter regardless of 688299553Serj * the ifnet interface's status. 689299553Serj */ 690299553Serj if (pf->msix > 1) { 691299553Serj error = ixl_setup_adminq_msix(pf); 692299553Serj if (error) { 693318357Serj device_printf(dev, "ixl_setup_adminq_msix() error: %d\n", 694299553Serj error); 695299553Serj goto err_late; 696299553Serj } 697299553Serj error = ixl_setup_adminq_tq(pf); 698299553Serj if (error) { 699318357Serj device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", 700299553Serj error); 701299553Serj goto err_late; 702299553Serj } 703299553Serj ixl_configure_intr0_msix(pf); 704318357Serj ixl_enable_intr0(hw); 705318357Serj 706318357Serj error = ixl_setup_queue_msix(vsi); 707318357Serj if (error) 708318357Serj device_printf(dev, "ixl_setup_queue_msix() error: %d\n", 709318357Serj error); 710318357Serj error = ixl_setup_queue_tqs(vsi); 711318357Serj if (error) 712318357Serj device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", 713318357Serj error); 714318357Serj } else { 715318357Serj error = ixl_setup_legacy(pf); 716318357Serj 717318357Serj error = ixl_setup_adminq_tq(pf); 718318357Serj if (error) { 719318357Serj device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", 720318357Serj error); 721318357Serj goto err_late; 722318357Serj } 723318357Serj 724318357Serj error = ixl_setup_queue_tqs(vsi); 725318357Serj if (error) 726318357Serj device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", 727318357Serj error); 728299553Serj } 729299546Serj 730318357Serj if (error) { 731318357Serj device_printf(dev, "interrupt setup error: %d\n", error); 732318357Serj } 733318357Serj 734318357Serj /* Set initial advertised speed sysctl value */ 735333343Serj ixl_set_initial_advertised_speeds(pf); 736318357Serj 737299549Serj /* Initialize statistics & add sysctls */ 738299549Serj ixl_add_device_sysctls(pf); 739299549Serj 740270346Sjfv ixl_pf_reset_stats(pf); 741270346Sjfv ixl_update_stats_counters(pf); 742270346Sjfv ixl_add_hw_stats(pf); 743266423Sjfv 744349163Serj /* Add protocol filters to list */ 745349163Serj ixl_init_filters(vsi); 746349163Serj 747266423Sjfv /* Register for VLAN events */ 748266423Sjfv vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 749270346Sjfv ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); 750266423Sjfv vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 751270346Sjfv ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); 752266423Sjfv 753279858Sjfv#ifdef PCI_IOV 754303967Ssbruno ixl_initialize_sriov(pf); 755279858Sjfv#endif 756279858Sjfv 757279860Sjfv#ifdef DEV_NETMAP 758343559Svmaffione ixl_netmap_attach(vsi); 759279860Sjfv#endif /* DEV_NETMAP */ 760318357Serj 761318357Serj#ifdef IXL_IW 762318357Serj if (hw->func_caps.iwarp && ixl_enable_iwarp) { 763318357Serj pf->iw_enabled = (pf->iw_msix > 0) ? true : false; 764318357Serj if (pf->iw_enabled) { 765318357Serj error = ixl_iw_pf_attach(pf); 766318357Serj if (error) { 767318357Serj device_printf(dev, 768318357Serj "interfacing to iwarp driver failed: %d\n", 769318357Serj error); 770318357Serj goto err_late; 771333343Serj } else 772333343Serj device_printf(dev, "iWARP ready\n"); 773318357Serj } else 774318357Serj device_printf(dev, 775318357Serj "iwarp disabled on this device (no msix vectors)\n"); 776318357Serj } else { 777318357Serj pf->iw_enabled = false; 778318357Serj device_printf(dev, "The device is not iWARP enabled\n"); 779318357Serj } 780318357Serj#endif 781349163Serj /* Start the local timer */ 782349163Serj IXL_PF_LOCK(pf); 783349163Serj callout_reset(&pf->timer, hz, ixl_local_timer, pf); 784349163Serj IXL_PF_UNLOCK(pf); 785318357Serj 786270346Sjfv INIT_DEBUGOUT("ixl_attach: end"); 787266423Sjfv return (0); 788266423Sjfv 789266423Sjfverr_late: 790303967Ssbruno if (vsi->ifp != NULL) { 791303967Ssbruno ether_ifdetach(vsi->ifp); 792274205Sjfv if_free(vsi->ifp); 793303967Ssbruno } 794266423Sjfverr_mac_hmc: 795266423Sjfv i40e_shutdown_lan_hmc(hw); 796266423Sjfverr_get_cap: 797266423Sjfv i40e_shutdown_adminq(hw); 798266423Sjfverr_out: 799270346Sjfv ixl_free_pci_resources(pf); 800274205Sjfv ixl_free_vsi(vsi); 801270346Sjfv IXL_PF_LOCK_DESTROY(pf); 802266423Sjfv return (error); 803266423Sjfv} 804266423Sjfv 805266423Sjfv/********************************************************************* 806266423Sjfv * Device removal routine 807266423Sjfv * 808266423Sjfv * The detach entry point is called when the driver is being removed. 809266423Sjfv * This routine stops the adapter and deallocates all the resources 810266423Sjfv * that were allocated for driver operation. 811266423Sjfv * 812266423Sjfv * return 0 on success, positive on failure 813266423Sjfv *********************************************************************/ 814266423Sjfv 815266423Sjfvstatic int 816270346Sjfvixl_detach(device_t dev) 817266423Sjfv{ 818270346Sjfv struct ixl_pf *pf = device_get_softc(dev); 819266423Sjfv struct i40e_hw *hw = &pf->hw; 820270346Sjfv struct ixl_vsi *vsi = &pf->vsi; 821299553Serj enum i40e_status_code status; 822318357Serj#if defined(PCI_IOV) || defined(IXL_IW) 823279858Sjfv int error; 824279858Sjfv#endif 825266423Sjfv 826270346Sjfv INIT_DEBUGOUT("ixl_detach: begin"); 827266423Sjfv 828266423Sjfv /* Make sure VLANS are not using driver */ 829266423Sjfv if (vsi->ifp->if_vlantrunk != NULL) { 830299553Serj device_printf(dev, "Vlan in use, detach first\n"); 831266423Sjfv return (EBUSY); 832266423Sjfv } 833266423Sjfv 834279858Sjfv#ifdef PCI_IOV 835279858Sjfv error = pci_iov_detach(dev); 836279858Sjfv if (error != 0) { 837279858Sjfv device_printf(dev, "SR-IOV in use; detach first.\n"); 838279858Sjfv return (error); 839279858Sjfv } 840279858Sjfv#endif 841279858Sjfv 842333343Serj /* Remove all previously allocated media types */ 843333343Serj ifmedia_removeall(&vsi->media); 844333343Serj 845279033Sjfv ether_ifdetach(vsi->ifp); 846299547Serj if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) 847279033Sjfv ixl_stop(pf); 848266423Sjfv 849266423Sjfv /* Shutdown LAN HMC */ 850349163Serj if (hw->hmc.hmc_obj) { 851349163Serj status = i40e_shutdown_lan_hmc(hw); 852349163Serj if (status) 853349163Serj device_printf(dev, 854349163Serj "Shutdown LAN HMC failed with code %s\n", i40e_stat_str(hw, status)); 855349163Serj } 856266423Sjfv 857318357Serj /* Teardown LAN queue resources */ 858318357Serj ixl_teardown_queue_msix(vsi); 859318357Serj ixl_free_queue_tqs(vsi); 860349163Serj 861349163Serj /* Timer enqueues admin task. Stop it before freeing the admin taskqueue */ 862349163Serj callout_drain(&pf->timer); 863349163Serj 864266423Sjfv /* Shutdown admin queue */ 865318357Serj ixl_disable_intr0(hw); 866318357Serj ixl_teardown_adminq_msix(pf); 867349163Serj 868266423Sjfv status = i40e_shutdown_adminq(hw); 869266423Sjfv if (status) 870266423Sjfv device_printf(dev, 871266423Sjfv "Shutdown Admin queue failed with code %d\n", status); 872266423Sjfv 873349163Serj ixl_free_adminq_tq(pf); 874349163Serj 875266423Sjfv /* Unregister VLAN events */ 876266423Sjfv if (vsi->vlan_attach != NULL) 877266423Sjfv EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); 878266423Sjfv if (vsi->vlan_detach != NULL) 879266423Sjfv EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); 880266423Sjfv 881318357Serj#ifdef IXL_IW 882318357Serj if (ixl_enable_iwarp && pf->iw_enabled) { 883318357Serj error = ixl_iw_pf_detach(pf); 884318357Serj if (error == EBUSY) { 885318357Serj device_printf(dev, "iwarp in use; stop it first.\n"); 886318357Serj return (error); 887318357Serj } 888318357Serj } 889318357Serj#endif 890318357Serj 891279860Sjfv#ifdef DEV_NETMAP 892279860Sjfv netmap_detach(vsi->ifp); 893279860Sjfv#endif /* DEV_NETMAP */ 894303967Ssbruno ixl_pf_qmgr_destroy(&pf->qmgr); 895270346Sjfv ixl_free_pci_resources(pf); 896266423Sjfv bus_generic_detach(dev); 897266423Sjfv if_free(vsi->ifp); 898270346Sjfv ixl_free_vsi(vsi); 899270346Sjfv IXL_PF_LOCK_DESTROY(pf); 900266423Sjfv return (0); 901266423Sjfv} 902266423Sjfv 903266423Sjfv/********************************************************************* 904266423Sjfv * 905266423Sjfv * Shutdown entry point 906266423Sjfv * 907266423Sjfv **********************************************************************/ 908266423Sjfv 909266423Sjfvstatic int 910270346Sjfvixl_shutdown(device_t dev) 911266423Sjfv{ 912270346Sjfv struct ixl_pf *pf = device_get_softc(dev); 913270346Sjfv ixl_stop(pf); 914266423Sjfv return (0); 915266423Sjfv} 916266423Sjfv 917