Commit 1f515486 authored by Doug Berger's avatar Doug Berger Committed by David S. Miller

net: bcmgenet: soft reset 40nm EPHYs before MAC init

It turns out that the "Workaround for putting the PHY in IDDQ mode"
used by the internal EPHYs on 40nm Set-Top Box chips when powering
down puts the interface to the GENET MAC in a state that can cause
subsequent MAC resets to be incomplete.

Rather than restore the forced soft reset when powering up internal
PHYs, this commit moves the invocation of phy_init_hw earlier in
the MAC initialization sequence to just before the MAC reset in the
open and resume functions. This allows the interface to be stable
and allows the MAC resets to be successful.

The bcmgenet_mii_probe() function is split in two to accommodate
this. The new function bcmgenet_mii_connect() handles the first
half of the functionality before the MAC initialization, and the
bcmgenet_mii_config() function is extended to provide the remaining
PHY configuration following the MAC initialization.

Fixes: 484bfa15 ("Revert "net: bcmgenet: Software reset EPHY after power on"")
Signed-off-by: default avatarDoug Berger <opendmb@gmail.com>
Acked-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fe586b82
...@@ -2872,6 +2872,12 @@ static int bcmgenet_open(struct net_device *dev) ...@@ -2872,6 +2872,12 @@ static int bcmgenet_open(struct net_device *dev)
if (priv->internal_phy) if (priv->internal_phy)
bcmgenet_power_up(priv, GENET_POWER_PASSIVE); bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
ret = bcmgenet_mii_connect(dev);
if (ret) {
netdev_err(dev, "failed to connect to PHY\n");
goto err_clk_disable;
}
/* take MAC out of reset */ /* take MAC out of reset */
bcmgenet_umac_reset(priv); bcmgenet_umac_reset(priv);
...@@ -2881,6 +2887,12 @@ static int bcmgenet_open(struct net_device *dev) ...@@ -2881,6 +2887,12 @@ static int bcmgenet_open(struct net_device *dev)
reg = bcmgenet_umac_readl(priv, UMAC_CMD); reg = bcmgenet_umac_readl(priv, UMAC_CMD);
priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); priv->crc_fwd_en = !!(reg & CMD_CRC_FWD);
ret = bcmgenet_mii_config(dev, true);
if (ret) {
netdev_err(dev, "unsupported PHY\n");
goto err_disconnect_phy;
}
bcmgenet_set_hw_addr(priv, dev->dev_addr); bcmgenet_set_hw_addr(priv, dev->dev_addr);
if (priv->internal_phy) { if (priv->internal_phy) {
...@@ -2896,7 +2908,7 @@ static int bcmgenet_open(struct net_device *dev) ...@@ -2896,7 +2908,7 @@ static int bcmgenet_open(struct net_device *dev)
ret = bcmgenet_init_dma(priv); ret = bcmgenet_init_dma(priv);
if (ret) { if (ret) {
netdev_err(dev, "failed to initialize DMA\n"); netdev_err(dev, "failed to initialize DMA\n");
goto err_clk_disable; goto err_disconnect_phy;
} }
/* Always enable ring 16 - descriptor ring */ /* Always enable ring 16 - descriptor ring */
...@@ -2919,25 +2931,19 @@ static int bcmgenet_open(struct net_device *dev) ...@@ -2919,25 +2931,19 @@ static int bcmgenet_open(struct net_device *dev)
goto err_irq0; goto err_irq0;
} }
ret = bcmgenet_mii_probe(dev);
if (ret) {
netdev_err(dev, "failed to connect to PHY\n");
goto err_irq1;
}
bcmgenet_netif_start(dev); bcmgenet_netif_start(dev);
netif_tx_start_all_queues(dev); netif_tx_start_all_queues(dev);
return 0; return 0;
err_irq1:
free_irq(priv->irq1, priv);
err_irq0: err_irq0:
free_irq(priv->irq0, priv); free_irq(priv->irq0, priv);
err_fini_dma: err_fini_dma:
bcmgenet_dma_teardown(priv); bcmgenet_dma_teardown(priv);
bcmgenet_fini_dma(priv); bcmgenet_fini_dma(priv);
err_disconnect_phy:
phy_disconnect(dev->phydev);
err_clk_disable: err_clk_disable:
if (priv->internal_phy) if (priv->internal_phy)
bcmgenet_power_down(priv, GENET_POWER_PASSIVE); bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
...@@ -3618,6 +3624,8 @@ static int bcmgenet_resume(struct device *d) ...@@ -3618,6 +3624,8 @@ static int bcmgenet_resume(struct device *d)
if (priv->internal_phy) if (priv->internal_phy)
bcmgenet_power_up(priv, GENET_POWER_PASSIVE); bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
phy_init_hw(dev->phydev);
bcmgenet_umac_reset(priv); bcmgenet_umac_reset(priv);
init_umac(priv); init_umac(priv);
...@@ -3626,8 +3634,6 @@ static int bcmgenet_resume(struct device *d) ...@@ -3626,8 +3634,6 @@ static int bcmgenet_resume(struct device *d)
if (priv->wolopts) if (priv->wolopts)
clk_disable_unprepare(priv->clk_wol); clk_disable_unprepare(priv->clk_wol);
phy_init_hw(dev->phydev);
/* Speed settings must be restored */ /* Speed settings must be restored */
bcmgenet_mii_config(priv->dev, false); bcmgenet_mii_config(priv->dev, false);
......
...@@ -720,8 +720,8 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); ...@@ -720,8 +720,8 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF);
/* MDIO routines */ /* MDIO routines */
int bcmgenet_mii_init(struct net_device *dev); int bcmgenet_mii_init(struct net_device *dev);
int bcmgenet_mii_connect(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);
void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev);
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);
......
...@@ -173,6 +173,46 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) ...@@ -173,6 +173,46 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
bcmgenet_fixed_phy_link_update); bcmgenet_fixed_phy_link_update);
} }
int bcmgenet_mii_connect(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
struct device_node *dn = priv->pdev->dev.of_node;
struct phy_device *phydev;
u32 phy_flags = 0;
int ret;
/* Communicate the integrated PHY revision */
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;
if (dn) {
phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup,
phy_flags, priv->phy_interface);
if (!phydev) {
pr_err("could not attach to PHY\n");
return -ENODEV;
}
} else {
phydev = dev->phydev;
phydev->dev_flags = phy_flags;
ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup,
priv->phy_interface);
if (ret) {
pr_err("could not attach to PHY\n");
return -ENODEV;
}
}
return 0;
}
int bcmgenet_mii_config(struct net_device *dev, bool init) int bcmgenet_mii_config(struct net_device *dev, bool init)
{ {
struct bcmgenet_priv *priv = netdev_priv(dev); struct bcmgenet_priv *priv = netdev_priv(dev);
...@@ -266,71 +306,21 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) ...@@ -266,71 +306,21 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
} }
if (init) if (init) {
dev_info(kdev, "configuring instance for %s\n", phy_name); linkmode_copy(phydev->advertising, phydev->supported);
return 0;
}
int bcmgenet_mii_probe(struct net_device *dev) /* The internal PHY has its link interrupts routed to the
{ * Ethernet MAC ISRs. On GENETv5 there is a hardware issue
struct bcmgenet_priv *priv = netdev_priv(dev); * that prevents the signaling of link UP interrupts when
struct device_node *dn = priv->pdev->dev.of_node; * the link operates at 10Mbps, so fallback to polling for
struct phy_device *phydev; * those versions of GENET.
u32 phy_flags = 0; */
int ret; if (priv->internal_phy && !GENET_IS_V5(priv))
phydev->irq = PHY_IGNORE_INTERRUPT;
/* Communicate the integrated PHY revision */
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;
if (dn) {
phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup,
phy_flags, priv->phy_interface);
if (!phydev) {
pr_err("could not attach to PHY\n");
return -ENODEV;
}
} else {
phydev = dev->phydev;
phydev->dev_flags = phy_flags;
ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup,
priv->phy_interface);
if (ret) {
pr_err("could not attach to PHY\n");
return -ENODEV;
}
}
/* Configure port multiplexer based on what the probed PHY device since dev_info(kdev, "configuring instance for %s\n", phy_name);
* reading the 'max-speed' property determines the maximum supported
* PHY speed which is needed for bcmgenet_mii_config() to configure
* things appropriately.
*/
ret = bcmgenet_mii_config(dev, true);
if (ret) {
phy_disconnect(dev->phydev);
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
* the link operates at 10Mbps, so fallback to polling for
* those versions of GENET.
*/
if (priv->internal_phy && !GENET_IS_V5(priv))
dev->phydev->irq = PHY_IGNORE_INTERRUPT;
return 0; return 0;
} }
......
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