Skip to content

Commit 1dec67e

Browse files
Aleksandr MishinPaolo Abeni
authored andcommitted
fsl/fman: Fix refcount handling of fman-related devices
In mac_probe() there are multiple calls to of_find_device_by_node(), fman_bind() and fman_port_bind() which takes references to of_dev->dev. Not all references taken by these calls are released later on error path in mac_probe() and in mac_remove() which lead to reference leaks. Add references release. Fixes: 3933961 ("fsl/fman: Add FMan MAC driver") Signed-off-by: Aleksandr Mishin <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent efeddd5 commit 1dec67e

File tree

1 file changed

+47
-15
lines changed
  • drivers/net/ethernet/freescale/fman

1 file changed

+47
-15
lines changed

drivers/net/ethernet/freescale/fman/mac.c

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ static int mac_probe(struct platform_device *_of_dev)
204204
if (err) {
205205
dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
206206
err = -EINVAL;
207-
goto _return_of_node_put;
207+
goto _return_dev_put;
208208
}
209209
/* cell-index 0 => FMan id 1 */
210210
fman_id = (u8)(val + 1);
@@ -213,40 +213,51 @@ static int mac_probe(struct platform_device *_of_dev)
213213
if (!priv->fman) {
214214
dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
215215
err = -ENODEV;
216-
goto _return_of_node_put;
216+
goto _return_dev_put;
217217
}
218218

219+
/* Two references have been taken in of_find_device_by_node()
220+
* and fman_bind(). Release one of them here. The second one
221+
* will be released in mac_remove().
222+
*/
223+
put_device(mac_dev->fman_dev);
219224
of_node_put(dev_node);
225+
dev_node = NULL;
220226

221227
/* Get the address of the memory mapped registers */
222228
mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
223229
if (!mac_dev->res) {
224230
dev_err(dev, "could not get registers\n");
225-
return -EINVAL;
231+
err = -EINVAL;
232+
goto _return_dev_put;
226233
}
227234

228235
err = devm_request_resource(dev, fman_get_mem_region(priv->fman),
229236
mac_dev->res);
230237
if (err) {
231238
dev_err_probe(dev, err, "could not request resource\n");
232-
return err;
239+
goto _return_dev_put;
233240
}
234241

235242
mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
236243
resource_size(mac_dev->res));
237244
if (!mac_dev->vaddr) {
238245
dev_err(dev, "devm_ioremap() failed\n");
239-
return -EIO;
246+
err = -EIO;
247+
goto _return_dev_put;
240248
}
241249

242-
if (!of_device_is_available(mac_node))
243-
return -ENODEV;
250+
if (!of_device_is_available(mac_node)) {
251+
err = -ENODEV;
252+
goto _return_dev_put;
253+
}
244254

245255
/* Get the cell-index */
246256
err = of_property_read_u32(mac_node, "cell-index", &val);
247257
if (err) {
248258
dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
249-
return -EINVAL;
259+
err = -EINVAL;
260+
goto _return_dev_put;
250261
}
251262
priv->cell_index = (u8)val;
252263

@@ -260,30 +271,34 @@ static int mac_probe(struct platform_device *_of_dev)
260271
if (unlikely(nph < 0)) {
261272
dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
262273
mac_node);
263-
return nph;
274+
err = nph;
275+
goto _return_dev_put;
264276
}
265277

266278
if (nph != ARRAY_SIZE(mac_dev->port)) {
267279
dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
268280
mac_node);
269-
return -EINVAL;
281+
err = -EINVAL;
282+
goto _return_dev_put;
270283
}
271284

272-
for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) {
285+
/* PORT_NUM determines the size of the port array */
286+
for (i = 0; i < PORT_NUM; i++) {
273287
/* Find the port node */
274288
dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
275289
if (!dev_node) {
276290
dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
277291
mac_node);
278-
return -EINVAL;
292+
err = -EINVAL;
293+
goto _return_dev_arr_put;
279294
}
280295

281296
of_dev = of_find_device_by_node(dev_node);
282297
if (!of_dev) {
283298
dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
284299
dev_node);
285300
err = -EINVAL;
286-
goto _return_of_node_put;
301+
goto _return_dev_arr_put;
287302
}
288303
mac_dev->fman_port_devs[i] = &of_dev->dev;
289304

@@ -292,9 +307,15 @@ static int mac_probe(struct platform_device *_of_dev)
292307
dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
293308
dev_node);
294309
err = -EINVAL;
295-
goto _return_of_node_put;
310+
goto _return_dev_arr_put;
296311
}
312+
/* Two references have been taken in of_find_device_by_node()
313+
* and fman_port_bind(). Release one of them here. The second
314+
* one will be released in mac_remove().
315+
*/
316+
put_device(mac_dev->fman_port_devs[i]);
297317
of_node_put(dev_node);
318+
dev_node = NULL;
298319
}
299320

300321
/* Get the PHY connection type */
@@ -314,7 +335,7 @@ static int mac_probe(struct platform_device *_of_dev)
314335

315336
err = init(mac_dev, mac_node, &params);
316337
if (err < 0)
317-
return err;
338+
goto _return_dev_arr_put;
318339

319340
if (!is_zero_ether_addr(mac_dev->addr))
320341
dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
@@ -329,6 +350,12 @@ static int mac_probe(struct platform_device *_of_dev)
329350

330351
return err;
331352

353+
_return_dev_arr_put:
354+
/* mac_dev is kzalloc'ed */
355+
for (i = 0; i < PORT_NUM; i++)
356+
put_device(mac_dev->fman_port_devs[i]);
357+
_return_dev_put:
358+
put_device(mac_dev->fman_dev);
332359
_return_of_node_put:
333360
of_node_put(dev_node);
334361
return err;
@@ -337,6 +364,11 @@ static int mac_probe(struct platform_device *_of_dev)
337364
static void mac_remove(struct platform_device *pdev)
338365
{
339366
struct mac_device *mac_dev = platform_get_drvdata(pdev);
367+
int i;
368+
369+
for (i = 0; i < PORT_NUM; i++)
370+
put_device(mac_dev->fman_port_devs[i]);
371+
put_device(mac_dev->fman_dev);
340372

341373
platform_device_unregister(mac_dev->priv->eth_dev);
342374
}

0 commit comments

Comments
 (0)