stmmac: get/set coalesce parameters via ethtool
authorGiuseppe CAVALLARO <peppe.cavallaro@st.com>
Sun, 25 Nov 2012 23:10:44 +0000 (23:10 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 26 Nov 2012 22:22:12 +0000 (17:22 -0500)
This patch is to get/set the tx/rx coalesce parameters
via ethtool interface.

Tests have been done on several platform with different GMAC chips w/o and w/
RX watchdog feature.

V2: reject coalesce settings that are not supported.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Reviewed-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c

index 7f7ccd217e4d6d7296bdc170b2a865047879dc9a..1372ce210b58b60aa32325b08a8da2d93b5abb6e 100644 (file)
@@ -524,6 +524,87 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
        return phy_ethtool_set_eee(priv->phydev, edata);
 }
 
+static u32 stmmac_usec2riwt(u32 usec, struct stmmac_priv *priv)
+{
+       unsigned long clk = clk_get_rate(priv->stmmac_clk);
+
+       if (!clk)
+               return 0;
+
+       return (usec * (clk / 1000000)) / 256;
+}
+
+static u32 stmmac_riwt2usec(u32 riwt, struct stmmac_priv *priv)
+{
+       unsigned long clk = clk_get_rate(priv->stmmac_clk);
+
+       if (!clk)
+               return 0;
+
+       return (riwt * 256) / (clk / 1000000);
+}
+
+static int stmmac_get_coalesce(struct net_device *dev,
+                              struct ethtool_coalesce *ec)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+
+       ec->tx_coalesce_usecs = priv->tx_coal_timer;
+       ec->tx_max_coalesced_frames = priv->tx_coal_frames;
+
+       if (priv->use_riwt)
+               ec->rx_coalesce_usecs = stmmac_riwt2usec(priv->rx_riwt, priv);
+
+       return 0;
+}
+
+static int stmmac_set_coalesce(struct net_device *dev,
+                              struct ethtool_coalesce *ec)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       unsigned int rx_riwt;
+
+       /* Check not supported parameters  */
+       if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) ||
+           (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) ||
+           (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) ||
+           (ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) ||
+           (ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) ||
+           (ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) ||
+           (ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) ||
+           (ec->rx_max_coalesced_frames_high) ||
+           (ec->tx_max_coalesced_frames_irq) ||
+           (ec->stats_block_coalesce_usecs) ||
+           (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval))
+               return -EOPNOTSUPP;
+
+       if (ec->rx_coalesce_usecs == 0)
+               return -EINVAL;
+
+       if ((ec->tx_coalesce_usecs == 0) &&
+           (ec->tx_max_coalesced_frames == 0))
+               return -EINVAL;
+
+       if ((ec->tx_coalesce_usecs > STMMAC_COAL_TX_TIMER) ||
+           (ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES))
+               return -EINVAL;
+
+       rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv);
+
+       if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT))
+               return -EINVAL;
+       else if (!priv->use_riwt)
+               return -EOPNOTSUPP;
+
+       /* Only copy relevant parameters, ignore all others. */
+       priv->tx_coal_frames = ec->tx_max_coalesced_frames;
+       priv->tx_coal_timer = ec->tx_coalesce_usecs;
+       priv->rx_riwt = rx_riwt;
+       priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt);
+
+       return 0;
+}
+
 static const struct ethtool_ops stmmac_ethtool_ops = {
        .begin = stmmac_check_if_running,
        .get_drvinfo = stmmac_ethtool_getdrvinfo,
@@ -544,6 +625,8 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
        .set_eee = stmmac_ethtool_op_set_eee,
        .get_sset_count = stmmac_get_sset_count,
        .get_ts_info = ethtool_op_get_ts_info,
+       .get_coalesce = stmmac_get_coalesce,
+       .set_coalesce = stmmac_set_coalesce,
 };
 
 void stmmac_set_ethtool_ops(struct net_device *netdev)