diff options
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_diag.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 146 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_hmc.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 364 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_type.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 29 |
8 files changed, 469 insertions, 90 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 001d7cfc9129..40706c15cdc3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -133,6 +133,7 @@ enum i40e_state_t { __I40E_GLOBAL_RESET_REQUESTED, __I40E_EMP_RESET_REQUESTED, __I40E_FILTER_OVERFLOW_PROMISC, + __I40E_SUSPENDED, }; enum i40e_interrupt_policy { @@ -199,6 +200,7 @@ struct i40e_pf { u16 num_tc_qps; /* num queue pairs per TC */ u16 num_lan_qps; /* num lan queues this pf has set up */ u16 num_lan_msix; /* num queue vectors for the base pf vsi */ + int queues_left; /* queues left unclaimed */ u16 rss_size; /* num queues in the RSS array */ u16 rss_size_max; /* HW defined max RSS queues */ u16 fdir_pf_filter_count; /* num of guaranteed filters for this PF */ @@ -501,6 +503,7 @@ int i40e_up(struct i40e_vsi *vsi); void i40e_down(struct i40e_vsi *vsi); extern const char i40e_driver_name[]; extern const char i40e_driver_version_str[]; +void i40e_do_reset_safe(struct i40e_pf *pf, u32 reset_flags); void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags); void i40e_update_stats(struct i40e_vsi *vsi); void i40e_update_eth_stats(struct i40e_vsi *vsi); @@ -530,6 +533,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, int i40e_vsi_release(struct i40e_vsi *vsi); struct i40e_vsi *i40e_vsi_lookup(struct i40e_pf *pf, enum i40e_vsi_type type, struct i40e_vsi *start_vsi); +int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count); struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, u16 uplink_seid, u16 downlink_seid, u8 enabled_tc); void i40e_veb_release(struct i40e_veb *veb); diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 9c675b5f1466..9a59dda6b5ce 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1462,19 +1462,19 @@ static ssize_t i40e_dbg_command_write(struct file *filp, } } else if (strncmp(cmd_buf, "pfr", 3) == 0) { dev_info(&pf->pdev->dev, "forcing PFR\n"); - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "corer", 5) == 0) { dev_info(&pf->pdev->dev, "forcing CoreR\n"); - i40e_do_reset(pf, (1 << __I40E_CORE_RESET_REQUESTED)); + i40e_do_reset_safe(pf, (1 << __I40E_CORE_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "globr", 5) == 0) { dev_info(&pf->pdev->dev, "forcing GlobR\n"); - i40e_do_reset(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED)); + i40e_do_reset_safe(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "empr", 4) == 0) { dev_info(&pf->pdev->dev, "forcing EMPR\n"); - i40e_do_reset(pf, (1 << __I40E_EMP_RESET_REQUESTED)); + i40e_do_reset_safe(pf, (1 << __I40E_EMP_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "read", 4) == 0) { u32 address; diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.c b/drivers/net/ethernet/intel/i40e/i40e_diag.c index dc6c41fade9e..98c1ef563bf0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_diag.c +++ b/drivers/net/ethernet/intel/i40e/i40e_diag.c @@ -119,7 +119,7 @@ i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw) /* read NVM control word and if NVM valid, validate EEPROM checksum*/ ret_code = i40e_read_nvm_word(hw, I40E_SR_NVM_CONTROL_WORD, ®_val); - if ((!ret_code) && + if (!ret_code && ((reg_val & I40E_SR_CONTROL_WORD_1_MASK) == (0x01 << I40E_SR_CONTROL_WORD_1_SHIFT))) { ret_code = i40e_validate_nvm_checksum(hw, NULL); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index fd3e379de6da..d6681f6bf291 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -193,32 +193,48 @@ static int i40e_get_settings(struct net_device *netdev, ecmd->supported = SUPPORTED_10000baseKR_Full; ecmd->advertising = ADVERTISED_10000baseKR_Full; break; - case I40E_PHY_TYPE_10GBASE_T: default: - ecmd->supported = SUPPORTED_10000baseT_Full; - ecmd->advertising = ADVERTISED_10000baseT_Full; + if (i40e_is_40G_device(hw->device_id)) { + ecmd->supported = SUPPORTED_40000baseSR4_Full; + ecmd->advertising = ADVERTISED_40000baseSR4_Full; + } else { + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->advertising = ADVERTISED_10000baseT_Full; + } break; } - /* for now just say autoneg all the time */ ecmd->supported |= SUPPORTED_Autoneg; + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->autoneg = ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ? + AUTONEG_ENABLE : AUTONEG_DISABLE); - if (hw->phy.media_type == I40E_MEDIA_TYPE_BACKPLANE) { + switch (hw->phy.media_type) { + case I40E_MEDIA_TYPE_BACKPLANE: ecmd->supported |= SUPPORTED_Backplane; ecmd->advertising |= ADVERTISED_Backplane; ecmd->port = PORT_NONE; - } else if (hw->phy.media_type == I40E_MEDIA_TYPE_BASET) { + break; + case I40E_MEDIA_TYPE_BASET: ecmd->supported |= SUPPORTED_TP; ecmd->advertising |= ADVERTISED_TP; ecmd->port = PORT_TP; - } else if (hw->phy.media_type == I40E_MEDIA_TYPE_DA) { + break; + case I40E_MEDIA_TYPE_DA: + case I40E_MEDIA_TYPE_CX4: ecmd->supported |= SUPPORTED_FIBRE; ecmd->advertising |= ADVERTISED_FIBRE; ecmd->port = PORT_DA; - } else { + break; + case I40E_MEDIA_TYPE_FIBER: ecmd->supported |= SUPPORTED_FIBRE; ecmd->advertising |= ADVERTISED_FIBRE; ecmd->port = PORT_FIBRE; + break; + case I40E_MEDIA_TYPE_UNKNOWN: + default: + ecmd->port = PORT_OTHER; + break; } ecmd->transceiver = XCVR_EXTERNAL; @@ -260,12 +276,14 @@ static void i40e_get_pauseparam(struct net_device *netdev, ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ? AUTONEG_ENABLE : AUTONEG_DISABLE); - pause->rx_pause = 0; - pause->tx_pause = 0; - if (hw_link_info->an_info & I40E_AQ_LINK_PAUSE_RX) + if (hw->fc.current_mode == I40E_FC_RX_PAUSE) { + pause->rx_pause = 1; + } else if (hw->fc.current_mode == I40E_FC_TX_PAUSE) { + pause->tx_pause = 1; + } else if (hw->fc.current_mode == I40E_FC_FULL) { pause->rx_pause = 1; - if (hw_link_info->an_info & I40E_AQ_LINK_PAUSE_TX) pause->tx_pause = 1; + } } static u32 i40e_get_msglevel(struct net_device *netdev) @@ -732,7 +750,6 @@ static int i40e_reg_test(struct net_device *netdev, u64 *data) netif_info(pf, hw, netdev, "register test\n"); *data = i40e_diag_reg_test(&pf->hw); - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); return *data; } @@ -780,20 +797,18 @@ static void i40e_diag_test(struct net_device *netdev, struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - set_bit(__I40E_TESTING, &pf->state); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ netif_info(pf, drv, netdev, "offline testing starting\n"); + set_bit(__I40E_TESTING, &pf->state); + /* Link test performed before hardware reset * so autoneg doesn't interfere with test result */ if (i40e_link_test(netdev, &data[I40E_ETH_TEST_LINK])) eth_test->flags |= ETH_TEST_FL_FAILED; - if (i40e_reg_test(netdev, &data[I40E_ETH_TEST_REG])) - eth_test->flags |= ETH_TEST_FL_FAILED; - if (i40e_eeprom_test(netdev, &data[I40E_ETH_TEST_EEPROM])) eth_test->flags |= ETH_TEST_FL_FAILED; @@ -803,6 +818,12 @@ static void i40e_diag_test(struct net_device *netdev, if (i40e_loopback_test(netdev, &data[I40E_ETH_TEST_LOOPBACK])) eth_test->flags |= ETH_TEST_FL_FAILED; + /* run reg test last, a reset is required after it */ + if (i40e_reg_test(netdev, &data[I40E_ETH_TEST_REG])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + clear_bit(__I40E_TESTING, &pf->state); + i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); } else { /* Online tests */ netif_info(pf, drv, netdev, "online testing starting\n"); @@ -816,7 +837,6 @@ static void i40e_diag_test(struct net_device *netdev, data[I40E_ETH_TEST_INTR] = 0; data[I40E_ETH_TEST_LOOPBACK] = 0; } - clear_bit(__I40E_TESTING, &pf->state); netif_info(pf, drv, netdev, "testing finished\n"); } @@ -1452,6 +1472,94 @@ static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) return ret; } +/** + * i40e_max_channels - get Max number of combined channels supported + * @vsi: vsi pointer + **/ +static unsigned int i40e_max_channels(struct i40e_vsi *vsi) +{ + /* TODO: This code assumes DCB and FD is disabled for now. */ + return vsi->alloc_queue_pairs; +} + +/** + * i40e_get_channels - Get the current channels enabled and max supported etc. + * @netdev: network interface device structure + * @ch: ethtool channels structure + * + * We don't support separate tx and rx queues as channels. The other count + * represents how many queues are being used for control. max_combined counts + * how many queue pairs we can support. They may not be mapped 1 to 1 with + * q_vectors since we support a lot more queue pairs than q_vectors. + **/ +static void i40e_get_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_vsi *vsi = np->vsi; + struct i40e_pf *pf = vsi->back; + + /* report maximum channels */ + ch->max_combined = i40e_max_channels(vsi); + + /* report info for other vector */ + ch->other_count = (pf->flags & I40E_FLAG_FDIR_ENABLED) ? 1 : 0; + ch->max_other = ch->other_count; + + /* Note: This code assumes DCB is disabled for now. */ + ch->combined_count = vsi->num_queue_pairs; +} + +/** + * i40e_set_channels - Set the new channels count. + * @netdev: network interface device structure + * @ch: ethtool channels structure + * + * The new channels count may not be the same as requested by the user + * since it gets rounded down to a power of 2 value. + **/ +static int i40e_set_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + unsigned int count = ch->combined_count; + struct i40e_vsi *vsi = np->vsi; + struct i40e_pf *pf = vsi->back; + int new_count; + + /* We do not support setting channels for any other VSI at present */ + if (vsi->type != I40E_VSI_MAIN) + return -EINVAL; + + /* verify they are not requesting separate vectors */ + if (!count || ch->rx_count || ch->tx_count) + return -EINVAL; + + /* verify other_count has not changed */ + if (ch->other_count != ((pf->flags & I40E_FLAG_FDIR_ENABLED) ? 1 : 0)) + return -EINVAL; + + /* verify the number of channels does not exceed hardware limits */ + if (count > i40e_max_channels(vsi)) + return -EINVAL; + + /* update feature limits from largest to smallest supported values */ + /* TODO: Flow director limit, DCB etc */ + + /* cap RSS limit */ + if (count > pf->rss_size_max) + count = pf->rss_size_max; + + /* use rss_reconfig to rebuild with new queue count and update traffic + * class queue mapping + */ + new_count = i40e_reconfig_rss_queues(pf, count); + if (new_count > 1) + return 0; + else + return -EINVAL; +} + static const struct ethtool_ops i40e_ethtool_ops = { .get_settings = i40e_get_settings, .get_drvinfo = i40e_get_drvinfo, @@ -1476,6 +1584,8 @@ static const struct ethtool_ops i40e_ethtool_ops = { .get_ethtool_stats = i40e_get_ethtool_stats, .get_coalesce = i40e_get_coalesce, .set_coalesce = i40e_set_coalesce, + .get_channels = i40e_get_channels, + .set_channels = i40e_set_channels, .get_ts_info = i40e_get_ts_info, }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_hmc.c index 901804af8b0e..bcedf3fb1143 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.c @@ -47,10 +47,10 @@ i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, u64 direct_mode_sz) { enum i40e_memory_type mem_type __attribute__((unused)); - i40e_status ret_code = 0; struct i40e_hmc_sd_entry *sd_entry; bool dma_mem_alloc_done = false; struct i40e_dma_mem mem; + i40e_status ret_code; u64 alloc_len; if (NULL == hmc_info->sd_table.sd_entry) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index a6291e23fe5f..fba0aada062a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -48,7 +48,7 @@ static void i40e_vsi_reinit_locked(struct i40e_vsi *vsi); static void i40e_handle_reset_warning(struct i40e_pf *pf); static int i40e_add_vsi(struct i40e_vsi *vsi); static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi); -static int i40e_setup_pf_switch(struct i40e_pf *pf); +static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit); static int i40e_setup_misc_vector(struct i40e_pf *pf); static void i40e_determine_queue_usage(struct i40e_pf *pf); static int i40e_setup_pf_filter_control(struct i40e_pf *pf); @@ -354,6 +354,9 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( struct rtnl_link_stats64 *vsi_stats = i40e_get_vsi_stats_struct(vsi); int i; + if (test_bit(__I40E_DOWN, &vsi->state)) + return stats; + rcu_read_lock(); for (i = 0; i < vsi->num_queue_pairs; i++) { struct i40e_ring *tx_ring, *rx_ring; @@ -3966,6 +3969,15 @@ static int i40e_open(struct net_device *netdev) if (err) goto err_setup_rx; + /* Notify the stack of the actual queue counts. */ + err = netif_set_real_num_tx_queues(netdev, pf->num_tx_queues); + if (err) + goto err_set_queues; + + err = netif_set_real_num_rx_queues(netdev, pf->num_rx_queues); + if (err) + goto err_set_queues; + err = i40e_up_complete(vsi); if (err) goto err_up_complete; @@ -3982,6 +3994,7 @@ static int i40e_open(struct net_device *netdev) err_up_complete: i40e_down(vsi); +err_set_queues: i40e_vsi_free_irq(vsi); err_setup_rx: i40e_vsi_free_rx_resources(vsi); @@ -4119,6 +4132,19 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) } /** + * i40e_do_reset_safe - Protected reset path for userland calls. + * @pf: board private structure + * @reset_flags: which reset is requested + * + **/ +void i40e_do_reset_safe(struct i40e_pf *pf, u32 reset_flags) +{ + rtnl_lock(); + i40e_do_reset(pf, reset_flags); + rtnl_unlock(); +} + +/** * i40e_handle_lan_overflow_event - Handler for LAN queue overflow event * @pf: board private structure * @e: event info posted on ARQ @@ -4363,6 +4389,7 @@ static void i40e_reset_subtask(struct i40e_pf *pf) { u32 reset_flags = 0; + rtnl_lock(); if (test_bit(__I40E_REINIT_REQUESTED, &pf->state)) { reset_flags |= (1 << __I40E_REINIT_REQUESTED); clear_bit(__I40E_REINIT_REQUESTED, &pf->state); @@ -4385,7 +4412,7 @@ static void i40e_reset_subtask(struct i40e_pf *pf) */ if (test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state)) { i40e_handle_reset_warning(pf); - return; + goto unlock; } /* If we're already down or resetting, just bail */ @@ -4393,6 +4420,9 @@ static void i40e_reset_subtask(struct i40e_pf *pf) !test_bit(__I40E_DOWN, &pf->state) && !test_bit(__I40E_CONFIG_BUSY, &pf->state)) i40e_do_reset(pf, reset_flags); + +unlock: + rtnl_unlock(); } /** @@ -4757,8 +4787,9 @@ static int i40e_prep_for_reset(struct i40e_pf *pf) /** * i40e_reset_and_rebuild - reset and rebuid using a saved config * @pf: board private structure + * @reinit: if the Main VSI needs to re-initialized. **/ -static void i40e_reset_and_rebuild(struct i40e_pf *pf) +static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) { struct i40e_driver_version dv; struct i40e_hw *hw = &pf->hw; @@ -4806,7 +4837,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf) } /* do basic switch setup */ - ret = i40e_setup_pf_switch(pf); + ret = i40e_setup_pf_switch(pf, reinit); if (ret) goto end_core_reset; @@ -4897,7 +4928,7 @@ static void i40e_handle_reset_warning(struct i40e_pf *pf) ret = i40e_prep_for_reset(pf); if (!ret) - i40e_reset_and_rebuild(pf); + i40e_reset_and_rebuild(pf, false); } /** @@ -5078,11 +5109,12 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi) /** * i40e_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the vsi * @type: VSI pointer + * @alloc_qvectors: a bool to specify if q_vectors need to be allocated. * * On error: returns error code (negative) * On success: returns 0 **/ -static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi) +static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi, bool alloc_qvectors) { int size; int ret = 0; @@ -5094,12 +5126,14 @@ static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi) return -ENOMEM; vsi->rx_rings = &vsi->tx_rings[vsi->alloc_queue_pairs]; - /* allocate memory for q_vector pointers */ - size = sizeof(struct i40e_q_vectors *) * vsi->num_q_vectors; - vsi->q_vectors = kzalloc(size, GFP_KERNEL); - if (!vsi->q_vectors) { - ret = -ENOMEM; - goto err_vectors; + if (alloc_qvectors) { + /* allocate memory for q_vector pointers */ + size = sizeof(struct i40e_q_vectors *) * vsi->num_q_vectors; + vsi->q_vectors = kzalloc(size, GFP_KERNEL); + if (!vsi->q_vectors) { + ret = -ENOMEM; + goto err_vectors; + } } return ret; @@ -5169,7 +5203,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) if (ret) goto err_rings; - ret = i40e_vsi_alloc_arrays(vsi); + ret = i40e_vsi_alloc_arrays(vsi, true); if (ret) goto err_rings; @@ -5191,15 +5225,18 @@ unlock_pf: /** * i40e_vsi_free_arrays - Free queue and vector pointer arrays for the VSI * @type: VSI pointer + * @free_qvectors: a bool to specify if q_vectors need to be freed. * * On error: returns error code (negative) * On success: returns 0 **/ -static void i40e_vsi_free_arrays(struct i40e_vsi *vsi) +static void i40e_vsi_free_arrays(struct i40e_vsi *vsi, bool free_qvectors) { /* free the ring and vector containers */ - kfree(vsi->q_vectors); - vsi->q_vectors = NULL; + if (free_qvectors) { + kfree(vsi->q_vectors); + vsi->q_vectors = NULL; + } kfree(vsi->tx_rings); vsi->tx_rings = NULL; vsi->rx_rings = NULL; @@ -5241,7 +5278,7 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi) i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx); i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx); - i40e_vsi_free_arrays(vsi); + i40e_vsi_free_arrays(vsi, true); pf->vsi[vsi->idx] = NULL; if (vsi->idx < pf->next_vsi) @@ -5391,15 +5428,18 @@ static int i40e_init_msix(struct i40e_pf *pf) /* The number of vectors we'll request will be comprised of: * - Add 1 for "other" cause for Admin Queue events, etc. * - The number of LAN queue pairs - * already adjusted for the NUMA node - * assumes symmetric Tx/Rx pairing + * - Queues being used for RSS. + * We don't need as many as max_rss_size vectors. + * use rss_size instead in the calculation since that + * is governed by number of cpus in the system. + * - assumes symmetric Tx/Rx pairing * - The number of VMDq pairs * Once we count this up, try the request. * * If we can't get what we want, we'll simplify to nearly nothing * and try again. If that still fails, we punt. */ - pf->num_lan_msix = pf->num_lan_qps; + pf->num_lan_msix = pf->num_lan_qps - (pf->rss_size_max - pf->rss_size); pf->num_vmdq_msix = pf->num_vmdq_qps; v_budget = 1 + pf->num_lan_msix; v_budget += (pf->num_vmdq_vsis * pf->num_vmdq_msix); @@ -5680,6 +5720,42 @@ static int i40e_config_rss(struct i40e_pf *pf) } /** + * i40e_reconfig_rss_queues - change number of queues for rss and rebuild + * @pf: board private structure + * @queue_count: the requested queue count for rss. + * + * returns 0 if rss is not enabled, if enabled returns the final rss queue + * count which may be different from the requested queue count. + **/ +int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count) +{ + if (!(pf->flags & I40E_FLAG_RSS_ENABLED)) + return 0; + + queue_count = min_t(int, queue_count, pf->rss_size_max); + queue_count = rounddown_pow_of_two(queue_count); + + if (queue_count != pf->rss_size) { + if (pf->queues_left < (queue_count - pf->rss_size)) { + dev_info(&pf->pdev->dev, + "Not enough queues to do RSS on %d queues: remaining queues %d\n", + queue_count, pf->queues_left); + return pf->rss_size; + } + i40e_prep_for_reset(pf); + + pf->num_lan_qps += (queue_count - pf->rss_size); + pf->queues_left -= (queue_count - pf->rss_size); + pf->rss_size = queue_count; + + i40e_reset_and_rebuild(pf, true); + i40e_config_rss(pf); + } + dev_info(&pf->pdev->dev, "RSS count: %d\n", pf->rss_size); + return pf->rss_size; +} + +/** * i40e_sw_init - Initialize general software structures (struct i40e_pf) * @pf: board private structure to initialize * @@ -5718,8 +5794,7 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->hw.func_caps.num_tx_qp); if (pf->hw.func_caps.rss) { pf->flags |= I40E_FLAG_RSS_ENABLED; - pf->rss_size = min_t(int, pf->rss_size_max, - nr_cpus_node(numa_node_id())); + pf->rss_size = min_t(int, pf->rss_size_max, num_online_cpus()); } else { pf->rss_size = 1; } @@ -5861,7 +5936,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) int etherdev_size; etherdev_size = sizeof(struct i40e_netdev_priv); - netdev = alloc_etherdev_mq(etherdev_size, vsi->num_queue_pairs); + netdev = alloc_etherdev_mq(etherdev_size, vsi->alloc_queue_pairs); if (!netdev) return -ENOMEM; @@ -6254,6 +6329,69 @@ vector_setup_out: } /** + * i40e_vsi_reinit_setup - return and reallocate resources for a VSI + * @vsi: pointer to the vsi. + * + * This re-allocates a vsi's queue resources. + * + * Returns pointer to the successfully allocated and configured VSI sw struct + * on success, otherwise returns NULL on failure. + **/ +static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi) +{ + struct i40e_pf *pf = vsi->back; + u8 enabled_tc; + int ret; + + i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx); + i40e_vsi_clear_rings(vsi); + + i40e_vsi_free_arrays(vsi, false); + i40e_set_num_rings_in_vsi(vsi); + ret = i40e_vsi_alloc_arrays(vsi, false); + if (ret) + goto err_vsi; + + ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs, vsi->idx); + if (ret < 0) { + dev_info(&pf->pdev->dev, "VSI %d get_lump failed %d\n", + vsi->seid, ret); + goto err_vsi; + } + vsi->base_queue = ret; + + /* Update the FW view of the VSI. Force a reset of TC and queue + * layout configurations. + */ + enabled_tc = pf->vsi[pf->lan_vsi]->tc_config.enabled_tc; + pf->vsi[pf->lan_vsi]->tc_config.enabled_tc = 0; + pf->vsi[pf->lan_vsi]->seid = pf->main_vsi_seid; + i40e_vsi_config_tc(pf->vsi[pf->lan_vsi], enabled_tc); + + /* assign it some queues */ + ret = i40e_alloc_rings(vsi); + if (ret) + goto err_rings; + + /* map all of the rings to the q_vectors */ + i40e_vsi_map_rings_to_vectors(vsi); + return vsi; + +err_rings: + i40e_vsi_free_q_vectors(vsi); + if (vsi->netdev_registered) { + vsi->netdev_registered = false; + unregister_netdev(vsi->netdev); + free_netdev(vsi->netdev); + vsi->netdev = NULL; + } + i40e_aq_delete_element(&pf->hw, vsi->seid, NULL); +err_vsi: + i40e_vsi_clear(vsi); + return NULL; +} + +/** * i40e_vsi_setup - Set up a VSI by a given type * @pf: board private structure * @type: VSI type @@ -6896,11 +7034,13 @@ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig) /** * i40e_setup_pf_switch - Setup the HW switch on startup or after reset * @pf: board private structure + * @reinit: if the Main VSI needs to re-initialized. * * Returns 0 on success, negative value on failure **/ -static int i40e_setup_pf_switch(struct i40e_pf *pf) +static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) { + u32 rxfc = 0, txfc = 0, rxfc_reg; int ret; /* find out what's out there already */ @@ -6920,7 +7060,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf) i40e_fdir_setup(pf); /* first time setup */ - if (pf->lan_vsi == I40E_NO_VSI) { + if (pf->lan_vsi == I40E_NO_VSI || reinit) { struct i40e_vsi *vsi = NULL; u16 uplink_seid; @@ -6931,8 +7071,10 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf) uplink_seid = pf->veb[pf->lan_veb]->seid; else uplink_seid = pf->mac_seid; - - vsi = i40e_vsi_setup(pf, I40E_VSI_MAIN, uplink_seid, 0); + if (pf->lan_vsi == I40E_NO_VSI) + vsi = i40e_vsi_setup(pf, I40E_VSI_MAIN, uplink_seid, 0); + else if (reinit) + vsi = i40e_vsi_reinit_setup(pf->vsi[pf->lan_vsi]); if (!vsi) { dev_info(&pf->pdev->dev, "setup of MAIN VSI failed\n"); i40e_fdir_teardown(pf); @@ -6971,20 +7113,65 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf) i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); i40e_link_event(pf); - /* Initialize user-specifics link properties */ + /* Initialize user-specific link properties */ pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED) ? true : false); - pf->hw.fc.requested_mode = I40E_FC_DEFAULT; - if (pf->hw.phy.link_info.an_info & - (I40E_AQ_LINK_PAUSE_TX | I40E_AQ_LINK_PAUSE_RX)) + /* requested_mode is set in probe or by ethtool */ + if (!pf->fc_autoneg_status) + goto no_autoneg; + + if ((pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) && + (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)) pf->hw.fc.current_mode = I40E_FC_FULL; else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) pf->hw.fc.current_mode = I40E_FC_TX_PAUSE; else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) pf->hw.fc.current_mode = I40E_FC_RX_PAUSE; else - pf->hw.fc.current_mode = I40E_FC_DEFAULT; + pf->hw.fc.current_mode = I40E_FC_NONE; + + /* sync the flow control settings with the auto-neg values */ + switch (pf->hw.fc.current_mode) { + case I40E_FC_FULL: + txfc = 1; + rxfc = 1; + break; + case I40E_FC_TX_PAUSE: + txfc = 1; + rxfc = 0; + break; + case I40E_FC_RX_PAUSE: + txfc = 0; + rxfc = 1; + break; + case I40E_FC_NONE: + case I40E_FC_DEFAULT: + txfc = 0; + rxfc = 0; + break; + case I40E_FC_PFC: + /* TBD */ + break; + /* no default case, we have to handle all possibilities here */ + } + + wr32(&pf->hw, I40E_PRTDCB_FCCFG, txfc << I40E_PRTDCB_FCCFG_TFCE_SHIFT); + + rxfc_reg = rd32(&pf->hw, I40E_PRTDCB_MFLCN) & + ~I40E_PRTDCB_MFLCN_RFCE_MASK; + rxfc_reg |= (rxfc << I40E_PRTDCB_MFLCN_RFCE_SHIFT); + wr32(&pf->hw, I40E_PRTDCB_MFLCN, rxfc_reg); + + goto fc_complete; + +no_autoneg: + /* disable L2 flow control, user can turn it on if they wish */ + wr32(&pf->hw, I40E_PRTDCB_FCCFG, 0); + wr32(&pf->hw, I40E_PRTDCB_MFLCN, rd32(&pf->hw, I40E_PRTDCB_MFLCN) & + ~I40E_PRTDCB_MFLCN_RFCE_MASK); + +fc_complete: return ret; } @@ -6998,7 +7185,7 @@ static u16 i40e_set_rss_size(struct i40e_pf *pf, int queues_left) int num_tc0; num_tc0 = min_t(int, queues_left, pf->rss_size_max); - num_tc0 = min_t(int, num_tc0, nr_cpus_node(numa_node_id())); + num_tc0 = min_t(int, num_tc0, num_online_cpus()); num_tc0 = rounddown_pow_of_two(num_tc0); return num_tc0; @@ -7049,7 +7236,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) pf->rss_size = i40e_set_rss_size(pf, queues_left); queues_left -= pf->rss_size; - pf->num_lan_qps = pf->rss_size; + pf->num_lan_qps = pf->rss_size_max; } else if (pf->flags & I40E_FLAG_RSS_ENABLED && !(pf->flags & I40E_FLAG_FDIR_ENABLED) && @@ -7068,7 +7255,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) return; } - pf->num_lan_qps = pf->rss_size + accum_tc_size; + pf->num_lan_qps = pf->rss_size_max + accum_tc_size; } else if (pf->flags & I40E_FLAG_RSS_ENABLED && (pf->flags & I40E_FLAG_FDIR_ENABLED) && @@ -7084,7 +7271,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) return; } - pf->num_lan_qps = pf->rss_size; + pf->num_lan_qps = pf->rss_size_max; } else if (pf->flags & I40E_FLAG_RSS_ENABLED && (pf->flags & I40E_FLAG_FDIR_ENABLED) && @@ -7104,7 +7291,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) return; } - pf->num_lan_qps = pf->rss_size + accum_tc_size; + pf->num_lan_qps = pf->rss_size_max + accum_tc_size; } else { dev_info(&pf->pdev->dev, @@ -7126,6 +7313,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf) queues_left -= (pf->num_vmdq_vsis * pf->num_vmdq_qps); } + pf->queues_left = queues_left; return; } @@ -7278,6 +7466,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pf_reset; } + /* set up a default setting for link flow control */ + pf->hw.fc.requested_mode = I40E_FC_NONE; + err = i40e_init_adminq(hw); dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw)); if (((hw->nvm.version & I40E_NVM_VERSION_HI_MASK) @@ -7355,7 +7546,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_switch_setup; } - err = i40e_setup_pf_switch(pf); + err = i40e_setup_pf_switch(pf, false); if (err) { dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err); goto err_vsis; @@ -7558,7 +7749,11 @@ static pci_ers_result_t i40e_pci_error_detected(struct pci_dev *pdev, dev_info(&pdev->dev, "%s: error %d\n", __func__, error); /* shutdown all operations */ - i40e_pf_quiesce_all_vsi(pf); + if (!test_bit(__I40E_SUSPENDED, &pf->state)) { + rtnl_lock(); + i40e_prep_for_reset(pf); + rtnl_unlock(); + } /* Request a slot reset */ return PCI_ERS_RESULT_NEED_RESET; @@ -7621,9 +7816,95 @@ static void i40e_pci_error_resume(struct pci_dev *pdev) struct i40e_pf *pf = pci_get_drvdata(pdev); dev_info(&pdev->dev, "%s\n", __func__); + if (test_bit(__I40E_SUSPENDED, &pf->state)) + return; + + rtnl_lock(); i40e_handle_reset_warning(pf); + rtnl_lock(); +} + +/** + * i40e_shutdown - PCI callback for shutting down + * @pdev: PCI device information struct + **/ +static void i40e_shutdown(struct pci_dev *pdev) +{ + struct i40e_pf *pf = pci_get_drvdata(pdev); + + set_bit(__I40E_SUSPENDED, &pf->state); + set_bit(__I40E_DOWN, &pf->state); + rtnl_lock(); + i40e_prep_for_reset(pf); + rtnl_unlock(); + + if (system_state == SYSTEM_POWER_OFF) { + pci_wake_from_d3(pdev, false); /* No WoL support yet */ + pci_set_power_state(pdev, PCI_D3hot); + } +} + +#ifdef CONFIG_PM +/** + * i40e_suspend - PCI callback for moving to D3 + * @pdev: PCI device information struct + **/ +static int i40e_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct i40e_pf *pf = pci_get_drvdata(pdev); + + set_bit(__I40E_SUSPENDED, &pf->state); + set_bit(__I40E_DOWN, &pf->state); + rtnl_lock(); + i40e_prep_for_reset(pf); + rtnl_unlock(); + + pci_wake_from_d3(pdev, false); /* No WoL support yet */ + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +/** + * i40e_resume - PCI callback for waking up from D3 + * @pdev: PCI device information struct + **/ +static int i40e_resume(struct pci_dev *pdev) +{ + struct i40e_pf *pf = pci_get_drvdata(pdev); + u32 err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + /* pci_restore_state() clears dev->state_saves, so + * call pci_save_state() again to restore it. + */ + pci_save_state(pdev); + + err = pci_enable_device_mem(pdev); + if (err) { + dev_err(&pdev->dev, + "%s: Cannot enable PCI device from suspend\n", + __func__); + return err; + } + pci_set_master(pdev); + + /* no wakeup events while running */ + pci_wake_from_d3(pdev, false); + + /* handling the reset will rebuild the device state */ + if (test_and_clear_bit(__I40E_SUSPENDED, &pf->state)) { + clear_bit(__I40E_DOWN, &pf->state); + rtnl_lock(); + i40e_reset_and_rebuild(pf, false); + rtnl_unlock(); + } + + return 0; } +#endif static const struct pci_error_handlers i40e_err_handler = { .error_detected = i40e_pci_error_detected, .slot_reset = i40e_pci_error_slot_reset, @@ -7635,6 +7916,11 @@ static struct pci_driver i40e_driver = { .id_table = i40e_pci_tbl, .probe = i40e_probe, .remove = i40e_remove, +#ifdef CONFIG_PM + .suspend = i40e_suspend, + .resume = i40e_resume, +#endif + .shutdown = i40e_shutdown, .err_handler = &i40e_err_handler, .sriov_configure = i40e_pci_sriov_configure, }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 8ae644570263..72a6028d24e0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -49,6 +49,10 @@ #define I40E_VF_DEVICE_ID 0x154C #define I40E_VF_HV_DEVICE_ID 0x1571 +#define i40e_is_40G_device(d) ((d) == I40E_QSFP_A_DEVICE_ID || \ + (d) == I40E_QSFP_B_DEVICE_ID || \ + (d) == I40E_QSFP_C_DEVICE_ID) + #define I40E_FW_API_VERSION_MAJOR 0x0001 #define I40E_FW_API_VERSION_MINOR 0x0000 diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index e7bdd47bafcf..68e1f8eff9b2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -521,6 +521,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) f = i40e_add_filter(vsi, vf->default_lan_addr.addr, 0, true, false); } + if (!f) { dev_err(&pf->pdev->dev, "Unable to add ucast filter\n"); ret = -ENOMEM; @@ -763,6 +764,7 @@ static void i40e_free_vf_res(struct i40e_vf *vf) vf->lan_vsi_index = 0; vf->lan_vsi_id = 0; } + /* reset some of the state varibles keeping * track of the resources */ @@ -1777,30 +1779,6 @@ error_param: } /** - * i40e_vc_fcoe_msg - * @vf: pointer to the vf info - * @msg: pointer to the msg buffer - * @msglen: msg length - * - * called from the vf for the fcoe msgs - **/ -static int i40e_vc_fcoe_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) -{ - i40e_status aq_ret = 0; - - if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) || - !test_bit(I40E_VF_STAT_FCOEENA, &vf->vf_states)) { - aq_ret = I40E_ERR_PARAM; - goto error_param; - } - aq_ret = I40E_ERR_NOT_IMPLEMENTED; - -error_param: - /* send the response to the vf */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_FCOE, aq_ret); -} - -/** * i40e_vc_validate_vf_msg * @vf: pointer to the vf info * @msg: pointer to the msg buffer @@ -1973,9 +1951,6 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode, case I40E_VIRTCHNL_OP_GET_STATS: ret = i40e_vc_get_stats_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_FCOE: - ret = i40e_vc_fcoe_msg(vf, msg, msglen); - break; case I40E_VIRTCHNL_OP_UNKNOWN: default: dev_err(&pf->pdev->dev, |