Commit a17aafa3 authored by David S. Miller's avatar David S. Miller

Merge branch 'bcmgenet-flow-control'

Florian Fainelli says:

====================
net: bcmgenet: support for flow control

This patch series adds support for flow control to the GENET driver, the
first 2 patches remove superfluous code, the 3rd one does re-organize
code a little bit and the 4th one ads the support for flow control
proper.
====================
parents 13807ded 2d8bdf52
...@@ -935,6 +935,48 @@ static int bcmgenet_set_coalesce(struct net_device *dev, ...@@ -935,6 +935,48 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
return 0; return 0;
} }
static void bcmgenet_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
struct bcmgenet_priv *priv;
u32 umac_cmd;
priv = netdev_priv(dev);
epause->autoneg = priv->autoneg_pause;
if (netif_carrier_ok(dev)) {
/* report active state when link is up */
umac_cmd = bcmgenet_umac_readl(priv, UMAC_CMD);
epause->tx_pause = !(umac_cmd & CMD_TX_PAUSE_IGNORE);
epause->rx_pause = !(umac_cmd & CMD_RX_PAUSE_IGNORE);
} else {
/* otherwise report stored settings */
epause->tx_pause = priv->tx_pause;
epause->rx_pause = priv->rx_pause;
}
}
static int bcmgenet_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
if (!dev->phydev)
return -ENODEV;
if (!phy_validate_pause(dev->phydev, epause))
return -EINVAL;
priv->autoneg_pause = !!epause->autoneg;
priv->tx_pause = !!epause->tx_pause;
priv->rx_pause = !!epause->rx_pause;
bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause);
return 0;
}
/* standard ethtool support functions. */ /* standard ethtool support functions. */
enum bcmgenet_stat_type { enum bcmgenet_stat_type {
BCMGENET_STAT_NETDEV = -1, BCMGENET_STAT_NETDEV = -1,
...@@ -1587,6 +1629,8 @@ static const struct ethtool_ops bcmgenet_ethtool_ops = { ...@@ -1587,6 +1629,8 @@ static const struct ethtool_ops bcmgenet_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info, .get_ts_info = ethtool_op_get_ts_info,
.get_rxnfc = bcmgenet_get_rxnfc, .get_rxnfc = bcmgenet_get_rxnfc,
.set_rxnfc = bcmgenet_set_rxnfc, .set_rxnfc = bcmgenet_set_rxnfc,
.get_pauseparam = bcmgenet_get_pauseparam,
.set_pauseparam = bcmgenet_set_pauseparam,
}; };
/* Power down the unimac, based on mode. */ /* Power down the unimac, based on mode. */
...@@ -3364,6 +3408,8 @@ static int bcmgenet_open(struct net_device *dev) ...@@ -3364,6 +3408,8 @@ static int bcmgenet_open(struct net_device *dev)
goto err_irq1; goto err_irq1;
} }
bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause);
bcmgenet_netif_start(dev); bcmgenet_netif_start(dev);
netif_tx_start_all_queues(dev); netif_tx_start_all_queues(dev);
...@@ -3408,11 +3454,6 @@ static void bcmgenet_netif_stop(struct net_device *dev) ...@@ -3408,11 +3454,6 @@ static void bcmgenet_netif_stop(struct net_device *dev)
*/ */
cancel_work_sync(&priv->bcmgenet_irq_work); cancel_work_sync(&priv->bcmgenet_irq_work);
priv->old_link = -1;
priv->old_speed = -1;
priv->old_duplex = -1;
priv->old_pause = -1;
/* tx reclaim */ /* tx reclaim */
bcmgenet_tx_reclaim_all(dev); bcmgenet_tx_reclaim_all(dev);
bcmgenet_fini_dma(priv); bcmgenet_fini_dma(priv);
...@@ -3950,6 +3991,11 @@ static int bcmgenet_probe(struct platform_device *pdev) ...@@ -3950,6 +3991,11 @@ static int bcmgenet_probe(struct platform_device *pdev)
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
/* Set default pause parameters */
priv->autoneg_pause = 1;
priv->tx_pause = 1;
priv->rx_pause = 1;
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(dev, &pdev->dev);
dev_set_drvdata(&pdev->dev, dev); dev_set_drvdata(&pdev->dev, dev);
dev->watchdog_timeo = 2 * HZ; dev->watchdog_timeo = 2 * HZ;
......
...@@ -594,6 +594,9 @@ struct bcmgenet_priv { ...@@ -594,6 +594,9 @@ struct bcmgenet_priv {
/* other misc variables */ /* other misc variables */
struct bcmgenet_hw_params *hw_params; struct bcmgenet_hw_params *hw_params;
unsigned autoneg_pause:1;
unsigned tx_pause:1;
unsigned rx_pause:1;
/* MDIO bus variables */ /* MDIO bus variables */
wait_queue_head_t wq; wait_queue_head_t wq;
...@@ -606,10 +609,6 @@ struct bcmgenet_priv { ...@@ -606,10 +609,6 @@ struct bcmgenet_priv {
bool clk_eee_enabled; bool clk_eee_enabled;
/* PHY device variables */ /* PHY device variables */
int old_link;
int old_speed;
int old_duplex;
int old_pause;
phy_interface_t phy_interface; phy_interface_t phy_interface;
int phy_addr; int phy_addr;
int ext_phy; int ext_phy;
...@@ -690,6 +689,7 @@ int bcmgenet_mii_init(struct net_device *dev); ...@@ -690,6 +689,7 @@ int bcmgenet_mii_init(struct net_device *dev);
int bcmgenet_mii_config(struct net_device *dev, bool init); int bcmgenet_mii_config(struct net_device *dev, bool init);
int bcmgenet_mii_probe(struct net_device *dev); int bcmgenet_mii_probe(struct net_device *dev);
void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev);
void bcmgenet_phy_pause_set(struct net_device *dev, bool rx, bool tx);
void bcmgenet_phy_power_set(struct net_device *dev, bool enable); void bcmgenet_phy_power_set(struct net_device *dev, bool enable);
void bcmgenet_mii_setup(struct net_device *dev); void bcmgenet_mii_setup(struct net_device *dev);
......
...@@ -25,92 +25,80 @@ ...@@ -25,92 +25,80 @@
#include "bcmgenet.h" #include "bcmgenet.h"
/* setup netdev link state when PHY link status change and static void bcmgenet_mac_config(struct net_device *dev)
* update UMAC and RGMII block when link up
*/
void bcmgenet_mii_setup(struct net_device *dev)
{ {
struct bcmgenet_priv *priv = netdev_priv(dev); struct bcmgenet_priv *priv = netdev_priv(dev);
struct phy_device *phydev = dev->phydev; struct phy_device *phydev = dev->phydev;
u32 reg, cmd_bits = 0; u32 reg, cmd_bits = 0;
bool status_changed = false;
if (priv->old_link != phydev->link) { /* speed */
status_changed = true; if (phydev->speed == SPEED_1000)
priv->old_link = phydev->link; cmd_bits = CMD_SPEED_1000;
} else if (phydev->speed == SPEED_100)
cmd_bits = CMD_SPEED_100;
else
cmd_bits = CMD_SPEED_10;
cmd_bits <<= CMD_SPEED_SHIFT;
if (phydev->link) { /* duplex */
/* check speed/duplex/pause changes */ if (phydev->duplex != DUPLEX_FULL) {
if (priv->old_speed != phydev->speed) { cmd_bits |= CMD_HD_EN |
status_changed = true; CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
priv->old_speed = phydev->speed; } else {
} /* pause capability defaults to Symmetric */
if (priv->autoneg_pause) {
bool tx_pause = 0, rx_pause = 0;
if (priv->old_duplex != phydev->duplex) { if (phydev->autoneg)
status_changed = true; phy_get_pause(phydev, &tx_pause, &rx_pause);
priv->old_duplex = phydev->duplex;
}
if (priv->old_pause != phydev->pause) { if (!tx_pause)
status_changed = true; cmd_bits |= CMD_TX_PAUSE_IGNORE;
priv->old_pause = phydev->pause; if (!rx_pause)
cmd_bits |= CMD_RX_PAUSE_IGNORE;
} }
/* done if nothing has changed */ /* Manual override */
if (!status_changed) if (!priv->rx_pause)
return; cmd_bits |= CMD_RX_PAUSE_IGNORE;
if (!priv->tx_pause)
/* speed */ cmd_bits |= CMD_TX_PAUSE_IGNORE;
if (phydev->speed == SPEED_1000) }
cmd_bits = CMD_SPEED_1000;
else if (phydev->speed == SPEED_100)
cmd_bits = CMD_SPEED_100;
else
cmd_bits = CMD_SPEED_10;
cmd_bits <<= CMD_SPEED_SHIFT;
/* duplex */
if (phydev->duplex != DUPLEX_FULL)
cmd_bits |= CMD_HD_EN;
/* pause capability */
if (!phydev->pause)
cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
/*
* Program UMAC and RGMII block based on established
* link speed, duplex, and pause. The speed set in
* umac->cmd tell RGMII block which clock to use for
* transmit -- 25MHz(100Mbps) or 125MHz(1Gbps).
* Receive clock is provided by the PHY.
*/
reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
reg &= ~OOB_DISABLE;
reg |= RGMII_LINK;
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
reg = bcmgenet_umac_readl(priv, UMAC_CMD); /* Program UMAC and RGMII block based on established
reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) | * link speed, duplex, and pause. The speed set in
CMD_HD_EN | * umac->cmd tell RGMII block which clock to use for
CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE); * transmit -- 25MHz(100Mbps) or 125MHz(1Gbps).
reg |= cmd_bits; * Receive clock is provided by the PHY.
if (reg & CMD_SW_RESET) { */
reg &= ~CMD_SW_RESET; reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
bcmgenet_umac_writel(priv, reg, UMAC_CMD); reg &= ~OOB_DISABLE;
udelay(2); reg |= RGMII_LINK;
reg |= CMD_TX_EN | CMD_RX_EN; bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
}
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
CMD_HD_EN |
CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE);
reg |= cmd_bits;
if (reg & CMD_SW_RESET) {
reg &= ~CMD_SW_RESET;
bcmgenet_umac_writel(priv, reg, UMAC_CMD); bcmgenet_umac_writel(priv, reg, UMAC_CMD);
} else { udelay(2);
/* done if nothing has changed */ reg |= CMD_TX_EN | CMD_RX_EN;
if (!status_changed)
return;
/* needed for MoCA fixed PHY to reflect correct link status */
netif_carrier_off(dev);
} }
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
}
/* setup netdev link state when PHY link status change and
* update UMAC and RGMII block when link up
*/
void bcmgenet_mii_setup(struct net_device *dev)
{
struct phy_device *phydev = dev->phydev;
if (phydev->link)
bcmgenet_mac_config(dev);
phy_print_status(phydev); phy_print_status(phydev);
} }
...@@ -130,6 +118,21 @@ static int bcmgenet_fixed_phy_link_update(struct net_device *dev, ...@@ -130,6 +118,21 @@ static int bcmgenet_fixed_phy_link_update(struct net_device *dev,
return 0; return 0;
} }
void bcmgenet_phy_pause_set(struct net_device *dev, bool rx, bool tx)
{
struct phy_device *phydev = dev->phydev;
linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising, rx);
linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising,
rx | tx);
phy_start_aneg(phydev);
mutex_lock(&phydev->lock);
if (phydev->link)
bcmgenet_mac_config(dev);
mutex_unlock(&phydev->lock);
}
void bcmgenet_phy_power_set(struct net_device *dev, bool enable) void bcmgenet_phy_power_set(struct net_device *dev, bool enable)
{ {
struct bcmgenet_priv *priv = netdev_priv(dev); struct bcmgenet_priv *priv = netdev_priv(dev);
...@@ -297,12 +300,6 @@ int bcmgenet_mii_probe(struct net_device *dev) ...@@ -297,12 +300,6 @@ int bcmgenet_mii_probe(struct net_device *dev)
if (priv->internal_phy) if (priv->internal_phy)
phy_flags = priv->gphy_rev; phy_flags = priv->gphy_rev;
/* Initialize link state variables that bcmgenet_mii_setup() uses */
priv->old_link = -1;
priv->old_speed = -1;
priv->old_duplex = -1;
priv->old_pause = -1;
/* This is an ugly quirk but we have not been correctly interpreting /* This is an ugly quirk but we have not been correctly interpreting
* the phy_interface values and we have done that across different * the phy_interface values and we have done that across different
* drivers, so at least we are consistent in our mistakes. * drivers, so at least we are consistent in our mistakes.
...@@ -386,8 +383,6 @@ int bcmgenet_mii_probe(struct net_device *dev) ...@@ -386,8 +383,6 @@ int bcmgenet_mii_probe(struct net_device *dev)
return ret; return ret;
} }
linkmode_copy(phydev->advertising, phydev->supported);
/* The internal PHY has its link interrupts routed to the /* The internal PHY has its link interrupts routed to the
* Ethernet MAC ISRs. On GENETv5 there is a hardware issue * Ethernet MAC ISRs. On GENETv5 there is a hardware issue
* that prevents the signaling of link UP interrupts when * that prevents the signaling of link UP interrupts when
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment