net: qcom/emac: add ethool support for setting pause parameters
authorTimur Tabi <timur@codeaurora.org>
Mon, 6 Feb 2017 21:34:52 +0000 (15:34 -0600)
committerDavid S. Miller <davem@davemloft.net>
Tue, 7 Feb 2017 18:18:52 +0000 (13:18 -0500)
To support setting the pause parameters, the driver can no longer just
mirror the PHY.  The set_pauseparam feature allows the driver to
force the setting in the MAC, regardless of how the PHY is configured.
This means that we now need to maintain an internal state for pause
frame support, and so get_pauseparam also needs to be updated.

If the interface is already running when the setting is changed, then
the interface is reset.

Note that if the MAC is configured to enable RX pause frame support
(i.e. it transmits pause frames to throttle the other end), but the
PHY is configured to block those frames, then the feature will not work.

Also some buffer size initialization code into emac_init_adapter(),
so that it lives with similar code, including the initializtion of
pause frame support.

Signed-off-by: Timur Tabi <timur@codeaurora.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qualcomm/emac/emac-ethtool.c
drivers/net/ethernet/qualcomm/emac/emac-mac.c
drivers/net/ethernet/qualcomm/emac/emac.c
drivers/net/ethernet/qualcomm/emac/emac.h

index cfc57d2c64f9aab459fba8386b1652db21c01bb6..c418a6e9a591e0711b8a0f961c7d84eaf7fb7ef4 100644 (file)
@@ -148,16 +148,26 @@ static void emac_get_ringparam(struct net_device *netdev,
 static void emac_get_pauseparam(struct net_device *netdev,
                                struct ethtool_pauseparam *pause)
 {
-       struct phy_device *phydev = netdev->phydev;
+       struct emac_adapter *adpt = netdev_priv(netdev);
 
-       if (phydev) {
-               if (phydev->autoneg)
-                       pause->autoneg = 1;
-               if (phydev->pause)
-                       pause->rx_pause = 1;
-               if (phydev->pause != phydev->asym_pause)
-                       pause->tx_pause = 1;
-       }
+       pause->autoneg = adpt->automatic ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+       pause->rx_pause = adpt->rx_flow_control ? 1 : 0;
+       pause->tx_pause = adpt->tx_flow_control ? 1 : 0;;
+}
+
+static int emac_set_pauseparam(struct net_device *netdev,
+                              struct ethtool_pauseparam *pause)
+{
+       struct emac_adapter *adpt = netdev_priv(netdev);
+
+       adpt->automatic = pause->autoneg == AUTONEG_ENABLE;
+       adpt->rx_flow_control = pause->rx_pause != 0;
+       adpt->tx_flow_control = pause->tx_pause != 0;
+
+       if (netif_running(netdev))
+               return emac_reinit_locked(adpt);
+
+       return 0;
 }
 
 static const struct ethtool_ops emac_ethtool_ops = {
@@ -172,7 +182,9 @@ static const struct ethtool_ops emac_ethtool_ops = {
        .get_ethtool_stats = emac_get_ethtool_stats,
 
        .get_ringparam = emac_get_ringparam,
+
        .get_pauseparam = emac_get_pauseparam,
+       .set_pauseparam = emac_set_pauseparam,
 
        .nway_reset = emac_nway_reset,
 
index b991219862b116d432deacdfc3f4de8437571966..4b3e0144ad5e124f51b12313ce058c2c5e8ce1fc 100644 (file)
@@ -565,11 +565,19 @@ static void emac_mac_start(struct emac_adapter *adpt)
 
        mac |= TXEN | RXEN;     /* enable RX/TX */
 
-       /* Configure MAC flow control to match the PHY's settings. */
-       if (phydev->pause)
-               mac |= RXFC;
-       if (phydev->pause != phydev->asym_pause)
-               mac |= TXFC;
+       /* Configure MAC flow control. If set to automatic, then match
+        * whatever the PHY does. Otherwise, enable or disable it, depending
+        * on what the user configured via ethtool.
+        */
+       mac &= ~(RXFC | TXFC);
+
+       if (adpt->automatic) {
+               /* If it's set to automatic, then update our local values */
+               adpt->rx_flow_control = phydev->pause;
+               adpt->tx_flow_control = phydev->pause != phydev->asym_pause;
+       }
+       mac |= adpt->rx_flow_control ? RXFC : 0;
+       mac |= adpt->tx_flow_control ? TXFC : 0;
 
        /* setup link speed */
        mac &= ~SPEED_MASK;
index 3387c0a8874634f4caa771837a11676797463cbc..28a8cdc364851e56a5757a8f2970853c0a462cc4 100644 (file)
@@ -436,6 +436,10 @@ static void emac_init_adapter(struct emac_adapter *adpt)
 {
        u32 reg;
 
+       adpt->rrd_size = EMAC_RRD_SIZE;
+       adpt->tpd_size = EMAC_TPD_SIZE;
+       adpt->rfd_size = EMAC_RFD_SIZE;
+
        /* descriptors */
        adpt->tx_desc_cnt = EMAC_DEF_TX_DESCS;
        adpt->rx_desc_cnt = EMAC_DEF_RX_DESCS;
@@ -456,6 +460,9 @@ static void emac_init_adapter(struct emac_adapter *adpt)
 
        /* others */
        adpt->preamble = EMAC_PREAMBLE_DEF;
+
+       /* default to automatic flow control */
+       adpt->automatic = true;
 }
 
 /* Get the clock */
@@ -675,10 +682,6 @@ static int emac_probe(struct platform_device *pdev)
        netdev->watchdog_timeo = EMAC_WATCHDOG_TIME;
        netdev->irq = adpt->irq.irq;
 
-       adpt->rrd_size = EMAC_RRD_SIZE;
-       adpt->tpd_size = EMAC_TPD_SIZE;
-       adpt->rfd_size = EMAC_RFD_SIZE;
-
        netdev->netdev_ops = &emac_netdev_ops;
 
        emac_init_adapter(adpt);
index ef91dcc7f646fd840eb4c5310c76b7df6b299317..e77fb6966cbbb6a9cd14ac44cf5c273ca1013dd1 100644 (file)
@@ -306,6 +306,13 @@ struct emac_adapter {
 
        unsigned int                    rxbuf_size;
 
+       /* Flow control / pause frames support. If automatic=True, do whatever
+        * the PHY does. Otherwise, use tx_flow_control and rx_flow_control.
+        */
+       bool                            automatic;
+       bool                            tx_flow_control;
+       bool                            rx_flow_control;
+
        /* Ring parameter */
        u8                              tpd_burst;
        u8                              rfd_burst;