|
@@ -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);
|
|
@@ -4118,6 +4131,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
|
|
@@ -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);
|
|
@@ -5679,6 +5719,42 @@ static int i40e_config_rss(struct i40e_pf *pf)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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;
|
|
|
|
|
@@ -6253,6 +6328,69 @@ vector_setup_out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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
|
|
@@ -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,
|
|
|
};
|