forked from Minki/linux
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:
parent
c306ad3618
commit
70814e819c
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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(®s->maccfg1);
|
||||
|
||||
if (!epause->autoneg) {
|
||||
u32 tempval;
|
||||
tempval = gfar_read(®s->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(®s->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(®s->maccfg1, tempval);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 *));
|
||||
|
Loading…
Reference in New Issue
Block a user