net: stmmac: add ethtool support for get/set channels
authorOng Boon Leong <boon.leong.ong@intel.com>
Tue, 15 Sep 2020 01:28:38 +0000 (09:28 +0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Sep 2020 22:39:31 +0000 (15:39 -0700)
Restructure NAPI add and delete process so that we can call them
accordingly in open() and ethtool_set_channels() accordingly.

Introduced stmmac_reinit_queues() to handle the transition needed
for changing Rx & Tx channels accordingly.

Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

index 9c02fc754bf1b8a1126ce5a9c0a6ba44ef319e33..509ce067538e65deee7701af12d20f50b8307173 100644 (file)
@@ -264,6 +264,7 @@ int stmmac_dvr_probe(struct device *device,
                     struct stmmac_resources *res);
 void stmmac_disable_eee_mode(struct stmmac_priv *priv);
 bool stmmac_eee_init(struct stmmac_priv *priv);
+int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
 
 #if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
 void stmmac_selftest_run(struct net_device *dev,
index ac5e8cc5fb9f53d3ba29d0f93df3ebee37a1e64c..db681287c2732db12f6bb1fa4af1f19173ccc98c 100644 (file)
@@ -840,6 +840,30 @@ static int stmmac_set_rxfh(struct net_device *dev, const u32 *indir,
                                    priv->plat->rx_queues_to_use);
 }
 
+static void stmmac_get_channels(struct net_device *dev,
+                               struct ethtool_channels *chan)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+
+       chan->rx_count = priv->plat->rx_queues_to_use;
+       chan->tx_count = priv->plat->tx_queues_to_use;
+       chan->max_rx = priv->dma_cap.number_rx_queues;
+       chan->max_tx = priv->dma_cap.number_tx_queues;
+}
+
+static int stmmac_set_channels(struct net_device *dev,
+                              struct ethtool_channels *chan)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+
+       if (chan->rx_count > priv->dma_cap.number_rx_queues ||
+           chan->tx_count > priv->dma_cap.number_tx_queues ||
+           !chan->rx_count || !chan->tx_count)
+               return -EINVAL;
+
+       return stmmac_reinit_queues(dev, chan->rx_count, chan->tx_count);
+}
+
 static int stmmac_get_ts_info(struct net_device *dev,
                              struct ethtool_ts_info *info)
 {
@@ -941,6 +965,8 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
        .get_ts_info = stmmac_get_ts_info,
        .get_coalesce = stmmac_get_coalesce,
        .set_coalesce = stmmac_set_coalesce,
+       .get_channels = stmmac_get_channels,
+       .set_channels = stmmac_set_channels,
        .get_tunable = stmmac_get_tunable,
        .set_tunable = stmmac_set_tunable,
        .get_link_ksettings = stmmac_ethtool_get_link_ksettings,
index 3fa24b310d20ef54f1ddf2290073fd14b5c90ada..c0e440dd43eaa200a79a1d354869c8c42ede9cd7 100644 (file)
@@ -4739,6 +4739,69 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
        return 0;
 }
 
+static void stmmac_napi_add(struct net_device *dev)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       u32 queue, maxq;
+
+       maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use);
+
+       for (queue = 0; queue < maxq; queue++) {
+               struct stmmac_channel *ch = &priv->channel[queue];
+
+               ch->priv_data = priv;
+               ch->index = queue;
+
+               if (queue < priv->plat->rx_queues_to_use) {
+                       netif_napi_add(dev, &ch->rx_napi, stmmac_napi_poll_rx,
+                                      NAPI_POLL_WEIGHT);
+               }
+               if (queue < priv->plat->tx_queues_to_use) {
+                       netif_tx_napi_add(dev, &ch->tx_napi,
+                                         stmmac_napi_poll_tx,
+                                         NAPI_POLL_WEIGHT);
+               }
+       }
+}
+
+static void stmmac_napi_del(struct net_device *dev)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       u32 queue, maxq;
+
+       maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use);
+
+       for (queue = 0; queue < maxq; queue++) {
+               struct stmmac_channel *ch = &priv->channel[queue];
+
+               if (queue < priv->plat->rx_queues_to_use)
+                       netif_napi_del(&ch->rx_napi);
+               if (queue < priv->plat->tx_queues_to_use)
+                       netif_napi_del(&ch->tx_napi);
+       }
+}
+
+int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       int ret = 0;
+
+       if (netif_running(dev))
+               stmmac_release(dev);
+
+       stmmac_napi_del(dev);
+
+       priv->plat->rx_queues_to_use = rx_cnt;
+       priv->plat->tx_queues_to_use = tx_cnt;
+
+       stmmac_napi_add(dev);
+
+       if (netif_running(dev))
+               ret = stmmac_open(dev);
+
+       return ret;
+}
+
 /**
  * stmmac_dvr_probe
  * @device: device pointer
@@ -4755,7 +4818,7 @@ int stmmac_dvr_probe(struct device *device,
 {
        struct net_device *ndev = NULL;
        struct stmmac_priv *priv;
-       u32 queue, rxq, maxq;
+       u32 rxq;
        int i, ret = 0;
 
        ndev = devm_alloc_etherdev_mqs(device, sizeof(struct stmmac_priv),
@@ -4920,25 +4983,7 @@ int stmmac_dvr_probe(struct device *device,
                priv->flow_ctrl = FLOW_AUTO;    /* RX/TX pause on */
 
        /* Setup channels NAPI */
-       maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use);
-
-       for (queue = 0; queue < maxq; queue++) {
-               struct stmmac_channel *ch = &priv->channel[queue];
-
-               spin_lock_init(&ch->lock);
-               ch->priv_data = priv;
-               ch->index = queue;
-
-               if (queue < priv->plat->rx_queues_to_use) {
-                       netif_napi_add(ndev, &ch->rx_napi, stmmac_napi_poll_rx,
-                                      NAPI_POLL_WEIGHT);
-               }
-               if (queue < priv->plat->tx_queues_to_use) {
-                       netif_tx_napi_add(ndev, &ch->tx_napi,
-                                         stmmac_napi_poll_tx,
-                                         NAPI_POLL_WEIGHT);
-               }
-       }
+       stmmac_napi_add(ndev);
 
        mutex_init(&priv->lock);
 
@@ -5003,14 +5048,7 @@ error_phy_setup:
            priv->hw->pcs != STMMAC_PCS_RTBI)
                stmmac_mdio_unregister(ndev);
 error_mdio_register:
-       for (queue = 0; queue < maxq; queue++) {
-               struct stmmac_channel *ch = &priv->channel[queue];
-
-               if (queue < priv->plat->rx_queues_to_use)
-                       netif_napi_del(&ch->rx_napi);
-               if (queue < priv->plat->tx_queues_to_use)
-                       netif_napi_del(&ch->tx_napi);
-       }
+       stmmac_napi_del(ndev);
 error_hw_init:
        destroy_workqueue(priv->wq);