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,41 +25,11 @@ ...@@ -25,41 +25,11 @@
#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) {
status_changed = true;
priv->old_link = phydev->link;
}
if (phydev->link) {
/* check speed/duplex/pause changes */
if (priv->old_speed != phydev->speed) {
status_changed = true;
priv->old_speed = phydev->speed;
}
if (priv->old_duplex != phydev->duplex) {
status_changed = true;
priv->old_duplex = phydev->duplex;
}
if (priv->old_pause != phydev->pause) {
status_changed = true;
priv->old_pause = phydev->pause;
}
/* done if nothing has changed */
if (!status_changed)
return;
/* speed */ /* speed */
if (phydev->speed == SPEED_1000) if (phydev->speed == SPEED_1000)
...@@ -71,15 +41,31 @@ void bcmgenet_mii_setup(struct net_device *dev) ...@@ -71,15 +41,31 @@ void bcmgenet_mii_setup(struct net_device *dev)
cmd_bits <<= CMD_SPEED_SHIFT; cmd_bits <<= CMD_SPEED_SHIFT;
/* duplex */ /* duplex */
if (phydev->duplex != DUPLEX_FULL) if (phydev->duplex != DUPLEX_FULL) {
cmd_bits |= CMD_HD_EN; cmd_bits |= CMD_HD_EN |
CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
} else {
/* pause capability defaults to Symmetric */
if (priv->autoneg_pause) {
bool tx_pause = 0, rx_pause = 0;
/* pause capability */ if (phydev->autoneg)
if (!phydev->pause) phy_get_pause(phydev, &tx_pause, &rx_pause);
cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
/* if (!tx_pause)
* Program UMAC and RGMII block based on established cmd_bits |= CMD_TX_PAUSE_IGNORE;
if (!rx_pause)
cmd_bits |= CMD_RX_PAUSE_IGNORE;
}
/* Manual override */
if (!priv->rx_pause)
cmd_bits |= CMD_RX_PAUSE_IGNORE;
if (!priv->tx_pause)
cmd_bits |= CMD_TX_PAUSE_IGNORE;
}
/* Program UMAC and RGMII block based on established
* link speed, duplex, and pause. The speed set in * link speed, duplex, and pause. The speed set in
* umac->cmd tell RGMII block which clock to use for * umac->cmd tell RGMII block which clock to use for
* transmit -- 25MHz(100Mbps) or 125MHz(1Gbps). * transmit -- 25MHz(100Mbps) or 125MHz(1Gbps).
...@@ -102,15 +88,17 @@ void bcmgenet_mii_setup(struct net_device *dev) ...@@ -102,15 +88,17 @@ void bcmgenet_mii_setup(struct net_device *dev)
reg |= CMD_TX_EN | CMD_RX_EN; reg |= CMD_TX_EN | CMD_RX_EN;
} }
bcmgenet_umac_writel(priv, reg, UMAC_CMD); bcmgenet_umac_writel(priv, reg, UMAC_CMD);
} else { }
/* done if nothing has changed */
if (!status_changed)
return;
/* needed for MoCA fixed PHY to reflect correct link status */ /* setup netdev link state when PHY link status change and
netif_carrier_off(dev); * 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