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. ====================
This commit is contained in:
commit
a17aafa3a4
@ -935,6 +935,48 @@ static int bcmgenet_set_coalesce(struct net_device *dev,
|
||||
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. */
|
||||
enum bcmgenet_stat_type {
|
||||
BCMGENET_STAT_NETDEV = -1,
|
||||
@ -1587,6 +1629,8 @@ static const struct ethtool_ops bcmgenet_ethtool_ops = {
|
||||
.get_ts_info = ethtool_op_get_ts_info,
|
||||
.get_rxnfc = bcmgenet_get_rxnfc,
|
||||
.set_rxnfc = bcmgenet_set_rxnfc,
|
||||
.get_pauseparam = bcmgenet_get_pauseparam,
|
||||
.set_pauseparam = bcmgenet_set_pauseparam,
|
||||
};
|
||||
|
||||
/* Power down the unimac, based on mode. */
|
||||
@ -3364,6 +3408,8 @@ static int bcmgenet_open(struct net_device *dev)
|
||||
goto err_irq1;
|
||||
}
|
||||
|
||||
bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause);
|
||||
|
||||
bcmgenet_netif_start(dev);
|
||||
|
||||
netif_tx_start_all_queues(dev);
|
||||
@ -3408,11 +3454,6 @@ static void bcmgenet_netif_stop(struct net_device *dev)
|
||||
*/
|
||||
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 */
|
||||
bcmgenet_tx_reclaim_all(dev);
|
||||
bcmgenet_fini_dma(priv);
|
||||
@ -3950,6 +3991,11 @@ static int bcmgenet_probe(struct platform_device *pdev)
|
||||
|
||||
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);
|
||||
dev_set_drvdata(&pdev->dev, dev);
|
||||
dev->watchdog_timeo = 2 * HZ;
|
||||
|
@ -594,6 +594,9 @@ struct bcmgenet_priv {
|
||||
|
||||
/* other misc variables */
|
||||
struct bcmgenet_hw_params *hw_params;
|
||||
unsigned autoneg_pause:1;
|
||||
unsigned tx_pause:1;
|
||||
unsigned rx_pause:1;
|
||||
|
||||
/* MDIO bus variables */
|
||||
wait_queue_head_t wq;
|
||||
@ -606,10 +609,6 @@ struct bcmgenet_priv {
|
||||
bool clk_eee_enabled;
|
||||
|
||||
/* PHY device variables */
|
||||
int old_link;
|
||||
int old_speed;
|
||||
int old_duplex;
|
||||
int old_pause;
|
||||
phy_interface_t phy_interface;
|
||||
int phy_addr;
|
||||
int ext_phy;
|
||||
@ -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_probe(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_mii_setup(struct net_device *dev);
|
||||
|
||||
|
@ -25,92 +25,80 @@
|
||||
|
||||
#include "bcmgenet.h"
|
||||
|
||||
static void bcmgenet_mac_config(struct net_device *dev)
|
||||
{
|
||||
struct bcmgenet_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
u32 reg, cmd_bits = 0;
|
||||
|
||||
/* speed */
|
||||
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 |
|
||||
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;
|
||||
|
||||
if (phydev->autoneg)
|
||||
phy_get_pause(phydev, &tx_pause, &rx_pause);
|
||||
|
||||
if (!tx_pause)
|
||||
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
|
||||
* 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);
|
||||
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);
|
||||
udelay(2);
|
||||
reg |= CMD_TX_EN | CMD_RX_EN;
|
||||
}
|
||||
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 bcmgenet_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
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 */
|
||||
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);
|
||||
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);
|
||||
udelay(2);
|
||||
reg |= CMD_TX_EN | CMD_RX_EN;
|
||||
}
|
||||
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 */
|
||||
netif_carrier_off(dev);
|
||||
}
|
||||
|
||||
if (phydev->link)
|
||||
bcmgenet_mac_config(dev);
|
||||
phy_print_status(phydev);
|
||||
}
|
||||
|
||||
@ -130,6 +118,21 @@ static int bcmgenet_fixed_phy_link_update(struct net_device *dev,
|
||||
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)
|
||||
{
|
||||
struct bcmgenet_priv *priv = netdev_priv(dev);
|
||||
@ -297,12 +300,6 @@ int bcmgenet_mii_probe(struct net_device *dev)
|
||||
if (priv->internal_phy)
|
||||
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
|
||||
* the phy_interface values and we have done that across different
|
||||
* drivers, so at least we are consistent in our mistakes.
|
||||
@ -386,8 +383,6 @@ int bcmgenet_mii_probe(struct net_device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
|
||||
/* The internal PHY has its link interrupts routed to the
|
||||
* Ethernet MAC ISRs. On GENETv5 there is a hardware issue
|
||||
* that prevents the signaling of link UP interrupts when
|
||||
|
Loading…
Reference in New Issue
Block a user