Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixl/if_ixl.c
Show All 29 Lines | /****************************************************************************** | ||||
POSSIBILITY OF SUCH DAMAGE. | POSSIBILITY OF SUCH DAMAGE. | ||||
******************************************************************************/ | ******************************************************************************/ | ||||
/*$FreeBSD$*/ | /*$FreeBSD$*/ | ||||
#include "ixl.h" | #include "ixl.h" | ||||
#include "ixl_pf.h" | #include "ixl_pf.h" | ||||
#ifdef IXL_IW | |||||
#include "ixl_iw.h" | |||||
#include "ixl_iw_int.h" | |||||
#endif | |||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
#include "ixl_pf_iov.h" | #include "ixl_pf_iov.h" | ||||
#endif | #endif | ||||
/********************************************************************* | /********************************************************************* | ||||
* Driver version | * Driver version | ||||
*********************************************************************/ | *********************************************************************/ | ||||
char ixl_driver_version[] = "1.6.6-k"; | char ixl_driver_version[] = "1.7.12-k"; | ||||
/********************************************************************* | /********************************************************************* | ||||
* PCI Device ID Table | * PCI Device ID Table | ||||
* | * | ||||
* Used by probe to select devices to load on | * Used by probe to select devices to load on | ||||
* Last field stores an index into ixl_strings | * Last field stores an index into ixl_strings | ||||
* Last entry must be all 0s | * Last entry must be all 0s | ||||
* | * | ||||
Show All 11 Lines | static ixl_vendor_info_t ixl_vendor_info_array[] = | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0}, | {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0}, | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0}, | {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0}, | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0}, | {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0}, | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0}, | {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0}, | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0}, | {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0}, | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0}, | {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0}, | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0}, | {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0}, | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0}, | {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0}, | ||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, 0, 0, 0}, | |||||
{I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, 0, 0, 0}, | |||||
/* required last entry */ | /* required last entry */ | ||||
{0, 0, 0, 0, 0} | {0, 0, 0, 0, 0} | ||||
}; | }; | ||||
/********************************************************************* | /********************************************************************* | ||||
* Table of branding strings | * Table of branding strings | ||||
*********************************************************************/ | *********************************************************************/ | ||||
Show All 33 Lines | |||||
static driver_t ixl_driver = { | static driver_t ixl_driver = { | ||||
"ixl", ixl_methods, sizeof(struct ixl_pf), | "ixl", ixl_methods, sizeof(struct ixl_pf), | ||||
}; | }; | ||||
devclass_t ixl_devclass; | devclass_t ixl_devclass; | ||||
DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); | DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); | ||||
MODULE_VERSION(ixl, 1); | |||||
MODULE_DEPEND(ixl, pci, 1, 1, 1); | MODULE_DEPEND(ixl, pci, 1, 1, 1); | ||||
MODULE_DEPEND(ixl, ether, 1, 1, 1); | MODULE_DEPEND(ixl, ether, 1, 1, 1); | ||||
#ifdef DEV_NETMAP | #if defined(DEV_NETMAP) && __FreeBSD_version >= 1100000 | ||||
MODULE_DEPEND(ixl, netmap, 1, 1, 1); | MODULE_DEPEND(ixl, netmap, 1, 1, 1); | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
/* | /* | ||||
** TUNEABLE PARAMETERS: | ** TUNEABLE PARAMETERS: | ||||
*/ | */ | ||||
static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, | static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, | ||||
"IXL driver parameters"); | "IXL driver parameters"); | ||||
/* | /* | ||||
* MSIX should be the default for best performance, | * MSIX should be the default for best performance, | ||||
* but this allows it to be forced off for testing. | * but this allows it to be forced off for testing. | ||||
*/ | */ | ||||
static int ixl_enable_msix = 1; | static int ixl_enable_msix = 1; | ||||
TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); | TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); | ||||
SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, | SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, | ||||
"Enable MSI-X interrupts"); | "Enable MSI-X interrupts"); | ||||
/* | /* | ||||
** Number of descriptors per ring: | ** Number of descriptors per ring: | ||||
** - TX and RX are the same size | ** - TX and RX are the same size | ||||
*/ | */ | ||||
static int ixl_ring_size = DEFAULT_RING; | static int ixl_ring_size = IXL_DEFAULT_RING; | ||||
TUNABLE_INT("hw.ixl.ring_size", &ixl_ring_size); | TUNABLE_INT("hw.ixl.ring_size", &ixl_ring_size); | ||||
SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ixl, OID_AUTO, ring_size, CTLFLAG_RDTUN, | ||||
&ixl_ring_size, 0, "Descriptor Ring Size"); | &ixl_ring_size, 0, "Descriptor Ring Size"); | ||||
/* | /* | ||||
** This can be set manually, if left as 0 the | ** This can be set manually, if left as 0 the | ||||
** number of queues will be calculated based | ** number of queues will be calculated based | ||||
** on cpus and msix vectors available. | ** on cpus and msix vectors available. | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, | ||||
&ixl_rx_itr, 0, "RX Interrupt Rate"); | &ixl_rx_itr, 0, "RX Interrupt Rate"); | ||||
static int ixl_tx_itr = IXL_ITR_4K; | static int ixl_tx_itr = IXL_ITR_4K; | ||||
TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); | TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); | ||||
SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, | ||||
&ixl_tx_itr, 0, "TX Interrupt Rate"); | &ixl_tx_itr, 0, "TX Interrupt Rate"); | ||||
#ifdef IXL_IW | |||||
int ixl_enable_iwarp = 0; | |||||
TUNABLE_INT("hw.ixl.enable_iwarp", &ixl_enable_iwarp); | |||||
#endif | |||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
#define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ | #define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ | ||||
#include <dev/netmap/if_ixl_netmap.h> | #include <dev/netmap/if_ixl_netmap.h> | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
/********************************************************************* | /********************************************************************* | ||||
* Device identification routine | * Device identification routine | ||||
* | * | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
ixl_save_pf_tunables(struct ixl_pf *pf) | ixl_save_pf_tunables(struct ixl_pf *pf) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
/* Save tunable information */ | /* Save tunable information */ | ||||
pf->enable_msix = ixl_enable_msix; | pf->enable_msix = ixl_enable_msix; | ||||
pf->max_queues = ixl_max_queues; | pf->max_queues = ixl_max_queues; | ||||
pf->ringsz = ixl_ring_size; | |||||
pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; | pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; | ||||
pf->dynamic_rx_itr = ixl_dynamic_rx_itr; | pf->dynamic_rx_itr = ixl_dynamic_rx_itr; | ||||
pf->dynamic_tx_itr = ixl_dynamic_tx_itr; | pf->dynamic_tx_itr = ixl_dynamic_tx_itr; | ||||
pf->tx_itr = ixl_tx_itr; | |||||
pf->rx_itr = ixl_rx_itr; | |||||
pf->dbg_mask = ixl_core_debug_mask; | pf->dbg_mask = ixl_core_debug_mask; | ||||
pf->hw.debug_mask = ixl_shared_debug_mask; | pf->hw.debug_mask = ixl_shared_debug_mask; | ||||
if (ixl_ring_size < IXL_MIN_RING | if (ixl_ring_size < IXL_MIN_RING | ||||
|| ixl_ring_size > IXL_MAX_RING | || ixl_ring_size > IXL_MAX_RING | ||||
|| ixl_ring_size % IXL_RING_INCREMENT != 0) { | || ixl_ring_size % IXL_RING_INCREMENT != 0) { | ||||
device_printf(dev, "Invalid ring_size value of %d set!\n", | device_printf(dev, "Invalid ring_size value of %d set!\n", | ||||
ixl_ring_size); | ixl_ring_size); | ||||
device_printf(dev, "ring_size must be between %d and %d, " | device_printf(dev, "ring_size must be between %d and %d, " | ||||
"inclusive, and must be a multiple of %d\n", | "inclusive, and must be a multiple of %d\n", | ||||
IXL_MIN_RING, IXL_MAX_RING, IXL_RING_INCREMENT); | IXL_MIN_RING, IXL_MAX_RING, IXL_RING_INCREMENT); | ||||
return (EINVAL); | device_printf(dev, "Using default value of %d instead\n", | ||||
} | IXL_DEFAULT_RING); | ||||
pf->ringsz = IXL_DEFAULT_RING; | |||||
} else | |||||
pf->ringsz = ixl_ring_size; | |||||
if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) { | |||||
device_printf(dev, "Invalid tx_itr value of %d set!\n", | |||||
ixl_tx_itr); | |||||
device_printf(dev, "tx_itr must be between %d and %d, " | |||||
"inclusive\n", | |||||
0, IXL_MAX_ITR); | |||||
device_printf(dev, "Using default value of %d instead\n", | |||||
IXL_ITR_4K); | |||||
pf->tx_itr = IXL_ITR_4K; | |||||
} else | |||||
pf->tx_itr = ixl_tx_itr; | |||||
if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) { | |||||
device_printf(dev, "Invalid rx_itr value of %d set!\n", | |||||
ixl_rx_itr); | |||||
device_printf(dev, "rx_itr must be between %d and %d, " | |||||
"inclusive\n", | |||||
0, IXL_MAX_ITR); | |||||
device_printf(dev, "Using default value of %d instead\n", | |||||
IXL_ITR_8K); | |||||
pf->rx_itr = IXL_ITR_8K; | |||||
} else | |||||
pf->rx_itr = ixl_rx_itr; | |||||
return (0); | return (0); | ||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* Device initialization routine | * Device initialization routine | ||||
* | * | ||||
* The attach entry point is called when the driver is being loaded. | * The attach entry point is called when the driver is being loaded. | ||||
* This routine identifies the type of hardware, allocates all resources | * This routine identifies the type of hardware, allocates all resources | ||||
▲ Show 20 Lines • Show All 197 Lines • ▼ Show 20 Lines | status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, | ||||
if (status) { | if (status) { | ||||
device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s," | device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s," | ||||
" aq_err %s\n", i40e_stat_str(hw, status), | " aq_err %s\n", i40e_stat_str(hw, status), | ||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | i40e_aq_str(hw, hw->aq.asq_last_status)); | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
/* Get the bus configuration and set the shared code's config */ | /* Get the bus configuration and set the shared code's config */ | ||||
ixl_get_bus_info(hw, dev); | ixl_get_bus_info(pf); | ||||
/* | /* | ||||
* In MSI-X mode, initialize the Admin Queue interrupt, | * In MSI-X mode, initialize the Admin Queue interrupt, | ||||
* so userland tools can communicate with the adapter regardless of | * so userland tools can communicate with the adapter regardless of | ||||
* the ifnet interface's status. | * the ifnet interface's status. | ||||
*/ | */ | ||||
if (pf->msix > 1) { | if (pf->msix > 1) { | ||||
error = ixl_setup_adminq_msix(pf); | error = ixl_setup_adminq_msix(pf); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixl_setup_adminq_msix error: %d\n", | device_printf(dev, "ixl_setup_adminq_msix() error: %d\n", | ||||
error); | error); | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
error = ixl_setup_adminq_tq(pf); | error = ixl_setup_adminq_tq(pf); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixl_setup_adminq_tq error: %d\n", | device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", | ||||
error); | error); | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
ixl_configure_intr0_msix(pf); | ixl_configure_intr0_msix(pf); | ||||
ixl_enable_adminq(hw); | ixl_enable_intr0(hw); | ||||
error = ixl_setup_queue_msix(vsi); | |||||
if (error) | |||||
device_printf(dev, "ixl_setup_queue_msix() error: %d\n", | |||||
error); | |||||
error = ixl_setup_queue_tqs(vsi); | |||||
if (error) | |||||
device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", | |||||
error); | |||||
} else { | |||||
error = ixl_setup_legacy(pf); | |||||
error = ixl_setup_adminq_tq(pf); | |||||
if (error) { | |||||
device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", | |||||
error); | |||||
goto err_late; | |||||
} | } | ||||
error = ixl_setup_queue_tqs(vsi); | |||||
if (error) | |||||
device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", | |||||
error); | |||||
} | |||||
if (error) { | |||||
device_printf(dev, "interrupt setup error: %d\n", error); | |||||
} | |||||
/* Set initial advertised speed sysctl value */ | |||||
ixl_get_initial_advertised_speeds(pf); | |||||
/* Initialize statistics & add sysctls */ | /* Initialize statistics & add sysctls */ | ||||
ixl_add_device_sysctls(pf); | ixl_add_device_sysctls(pf); | ||||
ixl_pf_reset_stats(pf); | ixl_pf_reset_stats(pf); | ||||
ixl_update_stats_counters(pf); | ixl_update_stats_counters(pf); | ||||
ixl_add_hw_stats(pf); | ixl_add_hw_stats(pf); | ||||
/* Register for VLAN events */ | /* Register for VLAN events */ | ||||
vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | ||||
ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); | ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); | ||||
vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | ||||
ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); | ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
ixl_initialize_sriov(pf); | ixl_initialize_sriov(pf); | ||||
#endif | #endif | ||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
ixl_netmap_attach(vsi); | ixl_netmap_attach(vsi); | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
#ifdef IXL_IW | |||||
if (hw->func_caps.iwarp && ixl_enable_iwarp) { | |||||
pf->iw_enabled = (pf->iw_msix > 0) ? true : false; | |||||
if (pf->iw_enabled) { | |||||
error = ixl_iw_pf_attach(pf); | |||||
if (error) { | |||||
device_printf(dev, | |||||
"interfacing to iwarp driver failed: %d\n", | |||||
error); | |||||
goto err_late; | |||||
} | |||||
} else | |||||
device_printf(dev, | |||||
"iwarp disabled on this device (no msix vectors)\n"); | |||||
} else { | |||||
pf->iw_enabled = false; | |||||
device_printf(dev, "The device is not iWARP enabled\n"); | |||||
} | |||||
#endif | |||||
INIT_DEBUGOUT("ixl_attach: end"); | INIT_DEBUGOUT("ixl_attach: end"); | ||||
return (0); | return (0); | ||||
err_late: | err_late: | ||||
if (vsi->ifp != NULL) { | if (vsi->ifp != NULL) { | ||||
ether_ifdetach(vsi->ifp); | ether_ifdetach(vsi->ifp); | ||||
if_free(vsi->ifp); | if_free(vsi->ifp); | ||||
} | } | ||||
Show All 20 Lines | |||||
static int | static int | ||||
ixl_detach(device_t dev) | ixl_detach(device_t dev) | ||||
{ | { | ||||
struct ixl_pf *pf = device_get_softc(dev); | struct ixl_pf *pf = device_get_softc(dev); | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
enum i40e_status_code status; | enum i40e_status_code status; | ||||
#ifdef PCI_IOV | #if defined(PCI_IOV) || defined(IXL_IW) | ||||
int error; | int error; | ||||
#endif | #endif | ||||
INIT_DEBUGOUT("ixl_detach: begin"); | INIT_DEBUGOUT("ixl_detach: begin"); | ||||
/* Make sure VLANS are not using driver */ | /* Make sure VLANS are not using driver */ | ||||
if (vsi->ifp->if_vlantrunk != NULL) { | if (vsi->ifp->if_vlantrunk != NULL) { | ||||
device_printf(dev, "Vlan in use, detach first\n"); | device_printf(dev, "Vlan in use, detach first\n"); | ||||
return (EBUSY); | return (EBUSY); | ||||
} | } | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
error = pci_iov_detach(dev); | error = pci_iov_detach(dev); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(dev, "SR-IOV in use; detach first.\n"); | device_printf(dev, "SR-IOV in use; detach first.\n"); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif | #endif | ||||
ether_ifdetach(vsi->ifp); | ether_ifdetach(vsi->ifp); | ||||
if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) | if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) | ||||
ixl_stop(pf); | ixl_stop(pf); | ||||
ixl_free_queue_tqs(vsi); | |||||
/* Shutdown LAN HMC */ | /* Shutdown LAN HMC */ | ||||
status = i40e_shutdown_lan_hmc(hw); | status = i40e_shutdown_lan_hmc(hw); | ||||
if (status) | if (status) | ||||
device_printf(dev, | device_printf(dev, | ||||
"Shutdown LAN HMC failed with code %d\n", status); | "Shutdown LAN HMC failed with code %d\n", status); | ||||
/* Teardown LAN queue resources */ | |||||
ixl_teardown_queue_msix(vsi); | |||||
ixl_free_queue_tqs(vsi); | |||||
/* Shutdown admin queue */ | /* Shutdown admin queue */ | ||||
ixl_disable_adminq(hw); | ixl_disable_intr0(hw); | ||||
ixl_free_adminq_tq(pf); | |||||
ixl_teardown_adminq_msix(pf); | ixl_teardown_adminq_msix(pf); | ||||
ixl_free_adminq_tq(pf); | |||||
status = i40e_shutdown_adminq(hw); | status = i40e_shutdown_adminq(hw); | ||||
if (status) | if (status) | ||||
device_printf(dev, | device_printf(dev, | ||||
"Shutdown Admin queue failed with code %d\n", status); | "Shutdown Admin queue failed with code %d\n", status); | ||||
/* Unregister VLAN events */ | /* Unregister VLAN events */ | ||||
if (vsi->vlan_attach != NULL) | if (vsi->vlan_attach != NULL) | ||||
EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); | EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); | ||||
if (vsi->vlan_detach != NULL) | if (vsi->vlan_detach != NULL) | ||||
EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); | EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); | ||||
callout_drain(&pf->timer); | callout_drain(&pf->timer); | ||||
#ifdef IXL_IW | |||||
if (ixl_enable_iwarp && pf->iw_enabled) { | |||||
error = ixl_iw_pf_detach(pf); | |||||
if (error == EBUSY) { | |||||
device_printf(dev, "iwarp in use; stop it first.\n"); | |||||
return (error); | |||||
} | |||||
} | |||||
#endif | |||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
netmap_detach(vsi->ifp); | netmap_detach(vsi->ifp); | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
ixl_pf_qmgr_destroy(&pf->qmgr); | ixl_pf_qmgr_destroy(&pf->qmgr); | ||||
ixl_free_pci_resources(pf); | ixl_free_pci_resources(pf); | ||||
bus_generic_detach(dev); | bus_generic_detach(dev); | ||||
if_free(vsi->ifp); | if_free(vsi->ifp); | ||||
ixl_free_vsi(vsi); | ixl_free_vsi(vsi); | ||||
Show All 18 Lines |