Commit 63158ac0 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 0cc76d2b 25382b99
Loading
Loading
Loading
Loading
+26 −15
Original line number Diff line number Diff line
@@ -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);

+1 −1
Original line number Diff line number Diff line
@@ -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);
+51 −61
Original line number Diff line number Diff line
@@ -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,60 +306,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
		bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
	}

	if (init)
		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;
	}

	if (init) {
		linkmode_copy(phydev->advertising, phydev->supported);

		/* The internal PHY has its link interrupts routed to the
@@ -329,7 +316,10 @@ int bcmgenet_mii_probe(struct net_device *dev)
		 * those versions of GENET.
		 */
		if (priv->internal_phy && !GENET_IS_V5(priv))
		dev->phydev->irq = PHY_IGNORE_INTERRUPT;
			phydev->irq = PHY_IGNORE_INTERRUPT;

		dev_info(kdev, "configuring instance for %s\n", phy_name);
	}

	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -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,				\