net: stmmac: dwmac-sun8i: Balance syscon (de)initialization
[ Upstream commit 9b1e39cf5dd81f33186cdb950fcf75a121f1a9a7 ] 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: 9f93ac8d4085 ("net-next: stmmac: Add dwmac-sun8i") Fixes: 634db83b8265 ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
35526a9c46
commit
60de77165d
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user