Skip to content

Commit ee97535

Browse files
ffainellidavem330
authored andcommitted
net: mdio: mdio-bcm-unimac: Manage clock around I/O accesses
Up until now we have managed not to have the mdio-bcm-unimac manage its clock except during probe and suspend/resume. This works most of the time, except where it does not. With a fully modular build, we can get into a situation whereby the GENET driver is fully registered, and so is the mdio-bcm-unimac driver, however the Ethernet PHY driver is not yet, because it depends on a resource that is not yet available (e.g.: GPIO provider). In that state, the network device is not usable yet, and so to conserve power, the GENET driver will have turned off its "main" clock which feeds its MDIO controller. When the PHY driver finally probes however, we make an access to the PHY registers to e.g.: disable interrupts, and this causes a bus error within the MDIO controller space because the MDIO controller clock(s) are turned off. To remedy that, we manage the clock around all of the I/O accesses to the hardware which are done exclusively during read, write and clock divider configuration. This ensures that the register space is accessible, and this also ensures that there are not unnecessarily elevated reference counts keeping the clocks active when the network device is administratively turned off. It would be the case with the previous way of managing the clock. Reviewed-by: Jacob Keller <[email protected]> Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 78b88ef commit ee97535

File tree

2 files changed

+53
-43
lines changed

2 files changed

+53
-43
lines changed

drivers/net/mdio/mdio-bcm-unimac.c

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
9494
int ret;
9595
u32 cmd;
9696

97+
ret = clk_prepare_enable(priv->clk);
98+
if (ret)
99+
return ret;
100+
97101
/* Prepare the read operation */
98102
cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT);
99103
unimac_mdio_writel(priv, cmd, MDIO_CMD);
@@ -103,7 +107,7 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
103107

104108
ret = priv->wait_func(priv->wait_func_data);
105109
if (ret)
106-
return ret;
110+
goto out;
107111

108112
cmd = unimac_mdio_readl(priv, MDIO_CMD);
109113

@@ -112,17 +116,27 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
112116
* that condition here and ignore the MDIO controller read failure
113117
* indication.
114118
*/
115-
if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (cmd & MDIO_READ_FAIL))
116-
return -EIO;
119+
if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (cmd & MDIO_READ_FAIL)) {
120+
ret = -EIO;
121+
goto out;
122+
}
117123

118-
return cmd & 0xffff;
124+
ret = cmd & 0xffff;
125+
out:
126+
clk_disable_unprepare(priv->clk);
127+
return ret;
119128
}
120129

121130
static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
122131
int reg, u16 val)
123132
{
124133
struct unimac_mdio_priv *priv = bus->priv;
125134
u32 cmd;
135+
int ret;
136+
137+
ret = clk_prepare_enable(priv->clk);
138+
if (ret)
139+
return ret;
126140

127141
/* Prepare the write operation */
128142
cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
@@ -131,7 +145,10 @@ static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
131145

132146
unimac_mdio_start(priv);
133147

134-
return priv->wait_func(priv->wait_func_data);
148+
ret = priv->wait_func(priv->wait_func_data);
149+
clk_disable_unprepare(priv->clk);
150+
151+
return ret;
135152
}
136153

137154
/* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with
@@ -178,14 +195,19 @@ static int unimac_mdio_reset(struct mii_bus *bus)
178195
return 0;
179196
}
180197

181-
static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv)
198+
static int unimac_mdio_clk_set(struct unimac_mdio_priv *priv)
182199
{
183200
unsigned long rate;
184201
u32 reg, div;
202+
int ret;
185203

186204
/* Keep the hardware default values */
187205
if (!priv->clk_freq)
188-
return;
206+
return 0;
207+
208+
ret = clk_prepare_enable(priv->clk);
209+
if (ret)
210+
return ret;
189211

190212
if (!priv->clk)
191213
rate = 250000000;
@@ -195,7 +217,8 @@ static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv)
195217
div = (rate / (2 * priv->clk_freq)) - 1;
196218
if (div & ~MDIO_CLK_DIV_MASK) {
197219
pr_warn("Incorrect MDIO clock frequency, ignoring\n");
198-
return;
220+
ret = 0;
221+
goto out;
199222
}
200223

201224
/* The MDIO clock is the reference clock (typically 250Mhz) divided by
@@ -205,6 +228,9 @@ static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv)
205228
reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT);
206229
reg |= div << MDIO_CLK_DIV_SHIFT;
207230
unimac_mdio_writel(priv, reg, MDIO_CFG);
231+
out:
232+
clk_disable_unprepare(priv->clk);
233+
return ret;
208234
}
209235

210236
static int unimac_mdio_probe(struct platform_device *pdev)
@@ -235,24 +261,12 @@ static int unimac_mdio_probe(struct platform_device *pdev)
235261
return -ENOMEM;
236262
}
237263

238-
priv->clk = devm_clk_get_optional(&pdev->dev, NULL);
239-
if (IS_ERR(priv->clk))
240-
return PTR_ERR(priv->clk);
241-
242-
ret = clk_prepare_enable(priv->clk);
243-
if (ret)
244-
return ret;
245-
246264
if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq))
247265
priv->clk_freq = 0;
248266

249-
unimac_mdio_clk_set(priv);
250-
251267
priv->mii_bus = mdiobus_alloc();
252-
if (!priv->mii_bus) {
253-
ret = -ENOMEM;
254-
goto out_clk_disable;
255-
}
268+
if (!priv->mii_bus)
269+
return -ENOMEM;
256270

257271
bus = priv->mii_bus;
258272
bus->priv = priv;
@@ -261,17 +275,29 @@ static int unimac_mdio_probe(struct platform_device *pdev)
261275
priv->wait_func = pdata->wait_func;
262276
priv->wait_func_data = pdata->wait_func_data;
263277
bus->phy_mask = ~pdata->phy_mask;
278+
priv->clk = pdata->clk;
264279
} else {
265280
bus->name = "unimac MII bus";
266281
priv->wait_func_data = priv;
267282
priv->wait_func = unimac_mdio_poll;
283+
priv->clk = devm_clk_get_optional(&pdev->dev, NULL);
284+
}
285+
286+
if (IS_ERR(priv->clk)) {
287+
ret = PTR_ERR(priv->clk);
288+
goto out_mdio_free;
268289
}
290+
269291
bus->parent = &pdev->dev;
270292
bus->read = unimac_mdio_read;
271293
bus->write = unimac_mdio_write;
272294
bus->reset = unimac_mdio_reset;
273295
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
274296

297+
ret = unimac_mdio_clk_set(priv);
298+
if (ret)
299+
goto out_mdio_free;
300+
275301
ret = of_mdiobus_register(bus, np);
276302
if (ret) {
277303
dev_err(&pdev->dev, "MDIO bus registration failed\n");
@@ -286,8 +312,6 @@ static int unimac_mdio_probe(struct platform_device *pdev)
286312

287313
out_mdio_free:
288314
mdiobus_free(bus);
289-
out_clk_disable:
290-
clk_disable_unprepare(priv->clk);
291315
return ret;
292316
}
293317

@@ -297,34 +321,17 @@ static void unimac_mdio_remove(struct platform_device *pdev)
297321

298322
mdiobus_unregister(priv->mii_bus);
299323
mdiobus_free(priv->mii_bus);
300-
clk_disable_unprepare(priv->clk);
301-
}
302-
303-
static int __maybe_unused unimac_mdio_suspend(struct device *d)
304-
{
305-
struct unimac_mdio_priv *priv = dev_get_drvdata(d);
306-
307-
clk_disable_unprepare(priv->clk);
308-
309-
return 0;
310324
}
311325

312326
static int __maybe_unused unimac_mdio_resume(struct device *d)
313327
{
314328
struct unimac_mdio_priv *priv = dev_get_drvdata(d);
315-
int ret;
316329

317-
ret = clk_prepare_enable(priv->clk);
318-
if (ret)
319-
return ret;
320-
321-
unimac_mdio_clk_set(priv);
322-
323-
return 0;
330+
return unimac_mdio_clk_set(priv);
324331
}
325332

326333
static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops,
327-
unimac_mdio_suspend, unimac_mdio_resume);
334+
NULL, unimac_mdio_resume);
328335

329336
static const struct of_device_id unimac_mdio_ids[] = {
330337
{ .compatible = "brcm,asp-v2.1-mdio", },

include/linux/platform_data/mdio-bcm-unimac.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
#ifndef __MDIO_BCM_UNIMAC_PDATA_H
22
#define __MDIO_BCM_UNIMAC_PDATA_H
33

4+
struct clk;
5+
46
struct unimac_mdio_pdata {
57
u32 phy_mask;
68
int (*wait_func)(void *data);
79
void *wait_func_data;
810
const char *bus_name;
11+
struct clk *clk;
912
};
1013

1114
#define UNIMAC_MDIO_DRV_NAME "unimac-mdio"

0 commit comments

Comments
 (0)