Commit 0366f7e0 authored by Ong Boon Leong's avatar Ong Boon Leong Committed by David S. Miller
Browse files

net: stmmac: add ethtool support for get/set channels



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: default avatarOng Boon Leong <boon.leong.ong@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 945c5704
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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,
+26 −0
Original line number Diff line number Diff line
@@ -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,
+66 −28
Original line number Diff line number Diff line
@@ -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);