ixgbe: Fix calculation of queue with VFs and flow director on interface flap
authorCambda Zhu <cambda@linux.alibaba.com>
Wed, 27 Nov 2019 09:03:55 +0000 (17:03 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Feb 2020 13:05:50 +0000 (13:05 +0000)
[ Upstream commit 4fad78ad6422d9bca62135bbed8b6abc4cbb85b8 ]

This patch fixes the calculation of queue when we restore flow director
filters after resetting adapter. In ixgbe_fdir_filter_restore(), filter's
vf may be zero which makes the queue outside of the rx_ring array.

The calculation is changed to the same as ixgbe_add_ethtool_fdir_entry().

Signed-off-by: Cambda Zhu <cambda@linux.alibaba.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

index 8ad20b7..4c729fa 100644 (file)
@@ -4804,7 +4804,7 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter)
        struct ixgbe_hw *hw = &adapter->hw;
        struct hlist_node *node2;
        struct ixgbe_fdir_filter *filter;
-       u64 action;
+       u8 queue;
 
        spin_lock(&adapter->fdir_perfect_lock);
 
@@ -4813,17 +4813,34 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter)
 
        hlist_for_each_entry_safe(filter, node2,
                                  &adapter->fdir_filter_list, fdir_node) {
-               action = filter->action;
-               if (action != IXGBE_FDIR_DROP_QUEUE && action != 0)
-                       action =
-                       (action >> ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF) - 1;
+               if (filter->action == IXGBE_FDIR_DROP_QUEUE) {
+                       queue = IXGBE_FDIR_DROP_QUEUE;
+               } else {
+                       u32 ring = ethtool_get_flow_spec_ring(filter->action);
+                       u8 vf = ethtool_get_flow_spec_ring_vf(filter->action);
+
+                       if (!vf && (ring >= adapter->num_rx_queues)) {
+                               e_err(drv, "FDIR restore failed without VF, ring: %u\n",
+                                     ring);
+                               continue;
+                       } else if (vf &&
+                                  ((vf > adapter->num_vfs) ||
+                                    ring >= adapter->num_rx_queues_per_pool)) {
+                               e_err(drv, "FDIR restore failed with VF, vf: %hhu, ring: %u\n",
+                                     vf, ring);
+                               continue;
+                       }
+
+                       /* Map the ring onto the absolute queue index */
+                       if (!vf)
+                               queue = adapter->rx_ring[ring]->reg_idx;
+                       else
+                               queue = ((vf - 1) *
+                                       adapter->num_rx_queues_per_pool) + ring;
+               }
 
                ixgbe_fdir_write_perfect_filter_82599(hw,
-                               &filter->filter,
-                               filter->sw_idx,
-                               (action == IXGBE_FDIR_DROP_QUEUE) ?
-                               IXGBE_FDIR_DROP_QUEUE :
-                               adapter->rx_ring[action]->reg_idx);
+                               &filter->filter, filter->sw_idx, queue);
        }
 
        spin_unlock(&adapter->fdir_perfect_lock);