From 819d899863dc019e5e5fff869578b056a93e35db Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 28 Feb 2019 15:26:03 -0800 Subject: [PATCH 01/15] ice: Use pf instead of vsi-back Many times in our functions we have a local variable pf, which is equivalent to vsi->back. Just use pf consistently instead of vsi->back where available. Signed-off-by: Jesse Brandeburg Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 60 ++++++++++++------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 49c75371af085..bda6ade755c38 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -301,7 +301,6 @@ static void ice_vsi_set_num_desc(struct ice_vsi *vsi) static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id) { struct ice_pf *pf = vsi->back; - struct ice_vf *vf = NULL; if (vsi->type == ICE_VSI_VF) @@ -325,8 +324,7 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id) vsi->num_q_vectors = pf->num_vf_msix - 1; break; default: - dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", - vsi->type); + dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); break; } @@ -573,7 +571,7 @@ static int __ice_vsi_get_qs_contig(struct ice_qs_cfg *qs_cfg) /** * __ice_vsi_get_qs_sc - Assign a scattered queues from PF to VSI - * @qs_cfg: gathered variables needed for PF->VSI queues assignment + * @qs_cfg: gathered variables needed for pf->vsi queues assignment * * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap */ @@ -917,6 +915,9 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) { u8 lut_type, hash_type; + struct ice_pf *pf; + + pf = vsi->back; switch (vsi->type) { case ICE_VSI_PF: @@ -930,8 +931,7 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; break; default: - dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", - vsi->type); + dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); return; } @@ -1018,10 +1018,11 @@ static int ice_vsi_init(struct ice_vsi *vsi) static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) { struct ice_q_vector *q_vector; + struct ice_pf *pf = vsi->back; struct ice_ring *ring; if (!vsi->q_vectors[v_idx]) { - dev_dbg(&vsi->back->pdev->dev, "Queue vector at index %d not found\n", + dev_dbg(&pf->pdev->dev, "Queue vector at index %d not found\n", v_idx); return; } @@ -1036,7 +1037,7 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) if (vsi->netdev) netif_napi_del(&q_vector->napi); - devm_kfree(&vsi->back->pdev->dev, q_vector); + devm_kfree(&pf->pdev->dev, q_vector); vsi->q_vectors[v_idx] = NULL; } @@ -1188,8 +1189,7 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) num_q_vectors, vsi->idx); break; default: - dev_warn(&vsi->back->pdev->dev, "Unknown VSI type %d\n", - vsi->type); + dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); break; } @@ -1198,7 +1198,7 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) "Failed to get tracking for %d HW vectors for VSI %d, err=%d\n", num_q_vectors, vsi->vsi_num, vsi->hw_base_vector); if (vsi->type != ICE_VSI_VF) { - ice_free_res(vsi->back->sw_irq_tracker, + ice_free_res(pf->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); pf->num_avail_sw_msix += num_q_vectors; } @@ -1409,13 +1409,13 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) vsi->rss_table_size); if (status) { - dev_err(&vsi->back->pdev->dev, + dev_err(&pf->pdev->dev, "set_rss_lut failed, error %d\n", status); err = -EIO; goto ice_vsi_cfg_rss_exit; } - key = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*key), GFP_KERNEL); + key = devm_kzalloc(&pf->pdev->dev, sizeof(*key), GFP_KERNEL); if (!key) { err = -ENOMEM; goto ice_vsi_cfg_rss_exit; @@ -1432,7 +1432,7 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) status = ice_aq_set_rss_key(&pf->hw, vsi->idx, key); if (status) { - dev_err(&vsi->back->pdev->dev, "set_rss_key failed, error %d\n", + dev_err(&pf->pdev->dev, "set_rss_key failed, error %d\n", status); err = -EIO; } @@ -1717,7 +1717,7 @@ ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings, int offset) i, num_q_grps, qg_buf, buf_len, NULL); if (status) { - dev_err(&vsi->back->pdev->dev, + dev_err(&pf->pdev->dev, "Failed to set LAN Tx queue context, error: %d\n", status); err = -ENODEV; @@ -2148,12 +2148,14 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc) { struct ice_vsi_ctx *ctxt; struct device *dev; + struct ice_pf *pf; int status; if (!vsi) return -EINVAL; - dev = &vsi->back->pdev->dev; + pf = vsi->back; + dev = &pf->pdev->dev; ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return -ENOMEM; @@ -2177,11 +2179,11 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc) cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID | ICE_AQ_VSI_PROP_SW_VALID); - status = ice_update_vsi(&vsi->back->hw, vsi->idx, ctxt, NULL); + status = ice_update_vsi(&pf->hw, vsi->idx, ctxt, NULL); if (status) { netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %d\n", ena ? "En" : "Dis", vsi->idx, vsi->vsi_num, status, - vsi->back->hw.adminq.sq_last_status); + pf->hw.adminq.sq_last_status); goto err_out; } @@ -2378,10 +2380,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, unroll_vector_base: /* reclaim SW interrupts back to the common pool */ - ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); + ice_free_res(pf->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); pf->num_avail_sw_msix += vsi->num_q_vectors; /* reclaim HW interrupt back to the common pool */ - ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); + ice_free_res(pf->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); pf->num_avail_hw_msix += vsi->num_q_vectors; unroll_alloc_q_vector: ice_vsi_free_q_vectors(vsi); @@ -2718,18 +2720,16 @@ int ice_vsi_release(struct ice_vsi *vsi) /* reclaim interrupt vectors back to PF */ if (vsi->type != ICE_VSI_VF) { /* reclaim SW interrupts back to the common pool */ - ice_free_res(vsi->back->sw_irq_tracker, vsi->sw_base_vector, - vsi->idx); + ice_free_res(pf->sw_irq_tracker, vsi->sw_base_vector, vsi->idx); pf->num_avail_sw_msix += vsi->num_q_vectors; /* reclaim HW interrupts back to the common pool */ - ice_free_res(vsi->back->hw_irq_tracker, vsi->hw_base_vector, - vsi->idx); + ice_free_res(pf->hw_irq_tracker, vsi->hw_base_vector, vsi->idx); pf->num_avail_hw_msix += vsi->num_q_vectors; } else if (test_bit(ICE_VF_STATE_CFG_INTR, vf->vf_states)) { /* Reclaim VF resources back only while freeing all VFs or * vector reassignment is requested */ - ice_free_res(vsi->back->hw_irq_tracker, vf->first_vector_idx, + ice_free_res(pf->hw_irq_tracker, vf->first_vector_idx, vsi->idx); pf->num_avail_hw_msix += pf->num_vf_msix; } @@ -2798,7 +2798,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) ice_vsi_clear_rings(vsi); ice_vsi_free_arrays(vsi, false); - ice_dev_onetime_setup(&vsi->back->hw); + ice_dev_onetime_setup(&pf->hw); if (vsi->type == ICE_VSI_VF) ice_vsi_set_num_qs(vsi, vf->vf_id); else @@ -2837,7 +2837,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) * receive traffic on first queue. Hence no need to capture * return value */ - if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) + if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) ice_vsi_cfg_rss_lut_key(vsi); break; case ICE_VSI_VF: @@ -2857,8 +2857,8 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) if (ret) goto err_vectors; - vsi->back->q_left_tx -= vsi->alloc_txq; - vsi->back->q_left_rx -= vsi->alloc_rxq; + pf->q_left_tx -= vsi->alloc_txq; + pf->q_left_rx -= vsi->alloc_rxq; break; default: break; @@ -2889,7 +2889,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) } err_vsi: ice_vsi_clear(vsi); - set_bit(__ICE_RESET_FAILED, vsi->back->state); + set_bit(__ICE_RESET_FAILED, pf->state); return ret; } From a52db6b2601f9904ce7fc4b32537823e5c1eb9ef Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 16 Apr 2019 10:21:14 -0700 Subject: [PATCH 02/15] ice: Fix for allowing too many MDD events on VF Disable VF if any malicious device driver (MDD) event is detected by hardware. Track vf->num_mdd_events for information about VF MDD events. Signed-off-by: Michal Swiatkowski Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 6b27be93bdf54..2352b4129a623 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1185,10 +1185,12 @@ static void ice_handle_mdd_event(struct ice_pf *pf) for (i = 0; i < pf->num_alloc_vfs && mdd_detected; i++) { struct ice_vf *vf = &pf->vf[i]; + mdd_detected = false; + reg = rd32(hw, VP_MDET_TX_PQM(i)); if (reg & VP_MDET_TX_PQM_VALID_M) { wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF); - vf->num_mdd_events++; + mdd_detected = true; dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", i); } @@ -1196,7 +1198,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) reg = rd32(hw, VP_MDET_TX_TCLAN(i)); if (reg & VP_MDET_TX_TCLAN_VALID_M) { wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF); - vf->num_mdd_events++; + mdd_detected = true; dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", i); } @@ -1204,7 +1206,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) reg = rd32(hw, VP_MDET_TX_TDPU(i)); if (reg & VP_MDET_TX_TDPU_VALID_M) { wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF); - vf->num_mdd_events++; + mdd_detected = true; dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", i); } @@ -1212,14 +1214,13 @@ static void ice_handle_mdd_event(struct ice_pf *pf) reg = rd32(hw, VP_MDET_RX(i)); if (reg & VP_MDET_RX_VALID_M) { wr32(hw, VP_MDET_RX(i), 0xFFFF); - vf->num_mdd_events++; + mdd_detected = true; dev_info(&pf->pdev->dev, "RX driver issue detected on VF %d\n", i); } - if (vf->num_mdd_events > ICE_DFLT_NUM_MDD_EVENTS_ALLOWED) { - dev_info(&pf->pdev->dev, - "Too many MDD events on VF %d, disabled\n", i); + if (mdd_detected) { + vf->num_mdd_events++; dev_info(&pf->pdev->dev, "Use PF Control I/F to re-enable the VF\n"); set_bit(ICE_VF_STATE_DIS, vf->vf_states); From e80e76db6c5bbc7a8f8512f3dc630a2170745b0b Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Tue, 16 Apr 2019 10:21:15 -0700 Subject: [PATCH 03/15] ice: Preserve VLAN Rx stripping settings When Tx insertion is set, we are not accounting for the state of Rx stripping. This causes Rx stripping to be enabled any time Tx insertion is changed, even when it's supposed to be disabled. Signed-off-by: Tony Nguyen Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index bda6ade755c38..947730d746120 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1932,6 +1932,10 @@ int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) */ ctxt->info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL; + /* Preserve existing VLAN strip setting */ + ctxt->info.vlan_flags |= (vsi->info.vlan_flags & + ICE_AQ_VSI_VLAN_EMOD_M); + ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); From bb877b22bcb5334fc4e1752fe77e96ab762c3738 Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Tue, 16 Apr 2019 10:21:16 -0700 Subject: [PATCH 04/15] ice: Don't remove VLAN filters that were never programmed In case of non-trusted VFs, it is possible to program VLAN filter far less than what is requested by the VF originally, thereby makes number of VLAN elements being tracked by VF different from actual VLAN tags. This patch makes sure that we are not attempting to remove VLAN filter that does not exist. Signed-off-by: Akeem G Abodunrin Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 6 +++++- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 12 +++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 947730d746120..83d0aef7f77e0 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1616,7 +1616,11 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) list_add(&list->list_entry, &tmp_add_list); status = ice_remove_vlan(&pf->hw, &tmp_add_list); - if (status) { + if (status == ICE_ERR_DOES_NOT_EXIST) { + dev_dbg(&pf->pdev->dev, + "Failed to remove VLAN %d on VSI %i, it does not exist, status: %d\n", + vid, vsi->vsi_num, status); + } else if (status) { dev_err(&pf->pdev->dev, "Error removing VLAN %d on vsi %i error: %d\n", vid, vsi->vsi_num, status); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index abc9587882674..f4b466cd4b7ab 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -2402,7 +2402,17 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) } } } else { - for (i = 0; i < vfl->num_elements; i++) { + /* In case of non_trusted VF, number of VLAN elements passed + * to PF for removal might be greater than number of VLANs + * filter programmed for that VF - So, use actual number of + * VLANS added earlier with add VLAN opcode. In order to avoid + * removing VLAN that doesn't exist, which result to sending + * erroneous failed message back to the VF + */ + int num_vf_vlan; + + num_vf_vlan = vf->num_vlan; + for (i = 0; i < vfl->num_elements && i < num_vf_vlan; i++) { u16 vid = vfl->vlan_id[i]; /* Make sure ice_vsi_kill_vlan is successful before From ba0db585bdb696d28bd6ec3ae9908d45c0bdeb37 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 16 Apr 2019 10:21:17 -0700 Subject: [PATCH 05/15] ice: Add more validation in ice_vc_cfg_irq_map_msg Add few checks to validate msg from iavf driver. Test if we have got enough q_vectors allocated in VSI connected with VF. Add masks for itr_indx and msix_indx to avoid writing to reserved fieldi of QINT. Clear q_vector->num_ring_rx/tx, without it we can increment this value every time we send irq map msg from VF. So after second call this value will be incorrect. Decrement num_vectors from msg, because last vector in iavf msg is misc vector (we don't set map for it). Signed-off-by: Michal Swiatkowski Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 2 ++ .../net/ethernet/intel/ice/ice_hw_autogen.h | 4 +++ drivers/net/ethernet/intel/ice/ice_lib.c | 32 +++++++++++-------- .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 26 +++++++-------- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 804d12c2f1df7..6f970edf50c79 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -83,6 +83,8 @@ extern const char ice_drv_ver[]; #define ICE_MAX_QS_PER_VF 256 #define ICE_MIN_QS_PER_VF 1 #define ICE_DFLT_QS_PER_VF 4 +#define ICE_NONQ_VECS_VF 1 +#define ICE_MAX_SCATTER_QS_PER_VF 16 #define ICE_MAX_BASE_QS_PER_VF 16 #define ICE_MAX_INTR_PER_VF 65 #define ICE_MIN_INTR_PER_VF (ICE_MIN_QS_PER_VF + 1) diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index e172ca002a0aa..ec25f26069b07 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -163,11 +163,15 @@ #define PFINT_OICR_ENA 0x0016C900 #define QINT_RQCTL(_QRX) (0x00150000 + ((_QRX) * 4)) #define QINT_RQCTL_MSIX_INDX_S 0 +#define QINT_RQCTL_MSIX_INDX_M ICE_M(0x7FF, 0) #define QINT_RQCTL_ITR_INDX_S 11 +#define QINT_RQCTL_ITR_INDX_M ICE_M(0x3, 11) #define QINT_RQCTL_CAUSE_ENA_M BIT(30) #define QINT_TQCTL(_DBQM) (0x00140000 + ((_DBQM) * 4)) #define QINT_TQCTL_MSIX_INDX_S 0 +#define QINT_TQCTL_MSIX_INDX_M ICE_M(0x7FF, 0) #define QINT_TQCTL_ITR_INDX_S 11 +#define QINT_TQCTL_ITR_INDX_M ICE_M(0x3, 11) #define QINT_TQCTL_CAUSE_ENA_M BIT(30) #define VPINT_ALLOC(_VF) (0x001D1000 + ((_VF) * 4)) #define VPINT_ALLOC_FIRST_S 0 diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 83d0aef7f77e0..caa00e8873ec7 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1879,33 +1879,37 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) * tracked for this PF. */ for (q = 0; q < q_vector->num_ring_tx; q++) { - int itr_idx = q_vector->tx.itr_idx; + int itr_idx = (q_vector->tx.itr_idx << + QINT_TQCTL_ITR_INDX_S) & + QINT_TQCTL_ITR_INDX_M; u32 val; if (vsi->type == ICE_VSI_VF) - val = QINT_TQCTL_CAUSE_ENA_M | - (itr_idx << QINT_TQCTL_ITR_INDX_S) | - ((i + 1) << QINT_TQCTL_MSIX_INDX_S); + val = QINT_TQCTL_CAUSE_ENA_M | itr_idx | + (((i + 1) << QINT_TQCTL_MSIX_INDX_S) & + QINT_TQCTL_MSIX_INDX_M); else - val = QINT_TQCTL_CAUSE_ENA_M | - (itr_idx << QINT_TQCTL_ITR_INDX_S) | - (reg_idx << QINT_TQCTL_MSIX_INDX_S); + val = QINT_TQCTL_CAUSE_ENA_M | itr_idx | + ((reg_idx << QINT_TQCTL_MSIX_INDX_S) & + QINT_TQCTL_MSIX_INDX_M); wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); txq++; } for (q = 0; q < q_vector->num_ring_rx; q++) { - int itr_idx = q_vector->rx.itr_idx; + int itr_idx = (q_vector->rx.itr_idx << + QINT_RQCTL_ITR_INDX_S) & + QINT_RQCTL_ITR_INDX_M; u32 val; if (vsi->type == ICE_VSI_VF) - val = QINT_RQCTL_CAUSE_ENA_M | - (itr_idx << QINT_RQCTL_ITR_INDX_S) | - ((i + 1) << QINT_RQCTL_MSIX_INDX_S); + val = QINT_RQCTL_CAUSE_ENA_M | itr_idx | + (((i + 1) << QINT_RQCTL_MSIX_INDX_S) & + QINT_RQCTL_MSIX_INDX_M); else - val = QINT_RQCTL_CAUSE_ENA_M | - (itr_idx << QINT_RQCTL_ITR_INDX_S) | - (reg_idx << QINT_RQCTL_MSIX_INDX_S); + val = QINT_RQCTL_CAUSE_ENA_M | itr_idx | + ((reg_idx << QINT_RQCTL_MSIX_INDX_S) & + QINT_RQCTL_MSIX_INDX_M); wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); rxq++; } diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index f4b466cd4b7ab..a805cbdd69be1 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -1814,14 +1814,22 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) struct ice_vsi *vsi = NULL; struct ice_pf *pf = vf->pf; unsigned long qmap; + u16 num_q_vectors; int i; - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + num_q_vectors = irqmap_info->num_vectors - ICE_NONQ_VECS_VF; + vsi = pf->vsi[vf->lan_vsi_idx]; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || + !vsi || vsi->num_q_vectors < num_q_vectors || + irqmap_info->num_vectors == 0) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } - for (i = 0; i < irqmap_info->num_vectors; i++) { + for (i = 0; i < num_q_vectors; i++) { + struct ice_q_vector *q_vector = vsi->q_vectors[i]; + map = &irqmap_info->vecmap[i]; vector_id = map->vector_id; @@ -1833,36 +1841,26 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) goto error_param; } - vsi = pf->vsi[vf->lan_vsi_idx]; - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - /* lookout for the invalid queue index */ qmap = map->rxq_map; + q_vector->num_ring_rx = 0; for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) { - struct ice_q_vector *q_vector; - if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } - q_vector = vsi->q_vectors[i]; q_vector->num_ring_rx++; q_vector->rx.itr_idx = map->rxitr_idx; vsi->rx_rings[vsi_q_id]->q_vector = q_vector; } qmap = map->txq_map; + q_vector->num_ring_tx = 0; for_each_set_bit(vsi_q_id, &qmap, ICE_MAX_BASE_QS_PER_VF) { - struct ice_q_vector *q_vector; - if (!ice_vc_isvalid_q_id(vf, vsi_id, vsi_q_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; } - q_vector = vsi->q_vectors[i]; q_vector->num_ring_tx++; q_vector->tx.itr_idx = map->txitr_idx; vsi->tx_rings[vsi_q_id]->q_vector = q_vector; From 207e3721acb4982f73453762ed8d6f3c7dc3de35 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 16 Apr 2019 10:21:18 -0700 Subject: [PATCH 06/15] ice: Do not unnecessarily initialize local variable The local variable speed does not need to be initialized and can cause some static analysis tools to complain the initial assigned value is never used. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 0f1c2267c9d76..da7878529929f 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1880,10 +1880,10 @@ void ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high, u16 link_speeds_bitmap) { - u16 speed = ICE_AQ_LINK_SPEED_UNKNOWN; u64 pt_high; u64 pt_low; int index; + u16 speed; /* We first check with low part of phy_type */ for (index = 0; index <= ICE_PHY_TYPE_LOW_MAX_INDEX; index++) { From a85a3847fb5164f08e2a5c0cc0b386f0a79293a6 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Tue, 16 Apr 2019 10:21:19 -0700 Subject: [PATCH 07/15] ice: Always free/allocate q_vectors Currently when probing/removing the driver we allocate/deallocate each vsi->q_vectors array in ice_vsi_alloc_arrays() and ice_vsi_free_arrays() respectively. However, we don't do this during the reset and VSI rebuild flow. This is inconsistent and unnecessary to have a difference between the two flows. This patch makes the change to always allocate/deallocate the vsi->q_vectors array regardless of the driver flow we are in. Also, update the comment for ice_vsi_free_arrays() to be more descriptive. Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 34 ++++++++++-------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index caa00e8873ec7..7a88bf639376c 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -232,12 +232,11 @@ static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena) /** * ice_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the VSI * @vsi: 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 ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors) +static int ice_vsi_alloc_arrays(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; @@ -252,15 +251,11 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi, bool alloc_qvectors) if (!vsi->rx_rings) goto err_rxrings; - if (alloc_qvectors) { - /* allocate memory for q_vector pointers */ - vsi->q_vectors = devm_kcalloc(&pf->pdev->dev, - vsi->num_q_vectors, - sizeof(*vsi->q_vectors), - GFP_KERNEL); - if (!vsi->q_vectors) - goto err_vectors; - } + /* allocate memory for q_vector pointers */ + vsi->q_vectors = devm_kcalloc(&pf->pdev->dev, vsi->num_q_vectors, + sizeof(*vsi->q_vectors), GFP_KERNEL); + if (!vsi->q_vectors) + goto err_vectors; return 0; @@ -389,16 +384,15 @@ void ice_vsi_delete(struct ice_vsi *vsi) } /** - * ice_vsi_free_arrays - clean up VSI resources + * ice_vsi_free_arrays - De-allocate queue and vector pointer arrays for the VSI * @vsi: pointer to VSI being cleared - * @free_qvectors: bool to specify if q_vectors should be deallocated */ -static void ice_vsi_free_arrays(struct ice_vsi *vsi, bool free_qvectors) +static void ice_vsi_free_arrays(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; /* free the ring and vector containers */ - if (free_qvectors && vsi->q_vectors) { + if (vsi->q_vectors) { devm_kfree(&pf->pdev->dev, vsi->q_vectors); vsi->q_vectors = NULL; } @@ -446,7 +440,7 @@ int ice_vsi_clear(struct ice_vsi *vsi) if (vsi->idx < pf->next_vsi) pf->next_vsi = vsi->idx; - ice_vsi_free_arrays(vsi, true); + ice_vsi_free_arrays(vsi); mutex_unlock(&pf->sw_mutex); devm_kfree(&pf->pdev->dev, vsi); @@ -512,14 +506,14 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type, u16 vf_id) switch (vsi->type) { case ICE_VSI_PF: - if (ice_vsi_alloc_arrays(vsi, true)) + if (ice_vsi_alloc_arrays(vsi)) goto err_rings; /* Setup default MSIX irq handler for VSI */ vsi->irq_handler = ice_msix_clean_rings; break; case ICE_VSI_VF: - if (ice_vsi_alloc_arrays(vsi, true)) + if (ice_vsi_alloc_arrays(vsi)) goto err_rings; break; default: @@ -2809,7 +2803,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) vsi->hw_base_vector = 0; ice_vsi_clear_rings(vsi); - ice_vsi_free_arrays(vsi, false); + ice_vsi_free_arrays(vsi); ice_dev_onetime_setup(&pf->hw); if (vsi->type == ICE_VSI_VF) ice_vsi_set_num_qs(vsi, vf->vf_id); @@ -2822,7 +2816,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) if (ret < 0) goto err_vsi; - ret = ice_vsi_alloc_arrays(vsi, false); + ret = ice_vsi_alloc_arrays(vsi); if (ret < 0) goto err_vsi; From e40c899a64ca6222ea45a045b2d7a09491274163 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Tue, 16 Apr 2019 10:21:20 -0700 Subject: [PATCH 08/15] ice: Refactor getting/setting coalesce Currently if the driver has an uneven amount of Rx/Tx queues setting the coalesce settings through ethtool will result in an error. This is happening because in the setting coalesce flow we are reporting an error if either Rx or Tx fails. Also, the flow for setting/getting per_q_coalesce and setting/getting coalesce settings for the entire device is different. Fix these issues by adding one function, ice_set_q_coalesce(), and another, ice_get_q_coalesce(), that both getting/setting per_q and entire device coalesce can use. This makes handling the error cases generic between the two flows and simplifies __ice_set_coalesce() and __ice_get_coalesce(). Also, add a header comment to __ice_set_coalesce(). Signed-off-by: Brett Creeley Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_ethtool.c | 152 ++++++++++++------- 1 file changed, 93 insertions(+), 59 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 0bfe696d8077e..08ec2f3c5977c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -2254,50 +2254,61 @@ ice_get_rc_coalesce(struct ethtool_coalesce *ec, enum ice_container_type c_type, return 0; } +/** + * ice_get_q_coalesce - get a queue's ITR/INTRL (coalesce) settings + * @vsi: VSI associated to the queue for getting ITR/INTRL (coalesce) settings + * @ec: coalesce settings to program the device with + * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index + * + * Return 0 on success, and negative under the following conditions: + * 1. Getting Tx or Rx ITR/INTRL (coalesce) settings failed. + * 2. The q_num passed in is not a valid number/index for Tx and Rx rings. + */ +static int +ice_get_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num) +{ + if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { + if (ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, + &vsi->rx_rings[q_num]->q_vector->rx)) + return -EINVAL; + if (ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, + &vsi->tx_rings[q_num]->q_vector->tx)) + return -EINVAL; + } else if (q_num < vsi->num_rxq) { + if (ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, + &vsi->rx_rings[q_num]->q_vector->rx)) + return -EINVAL; + } else if (q_num < vsi->num_txq) { + if (ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, + &vsi->tx_rings[q_num]->q_vector->tx)) + return -EINVAL; + } else { + return -EINVAL; + } + + return 0; +} + /** * __ice_get_coalesce - get ITR/INTRL values for the device * @netdev: pointer to the netdev associated with this query * @ec: ethtool structure to fill with driver's coalesce settings * @q_num: queue number to get the coalesce settings for + * + * If the caller passes in a negative q_num then we return coalesce settings + * based on queue number 0, else use the actual q_num passed in. */ static int __ice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, int q_num) { struct ice_netdev_priv *np = netdev_priv(netdev); - int tx = -EINVAL, rx = -EINVAL; struct ice_vsi *vsi = np->vsi; - if (q_num < 0) { - rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, - &vsi->rx_rings[0]->q_vector->rx); - tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, - &vsi->tx_rings[0]->q_vector->tx); - - goto update_coalesced_frames; - } - - if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { - rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, - &vsi->rx_rings[q_num]->q_vector->rx); - tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, - &vsi->tx_rings[q_num]->q_vector->tx); - } else if (q_num < vsi->num_rxq) { - rx = ice_get_rc_coalesce(ec, ICE_RX_CONTAINER, - &vsi->rx_rings[q_num]->q_vector->rx); - } else if (q_num < vsi->num_txq) { - tx = ice_get_rc_coalesce(ec, ICE_TX_CONTAINER, - &vsi->tx_rings[q_num]->q_vector->tx); - } else { - /* q_num is invalid for both Rx and Tx queues */ - return -EINVAL; - } + if (q_num < 0) + q_num = 0; -update_coalesced_frames: - /* either q_num is invalid for both Rx and Tx queues or setting coalesce - * failed completely - */ - if (tx && rx) + if (ice_get_q_coalesce(vsi, ec, q_num)) return -EINVAL; if (q_num < vsi->num_txq) @@ -2423,54 +2434,77 @@ ice_set_rc_coalesce(enum ice_container_type c_type, struct ethtool_coalesce *ec, return 0; } +/** + * ice_set_q_coalesce - set a queue's ITR/INTRL (coalesce) settings + * @vsi: VSI associated to the queue that need updating + * @ec: coalesce settings to program the device with + * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index + * + * Return 0 on success, and negative under the following conditions: + * 1. Setting Tx or Rx ITR/INTRL (coalesce) settings failed. + * 2. The q_num passed in is not a valid number/index for Tx and Rx rings. + */ +static int +ice_set_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num) +{ + if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { + if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, + &vsi->rx_rings[q_num]->q_vector->rx, + vsi)) + return -EINVAL; + + if (ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, + &vsi->tx_rings[q_num]->q_vector->tx, + vsi)) + return -EINVAL; + } else if (q_num < vsi->num_rxq) { + if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, + &vsi->rx_rings[q_num]->q_vector->rx, + vsi)) + return -EINVAL; + } else if (q_num < vsi->num_txq) { + if (ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, + &vsi->tx_rings[q_num]->q_vector->tx, + vsi)) + return -EINVAL; + } else { + return -EINVAL; + } + + return 0; +} + +/** + * __ice_set_coalesce - set ITR/INTRL values for the device + * @netdev: pointer to the netdev associated with this query + * @ec: ethtool structure to fill with driver's coalesce settings + * @q_num: queue number to get the coalesce settings for + * + * If the caller passes in a negative q_num then we set the coalesce settings + * for all Tx/Rx queues, else use the actual q_num passed in. + */ static int __ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, int q_num) { struct ice_netdev_priv *np = netdev_priv(netdev); - int rx = -EINVAL, tx = -EINVAL; struct ice_vsi *vsi = np->vsi; if (q_num < 0) { int i; ice_for_each_q_vector(vsi, i) { - struct ice_q_vector *q_vector = vsi->q_vectors[i]; - - if (ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, - &q_vector->rx, vsi) || - ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, - &q_vector->tx, vsi)) + if (ice_set_q_coalesce(vsi, ec, i)) return -EINVAL; } - goto set_work_lmt; } - if (q_num < vsi->num_rxq && q_num < vsi->num_txq) { - rx = ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, - &vsi->rx_rings[q_num]->q_vector->rx, - vsi); - tx = ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, - &vsi->tx_rings[q_num]->q_vector->tx, - vsi); - } else if (q_num < vsi->num_rxq) { - rx = ice_set_rc_coalesce(ICE_RX_CONTAINER, ec, - &vsi->rx_rings[q_num]->q_vector->rx, - vsi); - } else if (q_num < vsi->num_txq) { - tx = ice_set_rc_coalesce(ICE_TX_CONTAINER, ec, - &vsi->tx_rings[q_num]->q_vector->tx, - vsi); - } - - /* either q_num is invalid for both Rx and Tx queues or setting coalesce - * failed completely - */ - if (rx && tx) + if (ice_set_q_coalesce(vsi, ec, q_num)) return -EINVAL; set_work_lmt: + if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq) vsi->work_lmt = max(ec->tx_max_coalesced_frames_irq, ec->rx_max_coalesced_frames_irq); From c3a6825e825c73fbb24331b4804a2f589d0985cd Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Tue, 16 Apr 2019 10:21:21 -0700 Subject: [PATCH 09/15] ice: Suppress false-positive style issues reported by static analyzer A recent version of cppcheck falsely reports- Variable ip.hdr is assigned a value that is never used. ip is a union so the pointer ip.hdr is actually used when referenced as ip.v4 and ip.v6. Silence these false reports when using cppcheck with the --inline-suppr command-line option. Signed-off-by: Bruce Allan Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_txrx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index e5af775a3fd96..30f9060c8b3fb 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1849,6 +1849,7 @@ int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off) if (err < 0) return err; + /* cppcheck-suppress unreadVariable */ ip.hdr = skb_network_header(skb); l4.hdr = skb_transport_header(skb); From a03499d614b8d86a7edb4fa0c20e87003248d643 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Tue, 16 Apr 2019 10:21:22 -0700 Subject: [PATCH 10/15] ice: Remove __always_unused attribute The variable netdev is being used in this function; remove the __always_unused attribute from it. Signed-off-by: Tony Nguyen Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 08ec2f3c5977c..1341fde8d53fa 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -1251,7 +1251,7 @@ ice_get_settings_link_up(struct ethtool_link_ksettings *ks, */ static void ice_get_settings_link_down(struct ethtool_link_ksettings *ks, - struct net_device __always_unused *netdev) + struct net_device *netdev) { /* link is down and the driver needs to fall back on * supported PHY types to figure out what info to display From 8f529ff912073f778e3cd74e87fb69a36499fc2f Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Tue, 16 Apr 2019 10:21:23 -0700 Subject: [PATCH 11/15] ice: Separate if conditions for ice_set_features() Set features can have multiple features turned on|off in a single call. Grouping these all in an if/else means after one condition is met, other conditions/features will not be evaluated. Break the if/else statements by feature to ensure all features will be handled properly. Signed-off-by: Tony Nguyen Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 2352b4129a623..aa832d9b24583 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2873,6 +2873,9 @@ ice_set_features(struct net_device *netdev, netdev_features_t features) struct ice_vsi *vsi = np->vsi; int ret = 0; + /* Multiple features can be changed in one call so keep features in + * separate if/else statements to guarantee each feature is checked + */ if (features & NETIF_F_RXHASH && !(netdev->features & NETIF_F_RXHASH)) ret = ice_vsi_manage_rss_lut(vsi, true); else if (!(features & NETIF_F_RXHASH) && @@ -2885,8 +2888,9 @@ ice_set_features(struct net_device *netdev, netdev_features_t features) else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) && (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) ret = ice_vsi_manage_vlan_stripping(vsi, false); - else if ((features & NETIF_F_HW_VLAN_CTAG_TX) && - !(netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) + + if ((features & NETIF_F_HW_VLAN_CTAG_TX) && + !(netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) ret = ice_vsi_manage_vlan_insertion(vsi); else if (!(features & NETIF_F_HW_VLAN_CTAG_TX) && (netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) From d95276ced00060dc3d4d157b1eba61eb7830eb02 Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Tue, 16 Apr 2019 10:21:24 -0700 Subject: [PATCH 12/15] ice: Add function to program ethertype based filter rule on VSIs This patch adds function to program VSI with ethertype based filter rule, so that all flow control frames would be disallowed from being transmitted to the client, in order to prevent malicious VSI, especially VF from sending out PAUSE or PFC frames, and then control other VSIs traffic. Signed-off-by: Akeem G Abodunrin Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 2 + drivers/net/ethernet/intel/ice/ice_lib.c | 55 +++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_switch.c | 59 +++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_switch.h | 4 ++ 4 files changed, 120 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 6f970edf50c79..792e6e42030e1 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -255,6 +255,8 @@ struct ice_vsi { s16 vf_id; /* VF ID for SR-IOV VSIs */ + u16 ethtype; /* Ethernet protocol for pause frame */ + /* RSS config */ u16 rss_table_size; /* HW RSS table size */ u16 rss_size; /* Allocated RSS queues */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 7a88bf639376c..fbf1eba0cc2af 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2250,6 +2250,46 @@ ice_vsi_set_q_vectors_reg_idx(struct ice_vsi *vsi) return -EINVAL; } +/** + * ice_vsi_add_rem_eth_mac - Program VSI ethertype based filter with rule + * @vsi: the VSI being configured + * @add_rule: boolean value to add or remove ethertype filter rule + */ +static void +ice_vsi_add_rem_eth_mac(struct ice_vsi *vsi, bool add_rule) +{ + struct ice_fltr_list_entry *list; + struct ice_pf *pf = vsi->back; + LIST_HEAD(tmp_add_list); + enum ice_status status; + + list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL); + if (!list) + return; + + list->fltr_info.lkup_type = ICE_SW_LKUP_ETHERTYPE; + list->fltr_info.fltr_act = ICE_DROP_PACKET; + list->fltr_info.flag = ICE_FLTR_TX; + list->fltr_info.src_id = ICE_SRC_ID_VSI; + list->fltr_info.vsi_handle = vsi->idx; + list->fltr_info.l_data.ethertype_mac.ethertype = vsi->ethtype; + + INIT_LIST_HEAD(&list->list_entry); + list_add(&list->list_entry, &tmp_add_list); + + if (add_rule) + status = ice_add_eth_mac(&pf->hw, &tmp_add_list); + else + status = ice_remove_eth_mac(&pf->hw, &tmp_add_list); + + if (status) + dev_err(&pf->pdev->dev, + "Failure Adding or Removing Ethertype on VSI %i error: %d\n", + vsi->vsi_num, status); + + ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); +} + /** * ice_vsi_setup - Set up a VSI by a given type * @pf: board private structure @@ -2285,6 +2325,9 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, vsi->port_info = pi; vsi->vsw = pf->first_sw; + if (vsi->type == ICE_VSI_PF) + vsi->ethtype = ETH_P_PAUSE; + if (vsi->type == ICE_VSI_VF) vsi->vf_id = vf_id; @@ -2382,6 +2425,15 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, goto unroll_vector_base; } + /* Add switch rule to drop all Tx Flow Control Frames, of look up + * type ETHERTYPE from VSIs, and restrict malicious VF from sending + * out PAUSE or PFC frames. If enabled, FW can still send FC frames. + * The rule is added once for PF VSI in order to create appropriate + * recipe, since VSI/VSI list is ignored with drop action... + */ + if (vsi->type == ICE_VSI_PF) + ice_vsi_add_rem_eth_mac(vsi, true); + return vsi; unroll_vector_base: @@ -2740,6 +2792,9 @@ int ice_vsi_release(struct ice_vsi *vsi) pf->num_avail_hw_msix += pf->num_vf_msix; } + if (vsi->type == ICE_VSI_PF) + ice_vsi_add_rem_eth_mac(vsi, false); + ice_remove_vsi_fltr(&pf->hw, vsi->idx); ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx); ice_vsi_delete(vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 81f44939c8597..9f1f595ae7e67 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -1969,6 +1969,65 @@ ice_add_vlan(struct ice_hw *hw, struct list_head *v_list) return 0; } +/** + * ice_add_eth_mac - Add ethertype and MAC based filter rule + * @hw: pointer to the hardware structure + * @em_list: list of ether type MAC filter, MAC is optional + */ +enum ice_status +ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list) +{ + struct ice_fltr_list_entry *em_list_itr; + + if (!em_list || !hw) + return ICE_ERR_PARAM; + + list_for_each_entry(em_list_itr, em_list, list_entry) { + enum ice_sw_lkup_type l_type = + em_list_itr->fltr_info.lkup_type; + + if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && + l_type != ICE_SW_LKUP_ETHERTYPE) + return ICE_ERR_PARAM; + + em_list_itr->fltr_info.flag = ICE_FLTR_TX; + em_list_itr->status = ice_add_rule_internal(hw, l_type, + em_list_itr); + if (em_list_itr->status) + return em_list_itr->status; + } + return 0; +} + +/** + * ice_remove_eth_mac - Remove an ethertype (or MAC) based filter rule + * @hw: pointer to the hardware structure + * @em_list: list of ethertype or ethertype MAC entries + */ +enum ice_status +ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list) +{ + struct ice_fltr_list_entry *em_list_itr, *tmp; + + if (!em_list || !hw) + return ICE_ERR_PARAM; + + list_for_each_entry_safe(em_list_itr, tmp, em_list, list_entry) { + enum ice_sw_lkup_type l_type = + em_list_itr->fltr_info.lkup_type; + + if (l_type != ICE_SW_LKUP_ETHERTYPE_MAC && + l_type != ICE_SW_LKUP_ETHERTYPE) + return ICE_ERR_PARAM; + + em_list_itr->status = ice_remove_rule_internal(hw, l_type, + em_list_itr); + if (em_list_itr->status) + return em_list_itr->status; + } + return 0; +} + /** * ice_rem_sw_rule_info * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 88eb4be4d5a49..732b0b9b2e156 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -218,6 +218,10 @@ enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw); enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw); enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst); enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst); +enum ice_status +ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list); +enum ice_status +ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list); void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_handle); enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *m_list); From 0437f1a98a2812ad8f03673f688be9b2310accf8 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 16 Apr 2019 10:21:25 -0700 Subject: [PATCH 13/15] ice: Use bitfields where possible The driver was converted to not use bool, but it was neglected that the bools should have been converted to bit fields as bit fields in software structures are ok, as long as they use the correct kinds of unsigned types. This avoids wasting lots of storage space to store single bit values. One of the change hunks moves a variable lport out of a group of "combinable" bit fields because all bits of the u8 lport are valid and the variable can be packed in the struct in struct holes. Signed-off-by: Jesse Brandeburg Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_type.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 77bc0439e1085..a862af4cbf78b 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -326,6 +326,8 @@ struct ice_port_info { u8 port_state; #define ICE_SCHED_PORT_STATE_INIT 0x0 #define ICE_SCHED_PORT_STATE_READY 0x1 + u8 lport; +#define ICE_LPORT_MASK 0xff u16 dflt_tx_vsi_rule_id; u16 dflt_tx_vsi_num; u16 dflt_rx_vsi_rule_id; @@ -339,11 +341,9 @@ struct ice_port_info { struct ice_dcbx_cfg remote_dcbx_cfg; /* Peer Cfg */ struct ice_dcbx_cfg desired_dcbx_cfg; /* CEE Desired Cfg */ /* LLDP/DCBX Status */ - u8 dcbx_status; - u8 is_sw_lldp; - u8 lport; -#define ICE_LPORT_MASK 0xff - u8 is_vf; + u8 dcbx_status:3; /* see ICE_DCBX_STATUS_DIS */ + u8 is_sw_lldp:1; + u8 is_vf:1; }; struct ice_switch_info { From 0690527014936ef70b186bcccd1a5311e9071899 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 16 Apr 2019 10:21:26 -0700 Subject: [PATCH 14/15] ice: Use more efficient structures Move a bunch of members around to make more efficient use of memory, eliminating holes where possible. None of these members are hot path so cache line alignment is not very important here. Signed-off-by: Jesse Brandeburg Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h index 0038a4109c994..e0585394d984e 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.h +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h @@ -79,6 +79,7 @@ struct ice_rq_event_info { /* Control Queue information */ struct ice_ctl_q_info { enum ice_ctl_q qtype; + enum ice_aq_err rq_last_status; /* last status on receive queue */ struct ice_ctl_q_ring rq; /* receive queue */ struct ice_ctl_q_ring sq; /* send queue */ u32 sq_cmd_timeout; /* send queue cmd write back timeout */ @@ -86,10 +87,9 @@ struct ice_ctl_q_info { u16 num_sq_entries; /* send queue depth */ u16 rq_buf_size; /* receive queue buffer size */ u16 sq_buf_size; /* send queue buffer size */ + enum ice_aq_err sq_last_status; /* last status on send queue */ struct mutex sq_lock; /* Send queue lock */ struct mutex rq_lock; /* Receive queue lock */ - enum ice_aq_err sq_last_status; /* last status on send queue */ - enum ice_aq_err rq_last_status; /* last status on receive queue */ }; #endif /* _ICE_CONTROLQ_H_ */ From 64439f8f0bc4e9da1c6cb31c2ee642e3139f5731 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Tue, 16 Apr 2019 10:21:27 -0700 Subject: [PATCH 15/15] ice: Disable sniffing VF traffic on PF Delete code that add default Tx rule on PF. With this rule PF can see Tx VF traffic that should go outside. For traffic from VF to another VF default Tx rule on PF doesn't apply because of lower priority than VF mac rule. With this change on PF in promisc mode we can see only Rx traffic that doesn't match any other rule (mac etc.). We can't see Tx traffic from other VSI. Signed-off-by: Michal Swiatkowski Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 24 ++--------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index aa832d9b24583..7843abf4d44df 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -317,42 +317,22 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) test_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags)) { clear_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags); if (vsi->current_netdev_flags & IFF_PROMISC) { - /* Apply Tx filter rule to get traffic from VMs */ - status = ice_cfg_dflt_vsi(hw, vsi->idx, true, - ICE_FLTR_TX); - if (status) { - netdev_err(netdev, "Error setting default VSI %i tx rule\n", - vsi->vsi_num); - vsi->current_netdev_flags &= ~IFF_PROMISC; - err = -EIO; - goto out_promisc; - } /* Apply Rx filter rule to get traffic from wire */ status = ice_cfg_dflt_vsi(hw, vsi->idx, true, ICE_FLTR_RX); if (status) { - netdev_err(netdev, "Error setting default VSI %i rx rule\n", + netdev_err(netdev, "Error setting default VSI %i Rx rule\n", vsi->vsi_num); vsi->current_netdev_flags &= ~IFF_PROMISC; err = -EIO; goto out_promisc; } } else { - /* Clear Tx filter rule to stop traffic from VMs */ - status = ice_cfg_dflt_vsi(hw, vsi->idx, false, - ICE_FLTR_TX); - if (status) { - netdev_err(netdev, "Error clearing default VSI %i tx rule\n", - vsi->vsi_num); - vsi->current_netdev_flags |= IFF_PROMISC; - err = -EIO; - goto out_promisc; - } /* Clear Rx filter to remove traffic from wire */ status = ice_cfg_dflt_vsi(hw, vsi->idx, false, ICE_FLTR_RX); if (status) { - netdev_err(netdev, "Error clearing default VSI %i rx rule\n", + netdev_err(netdev, "Error clearing default VSI %i Rx rule\n", vsi->vsi_num); vsi->current_netdev_flags |= IFF_PROMISC; err = -EIO;