]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: stmmac: dwmac-sun8i: Balance syscon (de)initialization
authorSamuel Holland <samuel@sholland.org>
Sun, 3 Jan 2021 11:17:44 +0000 (05:17 -0600)
committerDavid S. Miller <davem@davemloft.net>
Wed, 6 Jan 2021 00:32:08 +0000 (16:32 -0800)
Previously, sun8i_dwmac_set_syscon was called from a chain of functions
in several different files:
    sun8i_dwmac_probe
      stmmac_dvr_probe
        stmmac_hw_init
          stmmac_hwif_init
            sun8i_dwmac_setup
              sun8i_dwmac_set_syscon
which made the lifetime of the syscon values hard to reason about. Part
of the problem is that there is no similar platform driver callback from
stmmac_dvr_remove. As a result, the driver unset the syscon value in
sun8i_dwmac_exit, but this leaves it uninitialized after a suspend/
resume cycle. It was also unset a second time (outside sun8i_dwmac_exit)
in the probe error path.

Move the init to the earliest available place in sun8i_dwmac_probe
(after stmmac_probe_config_dt, which initializes plat_dat), and the
deinit to the corresponding position in the cleanup order.

Since priv is not filled in until stmmac_dvr_probe, this requires
changing the sun8i_dwmac_set_syscon parameters to priv's two relevant
members.

Fixes: 3a69638775ff ("net-next: stmmac: Add dwmac-sun8i")
Fixes: b1a2a9eb0a76 ("net: stmmac: dwmac-sun8i: Handle integrated/external MDIOs")
Signed-off-by: Samuel Holland <samuel@sholland.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c

index e2c25c1c702a715c04fce965d266e32872c4ea67..a5e0eff4a38741153bd92dfef2737c12114928a4 100644 (file)
@@ -898,22 +898,23 @@ static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv)
        return ret;
 }
 
-static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
+static int sun8i_dwmac_set_syscon(struct device *dev,
+                                 struct plat_stmmacenet_data *plat)
 {
-       struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
-       struct device_node *node = priv->device->of_node;
+       struct sunxi_priv_data *gmac = plat->bsp_priv;
+       struct device_node *node = dev->of_node;
        int ret;
        u32 reg, val;
 
        ret = regmap_field_read(gmac->regmap_field, &val);
        if (ret) {
-               dev_err(priv->device, "Fail to read from regmap field.\n");
+               dev_err(dev, "Fail to read from regmap field.\n");
                return ret;
        }
 
        reg = gmac->variant->default_syscon_value;
        if (reg != val)
-               dev_warn(priv->device,
+               dev_warn(dev,
                         "Current syscon value is not the default %x (expect %x)\n",
                         val, reg);
 
@@ -926,9 +927,9 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
                /* Force EPHY xtal frequency to 24MHz. */
                reg |= H3_EPHY_CLK_SEL;
 
-               ret = of_mdio_parse_addr(priv->device, priv->plat->phy_node);
+               ret = of_mdio_parse_addr(dev, plat->phy_node);
                if (ret < 0) {
-                       dev_err(priv->device, "Could not parse MDIO addr\n");
+                       dev_err(dev, "Could not parse MDIO addr\n");
                        return ret;
                }
                /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
@@ -944,17 +945,17 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
 
        if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
                if (val % 100) {
-                       dev_err(priv->device, "tx-delay must be a multiple of 100\n");
+                       dev_err(dev, "tx-delay must be a multiple of 100\n");
                        return -EINVAL;
                }
                val /= 100;
-               dev_dbg(priv->device, "set tx-delay to %x\n", val);
+               dev_dbg(dev, "set tx-delay to %x\n", val);
                if (val <= gmac->variant->tx_delay_max) {
                        reg &= ~(gmac->variant->tx_delay_max <<
                                 SYSCON_ETXDC_SHIFT);
                        reg |= (val << SYSCON_ETXDC_SHIFT);
                } else {
-                       dev_err(priv->device, "Invalid TX clock delay: %d\n",
+                       dev_err(dev, "Invalid TX clock delay: %d\n",
                                val);
                        return -EINVAL;
                }
@@ -962,17 +963,17 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
 
        if (!of_property_read_u32(node, "allwinner,rx-delay-ps", &val)) {
                if (val % 100) {
-                       dev_err(priv->device, "rx-delay must be a multiple of 100\n");
+                       dev_err(dev, "rx-delay must be a multiple of 100\n");
                        return -EINVAL;
                }
                val /= 100;
-               dev_dbg(priv->device, "set rx-delay to %x\n", val);
+               dev_dbg(dev, "set rx-delay to %x\n", val);
                if (val <= gmac->variant->rx_delay_max) {
                        reg &= ~(gmac->variant->rx_delay_max <<
                                 SYSCON_ERXDC_SHIFT);
                        reg |= (val << SYSCON_ERXDC_SHIFT);
                } else {
-                       dev_err(priv->device, "Invalid RX clock delay: %d\n",
+                       dev_err(dev, "Invalid RX clock delay: %d\n",
                                val);
                        return -EINVAL;
                }
@@ -983,7 +984,7 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
        if (gmac->variant->support_rmii)
                reg &= ~SYSCON_RMII_EN;
 
-       switch (priv->plat->interface) {
+       switch (plat->interface) {
        case PHY_INTERFACE_MODE_MII:
                /* default */
                break;
@@ -997,8 +998,8 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
                reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII;
                break;
        default:
-               dev_err(priv->device, "Unsupported interface mode: %s",
-                       phy_modes(priv->plat->interface));
+               dev_err(dev, "Unsupported interface mode: %s",
+                       phy_modes(plat->interface));
                return -EINVAL;
        }
 
@@ -1023,8 +1024,6 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
                        sun8i_dwmac_unpower_internal_phy(gmac);
        }
 
-       sun8i_dwmac_unset_syscon(gmac);
-
        clk_disable_unprepare(gmac->tx_clk);
 
        if (gmac->regulator)
@@ -1059,16 +1058,11 @@ static struct mac_device_info *sun8i_dwmac_setup(void *ppriv)
 {
        struct mac_device_info *mac;
        struct stmmac_priv *priv = ppriv;
-       int ret;
 
        mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
        if (!mac)
                return NULL;
 
-       ret = sun8i_dwmac_set_syscon(priv);
-       if (ret)
-               return NULL;
-
        mac->pcsr = priv->ioaddr;
        mac->mac = &sun8i_dwmac_ops;
        mac->dma = &sun8i_dwmac_dma_ops;
@@ -1224,10 +1218,14 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
        plat_dat->exit = sun8i_dwmac_exit;
        plat_dat->setup = sun8i_dwmac_setup;
 
-       ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv);
+       ret = sun8i_dwmac_set_syscon(&pdev->dev, plat_dat);
        if (ret)
                goto dwmac_deconfig;
 
+       ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv);
+       if (ret)
+               goto dwmac_syscon;
+
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
        if (ret)
                goto dwmac_exit;
@@ -1256,11 +1254,12 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
 dwmac_mux:
        reset_control_put(gmac->rst_ephy);
        clk_put(gmac->ephy_clk);
-       sun8i_dwmac_unset_syscon(gmac);
 dwmac_remove:
        stmmac_dvr_remove(&pdev->dev);
 dwmac_exit:
        sun8i_dwmac_exit(pdev, gmac);
+dwmac_syscon:
+       sun8i_dwmac_unset_syscon(gmac);
 dwmac_deconfig:
        stmmac_remove_config_dt(pdev, plat_dat);
 
@@ -1281,6 +1280,7 @@ static int sun8i_dwmac_remove(struct platform_device *pdev)
        }
 
        stmmac_pltfr_remove(pdev);
+       sun8i_dwmac_unset_syscon(gmac);
 
        return 0;
 }