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) {
|
if (priv->internal_phy) {
|
||||||
int0_enable |= UMAC_IRQ_LINK_EVENT;
|
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) {
|
} else if (priv->ext_phy) {
|
||||||
int0_enable |= UMAC_IRQ_LINK_EVENT;
|
int0_enable |= UMAC_IRQ_LINK_EVENT;
|
||||||
} else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
|
} 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;
|
priv->irq0_stat = 0;
|
||||||
spin_unlock_irq(&priv->lock);
|
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 */
|
/* Link UP/DOWN event */
|
||||||
if (status & UMAC_IRQ_LINK_EVENT) {
|
if (status & UMAC_IRQ_LINK_EVENT)
|
||||||
priv->dev->phydev->link = !!(status & UMAC_IRQ_LINK_UP);
|
|
||||||
phy_mac_interrupt(priv->dev->phydev);
|
phy_mac_interrupt(priv->dev->phydev);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bcmgenet_isr1: handle Rx and Tx priority queues */
|
/* 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 */
|
/* 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) {
|
if (status) {
|
||||||
/* Save irq status for bottom-half processing. */
|
/* Save irq status for bottom-half processing. */
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
|
@ -2874,6 +2879,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);
|
||||||
|
|
||||||
|
@ -2883,6 +2894,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) {
|
||||||
|
@ -2898,7 +2915,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 */
|
||||||
|
@ -2921,25 +2938,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);
|
||||||
|
@ -3620,6 +3631,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);
|
||||||
|
@ -3628,8 +3641,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);
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -572,6 +572,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
|
||||||
.name = _name, \
|
.name = _name, \
|
||||||
/* PHY_BASIC_FEATURES */ \
|
/* PHY_BASIC_FEATURES */ \
|
||||||
.flags = PHY_IS_INTERNAL, \
|
.flags = PHY_IS_INTERNAL, \
|
||||||
|
.soft_reset = genphy_soft_reset, \
|
||||||
.config_init = bcm7xxx_config_init, \
|
.config_init = bcm7xxx_config_init, \
|
||||||
.suspend = bcm7xxx_suspend, \
|
.suspend = bcm7xxx_suspend, \
|
||||||
.resume = bcm7xxx_config_init, \
|
.resume = bcm7xxx_config_init, \
|
||||||
|
|
Loading…
Reference in New Issue