net: wangxun: add ethtool_ops for ring parameters
authorJiawen Wu <jiawenwu@trustnetic.com>
Wed, 3 Jan 2024 02:08:51 +0000 (10:08 +0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 4 Jan 2024 10:49:35 +0000 (10:49 +0000)
Support to query RX/TX depth with ethtool -g, and change RX/TX depth
with ethtool -G.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
drivers/net/ethernet/wangxun/libwx/wx_ethtool.h
drivers/net/ethernet/wangxun/libwx/wx_lib.c
drivers/net/ethernet/wangxun/libwx/wx_lib.h
drivers/net/ethernet/wangxun/libwx/wx_type.h
drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
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 e010303174df01ecbfc38f8e80c99dac9ac4d884..225ce36586f8aa9e6173ba30a17362b16613aeac 100644 (file)
@@ -229,3 +229,21 @@ int wx_set_pauseparam(struct net_device *netdev,
        return phylink_ethtool_set_pauseparam(wx->phylink, pause);
 }
 EXPORT_SYMBOL(wx_set_pauseparam);
+
+void wx_get_ringparam(struct net_device *netdev,
+                     struct ethtool_ringparam *ring,
+                     struct kernel_ethtool_ringparam *kernel_ring,
+                     struct netlink_ext_ack *extack)
+{
+       struct wx *wx = netdev_priv(netdev);
+
+       ring->rx_max_pending = WX_MAX_RXD;
+       ring->tx_max_pending = WX_MAX_TXD;
+       ring->rx_mini_max_pending = 0;
+       ring->rx_jumbo_max_pending = 0;
+       ring->rx_pending = wx->rx_ring_count;
+       ring->tx_pending = wx->tx_ring_count;
+       ring->rx_mini_pending = 0;
+       ring->rx_jumbo_pending = 0;
+}
+EXPORT_SYMBOL(wx_get_ringparam);
index 7d3d85f212eba17728cbc499421e21dd927f8e77..7651ec4b7dd95559a5f9d2d675da59557510a787 100644 (file)
@@ -22,4 +22,8 @@ void wx_get_pauseparam(struct net_device *netdev,
                       struct ethtool_pauseparam *pause);
 int wx_set_pauseparam(struct net_device *netdev,
                      struct ethtool_pauseparam *pause);
+void wx_get_ringparam(struct net_device *netdev,
+                     struct ethtool_ringparam *ring,
+                     struct kernel_ethtool_ringparam *kernel_ring,
+                     struct netlink_ext_ack *extack);
 #endif /* _WX_ETHTOOL_H_ */
index 347d3cec02a363652e9e0a6e13add05794d69a1a..b0b1ac545d5db4d621c4a4af3758f56a7025de82 100644 (file)
@@ -2671,4 +2671,70 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features)
 }
 EXPORT_SYMBOL(wx_set_features);
 
+void wx_set_ring(struct wx *wx, u32 new_tx_count,
+                u32 new_rx_count, struct wx_ring *temp_ring)
+{
+       int i, err = 0;
+
+       /* Setup new Tx resources and free the old Tx resources in that order.
+        * We can then assign the new resources to the rings via a memcpy.
+        * The advantage to this approach is that we are guaranteed to still
+        * have resources even in the case of an allocation failure.
+        */
+       if (new_tx_count != wx->tx_ring_count) {
+               for (i = 0; i < wx->num_tx_queues; i++) {
+                       memcpy(&temp_ring[i], wx->tx_ring[i],
+                              sizeof(struct wx_ring));
+
+                       temp_ring[i].count = new_tx_count;
+                       err = wx_setup_tx_resources(&temp_ring[i]);
+                       if (err) {
+                               wx_err(wx, "setup new tx resources failed, keep using the old config\n");
+                               while (i) {
+                                       i--;
+                                       wx_free_tx_resources(&temp_ring[i]);
+                               }
+                               return;
+                       }
+               }
+
+               for (i = 0; i < wx->num_tx_queues; i++) {
+                       wx_free_tx_resources(wx->tx_ring[i]);
+
+                       memcpy(wx->tx_ring[i], &temp_ring[i],
+                              sizeof(struct wx_ring));
+               }
+
+               wx->tx_ring_count = new_tx_count;
+       }
+
+       /* Repeat the process for the Rx rings if needed */
+       if (new_rx_count != wx->rx_ring_count) {
+               for (i = 0; i < wx->num_rx_queues; i++) {
+                       memcpy(&temp_ring[i], wx->rx_ring[i],
+                              sizeof(struct wx_ring));
+
+                       temp_ring[i].count = new_rx_count;
+                       err = wx_setup_rx_resources(&temp_ring[i]);
+                       if (err) {
+                               wx_err(wx, "setup new rx resources failed, keep using the old config\n");
+                               while (i) {
+                                       i--;
+                                       wx_free_rx_resources(&temp_ring[i]);
+                               }
+                               return;
+                       }
+               }
+
+               for (i = 0; i < wx->num_rx_queues; i++) {
+                       wx_free_rx_resources(wx->rx_ring[i]);
+                       memcpy(wx->rx_ring[i], &temp_ring[i],
+                              sizeof(struct wx_ring));
+               }
+
+               wx->rx_ring_count = new_rx_count;
+       }
+}
+EXPORT_SYMBOL(wx_set_ring);
+
 MODULE_LICENSE("GPL");
index df1f4a5951f06ccb44e583ac6a3301838e999832..af1381c13d9ea55c37aa35c0a6a863e72dc969f6 100644 (file)
@@ -29,5 +29,7 @@ int wx_setup_resources(struct wx *wx);
 void wx_get_stats64(struct net_device *netdev,
                    struct rtnl_link_stats64 *stats);
 int wx_set_features(struct net_device *netdev, netdev_features_t features);
+void wx_set_ring(struct wx *wx, u32 new_tx_count,
+                u32 new_rx_count, struct wx_ring *temp_ring);
 
 #endif /* _NGBE_LIB_H_ */
index 561f752defec1e6198a8348fa790b407b35d8ddc..24588bc1eb5770068eebafdf3fa711fabf5df7b8 100644 (file)
@@ -412,6 +412,12 @@ enum WX_MSCA_CMD_value {
 
 #define WX_MAX_RXD                   8192
 #define WX_MAX_TXD                   8192
+#define WX_MIN_RXD                   128
+#define WX_MIN_TXD                   128
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define WX_REQ_RX_DESCRIPTOR_MULTIPLE   8
+#define WX_REQ_TX_DESCRIPTOR_MULTIPLE   8
 
 #define WX_MAX_JUMBO_FRAME_SIZE      9432 /* max payload 9414 */
 #define VMDQ_P(p)                    p
index 9a89f9576180428634a58b3664d3b1b15fb2dd76..52d4167dcabecf7e8131da72bac66aa111e9bf04 100644 (file)
@@ -7,7 +7,10 @@
 
 #include "../libwx/wx_ethtool.h"
 #include "../libwx/wx_type.h"
+#include "../libwx/wx_lib.h"
+#include "../libwx/wx_hw.h"
 #include "ngbe_ethtool.h"
+#include "ngbe_type.h"
 
 static void ngbe_get_wol(struct net_device *netdev,
                         struct ethtool_wolinfo *wol)
@@ -41,6 +44,54 @@ static int ngbe_set_wol(struct net_device *netdev,
        return 0;
 }
 
+static int ngbe_set_ringparam(struct net_device *netdev,
+                             struct ethtool_ringparam *ring,
+                             struct kernel_ethtool_ringparam *kernel_ring,
+                             struct netlink_ext_ack *extack)
+{
+       struct wx *wx = netdev_priv(netdev);
+       u32 new_rx_count, new_tx_count;
+       struct wx_ring *temp_ring;
+       int i;
+
+       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);
+
+       new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD);
+       new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+       if (new_tx_count == wx->tx_ring_count &&
+           new_rx_count == wx->rx_ring_count)
+               return 0;
+
+       if (!netif_running(wx->netdev)) {
+               for (i = 0; i < wx->num_tx_queues; i++)
+                       wx->tx_ring[i]->count = new_tx_count;
+               for (i = 0; i < wx->num_rx_queues; i++)
+                       wx->rx_ring[i]->count = new_rx_count;
+               wx->tx_ring_count = new_tx_count;
+               wx->rx_ring_count = new_rx_count;
+
+               return 0;
+       }
+
+       /* 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;
+
+       ngbe_down(wx);
+
+       wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
+       kvfree(temp_ring);
+
+       wx_configure(wx);
+       ngbe_up(wx);
+
+       return 0;
+}
+
 static const struct ethtool_ops ngbe_ethtool_ops = {
        .get_drvinfo            = wx_get_drvinfo,
        .get_link               = ethtool_op_get_link,
@@ -56,6 +107,8 @@ static const struct ethtool_ops ngbe_ethtool_ops = {
        .get_pause_stats        = wx_get_pause_stats,
        .get_pauseparam         = wx_get_pauseparam,
        .set_pauseparam         = wx_set_pauseparam,
+       .get_ringparam          = wx_get_ringparam,
+       .set_ringparam          = ngbe_set_ringparam,
 };
 
 void ngbe_set_ethtool_ops(struct net_device *netdev)
index db5cae8384e53307d48e3e9bb3a57d03b9ba6e0f..96d80c595cb8621e82bb0b3a497f36231562f20c 100644 (file)
@@ -334,7 +334,7 @@ static void ngbe_disable_device(struct wx *wx)
        wx_update_stats(wx);
 }
 
-static void ngbe_down(struct wx *wx)
+void ngbe_down(struct wx *wx)
 {
        phylink_stop(wx->phylink);
        ngbe_disable_device(wx);
@@ -342,7 +342,7 @@ static void ngbe_down(struct wx *wx)
        wx_clean_all_rx_rings(wx);
 }
 
-static void ngbe_up(struct wx *wx)
+void ngbe_up(struct wx *wx)
 {
        wx_configure_vectors(wx);
 
index ff754d69bdf6c89828940e298045a01587264dbc..0a98080a197af8bbe8904aae462793d3de077325 100644 (file)
 
 extern char ngbe_driver_name[];
 
+void ngbe_down(struct wx *wx);
+void ngbe_up(struct wx *wx);
+
 #endif /* _NGBE_TYPE_H_ */
index cdaa1952824888e221845d656c06650e0a97786d..bd817248a8311c26166458b20c7f2c27c06d8670 100644 (file)
@@ -7,9 +7,57 @@
 
 #include "../libwx/wx_ethtool.h"
 #include "../libwx/wx_type.h"
+#include "../libwx/wx_lib.h"
 #include "txgbe_type.h"
 #include "txgbe_ethtool.h"
 
+static int txgbe_set_ringparam(struct net_device *netdev,
+                              struct ethtool_ringparam *ring,
+                              struct kernel_ethtool_ringparam *kernel_ring,
+                              struct netlink_ext_ack *extack)
+{
+       struct wx *wx = netdev_priv(netdev);
+       u32 new_rx_count, new_tx_count;
+       struct wx_ring *temp_ring;
+       int i;
+
+       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);
+
+       new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD);
+       new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+       if (new_tx_count == wx->tx_ring_count &&
+           new_rx_count == wx->rx_ring_count)
+               return 0;
+
+       if (!netif_running(wx->netdev)) {
+               for (i = 0; i < wx->num_tx_queues; i++)
+                       wx->tx_ring[i]->count = new_tx_count;
+               for (i = 0; i < wx->num_rx_queues; i++)
+                       wx->rx_ring[i]->count = new_rx_count;
+               wx->tx_ring_count = new_tx_count;
+               wx->rx_ring_count = new_rx_count;
+
+               return 0;
+       }
+
+       /* 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;
+
+       txgbe_down(wx);
+
+       wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
+       kvfree(temp_ring);
+
+       txgbe_up(wx);
+
+       return 0;
+}
+
 static const struct ethtool_ops txgbe_ethtool_ops = {
        .get_drvinfo            = wx_get_drvinfo,
        .nway_reset             = wx_nway_reset,
@@ -23,6 +71,8 @@ static const struct ethtool_ops txgbe_ethtool_ops = {
        .get_pause_stats        = wx_get_pause_stats,
        .get_pauseparam         = wx_get_pauseparam,
        .set_pauseparam         = wx_set_pauseparam,
+       .get_ringparam          = wx_get_ringparam,
+       .set_ringparam          = txgbe_set_ringparam,
 };
 
 void txgbe_set_ethtool_ops(struct net_device *netdev)
index 1007ae2541ce35794c3d1ca59c0b40ca315377c0..bcc47bc6264ab33c92bc0ae2cb75e65a16a44628 100644 (file)
@@ -288,7 +288,7 @@ static void txgbe_disable_device(struct wx *wx)
        wx_update_stats(wx);
 }
 
-static void txgbe_down(struct wx *wx)
+void txgbe_down(struct wx *wx)
 {
        txgbe_disable_device(wx);
        txgbe_reset(wx);
@@ -298,6 +298,12 @@ static void txgbe_down(struct wx *wx)
        wx_clean_all_rx_rings(wx);
 }
 
+void txgbe_up(struct wx *wx)
+{
+       wx_configure(wx);
+       txgbe_up_complete(wx);
+}
+
 /**
  *  txgbe_init_type_code - Initialize the shared code
  *  @wx: pointer to hardware structure
index 5494ea88df0a2071ff66fbcff0d7dacba8214822..801fd0aed1ff5ced2f1ecd626f4d08fed188a3d6 100644 (file)
 
 extern char txgbe_driver_name[];
 
+void txgbe_down(struct wx *wx);
+void txgbe_up(struct wx *wx);
+
 #define NODE_PROP(_NAME, _PROP)                        \
        (const struct software_node) {          \
                .name = _NAME,                  \