net: txgbe: fix to control VLAN strip
authorJiawen Wu <jiawenwu@trustnetic.com>
Fri, 17 May 2024 06:51:40 +0000 (14:51 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 17 May 2024 09:17:36 +0000 (10:17 +0100)
When VLAN tag strip is changed to enable or disable, the hardware requires
the Rx ring to be in a disabled state, otherwise the feature cannot be
changed.

Fixes: f3b03c655f67 ("net: wangxun: Implement vlan add and kill functions")
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/wangxun/libwx/wx_hw.c
drivers/net/ethernet/wangxun/libwx/wx_lib.c
drivers/net/ethernet/wangxun/libwx/wx_type.h
drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
drivers/net/ethernet/wangxun/txgbe/txgbe_type.h

index 3662483bfe2e782953cb895830c772af43a7c4f2..7c4b6881a93fc2bb8edd987aa119edf732814572 100644 (file)
@@ -1958,6 +1958,8 @@ int wx_sw_init(struct wx *wx)
                return -ENOMEM;
        }
 
+       bitmap_zero(wx->state, WX_STATE_NBITS);
+
        return 0;
 }
 EXPORT_SYMBOL(wx_sw_init);
index d0cb09a4bd3d482a938000104854cdc551feaabd..07ba3a270a14fa48ad6d1d9c984c7b12cd36d555 100644 (file)
@@ -2692,9 +2692,9 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features)
 
        netdev->features = features;
 
-       if (changed &
-           (NETIF_F_HW_VLAN_CTAG_RX |
-            NETIF_F_HW_VLAN_STAG_RX))
+       if (wx->mac.type == wx_mac_sp && changed & NETIF_F_HW_VLAN_CTAG_RX)
+               wx->do_reset(netdev);
+       else if (changed & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER))
                wx_set_rx_mode(netdev);
 
        return 0;
index 1fdeb464d5f4a5a8ac6de32b4617518b59b62a76..5aaf7b1fa2db9ca15a075ce7d162cd025f107ed4 100644 (file)
@@ -982,8 +982,13 @@ struct wx_hw_stats {
        u64 qmprc;
 };
 
+enum wx_state {
+       WX_STATE_RESETTING,
+       WX_STATE_NBITS,         /* must be last */
+};
 struct wx {
        unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+       DECLARE_BITMAP(state, WX_STATE_NBITS);
 
        void *priv;
        u8 __iomem *hw_addr;
@@ -1071,6 +1076,8 @@ struct wx {
        u64 hw_csum_rx_good;
        u64 hw_csum_rx_error;
        u64 alloc_rx_buff_failed;
+
+       void (*do_reset)(struct net_device *netdev);
 };
 
 #define WX_INTR_ALL (~0ULL)
@@ -1131,4 +1138,19 @@ static inline struct wx *phylink_to_wx(struct phylink_config *config)
        return container_of(config, struct wx, phylink_config);
 }
 
+static inline int wx_set_state_reset(struct wx *wx)
+{
+       u8 timeout = 50;
+
+       while (test_and_set_bit(WX_STATE_RESETTING, wx->state)) {
+               timeout--;
+               if (!timeout)
+                       return -EBUSY;
+
+               usleep_range(1000, 2000);
+       }
+
+       return 0;
+}
+
 #endif /* _WX_TYPE_H_ */
index 786a652ae64f310bce7a6e31f3a8805d1ba29054..46a5a3e952021a1369d7883a4e3d4eeef212b3b7 100644 (file)
@@ -52,7 +52,7 @@ static int ngbe_set_ringparam(struct net_device *netdev,
        struct wx *wx = netdev_priv(netdev);
        u32 new_rx_count, new_tx_count;
        struct wx_ring *temp_ring;
-       int i;
+       int i, err = 0;
 
        new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD);
        new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE);
@@ -64,6 +64,10 @@ static int ngbe_set_ringparam(struct net_device *netdev,
            new_rx_count == wx->rx_ring_count)
                return 0;
 
+       err = wx_set_state_reset(wx);
+       if (err)
+               return err;
+
        if (!netif_running(wx->netdev)) {
                for (i = 0; i < wx->num_tx_queues; i++)
                        wx->tx_ring[i]->count = new_tx_count;
@@ -72,14 +76,16 @@ static int ngbe_set_ringparam(struct net_device *netdev,
                wx->tx_ring_count = new_tx_count;
                wx->rx_ring_count = new_rx_count;
 
-               return 0;
+               goto clear_reset;
        }
 
        /* allocate temporary buffer to store rings in */
        i = max_t(int, wx->num_tx_queues, wx->num_rx_queues);
        temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL);
-       if (!temp_ring)
-               return -ENOMEM;
+       if (!temp_ring) {
+               err = -ENOMEM;
+               goto clear_reset;
+       }
 
        ngbe_down(wx);
 
@@ -89,7 +95,9 @@ static int ngbe_set_ringparam(struct net_device *netdev,
        wx_configure(wx);
        ngbe_up(wx);
 
-       return 0;
+clear_reset:
+       clear_bit(WX_STATE_RESETTING, wx->state);
+       return err;
 }
 
 static int ngbe_set_channels(struct net_device *dev,
index db675512ce4dc6fcac47243b5c2f7f680df3dba9..31fde3fa7c6b55ec50d1518b31dbf509a939480b 100644 (file)
@@ -19,7 +19,7 @@ static int txgbe_set_ringparam(struct net_device *netdev,
        struct wx *wx = netdev_priv(netdev);
        u32 new_rx_count, new_tx_count;
        struct wx_ring *temp_ring;
-       int i;
+       int i, err = 0;
 
        new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD);
        new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE);
@@ -31,6 +31,10 @@ static int txgbe_set_ringparam(struct net_device *netdev,
            new_rx_count == wx->rx_ring_count)
                return 0;
 
+       err = wx_set_state_reset(wx);
+       if (err)
+               return err;
+
        if (!netif_running(wx->netdev)) {
                for (i = 0; i < wx->num_tx_queues; i++)
                        wx->tx_ring[i]->count = new_tx_count;
@@ -39,14 +43,16 @@ static int txgbe_set_ringparam(struct net_device *netdev,
                wx->tx_ring_count = new_tx_count;
                wx->rx_ring_count = new_rx_count;
 
-               return 0;
+               goto clear_reset;
        }
 
        /* allocate temporary buffer to store rings in */
        i = max_t(int, wx->num_tx_queues, wx->num_rx_queues);
        temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL);
-       if (!temp_ring)
-               return -ENOMEM;
+       if (!temp_ring) {
+               err = -ENOMEM;
+               goto clear_reset;
+       }
 
        txgbe_down(wx);
 
@@ -55,7 +61,9 @@ static int txgbe_set_ringparam(struct net_device *netdev,
 
        txgbe_up(wx);
 
-       return 0;
+clear_reset:
+       clear_bit(WX_STATE_RESETTING, wx->state);
+       return err;
 }
 
 static int txgbe_set_channels(struct net_device *dev,
index b3c0058b045da2b445c6f465653fa09bc234fe52..8c7a74981b907fc3eed08d993a89f7e6ab4a456b 100644 (file)
@@ -269,6 +269,8 @@ static int txgbe_sw_init(struct wx *wx)
        wx->tx_work_limit = TXGBE_DEFAULT_TX_WORK;
        wx->rx_work_limit = TXGBE_DEFAULT_RX_WORK;
 
+       wx->do_reset = txgbe_do_reset;
+
        return 0;
 }
 
@@ -421,6 +423,34 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc)
        return 0;
 }
 
+static void txgbe_reinit_locked(struct wx *wx)
+{
+       int err = 0;
+
+       netif_trans_update(wx->netdev);
+
+       err = wx_set_state_reset(wx);
+       if (err) {
+               wx_err(wx, "wait device reset timeout\n");
+               return;
+       }
+
+       txgbe_down(wx);
+       txgbe_up(wx);
+
+       clear_bit(WX_STATE_RESETTING, wx->state);
+}
+
+void txgbe_do_reset(struct net_device *netdev)
+{
+       struct wx *wx = netdev_priv(netdev);
+
+       if (netif_running(netdev))
+               txgbe_reinit_locked(wx);
+       else
+               txgbe_reset(wx);
+}
+
 static const struct net_device_ops txgbe_netdev_ops = {
        .ndo_open               = txgbe_open,
        .ndo_stop               = txgbe_close,
index 1b4ff50d58571da6a234e1b83df8284fd0cf4bc4..f434a7865cb7b737a9b2197818b95fa5ed85d32e 100644 (file)
@@ -134,6 +134,7 @@ extern char txgbe_driver_name[];
 void txgbe_down(struct wx *wx);
 void txgbe_up(struct wx *wx);
 int txgbe_setup_tc(struct net_device *dev, u8 tc);
+void txgbe_do_reset(struct net_device *netdev);
 
 #define NODE_PROP(_NAME, _PROP)                        \
        (const struct software_node) {          \