diff options
Diffstat (limited to 'sys/dev/ixl/if_ixl.c')
-rw-r--r-- | sys/dev/ixl/if_ixl.c | 194 |
1 files changed, 168 insertions, 26 deletions
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c index ca4644f6b1ce..ca1eb9c695b1 100644 --- a/sys/dev/ixl/if_ixl.c +++ b/sys/dev/ixl/if_ixl.c @@ -48,7 +48,7 @@ /********************************************************************* * Driver version *********************************************************************/ -char ixl_driver_version[] = "1.4.7-k"; +char ixl_driver_version[] = "1.4.9-k"; /********************************************************************* * PCI Device ID Table @@ -63,7 +63,6 @@ char ixl_driver_version[] = "1.4.7-k"; static ixl_vendor_info_t ixl_vendor_info_array[] = { {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_A, 0, 0, 0}, {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0}, {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0}, {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0}, @@ -71,8 +70,6 @@ static ixl_vendor_info_t ixl_vendor_info_array[] = {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 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_20G_KR2, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_20G_KR2_A, 0, 0, 0}, /* required last entry */ {0, 0, 0, 0, 0} }; @@ -552,7 +549,7 @@ ixl_attach(device_t dev) i40e_clear_hw(hw); error = i40e_pf_reset(hw); if (error) { - device_printf(dev,"PF reset failure %x\n", error); + device_printf(dev, "PF reset failure %x\n", error); error = EIO; goto err_out; } @@ -566,7 +563,7 @@ ixl_attach(device_t dev) /* Initialize the shared code */ error = i40e_init_shared_code(hw); if (error) { - device_printf(dev,"Unable to initialize the shared code\n"); + device_printf(dev, "Unable to initialize the shared code\n"); error = EIO; goto err_out; } @@ -668,8 +665,7 @@ ixl_attach(device_t dev) } /* Limit PHY interrupts to link, autoneg, and modules failure */ - error = i40e_aq_set_phy_int_mask(hw, - I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, + error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, NULL); if (error) { device_printf(dev, "i40e_aq_set_phy_mask() failed: err %d," @@ -1184,15 +1180,14 @@ ixl_init_locked(struct ixl_pf *pf) #ifdef IXL_FDIR filter.enable_fdir = TRUE; #endif + filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; if (i40e_set_filter_control(hw, &filter)) - device_printf(dev, "set_filter_control() failed\n"); + device_printf(dev, "i40e_set_filter_control() failed\n"); /* Set up RSS */ ixl_config_rss(vsi); - /* - ** Prepare the VSI: rings, hmc contexts, etc... - */ + /* Prepare the VSI: rings, hmc contexts, etc... */ if (ixl_initialize_vsi(vsi)) { device_printf(dev, "initialize vsi failed!!\n"); return; @@ -1204,9 +1199,6 @@ ixl_init_locked(struct ixl_pf *pf) /* Setup vlan's if needed */ ixl_setup_vlan_filters(vsi); - /* Start the local timer */ - callout_reset(&pf->timer, hz, ixl_local_timer, pf); - /* Set up MSI/X routing and the ITR settings */ if (ixl_enable_msix) { ixl_configure_msix(pf); @@ -1236,19 +1228,163 @@ ixl_init_locked(struct ixl_pf *pf) i40e_get_link_status(hw, &pf->link_up); ixl_update_link_status(pf); + /* Start the local timer */ + callout_reset(&pf->timer, hz, ixl_local_timer, pf); + /* Now inform the stack we're ready */ ifp->if_drv_flags |= IFF_DRV_RUNNING; - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; return; } +// XXX: super experimental stuff +static int +ixl_teardown_hw_structs(struct ixl_pf *pf) +{ + enum i40e_status_code status = 0; + struct i40e_hw *hw = &pf->hw; + device_t dev = pf->dev; + + /* Shutdown LAN HMC */ + if (hw->hmc.hmc_obj) { + status = i40e_shutdown_lan_hmc(hw); + if (status) { + device_printf(dev, + "init: LAN HMC shutdown failure; status %d\n", status); + goto err_out; + } + } + + // XXX: This gets called when we know the adminq is inactive; + // so we already know it's setup when we get here. + + /* Shutdown admin queue */ + status = i40e_shutdown_adminq(hw); + if (status) + device_printf(dev, + "init: Admin Queue shutdown failure; status %d\n", status); + +err_out: + return (status); +} + +static int +ixl_reset(struct ixl_pf *pf) +{ + struct i40e_hw *hw = &pf->hw; + device_t dev = pf->dev; + int error = 0; + + // XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary + i40e_clear_hw(hw); + error = i40e_pf_reset(hw); + if (error) { + device_printf(dev, "init: PF reset failure"); + error = EIO; + goto err_out; + } + + error = i40e_init_adminq(hw); + if (error) { + device_printf(dev, "init: Admin queue init failure; status code %d", error); + error = EIO; + goto err_out; + } + + i40e_clear_pxe_mode(hw); + + error = ixl_get_hw_capabilities(pf); + if (error) { + device_printf(dev, "init: Error retrieving HW capabilities; status code %d\n", error); + goto err_out; + } + + error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, + hw->func_caps.num_rx_qp, 0, 0); + if (error) { + device_printf(dev, "init: LAN HMC init failed; status code %d\n", error); + error = EIO; + goto err_out; + } + + error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); + if (error) { + device_printf(dev, "init: LAN HMC config failed; status code %d\n", error); + error = EIO; + goto err_out; + } + + // XXX: need to do switch config here? + + error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, + NULL); + if (error) { + device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d," + " aq_err %d\n", error, hw->aq.asq_last_status); + error = EIO; + goto err_out; + } + + u8 set_fc_err_mask; + error = i40e_set_fc(hw, &set_fc_err_mask, true); + if (error) { + device_printf(dev, "init: setting link flow control failed; retcode %d," + " fc_err_mask 0x%02x\n", error, set_fc_err_mask); + goto err_out; + } + + // XXX: (Rebuild VSIs?) + + // Firmware delay workaround + if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || + (hw->aq.fw_maj_ver < 4)) { + i40e_msec_delay(75); + error = i40e_aq_set_link_restart_an(hw, TRUE, NULL); + if (error) { + device_printf(dev, "init: link restart failed, aq_err %d\n", + hw->aq.asq_last_status); + goto err_out; + } + } + + // [add_filter_to_drop_tx_flow_control_frames] + // - TODO: Implement + + // i40e_send_version + // - TODO: Properly implement + struct i40e_driver_version dv; + + dv.major_version = 1; + dv.minor_version = 1; + dv.build_version = 1; + dv.subbuild_version = 0; + // put in a driver version string that is less than 0x80 bytes long + bzero(&dv.driver_string, sizeof(dv.driver_string)); + i40e_aq_send_driver_version(hw, &dv, NULL); + +err_out: + return (error); +} + static void ixl_init(void *arg) { struct ixl_pf *pf = arg; int ret = 0; + /* + * If the aq is dead here, it probably means something outside of the driver + * did something to the adapter, like a PF reset. + * So rebuild the driver's state here if that occurs. + */ + if (!i40e_check_asq_alive(&pf->hw)) { + device_printf(pf->dev, "asq is not alive; rebuilding...\n"); + IXL_PF_LOCK(pf); + ixl_teardown_hw_structs(pf); + ixl_reset(pf); + IXL_PF_UNLOCK(pf); + } + /* Set up interrupt routing here */ if (pf->msix > 1) ret = ixl_assign_vsi_msix(pf); @@ -1992,7 +2128,7 @@ ixl_assign_vsi_legacy(struct ixl_pf *pf) pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (pf->res == NULL) { - device_printf(dev,"Unable to allocate" + device_printf(dev, "Unable to allocate" " bus resource: vsi legacy/msi interrupt\n"); return (ENXIO); } @@ -2829,11 +2965,11 @@ ixl_initialize_vsi(struct ixl_vsi *vsi) ctxt.pf_num = hw->pf_id; err = i40e_aq_get_vsi_params(hw, &ctxt, NULL); if (err) { - device_printf(dev,"get vsi params failed %x!!\n", err); + device_printf(dev, "i40e_aq_get_vsi_params() failed, error %d\n", err); return (err); } #ifdef IXL_DEBUG - printf("get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " + device_printf(dev, "get_vsi_params: seid: %d, uplinkseid: %d, vsi_number: %d, " "vsis_allocated: %d, vsis_unallocated: %d, flags: 0x%x, " "pfnum: %d, vfnum: %d, stat idx: %d, enabled: %d\n", ctxt.seid, ctxt.uplink_seid, ctxt.vsi_number, @@ -2849,15 +2985,15 @@ ixl_initialize_vsi(struct ixl_vsi *vsi) ctxt.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; ctxt.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG; ctxt.info.queue_mapping[0] = 0; - ctxt.info.tc_mapping[0] = 0x0800; + ctxt.info.tc_mapping[0] = 0x0c00; /* Set VLAN receive stripping mode */ ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) - ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; + ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; else - ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; + ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; /* Keep copy of VSI info in VSI for statistic counters */ memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); @@ -2871,8 +3007,8 @@ ixl_initialize_vsi(struct ixl_vsi *vsi) err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); if (err) { - device_printf(dev,"update vsi params failed %x!!\n", - hw->aq.asq_last_status); + device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d, aq_error %d\n", + err, hw->aq.asq_last_status); return (err); } @@ -2884,7 +3020,6 @@ ixl_initialize_vsi(struct ixl_vsi *vsi) u32 txctl; u16 size; - /* Setup the HMC TX Context */ size = que->num_desc * sizeof(struct i40e_tx_desc); memset(&tctx, 0, sizeof(struct i40e_hmc_obj_txq)); @@ -5051,8 +5186,15 @@ ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd) nvma = (struct i40e_nvm_access *)ifd->ifd_data; status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno); + if (status) + device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n", + status, perrno); - return (status) ? perrno : 0; + /* Convert EPERM error code for tools */ + if (perrno == -EPERM) + return (-EACCES); + else + return (perrno); } #ifdef IXL_DEBUG_SYSCTL |