From: Andrii Staikov <[email protected]>

[ Upstream commit 31deb12e85c35ddd2c037f0107d05d8674cab2c0 ]

Currently, if a VF is disabled using the
'ip link set dev $ETHX vf $VF_NUM state disable' command, the VF is still
able to receive traffic.

Fix the behavior of the 'ip link set dev $ETHX vf $VF_NUM state disable'
to completely shutdown the VF's queues making it entirely disabled and
not able to receive or send any traffic.

Modify the behavior of the 'ip link set $ETHX vf $VF_NUM state enable'
command to make a VF do reinitialization bringing the queues back up.

Co-developed-by: Aleksandr Loktionov <[email protected]>
Signed-off-by: Aleksandr Loktionov <[email protected]>
Reviewed-by: Jan Sokolowski <[email protected]>
Reviewed-by: Wojciech Drewek <[email protected]>
Reviewed-by: Przemek Kitszel <[email protected]>
Signed-off-by: Andrii Staikov <[email protected]>
Tested-by: Rafal Romanowski <[email protected]>
Signed-off-by: Tony Nguyen <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
---
 .../ethernet/intel/i40e/i40e_virtchnl_pf.c    | 32 +++++++++++++++++++
 .../ethernet/intel/i40e/i40e_virtchnl_pf.h    |  1 +
 2 files changed, 33 insertions(+)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c 
b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index dfaa34f2473a..91892d07124f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -2519,6 +2519,14 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, 
u8 *msg)
        i40e_status aq_ret = 0;
        int i;
 
+       if (vf->is_disabled_from_host) {
+               aq_ret = -EPERM;
+               dev_info(&pf->pdev->dev,
+                        "Admin has disabled VF %d, will not enable queues\n",
+                        vf->vf_id);
+               goto error_param;
+       }
+
        if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
                aq_ret = I40E_ERR_PARAM;
                goto error_param;
@@ -4561,9 +4569,12 @@ int i40e_ndo_set_vf_link_state(struct net_device 
*netdev, int vf_id, int link)
        struct i40e_pf *pf = np->vsi->back;
        struct virtchnl_pf_event pfe;
        struct i40e_hw *hw = &pf->hw;
+       struct i40e_vsi *vsi;
+       unsigned long q_map;
        struct i40e_vf *vf;
        int abs_vf_id;
        int ret = 0;
+       int tmp;
 
        if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
                dev_warn(&pf->pdev->dev, "Unable to configure VFs, other 
operation is pending.\n");
@@ -4586,6 +4597,9 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, 
int vf_id, int link)
        switch (link) {
        case IFLA_VF_LINK_STATE_AUTO:
                vf->link_forced = false;
+               vf->is_disabled_from_host = false;
+               /* reset needed to reinit VF resources */
+               i40e_vc_reset_vf(vf, true);
                pfe.event_data.link_event.link_status =
                        pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP;
                pfe.event_data.link_event.link_speed =
@@ -4595,6 +4609,9 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, 
int vf_id, int link)
        case IFLA_VF_LINK_STATE_ENABLE:
                vf->link_forced = true;
                vf->link_up = true;
+               vf->is_disabled_from_host = false;
+               /* reset needed to reinit VF resources */
+               i40e_vc_reset_vf(vf, true);
                pfe.event_data.link_event.link_status = true;
                pfe.event_data.link_event.link_speed = VIRTCHNL_LINK_SPEED_40GB;
                break;
@@ -4603,6 +4620,21 @@ int i40e_ndo_set_vf_link_state(struct net_device 
*netdev, int vf_id, int link)
                vf->link_up = false;
                pfe.event_data.link_event.link_status = false;
                pfe.event_data.link_event.link_speed = 0;
+
+               vsi = pf->vsi[vf->lan_vsi_idx];
+               q_map = BIT(vsi->num_queue_pairs) - 1;
+
+               vf->is_disabled_from_host = true;
+
+               /* Try to stop both Tx&Rx rings even if one of the calls fails
+                * to ensure we stop the rings even in case of errors.
+                * If any of them returns with an error then the first
+                * error that occurred will be returned.
+                */
+               tmp = i40e_ctrl_vf_tx_rings(vsi, q_map, false);
+               ret = i40e_ctrl_vf_rx_rings(vsi, q_map, false);
+
+               ret = tmp ? tmp : ret;
                break;
        default:
                ret = -EINVAL;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h 
b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index 358bbdb58795..010e5730465e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -98,6 +98,7 @@ struct i40e_vf {
        bool link_forced;
        bool link_up;           /* only valid if VF link is forced */
        bool spoofchk;
+       bool is_disabled_from_host; /* PF ctrl of VF enable/disable */
        u16 num_vlan;
 
        /* ADq related variables */
-- 
2.43.0

Reply via email to