Commit b3319b10523d8dac82b134a05de2a403119abebd
Committed by
David S. Miller
1 parent
29fb00e047
fsl_pq_mdio: Fix iomem unmapping for non-eTSEC2.0 controllers
We use a rather complicated logic to support eTSEC and eTSEC2.0 registers maps in a single driver. Currently, the code tries to unmap 'regs', but for non-eTSEC2.0 controllers 'regs' doesn't point to a mapping start, and this might cause badness on probe failure or module removal: Freescale PowerQUICC MII Bus: probed Trying to vfree() nonexistent vm area (e107f000) ------------[ cut here ]------------ Badness at c00a7754 [verbose debug info unavailable] NIP: c00a7754 LR: c00a7754 CTR: c02231ec [...] NIP [c00a7754] __vunmap+0xec/0xf4 LR [c00a7754] __vunmap+0xec/0xf4 Call Trace: [df827e50] [c00a7754] __vunmap+0xec/0xf4 (unreliable) [df827e70] [c001519c] iounmap+0x44/0x54 [df827e80] [c028b924] fsl_pq_mdio_probe+0x1cc/0x2fc [df827eb0] [c02fb9b4] of_platform_device_probe+0x5c/0x84 [df827ed0] [c0229928] really_probe+0x78/0x1a8 [df827ef0] [c0229b20] __driver_attach+0xa4/0xa8 Fix this by introducing a proper priv structure (finally!), which now holds 'regs' and 'map' fields separately. Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 23 additions and 7 deletions Side-by-side Diff
drivers/net/fsl_pq_mdio.c
... | ... | @@ -46,6 +46,11 @@ |
46 | 46 | #include "gianfar.h" |
47 | 47 | #include "fsl_pq_mdio.h" |
48 | 48 | |
49 | +struct fsl_pq_mdio_priv { | |
50 | + void __iomem *map; | |
51 | + struct fsl_pq_mdio __iomem *regs; | |
52 | +}; | |
53 | + | |
49 | 54 | /* |
50 | 55 | * Write value to the PHY at mii_id at register regnum, |
51 | 56 | * on the bus attached to the local interface, which may be different from the |
... | ... | @@ -105,7 +110,9 @@ |
105 | 110 | |
106 | 111 | static struct fsl_pq_mdio __iomem *fsl_pq_mdio_get_regs(struct mii_bus *bus) |
107 | 112 | { |
108 | - return (void __iomem __force *)bus->priv; | |
113 | + struct fsl_pq_mdio_priv *priv = bus->priv; | |
114 | + | |
115 | + return priv->regs; | |
109 | 116 | } |
110 | 117 | |
111 | 118 | /* |
... | ... | @@ -266,6 +273,7 @@ |
266 | 273 | { |
267 | 274 | struct device_node *np = ofdev->node; |
268 | 275 | struct device_node *tbi; |
276 | + struct fsl_pq_mdio_priv *priv; | |
269 | 277 | struct fsl_pq_mdio __iomem *regs = NULL; |
270 | 278 | void __iomem *map; |
271 | 279 | u32 __iomem *tbipa; |
272 | 280 | |
273 | 281 | |
... | ... | @@ -274,14 +282,19 @@ |
274 | 282 | u64 addr = 0, size = 0; |
275 | 283 | int err = 0; |
276 | 284 | |
285 | + priv = kzalloc(sizeof(*priv), GFP_KERNEL); | |
286 | + if (!priv) | |
287 | + return -ENOMEM; | |
288 | + | |
277 | 289 | new_bus = mdiobus_alloc(); |
278 | 290 | if (NULL == new_bus) |
279 | - return -ENOMEM; | |
291 | + goto err_free_priv; | |
280 | 292 | |
281 | 293 | new_bus->name = "Freescale PowerQUICC MII Bus", |
282 | 294 | new_bus->read = &fsl_pq_mdio_read, |
283 | 295 | new_bus->write = &fsl_pq_mdio_write, |
284 | 296 | new_bus->reset = &fsl_pq_mdio_reset, |
297 | + new_bus->priv = priv; | |
285 | 298 | fsl_pq_mdio_bus_name(new_bus->id, np); |
286 | 299 | |
287 | 300 | /* Set the PHY base address */ |
... | ... | @@ -291,6 +304,7 @@ |
291 | 304 | err = -ENOMEM; |
292 | 305 | goto err_free_bus; |
293 | 306 | } |
307 | + priv->map = map; | |
294 | 308 | |
295 | 309 | if (of_device_is_compatible(np, "fsl,gianfar-mdio") || |
296 | 310 | of_device_is_compatible(np, "fsl,gianfar-tbi") || |
297 | 311 | |
... | ... | @@ -298,9 +312,8 @@ |
298 | 312 | of_device_is_compatible(np, "ucc_geth_phy")) |
299 | 313 | map -= offsetof(struct fsl_pq_mdio, miimcfg); |
300 | 314 | regs = map; |
315 | + priv->regs = regs; | |
301 | 316 | |
302 | - new_bus->priv = (void __force *)regs; | |
303 | - | |
304 | 317 | new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); |
305 | 318 | |
306 | 319 | if (NULL == new_bus->irq) { |
307 | 320 | |
... | ... | @@ -392,10 +405,11 @@ |
392 | 405 | err_free_irqs: |
393 | 406 | kfree(new_bus->irq); |
394 | 407 | err_unmap_regs: |
395 | - iounmap(regs); | |
408 | + iounmap(priv->map); | |
396 | 409 | err_free_bus: |
397 | 410 | kfree(new_bus); |
398 | - | |
411 | +err_free_priv: | |
412 | + kfree(priv); | |
399 | 413 | return err; |
400 | 414 | } |
401 | 415 | |
402 | 416 | |
403 | 417 | |
... | ... | @@ -404,14 +418,16 @@ |
404 | 418 | { |
405 | 419 | struct device *device = &ofdev->dev; |
406 | 420 | struct mii_bus *bus = dev_get_drvdata(device); |
421 | + struct fsl_pq_mdio_priv *priv = bus->priv; | |
407 | 422 | |
408 | 423 | mdiobus_unregister(bus); |
409 | 424 | |
410 | 425 | dev_set_drvdata(device, NULL); |
411 | 426 | |
412 | - iounmap(fsl_pq_mdio_get_regs(bus)); | |
427 | + iounmap(priv->map); | |
413 | 428 | bus->priv = NULL; |
414 | 429 | mdiobus_free(bus); |
430 | + kfree(priv); | |
415 | 431 | |
416 | 432 | return 0; |
417 | 433 | } |