Merge branch 'net-bcmgenet-restore-internal-EPHY-support'
Doug Berger says: ==================== net: bcmgenet: restore internal EPHY support I managed to get my hands on an old BCM97435SVMB board to do some testing with the latest kernel and uncovered a number of things that managed to get broken over the years (some by me ;). This commit set attempts to correct the errors I observed in my testing. The first commit applies to all internal PHYs to restore proper reporting of link status when a link comes up. The second commit restores the soft reset to the initialization of the older internal EPHYs used by 40nm Set-Top Box devices. The third corrects a bug I introduced when removing excessive soft resets by altering the initialization sequence in a way that keeps the GENETv3 MAC interface happy. Finally, I observed a number of issues when manually configuring the network interface of the older EPHYs that appear to be resolved by the fourth commit. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
63158ac0ba
|
@ -2018,6 +2018,8 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv)
|
|||
*/
|
||||
if (priv->internal_phy) {
|
||||
int0_enable |= UMAC_IRQ_LINK_EVENT;
|
||||
if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
|
||||
int0_enable |= UMAC_IRQ_PHY_DET_R;
|
||||
} else if (priv->ext_phy) {
|
||||
int0_enable |= UMAC_IRQ_LINK_EVENT;
|
||||
} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
|
||||
|
@ -2611,11 +2613,14 @@ static void bcmgenet_irq_task(struct work_struct *work)
|
|||
priv->irq0_stat = 0;
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
if (status & UMAC_IRQ_PHY_DET_R &&
|
||||
priv->dev->phydev->autoneg != AUTONEG_ENABLE)
|
||||
phy_init_hw(priv->dev->phydev);
|
||||
|
||||
/* Link UP/DOWN event */
|
||||
if (status & UMAC_IRQ_LINK_EVENT) {
|
||||
priv->dev->phydev->link = !!(status & UMAC_IRQ_LINK_UP);
|
||||
if (status & UMAC_IRQ_LINK_EVENT)
|
||||
phy_mac_interrupt(priv->dev->phydev);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* bcmgenet_isr1: handle Rx and Tx priority queues */
|
||||
|
@ -2710,7 +2715,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/* all other interested interrupts handled in bottom half */
|
||||
status &= UMAC_IRQ_LINK_EVENT;
|
||||
status &= (UMAC_IRQ_LINK_EVENT | UMAC_IRQ_PHY_DET_R);
|
||||
if (status) {
|
||||
/* Save irq status for bottom-half processing. */
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
@ -2874,6 +2879,12 @@ static int bcmgenet_open(struct net_device *dev)
|
|||
if (priv->internal_phy)
|
||||
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 */
|
||||
bcmgenet_umac_reset(priv);
|
||||
|
||||
|
@ -2883,6 +2894,12 @@ static int bcmgenet_open(struct net_device *dev)
|
|||
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
|
||||
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);
|
||||
|
||||
if (priv->internal_phy) {
|
||||
|
@ -2898,7 +2915,7 @@ static int bcmgenet_open(struct net_device *dev)
|
|||
ret = bcmgenet_init_dma(priv);
|
||||
if (ret) {
|
||||
netdev_err(dev, "failed to initialize DMA\n");
|
||||
goto err_clk_disable;
|
||||
goto err_disconnect_phy;
|
||||
}
|
||||
|
||||
/* Always enable ring 16 - descriptor ring */
|
||||
|
@ -2921,25 +2938,19 @@ static int bcmgenet_open(struct net_device *dev)
|
|||
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);
|
||||
|
||||
netif_tx_start_all_queues(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq1:
|
||||
free_irq(priv->irq1, priv);
|
||||
err_irq0:
|
||||
free_irq(priv->irq0, priv);
|
||||
err_fini_dma:
|
||||
bcmgenet_dma_teardown(priv);
|
||||
bcmgenet_fini_dma(priv);
|
||||
err_disconnect_phy:
|
||||
phy_disconnect(dev->phydev);
|
||||
err_clk_disable:
|
||||
if (priv->internal_phy)
|
||||
bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
|
||||
|
@ -3620,6 +3631,8 @@ static int bcmgenet_resume(struct device *d)
|
|||
if (priv->internal_phy)
|
||||
bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
|
||||
|
||||
phy_init_hw(dev->phydev);
|
||||
|
||||
bcmgenet_umac_reset(priv);
|
||||
|
||||
init_umac(priv);
|
||||
|
@ -3628,8 +3641,6 @@ static int bcmgenet_resume(struct device *d)
|
|||
if (priv->wolopts)
|
||||
clk_disable_unprepare(priv->clk_wol);
|
||||
|
||||
phy_init_hw(dev->phydev);
|
||||
|
||||
/* Speed settings must be restored */
|
||||
bcmgenet_mii_config(priv->dev, false);
|
||||
|
||||
|
|
|
@ -720,8 +720,8 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF);
|
|||
|
||||
/* MDIO routines */
|
||||
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_probe(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_mii_setup(struct net_device *dev);
|
||||
|
|
|
@ -173,6 +173,46 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
|
|||
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)
|
||||
{
|
||||
struct bcmgenet_priv *priv = netdev_priv(dev);
|
||||
|
@ -266,71 +306,21 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
|
|||
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
|
||||
}
|
||||
|
||||
if (init)
|
||||
if (init) {
|
||||
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))
|
||||
phydev->irq = PHY_IGNORE_INTERRUPT;
|
||||
|
||||
dev_info(kdev, "configuring instance for %s\n", phy_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcmgenet_mii_probe(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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure port multiplexer based on what the probed PHY device since
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -572,6 +572,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
|
|||
.name = _name, \
|
||||
/* PHY_BASIC_FEATURES */ \
|
||||
.flags = PHY_IS_INTERNAL, \
|
||||
.soft_reset = genphy_soft_reset, \
|
||||
.config_init = bcm7xxx_config_init, \
|
||||
.suspend = bcm7xxx_suspend, \
|
||||
.resume = bcm7xxx_config_init, \
|
||||
|
|
Loading…
Reference in New Issue