Commit 9b1e39cf authored by Samuel Holland's avatar Samuel Holland Committed by David S. Miller

net: stmmac: dwmac-sun8i: Balance syscon (de)initialization

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: 9f93ac8d ("net-next: stmmac: Add dwmac-sun8i")
Fixes: 634db83b ("net: stmmac: dwmac-sun8i: Handle integrated/external MDIOs")
Signed-off-by: default avatarSamuel Holland <samuel@sholland.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b8239638
...@@ -898,22 +898,23 @@ static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv) ...@@ -898,22 +898,23 @@ static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv)
return ret; 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 sunxi_priv_data *gmac = plat->bsp_priv;
struct device_node *node = priv->device->of_node; struct device_node *node = dev->of_node;
int ret; int ret;
u32 reg, val; u32 reg, val;
ret = regmap_field_read(gmac->regmap_field, &val); ret = regmap_field_read(gmac->regmap_field, &val);
if (ret) { 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; return ret;
} }
reg = gmac->variant->default_syscon_value; reg = gmac->variant->default_syscon_value;
if (reg != val) if (reg != val)
dev_warn(priv->device, dev_warn(dev,
"Current syscon value is not the default %x (expect %x)\n", "Current syscon value is not the default %x (expect %x)\n",
val, reg); val, reg);
...@@ -926,9 +927,9 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) ...@@ -926,9 +927,9 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
/* Force EPHY xtal frequency to 24MHz. */ /* Force EPHY xtal frequency to 24MHz. */
reg |= H3_EPHY_CLK_SEL; 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) { if (ret < 0) {
dev_err(priv->device, "Could not parse MDIO addr\n"); dev_err(dev, "Could not parse MDIO addr\n");
return ret; return ret;
} }
/* of_mdio_parse_addr returns a valid (0 ~ 31) PHY /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
...@@ -944,17 +945,17 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) ...@@ -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 (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
if (val % 100) { 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; return -EINVAL;
} }
val /= 100; 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) { if (val <= gmac->variant->tx_delay_max) {
reg &= ~(gmac->variant->tx_delay_max << reg &= ~(gmac->variant->tx_delay_max <<
SYSCON_ETXDC_SHIFT); SYSCON_ETXDC_SHIFT);
reg |= (val << SYSCON_ETXDC_SHIFT); reg |= (val << SYSCON_ETXDC_SHIFT);
} else { } else {
dev_err(priv->device, "Invalid TX clock delay: %d\n", dev_err(dev, "Invalid TX clock delay: %d\n",
val); val);
return -EINVAL; return -EINVAL;
} }
...@@ -962,17 +963,17 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) ...@@ -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 (!of_property_read_u32(node, "allwinner,rx-delay-ps", &val)) {
if (val % 100) { 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; return -EINVAL;
} }
val /= 100; 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) { if (val <= gmac->variant->rx_delay_max) {
reg &= ~(gmac->variant->rx_delay_max << reg &= ~(gmac->variant->rx_delay_max <<
SYSCON_ERXDC_SHIFT); SYSCON_ERXDC_SHIFT);
reg |= (val << SYSCON_ERXDC_SHIFT); reg |= (val << SYSCON_ERXDC_SHIFT);
} else { } else {
dev_err(priv->device, "Invalid RX clock delay: %d\n", dev_err(dev, "Invalid RX clock delay: %d\n",
val); val);
return -EINVAL; return -EINVAL;
} }
...@@ -983,7 +984,7 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) ...@@ -983,7 +984,7 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
if (gmac->variant->support_rmii) if (gmac->variant->support_rmii)
reg &= ~SYSCON_RMII_EN; reg &= ~SYSCON_RMII_EN;
switch (priv->plat->interface) { switch (plat->interface) {
case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_MII:
/* default */ /* default */
break; break;
...@@ -997,8 +998,8 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) ...@@ -997,8 +998,8 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII; reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII;
break; break;
default: default:
dev_err(priv->device, "Unsupported interface mode: %s", dev_err(dev, "Unsupported interface mode: %s",
phy_modes(priv->plat->interface)); phy_modes(plat->interface));
return -EINVAL; return -EINVAL;
} }
...@@ -1023,8 +1024,6 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv) ...@@ -1023,8 +1024,6 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
sun8i_dwmac_unpower_internal_phy(gmac); sun8i_dwmac_unpower_internal_phy(gmac);
} }
sun8i_dwmac_unset_syscon(gmac);
clk_disable_unprepare(gmac->tx_clk); clk_disable_unprepare(gmac->tx_clk);
if (gmac->regulator) if (gmac->regulator)
...@@ -1059,16 +1058,11 @@ static struct mac_device_info *sun8i_dwmac_setup(void *ppriv) ...@@ -1059,16 +1058,11 @@ static struct mac_device_info *sun8i_dwmac_setup(void *ppriv)
{ {
struct mac_device_info *mac; struct mac_device_info *mac;
struct stmmac_priv *priv = ppriv; struct stmmac_priv *priv = ppriv;
int ret;
mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
if (!mac) if (!mac)
return NULL; return NULL;
ret = sun8i_dwmac_set_syscon(priv);
if (ret)
return NULL;
mac->pcsr = priv->ioaddr; mac->pcsr = priv->ioaddr;
mac->mac = &sun8i_dwmac_ops; mac->mac = &sun8i_dwmac_ops;
mac->dma = &sun8i_dwmac_dma_ops; mac->dma = &sun8i_dwmac_dma_ops;
...@@ -1224,10 +1218,14 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) ...@@ -1224,10 +1218,14 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
plat_dat->exit = sun8i_dwmac_exit; plat_dat->exit = sun8i_dwmac_exit;
plat_dat->setup = sun8i_dwmac_setup; 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) if (ret)
goto dwmac_deconfig; 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); ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret) if (ret)
goto dwmac_exit; goto dwmac_exit;
...@@ -1256,11 +1254,12 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) ...@@ -1256,11 +1254,12 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
dwmac_mux: dwmac_mux:
reset_control_put(gmac->rst_ephy); reset_control_put(gmac->rst_ephy);
clk_put(gmac->ephy_clk); clk_put(gmac->ephy_clk);
sun8i_dwmac_unset_syscon(gmac);
dwmac_remove: dwmac_remove:
stmmac_dvr_remove(&pdev->dev); stmmac_dvr_remove(&pdev->dev);
dwmac_exit: dwmac_exit:
sun8i_dwmac_exit(pdev, gmac); sun8i_dwmac_exit(pdev, gmac);
dwmac_syscon:
sun8i_dwmac_unset_syscon(gmac);
dwmac_deconfig: dwmac_deconfig:
stmmac_remove_config_dt(pdev, plat_dat); stmmac_remove_config_dt(pdev, plat_dat);
...@@ -1281,6 +1280,7 @@ static int sun8i_dwmac_remove(struct platform_device *pdev) ...@@ -1281,6 +1280,7 @@ static int sun8i_dwmac_remove(struct platform_device *pdev)
} }
stmmac_pltfr_remove(pdev); stmmac_pltfr_remove(pdev);
sun8i_dwmac_unset_syscon(gmac);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment