Skip to content

Commit

Permalink
net: ethernet: Add helper for set_pauseparam for Asym Pause
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Andrew Lunn authored and David S. Miller committed Sep 13, 2018
1 parent c306ad3 commit 70814e8
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 148 deletions.
26 changes: 4 additions & 22 deletions drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
Expand Down
9 changes: 1 addition & 8 deletions drivers/net/ethernet/aurora/nb8800.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
43 changes: 12 additions & 31 deletions drivers/net/ethernet/broadcom/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -12503,54 +12502,36 @@ 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);
else
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;
Expand Down
17 changes: 3 additions & 14 deletions drivers/net/ethernet/faraday/ftgmac100.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
23 changes: 1 addition & 22 deletions drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
49 changes: 15 additions & 34 deletions drivers/net/ethernet/freescale/gianfar_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
8 changes: 1 addition & 7 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 1 addition & 10 deletions drivers/net/ethernet/socionext/sni_ave.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
30 changes: 30 additions & 0 deletions drivers/net/phy/phy_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions include/linux/phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *));
Expand Down

0 comments on commit 70814e8

Please sign in to comment.