Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixl/if_ixl.c
Show First 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
#include "ixl_pf_iov.h" | #include "ixl_pf_iov.h" | ||||
#endif | #endif | ||||
/********************************************************************* | /********************************************************************* | ||||
* Driver version | * Driver version | ||||
*********************************************************************/ | *********************************************************************/ | ||||
#define IXL_DRIVER_VERSION_MAJOR 2 | #define IXL_DRIVER_VERSION_MAJOR 2 | ||||
#define IXL_DRIVER_VERSION_MINOR 1 | #define IXL_DRIVER_VERSION_MINOR 2 | ||||
#define IXL_DRIVER_VERSION_BUILD 0 | #define IXL_DRIVER_VERSION_BUILD 0 | ||||
#define IXL_DRIVER_VERSION_STRING \ | #define IXL_DRIVER_VERSION_STRING \ | ||||
__XSTRING(IXL_DRIVER_VERSION_MAJOR) "." \ | __XSTRING(IXL_DRIVER_VERSION_MAJOR) "." \ | ||||
__XSTRING(IXL_DRIVER_VERSION_MINOR) "." \ | __XSTRING(IXL_DRIVER_VERSION_MINOR) "." \ | ||||
__XSTRING(IXL_DRIVER_VERSION_BUILD) "-k" | __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k" | ||||
/********************************************************************* | /********************************************************************* | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
static void ixl_if_vflr_handle(if_ctx_t ctx); | static void ixl_if_vflr_handle(if_ctx_t ctx); | ||||
#endif | #endif | ||||
/*** Other ***/ | /*** Other ***/ | ||||
static u_int ixl_mc_filter_apply(void *, struct sockaddr_dl *, u_int); | static u_int ixl_mc_filter_apply(void *, struct sockaddr_dl *, u_int); | ||||
static void ixl_save_pf_tunables(struct ixl_pf *); | static void ixl_save_pf_tunables(struct ixl_pf *); | ||||
static int ixl_allocate_pci_resources(struct ixl_pf *); | static int ixl_allocate_pci_resources(struct ixl_pf *); | ||||
static void ixl_setup_ssctx(struct ixl_pf *pf); | |||||
static void ixl_admin_timer(void *arg); | |||||
/********************************************************************* | /********************************************************************* | ||||
* FreeBSD Device Interface Entry Points | * FreeBSD Device Interface Entry Points | ||||
*********************************************************************/ | *********************************************************************/ | ||||
static device_method_t ixl_methods[] = { | static device_method_t ixl_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_register, ixl_register), | DEVMETHOD(device_register, ixl_register), | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
** TUNEABLE PARAMETERS: | ** TUNEABLE PARAMETERS: | ||||
*/ | */ | ||||
static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, | static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, | ||||
"ixl driver parameters"); | "ixl driver parameters"); | ||||
#ifdef IXL_DEBUG_FC | |||||
/* | /* | ||||
* Leave this on unless you need to send flow control | * Leave this on unless you need to send flow control | ||||
* frames (or other control frames) from software | * frames (or other control frames) from software | ||||
*/ | */ | ||||
static int ixl_enable_tx_fc_filter = 1; | static int ixl_enable_tx_fc_filter = 1; | ||||
TUNABLE_INT("hw.ixl.enable_tx_fc_filter", | TUNABLE_INT("hw.ixl.enable_tx_fc_filter", | ||||
&ixl_enable_tx_fc_filter); | &ixl_enable_tx_fc_filter); | ||||
SYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN, | ||||
&ixl_enable_tx_fc_filter, 0, | &ixl_enable_tx_fc_filter, 0, | ||||
"Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources"); | "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources"); | ||||
#endif | |||||
#ifdef IXL_DEBUG | |||||
static int ixl_debug_recovery_mode = 0; | |||||
TUNABLE_INT("hw.ixl.debug_recovery_mode", | |||||
&ixl_debug_recovery_mode); | |||||
SYSCTL_INT(_hw_ixl, OID_AUTO, debug_recovery_mode, CTLFLAG_RDTUN, | |||||
&ixl_debug_recovery_mode, 0, | |||||
"Act like when FW entered recovery mode (for debuging)"); | |||||
#endif | |||||
static int ixl_i2c_access_method = 0; | static int ixl_i2c_access_method = 0; | ||||
TUNABLE_INT("hw.ixl.i2c_access_method", | TUNABLE_INT("hw.ixl.i2c_access_method", | ||||
&ixl_i2c_access_method); | &ixl_i2c_access_method); | ||||
SYSCTL_INT(_hw_ixl, OID_AUTO, i2c_access_method, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ixl, OID_AUTO, i2c_access_method, CTLFLAG_RDTUN, | ||||
&ixl_i2c_access_method, 0, | &ixl_i2c_access_method, 0, | ||||
IXL_SYSCTL_HELP_I2C_METHOD); | IXL_SYSCTL_HELP_I2C_METHOD); | ||||
static int ixl_enable_vf_loopback = 1; | static int ixl_enable_vf_loopback = 1; | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | ixl_allocate_pci_resources(struct ixl_pf *pf) | ||||
device_t dev = iflib_get_dev(pf->vsi.ctx); | device_t dev = iflib_get_dev(pf->vsi.ctx); | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
int rid; | int rid; | ||||
/* Map BAR0 */ | /* Map BAR0 */ | ||||
rid = PCIR_BAR(0); | rid = PCIR_BAR(0); | ||||
pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | ||||
&rid, RF_ACTIVE); | &rid, RF_ACTIVE); | ||||
if (!(pf->pci_mem)) { | if (!(pf->pci_mem)) { | ||||
device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); | device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* Save off the PCI information */ | /* Save off the PCI information */ | ||||
hw->vendor_id = pci_get_vendor(dev); | hw->vendor_id = pci_get_vendor(dev); | ||||
hw->device_id = pci_get_device(dev); | hw->device_id = pci_get_device(dev); | ||||
Show All 12 Lines | ixl_allocate_pci_resources(struct ixl_pf *pf) | ||||
pf->osdep.mem_bus_space_handle = | pf->osdep.mem_bus_space_handle = | ||||
rman_get_bushandle(pf->pci_mem); | rman_get_bushandle(pf->pci_mem); | ||||
pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); | pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); | ||||
pf->osdep.flush_reg = I40E_GLGEN_STAT; | pf->osdep.flush_reg = I40E_GLGEN_STAT; | ||||
pf->osdep.dev = dev; | pf->osdep.dev = dev; | ||||
pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; | pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; | ||||
pf->hw.back = &pf->osdep; | pf->hw.back = &pf->osdep; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | |||||
ixl_setup_ssctx(struct ixl_pf *pf) | |||||
{ | |||||
if_softc_ctx_t scctx = pf->vsi.shared; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
if (IXL_PF_IN_RECOVERY_MODE(pf)) { | |||||
scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 1; | |||||
scctx->isc_ntxqsets = scctx->isc_nrxqsets = 1; | |||||
} else if (hw->mac.type == I40E_MAC_X722) | |||||
scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 128; | |||||
else | |||||
scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 64; | |||||
if (pf->vsi.enable_head_writeback) { | |||||
scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] | |||||
* sizeof(struct i40e_tx_desc) + sizeof(u32), DBA_ALIGN); | |||||
scctx->isc_txrx = &ixl_txrx_hwb; | |||||
} else { | |||||
scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] | |||||
* sizeof(struct i40e_tx_desc), DBA_ALIGN); | |||||
scctx->isc_txrx = &ixl_txrx_dwb; | |||||
} | |||||
scctx->isc_txrx->ift_legacy_intr = ixl_intr; | |||||
scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] | |||||
* sizeof(union i40e_32byte_rx_desc), DBA_ALIGN); | |||||
scctx->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR); | |||||
scctx->isc_tx_nsegments = IXL_MAX_TX_SEGS; | |||||
scctx->isc_tx_tso_segments_max = IXL_MAX_TSO_SEGS; | |||||
scctx->isc_tx_tso_size_max = IXL_TSO_SIZE; | |||||
scctx->isc_tx_tso_segsize_max = IXL_MAX_DMA_SEG_SIZE; | |||||
scctx->isc_rss_table_size = pf->hw.func_caps.rss_table_size; | |||||
scctx->isc_tx_csum_flags = CSUM_OFFLOAD; | |||||
scctx->isc_capabilities = scctx->isc_capenable = IXL_CAPS; | |||||
} | |||||
static void | |||||
ixl_admin_timer(void *arg) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg; | |||||
/* Fire off the admin task */ | |||||
iflib_admin_intr_deferred(pf->vsi.ctx); | |||||
/* Reschedule the admin timer */ | |||||
callout_schedule(&pf->admin_timer, hz/2); | |||||
} | |||||
static int | static int | ||||
ixl_attach_pre_recovery_mode(struct ixl_pf *pf) | |||||
{ | |||||
struct ixl_vsi *vsi = &pf->vsi; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
device_t dev = pf->dev; | |||||
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"); | |||||
i40e_get_mac_addr(hw, hw->mac.addr); | |||||
if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { | |||||
ixl_configure_intr0_msix(pf); | |||||
ixl_enable_intr0(hw); | |||||
} | |||||
ixl_setup_ssctx(pf); | |||||
return (0); | |||||
} | |||||
static int | |||||
ixl_if_attach_pre(if_ctx_t ctx) | ixl_if_attach_pre(if_ctx_t ctx) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
struct ixl_pf *pf; | struct ixl_pf *pf; | ||||
struct i40e_hw *hw; | struct i40e_hw *hw; | ||||
struct ixl_vsi *vsi; | struct ixl_vsi *vsi; | ||||
if_softc_ctx_t scctx; | enum i40e_get_fw_lldp_status_resp lldp_status; | ||||
struct i40e_filter_control_settings filter; | struct i40e_filter_control_settings filter; | ||||
enum i40e_status_code status; | enum i40e_status_code status; | ||||
int error = 0; | int error = 0; | ||||
dev = iflib_get_dev(ctx); | dev = iflib_get_dev(ctx); | ||||
pf = iflib_get_softc(ctx); | pf = iflib_get_softc(ctx); | ||||
INIT_DBG_DEV(dev, "begin"); | INIT_DBG_DEV(dev, "begin"); | ||||
vsi = &pf->vsi; | vsi = &pf->vsi; | ||||
vsi->back = pf; | vsi->back = pf; | ||||
pf->dev = dev; | pf->dev = dev; | ||||
hw = &pf->hw; | hw = &pf->hw; | ||||
vsi->dev = dev; | vsi->dev = dev; | ||||
vsi->hw = &pf->hw; | vsi->hw = &pf->hw; | ||||
vsi->id = 0; | vsi->id = 0; | ||||
vsi->num_vlans = 0; | vsi->num_vlans = 0; | ||||
vsi->ctx = ctx; | vsi->ctx = ctx; | ||||
vsi->media = iflib_get_media(ctx); | vsi->media = iflib_get_media(ctx); | ||||
vsi->shared = scctx = iflib_get_softc_ctx(ctx); | vsi->shared = iflib_get_softc_ctx(ctx); | ||||
snprintf(pf->admin_mtx_name, sizeof(pf->admin_mtx_name), | |||||
"%s:admin", device_get_nameunit(dev)); | |||||
mtx_init(&pf->admin_mtx, pf->admin_mtx_name, NULL, MTX_DEF); | |||||
callout_init_mtx(&pf->admin_timer, &pf->admin_mtx, 0); | |||||
/* Save tunable values */ | /* Save tunable values */ | ||||
ixl_save_pf_tunables(pf); | ixl_save_pf_tunables(pf); | ||||
/* Do PCI setup - map BAR0, etc */ | /* Do PCI setup - map BAR0, etc */ | ||||
if (ixl_allocate_pci_resources(pf)) { | if (ixl_allocate_pci_resources(pf)) { | ||||
device_printf(dev, "Allocation of PCI resources failed\n"); | device_printf(dev, "Allocation of PCI resources failed\n"); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto err_pci_res; | goto err_pci_res; | ||||
} | } | ||||
/* Establish a clean starting point */ | /* Establish a clean starting point */ | ||||
i40e_clear_hw(hw); | i40e_clear_hw(hw); | ||||
status = i40e_pf_reset(hw); | i40e_set_mac_type(hw); | ||||
if (status) { | |||||
device_printf(dev, "PF reset failure %s\n", | error = ixl_pf_reset(pf); | ||||
i40e_stat_str(hw, status)); | if (error) | ||||
error = EIO; | |||||
goto err_out; | goto err_out; | ||||
} | |||||
/* Initialize the shared code */ | /* Initialize the shared code */ | ||||
status = i40e_init_shared_code(hw); | status = i40e_init_shared_code(hw); | ||||
if (status) { | if (status) { | ||||
device_printf(dev, "Unable to initialize shared code, error %s\n", | device_printf(dev, "Unable to initialize shared code, error %s\n", | ||||
i40e_stat_str(hw, status)); | i40e_stat_str(hw, status)); | ||||
error = EIO; | error = EIO; | ||||
goto err_out; | goto err_out; | ||||
Show All 30 Lines | if (status == I40E_ERR_FIRMWARE_API_VERSION) { | ||||
device_printf(dev, "Please install the most recent version " | device_printf(dev, "Please install the most recent version " | ||||
"of the network driver.\n"); | "of the network driver.\n"); | ||||
} else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4) { | } else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4) { | ||||
device_printf(dev, "The driver for the device detected " | device_printf(dev, "The driver for the device detected " | ||||
"an older version of the NVM image than expected.\n"); | "an older version of the NVM image than expected.\n"); | ||||
device_printf(dev, "Please update the NVM image.\n"); | device_printf(dev, "Please update the NVM image.\n"); | ||||
} | } | ||||
if (IXL_PF_IN_RECOVERY_MODE(pf)) { | |||||
error = ixl_attach_pre_recovery_mode(pf); | |||||
if (error) | |||||
goto err_out; | |||||
return (error); | |||||
} | |||||
/* Clear PXE mode */ | /* Clear PXE mode */ | ||||
i40e_clear_pxe_mode(hw); | i40e_clear_pxe_mode(hw); | ||||
/* Get capabilities from the device */ | /* Get capabilities from the device */ | ||||
error = ixl_get_hw_capabilities(pf); | error = ixl_get_hw_capabilities(pf); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "get_hw_capabilities failed: %d\n", | device_printf(dev, "get_hw_capabilities failed: %d\n", | ||||
error); | error); | ||||
goto err_get_cap; | goto err_get_cap; | ||||
} | } | ||||
/* Set up host memory cache */ | /* Set up host memory cache */ | ||||
status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, | error = ixl_setup_hmc(pf); | ||||
hw->func_caps.num_rx_qp, 0, 0); | if (error) | ||||
if (status) { | |||||
device_printf(dev, "init_lan_hmc failed: %s\n", | |||||
i40e_stat_str(hw, status)); | |||||
goto err_get_cap; | |||||
} | |||||
status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); | |||||
if (status) { | |||||
device_printf(dev, "configure_lan_hmc failed: %s\n", | |||||
i40e_stat_str(hw, status)); | |||||
goto err_mac_hmc; | goto err_mac_hmc; | ||||
} | |||||
/* Disable LLDP from the firmware for certain NVM versions */ | /* Disable LLDP from the firmware for certain NVM versions */ | ||||
if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || | if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || | ||||
(pf->hw.aq.fw_maj_ver < 4)) { | (pf->hw.aq.fw_maj_ver < 4)) { | ||||
i40e_aq_stop_lldp(hw, TRUE, NULL); | i40e_aq_stop_lldp(hw, true, false, NULL); | ||||
pf->state |= IXL_PF_STATE_FW_LLDP_DISABLED; | pf->state |= IXL_PF_STATE_FW_LLDP_DISABLED; | ||||
} | } | ||||
/* Get MAC addresses from hardware */ | /* Get MAC addresses from hardware */ | ||||
i40e_get_mac_addr(hw, hw->mac.addr); | i40e_get_mac_addr(hw, hw->mac.addr); | ||||
error = i40e_validate_mac_addr(hw->mac.addr); | error = i40e_validate_mac_addr(hw->mac.addr); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "validate_mac_addr failed: %d\n", error); | device_printf(dev, "validate_mac_addr failed: %d\n", error); | ||||
goto err_mac_hmc; | goto err_mac_hmc; | ||||
} | } | ||||
bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); | bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); | ||||
iflib_set_mac(ctx, hw->mac.addr); | iflib_set_mac(ctx, hw->mac.addr); | ||||
i40e_get_port_mac_addr(hw, hw->mac.port_addr); | i40e_get_port_mac_addr(hw, hw->mac.port_addr); | ||||
/* Set up the device filtering */ | /* Set up the device filtering */ | ||||
bzero(&filter, sizeof(filter)); | bzero(&filter, sizeof(filter)); | ||||
filter.enable_ethtype = TRUE; | filter.enable_ethtype = TRUE; | ||||
filter.enable_macvlan = TRUE; | filter.enable_macvlan = TRUE; | ||||
filter.enable_fdir = FALSE; | filter.enable_fdir = FALSE; | ||||
filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; | filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; | ||||
if (i40e_set_filter_control(hw, &filter)) | if (i40e_set_filter_control(hw, &filter)) | ||||
device_printf(dev, "i40e_set_filter_control() failed\n"); | device_printf(dev, "i40e_set_filter_control() failed\n"); | ||||
/* Query device FW LLDP status */ | /* Query device FW LLDP status */ | ||||
ixl_get_fw_lldp_status(pf); | if (i40e_get_fw_lldp_status(hw, &lldp_status) == I40E_SUCCESS) { | ||||
if (lldp_status == I40E_GET_FW_LLDP_STATUS_DISABLED) { | |||||
atomic_set_32(&pf->state, | |||||
IXL_PF_STATE_FW_LLDP_DISABLED); | |||||
} else { | |||||
atomic_clear_32(&pf->state, | |||||
IXL_PF_STATE_FW_LLDP_DISABLED); | |||||
} | |||||
} | |||||
/* Tell FW to apply DCB config on link up */ | /* Tell FW to apply DCB config on link up */ | ||||
i40e_aq_set_dcb_parameters(hw, true, NULL); | i40e_aq_set_dcb_parameters(hw, true, NULL); | ||||
/* Fill out iflib parameters */ | /* Fill out iflib parameters */ | ||||
if (hw->mac.type == I40E_MAC_X722) | ixl_setup_ssctx(pf); | ||||
scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 128; | |||||
else | |||||
scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 64; | |||||
if (vsi->enable_head_writeback) { | |||||
scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] | |||||
* sizeof(struct i40e_tx_desc) + sizeof(u32), DBA_ALIGN); | |||||
scctx->isc_txrx = &ixl_txrx_hwb; | |||||
} else { | |||||
scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] | |||||
* sizeof(struct i40e_tx_desc), DBA_ALIGN); | |||||
scctx->isc_txrx = &ixl_txrx_dwb; | |||||
} | |||||
scctx->isc_txrx->ift_legacy_intr = ixl_intr; | |||||
scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] | |||||
* sizeof(union i40e_32byte_rx_desc), DBA_ALIGN); | |||||
scctx->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR); | |||||
scctx->isc_tx_nsegments = IXL_MAX_TX_SEGS; | |||||
scctx->isc_tx_tso_segments_max = IXL_MAX_TSO_SEGS; | |||||
scctx->isc_tx_tso_size_max = IXL_TSO_SIZE; | |||||
scctx->isc_tx_tso_segsize_max = IXL_MAX_DMA_SEG_SIZE; | |||||
scctx->isc_rss_table_size = pf->hw.func_caps.rss_table_size; | |||||
scctx->isc_tx_csum_flags = CSUM_OFFLOAD; | |||||
scctx->isc_capabilities = scctx->isc_capenable = IXL_CAPS; | |||||
INIT_DBG_DEV(dev, "end"); | INIT_DBG_DEV(dev, "end"); | ||||
return (0); | return (0); | ||||
err_mac_hmc: | err_mac_hmc: | ||||
i40e_shutdown_lan_hmc(hw); | ixl_shutdown_hmc(pf); | ||||
err_get_cap: | err_get_cap: | ||||
i40e_shutdown_adminq(hw); | i40e_shutdown_adminq(hw); | ||||
err_out: | err_out: | ||||
ixl_free_pci_resources(pf); | ixl_free_pci_resources(pf); | ||||
err_pci_res: | err_pci_res: | ||||
mtx_lock(&pf->admin_mtx); | |||||
callout_stop(&pf->admin_timer); | |||||
mtx_unlock(&pf->admin_mtx); | |||||
mtx_destroy(&pf->admin_mtx); | |||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
ixl_if_attach_post(if_ctx_t ctx) | ixl_if_attach_post(if_ctx_t ctx) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
struct ixl_pf *pf; | struct ixl_pf *pf; | ||||
Show All 17 Lines | ixl_if_attach_post(if_ctx_t ctx) | ||||
/* Setup OS network interface / ifnet */ | /* Setup OS network interface / ifnet */ | ||||
if (ixl_setup_interface(dev, pf)) { | if (ixl_setup_interface(dev, pf)) { | ||||
device_printf(dev, "interface setup failed!\n"); | device_printf(dev, "interface setup failed!\n"); | ||||
error = EIO; | error = EIO; | ||||
goto err; | goto err; | ||||
} | } | ||||
if (IXL_PF_IN_RECOVERY_MODE(pf)) { | |||||
/* Keep admin queue interrupts active while driver is loaded */ | |||||
if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { | |||||
ixl_configure_intr0_msix(pf); | |||||
ixl_enable_intr0(hw); | |||||
} | |||||
ixl_add_sysctls_recovery_mode(pf); | |||||
/* Start the admin timer */ | |||||
mtx_lock(&pf->admin_mtx); | |||||
callout_reset(&pf->admin_timer, hz/2, ixl_admin_timer, pf); | |||||
mtx_unlock(&pf->admin_mtx); | |||||
return (0); | |||||
} | |||||
/* Determine link state */ | /* Determine link state */ | ||||
if (ixl_attach_get_link_status(pf)) { | if (ixl_attach_get_link_status(pf)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto err; | goto err; | ||||
} | } | ||||
error = ixl_switch_config(pf); | error = ixl_switch_config(pf); | ||||
if (error) { | if (error) { | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | if (hw->func_caps.iwarp && ixl_enable_iwarp) { | ||||
} else | } else | ||||
device_printf(dev, "iWARP disabled on this device " | device_printf(dev, "iWARP disabled on this device " | ||||
"(no MSI-X vectors)\n"); | "(no MSI-X vectors)\n"); | ||||
} else { | } else { | ||||
pf->iw_enabled = false; | pf->iw_enabled = false; | ||||
device_printf(dev, "The device is not iWARP enabled\n"); | device_printf(dev, "The device is not iWARP enabled\n"); | ||||
} | } | ||||
#endif | #endif | ||||
/* Start the admin timer */ | |||||
mtx_lock(&pf->admin_mtx); | |||||
callout_reset(&pf->admin_timer, hz/2, ixl_admin_timer, pf); | |||||
mtx_unlock(&pf->admin_mtx); | |||||
INIT_DBG_DEV(dev, "end"); | INIT_DBG_DEV(dev, "end"); | ||||
return (0); | return (0); | ||||
err: | err: | ||||
INIT_DEBUGOUT("end: error %d", error); | INIT_DEBUGOUT("end: error %d", error); | ||||
/* ixl_if_detach() is called on error from this */ | /* ixl_if_detach() is called on error from this */ | ||||
return (error); | return (error); | ||||
Show All 12 Lines | ixl_if_detach(if_ctx_t ctx) | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
enum i40e_status_code status; | enum i40e_status_code status; | ||||
#ifdef IXL_IW | #ifdef IXL_IW | ||||
int error; | int error; | ||||
#endif | #endif | ||||
INIT_DBG_DEV(dev, "begin"); | INIT_DBG_DEV(dev, "begin"); | ||||
/* Stop the admin timer */ | |||||
mtx_lock(&pf->admin_mtx); | |||||
callout_stop(&pf->admin_timer); | |||||
mtx_unlock(&pf->admin_mtx); | |||||
mtx_destroy(&pf->admin_mtx); | |||||
#ifdef IXL_IW | #ifdef IXL_IW | ||||
if (ixl_enable_iwarp && pf->iw_enabled) { | if (ixl_enable_iwarp && pf->iw_enabled) { | ||||
error = ixl_iw_pf_detach(pf); | error = ixl_iw_pf_detach(pf); | ||||
if (error == EBUSY) { | if (error == EBUSY) { | ||||
device_printf(dev, "iwarp in use; stop it first.\n"); | device_printf(dev, "iwarp in use; stop it first.\n"); | ||||
//return (error); | //return (error); | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
/* Remove all previously allocated media types */ | /* Remove all previously allocated media types */ | ||||
ifmedia_removeall(vsi->media); | ifmedia_removeall(vsi->media); | ||||
/* Shutdown LAN HMC */ | /* Shutdown LAN HMC */ | ||||
if (hw->hmc.hmc_obj) { | ixl_shutdown_hmc(pf); | ||||
status = i40e_shutdown_lan_hmc(hw); | |||||
if (status) | |||||
device_printf(dev, | |||||
"i40e_shutdown_lan_hmc() failed with status %s\n", | |||||
i40e_stat_str(hw, status)); | |||||
} | |||||
/* Shutdown admin queue */ | /* Shutdown admin queue */ | ||||
ixl_disable_intr0(hw); | ixl_disable_intr0(hw); | ||||
status = i40e_shutdown_adminq(hw); | status = i40e_shutdown_adminq(hw); | ||||
if (status) | if (status) | ||||
device_printf(dev, | device_printf(dev, | ||||
"i40e_shutdown_adminq() failed with status %s\n", | "i40e_shutdown_adminq() failed with status %s\n", | ||||
i40e_stat_str(hw, status)); | i40e_stat_str(hw, status)); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | ixl_if_init(if_ctx_t ctx) | ||||
struct ixl_pf *pf = iflib_get_softc(ctx); | struct ixl_pf *pf = iflib_get_softc(ctx); | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct ifnet *ifp = iflib_get_ifp(ctx); | struct ifnet *ifp = iflib_get_ifp(ctx); | ||||
device_t dev = iflib_get_dev(ctx); | device_t dev = iflib_get_dev(ctx); | ||||
u8 tmpaddr[ETHER_ADDR_LEN]; | u8 tmpaddr[ETHER_ADDR_LEN]; | ||||
int ret; | int ret; | ||||
if (IXL_PF_IN_RECOVERY_MODE(pf)) | |||||
return; | |||||
/* | /* | ||||
* If the aq is dead here, it probably means something outside of the driver | * If the aq is dead here, it probably means something outside of the driver | ||||
* did something to the adapter, like a PF reset. | * did something to the adapter, like a PF reset. | ||||
* So, rebuild the driver's state here if that occurs. | * So, rebuild the driver's state here if that occurs. | ||||
*/ | */ | ||||
if (!i40e_check_asq_alive(&pf->hw)) { | if (!i40e_check_asq_alive(&pf->hw)) { | ||||
device_printf(dev, "Admin Queue is down; resetting...\n"); | device_printf(dev, "Admin Queue is down; resetting...\n"); | ||||
ixl_teardown_hw_structs(pf); | ixl_teardown_hw_structs(pf); | ||||
ixl_rebuild_hw_structs_after_reset(pf); | ixl_rebuild_hw_structs_after_reset(pf, false); | ||||
} | } | ||||
/* Get the latest mac address... User might use a LAA */ | /* Get the latest mac address... User might use a LAA */ | ||||
bcopy(IF_LLADDR(vsi->ifp), tmpaddr, ETH_ALEN); | bcopy(IF_LLADDR(vsi->ifp), tmpaddr, ETH_ALEN); | ||||
if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && | if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && | ||||
(i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { | (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { | ||||
ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); | ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); | ||||
bcopy(tmpaddr, hw->mac.addr, ETH_ALEN); | bcopy(tmpaddr, hw->mac.addr, ETH_ALEN); | ||||
Show All 9 Lines | ixl_if_init(if_ctx_t ctx) | ||||
iflib_set_mac(ctx, hw->mac.addr); | iflib_set_mac(ctx, hw->mac.addr); | ||||
/* Prepare the VSI: rings, hmc contexts, etc... */ | /* Prepare the VSI: rings, hmc contexts, etc... */ | ||||
if (ixl_initialize_vsi(vsi)) { | if (ixl_initialize_vsi(vsi)) { | ||||
device_printf(dev, "initialize vsi failed!!\n"); | device_printf(dev, "initialize vsi failed!!\n"); | ||||
return; | return; | ||||
} | } | ||||
/* Reconfigure multicast filters in HW */ | /* Reconfigure multicast filters in HW */ | ||||
ixl_if_multi_set(ctx); | ixl_if_multi_set(ctx); | ||||
/* Set up RSS */ | /* Set up RSS */ | ||||
ixl_config_rss(pf); | ixl_config_rss(pf); | ||||
/* Set up MSI-X routing and the ITR settings */ | /* Set up MSI-X routing and the ITR settings */ | ||||
if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { | if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { | ||||
Show All 30 Lines | |||||
void | void | ||||
ixl_if_stop(if_ctx_t ctx) | ixl_if_stop(if_ctx_t ctx) | ||||
{ | { | ||||
struct ixl_pf *pf = iflib_get_softc(ctx); | struct ixl_pf *pf = iflib_get_softc(ctx); | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
INIT_DEBUGOUT("ixl_if_stop: begin\n"); | INIT_DEBUGOUT("ixl_if_stop: begin\n"); | ||||
if (IXL_PF_IN_RECOVERY_MODE(pf)) | |||||
return; | |||||
// TODO: This may need to be reworked | // TODO: This may need to be reworked | ||||
#ifdef IXL_IW | #ifdef IXL_IW | ||||
/* Stop iWARP device */ | /* Stop iWARP device */ | ||||
if (ixl_enable_iwarp && pf->iw_enabled) | if (ixl_enable_iwarp && pf->iw_enabled) | ||||
ixl_iw_pf_stop(pf); | ixl_iw_pf_stop(pf); | ||||
#endif | #endif | ||||
ixl_disable_rings_intr(vsi); | ixl_disable_rings_intr(vsi); | ||||
▲ Show 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | ixl_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets) | ||||
MPASS(scctx->isc_ntxqsets == ntxqsets); | MPASS(scctx->isc_ntxqsets == ntxqsets); | ||||
/* Allocate queue structure memory */ | /* Allocate queue structure memory */ | ||||
if (!(vsi->tx_queues = | if (!(vsi->tx_queues = | ||||
(struct ixl_tx_queue *) malloc(sizeof(struct ixl_tx_queue) *ntxqsets, M_IXL, M_NOWAIT | M_ZERO))) { | (struct ixl_tx_queue *) malloc(sizeof(struct ixl_tx_queue) *ntxqsets, M_IXL, M_NOWAIT | M_ZERO))) { | ||||
device_printf(iflib_get_dev(ctx), "Unable to allocate TX ring memory\n"); | device_printf(iflib_get_dev(ctx), "Unable to allocate TX ring memory\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
for (i = 0, que = vsi->tx_queues; i < ntxqsets; i++, que++) { | for (i = 0, que = vsi->tx_queues; i < ntxqsets; i++, que++) { | ||||
struct tx_ring *txr = &que->txr; | struct tx_ring *txr = &que->txr; | ||||
txr->me = i; | txr->me = i; | ||||
que->vsi = vsi; | que->vsi = vsi; | ||||
if (!vsi->enable_head_writeback) { | if (!vsi->enable_head_writeback) { | ||||
/* Allocate report status array */ | /* Allocate report status array */ | ||||
if (!(txr->tx_rsq = malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_IXL, M_NOWAIT))) { | if (!(txr->tx_rsq = malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_IXL, M_NOWAIT))) { | ||||
device_printf(iflib_get_dev(ctx), "failed to allocate tx_rsq memory\n"); | device_printf(iflib_get_dev(ctx), "failed to allocate tx_rsq memory\n"); | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
/* Init report status array */ | /* Init report status array */ | ||||
for (j = 0; j < scctx->isc_ntxd[0]; j++) | for (j = 0; j < scctx->isc_ntxd[0]; j++) | ||||
txr->tx_rsq[j] = QIDX_INVALID; | txr->tx_rsq[j] = QIDX_INVALID; | ||||
} | } | ||||
/* get the virtual and physical address of the hardware queues */ | /* get the virtual and physical address of the hardware queues */ | ||||
txr->tail = I40E_QTX_TAIL(txr->me); | txr->tail = I40E_QTX_TAIL(txr->me); | ||||
txr->tx_base = (struct i40e_tx_desc *)vaddrs[i * ntxqs]; | txr->tx_base = (struct i40e_tx_desc *)vaddrs[i * ntxqs]; | ||||
txr->tx_paddr = paddrs[i * ntxqs]; | txr->tx_paddr = paddrs[i * ntxqs]; | ||||
txr->que = que; | txr->que = que; | ||||
} | } | ||||
return (0); | return (0); | ||||
fail: | fail: | ||||
ixl_if_queues_free(ctx); | ixl_if_queues_free(ctx); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets) | ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets) | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | ixl_if_queues_free(if_ctx_t ctx) | ||||
if (vsi->tx_queues != NULL) { | if (vsi->tx_queues != NULL) { | ||||
free(vsi->tx_queues, M_IXL); | free(vsi->tx_queues, M_IXL); | ||||
vsi->tx_queues = NULL; | vsi->tx_queues = NULL; | ||||
} | } | ||||
if (vsi->rx_queues != NULL) { | if (vsi->rx_queues != NULL) { | ||||
free(vsi->rx_queues, M_IXL); | free(vsi->rx_queues, M_IXL); | ||||
vsi->rx_queues = NULL; | vsi->rx_queues = NULL; | ||||
} | } | ||||
if (!IXL_PF_IN_RECOVERY_MODE(pf)) | |||||
sysctl_ctx_free(&vsi->sysctl_ctx); | |||||
} | } | ||||
void | void | ||||
ixl_update_link_status(struct ixl_pf *pf) | ixl_update_link_status(struct ixl_pf *pf) | ||||
{ | { | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
u64 baudrate; | u64 baudrate; | ||||
if (pf->link_up) { | if (pf->link_up) { | ||||
if (vsi->link_active == FALSE) { | if (vsi->link_active == FALSE) { | ||||
vsi->link_active = TRUE; | vsi->link_active = TRUE; | ||||
baudrate = ixl_max_aq_speed_to_value(hw->phy.link_info.link_speed); | baudrate = ixl_max_aq_speed_to_value(hw->phy.link_info.link_speed); | ||||
iflib_link_state_change(vsi->ctx, LINK_STATE_UP, baudrate); | iflib_link_state_change(vsi->ctx, LINK_STATE_UP, baudrate); | ||||
ixl_link_up_msg(pf); | ixl_link_up_msg(pf); | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
ixl_broadcast_link_state(pf); | ixl_broadcast_link_state(pf); | ||||
#endif | #endif | ||||
} | } | ||||
} else { /* Link down */ | } else { /* Link down */ | ||||
if (vsi->link_active == TRUE) { | if (vsi->link_active == TRUE) { | ||||
vsi->link_active = FALSE; | vsi->link_active = FALSE; | ||||
iflib_link_state_change(vsi->ctx, LINK_STATE_DOWN, 0); | iflib_link_state_change(vsi->ctx, LINK_STATE_DOWN, 0); | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
ixl_broadcast_link_state(pf); | ixl_broadcast_link_state(pf); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | #endif | ||||
wr32(hw, I40E_PFINT_ICR0_ENA, reg); | wr32(hw, I40E_PFINT_ICR0_ENA, reg); | ||||
return (status); | return (status); | ||||
} | } | ||||
static void | static void | ||||
ixl_if_update_admin_status(if_ctx_t ctx) | ixl_if_update_admin_status(if_ctx_t ctx) | ||||
{ | { | ||||
struct ixl_pf *pf = iflib_get_softc(ctx); | struct ixl_pf *pf = iflib_get_softc(ctx); | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
u16 pending; | u16 pending; | ||||
if (pf->state & IXL_PF_STATE_ADAPTER_RESETTING) | if (pf->state & IXL_PF_STATE_ADAPTER_RESETTING) | ||||
ixl_handle_empr_reset(pf); | ixl_handle_empr_reset(pf); | ||||
/* | |||||
* Admin Queue is shut down while handling reset. | |||||
* Don't proceed if it hasn't been re-initialized | |||||
* e.g due to an issue with new FW. | |||||
*/ | |||||
if (!i40e_check_asq_alive(&pf->hw)) | |||||
return; | |||||
if (pf->state & IXL_PF_STATE_MDD_PENDING) | if (pf->state & IXL_PF_STATE_MDD_PENDING) | ||||
ixl_handle_mdd_event(pf); | ixl_handle_mdd_event(pf); | ||||
ixl_process_adminq(pf, &pending); | ixl_process_adminq(pf, &pending); | ||||
ixl_update_link_status(pf); | ixl_update_link_status(pf); | ||||
ixl_update_stats_counters(pf); | |||||
/* | /* | ||||
* If there are still messages to process, reschedule ourselves. | * If there are still messages to process, reschedule ourselves. | ||||
* Otherwise, re-enable our interrupt and go to sleep. | * Otherwise, re-enable our interrupt and go to sleep. | ||||
*/ | */ | ||||
if (pending > 0) | if (pending > 0) | ||||
iflib_admin_intr_deferred(ctx); | iflib_admin_intr_deferred(ctx); | ||||
else | else | ||||
ixl_enable_intr0(hw); | ixl_enable_intr0(hw); | ||||
▲ Show 20 Lines • Show All 221 Lines • ▼ Show 20 Lines | ixl_if_promisc_set(if_ctx_t ctx, int flags) | ||||
err = i40e_aq_set_vsi_multicast_promiscuous(hw, | err = i40e_aq_set_vsi_multicast_promiscuous(hw, | ||||
vsi->seid, multi, NULL); | vsi->seid, multi, NULL); | ||||
return (err); | return (err); | ||||
} | } | ||||
static void | static void | ||||
ixl_if_timer(if_ctx_t ctx, uint16_t qid) | ixl_if_timer(if_ctx_t ctx, uint16_t qid) | ||||
{ | { | ||||
struct ixl_pf *pf = iflib_get_softc(ctx); | |||||
if (qid != 0) | if (qid != 0) | ||||
return; | return; | ||||
/* Fire off the adminq task */ | ixl_update_stats_counters(pf); | ||||
iflib_admin_intr_deferred(ctx); | |||||
} | } | ||||
static void | static void | ||||
ixl_if_vlan_register(if_ctx_t ctx, u16 vtag) | ixl_if_vlan_register(if_ctx_t ctx, u16 vtag) | ||||
{ | { | ||||
struct ixl_pf *pf = iflib_get_softc(ctx); | struct ixl_pf *pf = iflib_get_softc(ctx); | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct i40e_hw *hw = vsi->hw; | struct i40e_hw *hw = vsi->hw; | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | |||||
* Sanity check and save off tunable values. | * Sanity check and save off tunable values. | ||||
*/ | */ | ||||
static void | static void | ||||
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 */ | ||||
#ifdef IXL_DEBUG_FC | |||||
pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; | pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; | ||||
#endif | |||||
#ifdef IXL_DEBUG | |||||
pf->recovery_mode = ixl_debug_recovery_mode; | |||||
#endif | |||||
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; | ||||
pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback); | pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback); | ||||
pf->enable_vf_loopback = !!(ixl_enable_vf_loopback); | pf->enable_vf_loopback = !!(ixl_enable_vf_loopback); | ||||
#if 0 | #if 0 | ||||
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; | ||||
#endif | #endif | ||||
Show All 31 Lines |