net: ethernet: Add helper for set_pauseparam for Asym Pause

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>
This commit is contained in:
Andrew Lunn 2018-09-12 01:53:17 +02:00 committed by David S. Miller
parent c306ad3618
commit 70814e819c
10 changed files with 68 additions and 147 deletions

View 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;

View 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)

View 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;

View 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);
}

View 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);

View 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 = gfar_read(&regs->maccfg1);
if (!epause->autoneg) {
u32 tempval;
tempval = gfar_read(&regs->maccfg1);
tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
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);
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;

View 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)

View 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;
}

View 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;

View 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 *));