+++ /dev/null
-From foo@baz Wed 06 Nov 2019 03:23:18 PM CET
-From: Doug Berger <opendmb@gmail.com>
-Date: Wed, 16 Oct 2019 16:06:31 -0700
-Subject: net: bcmgenet: soft reset 40nm EPHYs before MAC init
-
-From: Doug Berger <opendmb@gmail.com>
-
-[ Upstream commit 1f515486275a08a17a2c806b844cca18f7de5b34 ]
-
-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: 484bfa1507bf ("Revert "net: bcmgenet: Software reset EPHY after power on"")
-Signed-off-by: Doug Berger <opendmb@gmail.com>
-Acked-by: Florian Fainelli <f.fainelli@gmail.com>
-Signed-off-by: David S. Miller <davem@davemloft.net>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 28 +++---
- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2
- drivers/net/ethernet/broadcom/genet/bcmmii.c | 112 +++++++++++--------------
- 3 files changed, 69 insertions(+), 73 deletions(-)
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
-@@ -2877,6 +2877,12 @@ static int bcmgenet_open(struct net_devi
- 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);
-
-@@ -2886,6 +2892,12 @@ static int bcmgenet_open(struct net_devi
- 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) {
-@@ -2901,7 +2913,7 @@ static int bcmgenet_open(struct net_devi
- 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 */
-@@ -2924,25 +2936,19 @@ static int bcmgenet_open(struct net_devi
- 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);
-@@ -3625,6 +3631,8 @@ static int bcmgenet_resume(struct device
- if (priv->internal_phy)
- bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
-
-+ phy_init_hw(dev->phydev);
-+
- bcmgenet_umac_reset(priv);
-
- init_umac(priv);
-@@ -3633,8 +3641,6 @@ static int bcmgenet_resume(struct device
- 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);
-
---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
-+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
-@@ -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);
---- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
-+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
-@@ -173,6 +173,46 @@ static void bcmgenet_moca_phy_setup(stru
- 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_devic
- 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;
-+ if (init) {
-+ linkmode_copy(phydev->advertising, phydev->supported);
-
-- ret = phy_connect_direct(dev, phydev, bcmgenet_mii_setup,
-- priv->phy_interface);
-- if (ret) {
-- pr_err("could not attach to PHY\n");
-- return -ENODEV;
-- }
-- }
-+ /* 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;
-
-- /* 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;
-+ dev_info(kdev, "configuring instance for %s\n", phy_name);
- }
-
-- 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;
- }
-