Skip to content

Commit 374d410

Browse files
author
Paolo Abeni
committed
Merge branch 'fsl-fman-fix-refcount-handling-of-fman-related-devices'
Aleksandr Mishin says: ==================== fsl/fman: Fix refcount handling of fman-related devices The series is intended to fix refcount handling for fman-related "struct device" objects - the devices are not released upon driver removal or in the error paths during probe. This leads to device reference leaks. The device pointers are now saved to struct mac_device and properly handled in the driver's probe and removal functions. Originally reported by Simon Horman <[email protected]> (https://lore.kernel.org/all/[email protected]/) Compile tested only. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 3b05b9c + 1dec67e commit 374d410

File tree

2 files changed

+56
-18
lines changed

2 files changed

+56
-18
lines changed

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

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -197,55 +197,67 @@ static int mac_probe(struct platform_device *_of_dev)
197197
err = -EINVAL;
198198
goto _return_of_node_put;
199199
}
200+
mac_dev->fman_dev = &of_dev->dev;
200201

201202
/* Get the FMan cell-index */
202203
err = of_property_read_u32(dev_node, "cell-index", &val);
203204
if (err) {
204205
dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
205206
err = -EINVAL;
206-
goto _return_of_node_put;
207+
goto _return_dev_put;
207208
}
208209
/* cell-index 0 => FMan id 1 */
209210
fman_id = (u8)(val + 1);
210211

211-
priv->fman = fman_bind(&of_dev->dev);
212+
priv->fman = fman_bind(mac_dev->fman_dev);
212213
if (!priv->fman) {
213214
dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
214215
err = -ENODEV;
215-
goto _return_of_node_put;
216+
goto _return_dev_put;
216217
}
217218

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);
218224
of_node_put(dev_node);
225+
dev_node = NULL;
219226

220227
/* Get the address of the memory mapped registers */
221228
mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
222229
if (!mac_dev->res) {
223230
dev_err(dev, "could not get registers\n");
224-
return -EINVAL;
231+
err = -EINVAL;
232+
goto _return_dev_put;
225233
}
226234

227235
err = devm_request_resource(dev, fman_get_mem_region(priv->fman),
228236
mac_dev->res);
229237
if (err) {
230238
dev_err_probe(dev, err, "could not request resource\n");
231-
return err;
239+
goto _return_dev_put;
232240
}
233241

234242
mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
235243
resource_size(mac_dev->res));
236244
if (!mac_dev->vaddr) {
237245
dev_err(dev, "devm_ioremap() failed\n");
238-
return -EIO;
246+
err = -EIO;
247+
goto _return_dev_put;
239248
}
240249

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

244255
/* Get the cell-index */
245256
err = of_property_read_u32(mac_node, "cell-index", &val);
246257
if (err) {
247258
dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
248-
return -EINVAL;
259+
err = -EINVAL;
260+
goto _return_dev_put;
249261
}
250262
priv->cell_index = (u8)val;
251263

@@ -259,40 +271,51 @@ static int mac_probe(struct platform_device *_of_dev)
259271
if (unlikely(nph < 0)) {
260272
dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
261273
mac_node);
262-
return nph;
274+
err = nph;
275+
goto _return_dev_put;
263276
}
264277

265278
if (nph != ARRAY_SIZE(mac_dev->port)) {
266279
dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
267280
mac_node);
268-
return -EINVAL;
281+
err = -EINVAL;
282+
goto _return_dev_put;
269283
}
270284

271-
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++) {
272287
/* Find the port node */
273288
dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
274289
if (!dev_node) {
275290
dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
276291
mac_node);
277-
return -EINVAL;
292+
err = -EINVAL;
293+
goto _return_dev_arr_put;
278294
}
279295

280296
of_dev = of_find_device_by_node(dev_node);
281297
if (!of_dev) {
282298
dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
283299
dev_node);
284300
err = -EINVAL;
285-
goto _return_of_node_put;
301+
goto _return_dev_arr_put;
286302
}
303+
mac_dev->fman_port_devs[i] = &of_dev->dev;
287304

288-
mac_dev->port[i] = fman_port_bind(&of_dev->dev);
305+
mac_dev->port[i] = fman_port_bind(mac_dev->fman_port_devs[i]);
289306
if (!mac_dev->port[i]) {
290307
dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
291308
dev_node);
292309
err = -EINVAL;
293-
goto _return_of_node_put;
310+
goto _return_dev_arr_put;
294311
}
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]);
295317
of_node_put(dev_node);
318+
dev_node = NULL;
296319
}
297320

298321
/* Get the PHY connection type */
@@ -312,7 +335,7 @@ static int mac_probe(struct platform_device *_of_dev)
312335

313336
err = init(mac_dev, mac_node, &params);
314337
if (err < 0)
315-
return err;
338+
goto _return_dev_arr_put;
316339

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

328351
return err;
329352

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);
330359
_return_of_node_put:
331360
of_node_put(dev_node);
332361
return err;
@@ -335,6 +364,11 @@ static int mac_probe(struct platform_device *_of_dev)
335364
static void mac_remove(struct platform_device *pdev)
336365
{
337366
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);
338372

339373
platform_device_unregister(mac_dev->priv->eth_dev);
340374
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
struct fman_mac;
2020
struct mac_priv_s;
2121

22+
#define PORT_NUM 2
2223
struct mac_device {
2324
void __iomem *vaddr;
2425
struct device *dev;
2526
struct resource *res;
2627
u8 addr[ETH_ALEN];
27-
struct fman_port *port[2];
28+
struct fman_port *port[PORT_NUM];
2829
struct phylink *phylink;
2930
struct phylink_config phylink_config;
3031
phy_interface_t phy_if;
@@ -52,6 +53,9 @@ struct mac_device {
5253

5354
struct fman_mac *fman_mac;
5455
struct mac_priv_s *priv;
56+
57+
struct device *fman_dev;
58+
struct device *fman_port_devs[PORT_NUM];
5559
};
5660

5761
static inline struct mac_device

0 commit comments

Comments
 (0)