net: ethernet: Add helper for set_pauseparam for Asym Pause
authorAndrew Lunn <andrew@lunn.ch>
Tue, 11 Sep 2018 23:53:17 +0000 (01:53 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 13 Sep 2018 03:24:21 +0000 (20:24 -0700)
ethtool can be used to enable/disable pause. Add a helper to configure
the PHY when asym pause is supported.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
drivers/net/ethernet/aurora/nb8800.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/socionext/sni_ave.c
drivers/net/phy/phy_device.c
include/linux/phy.h

index 4f50f11..dfe03af 100644 (file)
@@ -306,7 +306,6 @@ static int xgene_set_pauseparam(struct net_device *ndev,
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct phy_device *phydev = ndev->phydev;
-       u32 oldadv, newadv;
 
        if (phy_interface_mode_is_rgmii(pdata->phy_mode) ||
            pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
@@ -322,29 +321,12 @@ static int xgene_set_pauseparam(struct net_device *ndev,
                pdata->tx_pause = pp->tx_pause;
                pdata->rx_pause = pp->rx_pause;
 
-               oldadv = phydev->advertising;
-               newadv = oldadv & ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+               phy_set_asym_pause(phydev, pp->rx_pause,  pp->tx_pause);
 
-               if (pp->rx_pause)
-                       newadv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
-
-               if (pp->tx_pause)
-                       newadv ^= ADVERTISED_Asym_Pause;
-
-               if (oldadv ^ newadv) {
-                       phydev->advertising = newadv;
-
-                       if (phydev->autoneg)
-                               return phy_start_aneg(phydev);
-
-                       if (!pp->autoneg) {
-                               pdata->mac_ops->flowctl_tx(pdata,
-                                                          pdata->tx_pause);
-                               pdata->mac_ops->flowctl_rx(pdata,
-                                                          pdata->rx_pause);
-                       }
+               if (!pp->autoneg) {
+                       pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
+                       pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
                }
-
        } else {
                if (pp->autoneg)
                        return -EINVAL;
index c8d1f8f..6f56276 100644 (file)
@@ -935,18 +935,11 @@ static void nb8800_pause_adv(struct net_device *dev)
 {
        struct nb8800_priv *priv = netdev_priv(dev);
        struct phy_device *phydev = dev->phydev;
-       u32 adv = 0;
 
        if (!phydev)
                return;
 
-       if (priv->pause_rx)
-               adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
-       if (priv->pause_tx)
-               adv ^= ADVERTISED_Asym_Pause;
-
-       phydev->supported |= adv;
-       phydev->advertising |= adv;
+       phy_set_asym_pause(phydev, priv->pause_rx, priv->pause_tx);
 }
 
 static int nb8800_open(struct net_device *dev)
index 193e990..b2a3d00 100644 (file)
@@ -12492,7 +12492,6 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
                tg3_warn_mgmt_link_flap(tp);
 
        if (tg3_flag(tp, USE_PHYLIB)) {
-               u32 newadv;
                struct phy_device *phydev;
 
                phydev = mdiobus_get_phy(tp->mdio_bus, tp->phy_addr);
@@ -12503,20 +12502,16 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
                        return -EINVAL;
 
                tp->link_config.flowctrl = 0;
+               phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
                if (epause->rx_pause) {
                        tp->link_config.flowctrl |= FLOW_CTRL_RX;
 
                        if (epause->tx_pause) {
                                tp->link_config.flowctrl |= FLOW_CTRL_TX;
-                               newadv = ADVERTISED_Pause;
-                       } else
-                               newadv = ADVERTISED_Pause |
-                                        ADVERTISED_Asym_Pause;
+                       }
                } else if (epause->tx_pause) {
                        tp->link_config.flowctrl |= FLOW_CTRL_TX;
-                       newadv = ADVERTISED_Asym_Pause;
-               } else
-                       newadv = 0;
+               }
 
                if (epause->autoneg)
                        tg3_flag_set(tp, PAUSE_AUTONEG);
@@ -12524,33 +12519,19 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
                        tg3_flag_clear(tp, PAUSE_AUTONEG);
 
                if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
-                       u32 oldadv = phydev->advertising &
-                                    (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
-                       if (oldadv != newadv) {
-                               phydev->advertising &=
-                                       ~(ADVERTISED_Pause |
-                                         ADVERTISED_Asym_Pause);
-                               phydev->advertising |= newadv;
-                               if (phydev->autoneg) {
-                                       /*
-                                        * Always renegotiate the link to
-                                        * inform our link partner of our
-                                        * flow control settings, even if the
-                                        * flow control is forced.  Let
-                                        * tg3_adjust_link() do the final
-                                        * flow control setup.
-                                        */
-                                       return phy_start_aneg(phydev);
-                               }
+                       if (phydev->autoneg) {
+                               /* phy_set_asym_pause() will
+                                * renegotiate the link to inform our
+                                * link partner of our flow control
+                                * settings, even if the flow control
+                                * is forced.  Let tg3_adjust_link()
+                                * do the final flow control setup.
+                                */
+                               return 0;
                        }
 
                        if (!epause->autoneg)
                                tg3_setup_flow_control(tp, 0, 0);
-               } else {
-                       tp->link_config.advertising &=
-                                       ~(ADVERTISED_Pause |
-                                         ADVERTISED_Asym_Pause);
-                       tp->link_config.advertising |= newadv;
                }
        } else {
                int irq_sync = 0;
index 3f319ee..d8ead7e 100644 (file)
@@ -1219,22 +1219,11 @@ static int ftgmac100_set_pauseparam(struct net_device *netdev,
        priv->tx_pause = pause->tx_pause;
        priv->rx_pause = pause->rx_pause;
 
-       if (phydev) {
-               phydev->advertising &= ~ADVERTISED_Pause;
-               phydev->advertising &= ~ADVERTISED_Asym_Pause;
+       if (phydev)
+               phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause);
 
-               if (pause->rx_pause) {
-                       phydev->advertising |= ADVERTISED_Pause;
-                       phydev->advertising |= ADVERTISED_Asym_Pause;
-               }
-
-               if (pause->tx_pause)
-                       phydev->advertising ^= ADVERTISED_Asym_Pause;
-       }
        if (netif_running(netdev)) {
-               if (phydev && priv->aneg_pause)
-                       phy_start_aneg(phydev);
-               else
+               if (!(phydev && priv->aneg_pause))
                        ftgmac100_config_pause(priv);
        }
 
index 3184c8f..1f8cdbc 100644 (file)
@@ -210,29 +210,8 @@ static int dpaa_set_pauseparam(struct net_device *net_dev,
        /* Determine the sym/asym advertised PAUSE capabilities from the desired
         * rx/tx pause settings.
         */
-       newadv = 0;
-       if (epause->rx_pause)
-               newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
-       if (epause->tx_pause)
-               newadv ^= ADVERTISED_Asym_Pause;
 
-       oldadv = phydev->advertising &
-                       (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
-
-       /* If there are differences between the old and the new advertised
-        * values, restart PHY autonegotiation and advertise the new values.
-        */
-       if (oldadv != newadv) {
-               phydev->advertising &= ~(ADVERTISED_Pause
-                               | ADVERTISED_Asym_Pause);
-               phydev->advertising |= newadv;
-               if (phydev->autoneg) {
-                       err = phy_start_aneg(phydev);
-                       if (err < 0)
-                               netdev_err(net_dev, "phy_start_aneg() = %d\n",
-                                          err);
-               }
-       }
+       phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
 
        fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
        err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
index 395a526..3545e8f 100644 (file)
@@ -503,7 +503,6 @@ static int gfar_spauseparam(struct net_device *dev,
        struct gfar_private *priv = netdev_priv(dev);
        struct phy_device *phydev = dev->phydev;
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       u32 oldadv, newadv;
 
        if (!phydev)
                return -ENODEV;
@@ -514,54 +513,36 @@ static int gfar_spauseparam(struct net_device *dev,
                return -EINVAL;
 
        priv->rx_pause_en = priv->tx_pause_en = 0;
+       phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
        if (epause->rx_pause) {
                priv->rx_pause_en = 1;
 
                if (epause->tx_pause) {
                        priv->tx_pause_en = 1;
-                       /* FLOW_CTRL_RX & TX */
-                       newadv = ADVERTISED_Pause;
-               } else  /* FLOW_CTLR_RX */
-                       newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+               }
        } else if (epause->tx_pause) {
                priv->tx_pause_en = 1;
-               /* FLOW_CTLR_TX */
-               newadv = ADVERTISED_Asym_Pause;
-       } else
-               newadv = 0;
+       }
 
        if (epause->autoneg)
                priv->pause_aneg_en = 1;
        else
                priv->pause_aneg_en = 0;
 
-       oldadv = phydev->advertising &
-               (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
-       if (oldadv != newadv) {
-               phydev->advertising &=
-                       ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
-               phydev->advertising |= newadv;
-               if (phydev->autoneg)
-                       /* inform link partner of our
-                        * new flow ctrl settings
-                        */
-                       return phy_start_aneg(phydev);
-
-               if (!epause->autoneg) {
-                       u32 tempval;
-                       tempval = gfar_read(&regs->maccfg1);
-                       tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
-
-                       priv->tx_actual_en = 0;
-                       if (priv->tx_pause_en) {
-                               priv->tx_actual_en = 1;
-                               tempval |= MACCFG1_TX_FLOW;
-                       }
+       if (!epause->autoneg) {
+               u32 tempval = gfar_read(&regs->maccfg1);
 
-                       if (priv->rx_pause_en)
-                               tempval |= MACCFG1_RX_FLOW;
-                       gfar_write(&regs->maccfg1, tempval);
+               tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
+
+               priv->tx_actual_en = 0;
+               if (priv->tx_pause_en) {
+                       priv->tx_actual_en = 1;
+                       tempval |= MACCFG1_TX_FLOW;
                }
+
+               if (priv->rx_pause_en)
+                       tempval |= MACCFG1_RX_FLOW;
+               gfar_write(&regs->maccfg1, tempval);
        }
 
        return 0;
index c56db06..cf18608 100644 (file)
@@ -5228,13 +5228,7 @@ static void hclge_set_flowctrl_adv(struct hclge_dev *hdev, u32 rx_en, u32 tx_en)
        if (!phydev)
                return;
 
-       phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
-
-       if (rx_en)
-               phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
-
-       if (tx_en)
-               phydev->advertising ^= ADVERTISED_Asym_Pause;
+       phy_set_asym_pause(phydev, rx_en, tx_en);
 }
 
 static int hclge_cfg_pauseparam(struct hclge_dev *hdev, u32 rx_en, u32 tx_en)
index a50720e..61e6abb 100644 (file)
@@ -461,16 +461,7 @@ static int ave_ethtool_set_pauseparam(struct net_device *ndev,
        priv->pause_rx   = pause->rx_pause;
        priv->pause_tx   = pause->tx_pause;
 
-       phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
-       if (pause->rx_pause)
-               phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
-       if (pause->tx_pause)
-               phydev->advertising ^= ADVERTISED_Asym_Pause;
-
-       if (pause->autoneg) {
-               if (netif_running(ndev))
-                       phy_start_aneg(phydev);
-       }
+       phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause);
 
        return 0;
 }
index e657d5a..5732d89 100644 (file)
@@ -1810,6 +1810,36 @@ void phy_support_asym_pause(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_support_asym_pause);
 
+/**
+ * phy_set_asym_pause - Configure Pause and Asym Pause
+ * @phydev: target phy_device struct
+ * @rx: Receiver Pause is supported
+ * @tx: Transmit Pause is supported
+ *
+ * Description: Configure advertised Pause support depending on if
+ * transmit and receiver pause is supported. If there has been a
+ * change in adverting, trigger a new autoneg. Generally called from
+ * the set_pauseparam .ndo.
+ */
+void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx)
+{
+       u16 oldadv = phydev->advertising;
+       u16 newadv = oldadv &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+
+       if (rx)
+               newadv |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+       if (tx)
+               newadv ^= SUPPORTED_Asym_Pause;
+
+       if (oldadv != newadv) {
+               phydev->advertising = newadv;
+
+               if (phydev->autoneg)
+                       phy_start_aneg(phydev);
+       }
+}
+EXPORT_SYMBOL(phy_set_asym_pause);
+
 static void of_set_phy_supported(struct phy_device *phydev)
 {
        struct device_node *node = phydev->mdio.dev.of_node;
index bc5d6c3..e4062ba 100644 (file)
@@ -1052,6 +1052,7 @@ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
 void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode);
 void phy_support_sym_pause(struct phy_device *phydev);
 void phy_support_asym_pause(struct phy_device *phydev);
+void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx);
 
 int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
                       int (*run)(struct phy_device *));