MIPS: SGI-IP30: Fix platform-device leak in bridge_platform_create()

In error case in bridge_platform_create after calling
platform_device_add()/platform_device_add_data()/
platform_device_add_resources(), release the failed
'pdev' or it will be leak, call platform_device_put()
to fix this problem.

Besides, 'pdev' is divided into 'pdev_wd' and 'pdev_bd',
use platform_device_unregister() to release sgi_w1
resources when xtalk-bridge registration fails.

Fixes: fd27234f24 ("MIPS: add support for SGI Octane (IP30)")
Signed-off-by: Lin Yujun <linyujun809@huawei.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
This commit is contained in:
Lin Yujun 2022-09-14 11:28:07 +08:00 committed by Thomas Bogendoerfer
parent 0153682e9e
commit 1e6d11fe72

View file

@ -40,12 +40,15 @@ static void bridge_platform_create(int widget, int masterwid)
{ {
struct xtalk_bridge_platform_data *bd; struct xtalk_bridge_platform_data *bd;
struct sgi_w1_platform_data *wd; struct sgi_w1_platform_data *wd;
struct platform_device *pdev; struct platform_device *pdev_wd;
struct platform_device *pdev_bd;
struct resource w1_res; struct resource w1_res;
wd = kzalloc(sizeof(*wd), GFP_KERNEL); wd = kzalloc(sizeof(*wd), GFP_KERNEL);
if (!wd) if (!wd) {
goto no_mem; pr_warn("xtalk:%x bridge create out of memory\n", widget);
return;
}
snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx", snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
IP30_SWIN_BASE(widget)); IP30_SWIN_BASE(widget));
@ -56,24 +59,35 @@ static void bridge_platform_create(int widget, int masterwid)
w1_res.end = w1_res.start + 3; w1_res.end = w1_res.start + 3;
w1_res.flags = IORESOURCE_MEM; w1_res.flags = IORESOURCE_MEM;
pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO); pdev_wd = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
if (!pdev) { if (!pdev_wd) {
kfree(wd); pr_warn("xtalk:%x bridge create out of memory\n", widget);
goto no_mem; goto err_kfree_wd;
}
if (platform_device_add_resources(pdev_wd, &w1_res, 1)) {
pr_warn("xtalk:%x bridge failed to add platform resources.\n", widget);
goto err_put_pdev_wd;
}
if (platform_device_add_data(pdev_wd, wd, sizeof(*wd))) {
pr_warn("xtalk:%x bridge failed to add platform data.\n", widget);
goto err_put_pdev_wd;
}
if (platform_device_add(pdev_wd)) {
pr_warn("xtalk:%x bridge failed to add platform device.\n", widget);
goto err_put_pdev_wd;
} }
platform_device_add_resources(pdev, &w1_res, 1);
platform_device_add_data(pdev, wd, sizeof(*wd));
/* platform_device_add_data() duplicates the data */ /* platform_device_add_data() duplicates the data */
kfree(wd); kfree(wd);
platform_device_add(pdev);
bd = kzalloc(sizeof(*bd), GFP_KERNEL); bd = kzalloc(sizeof(*bd), GFP_KERNEL);
if (!bd) if (!bd) {
goto no_mem; pr_warn("xtalk:%x bridge create out of memory\n", widget);
pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO); goto err_unregister_pdev_wd;
if (!pdev) { }
kfree(bd); pdev_bd = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
goto no_mem; if (!pdev_bd) {
pr_warn("xtalk:%x bridge create out of memory\n", widget);
goto err_kfree_bd;
} }
bd->bridge_addr = IP30_RAW_SWIN_BASE(widget); bd->bridge_addr = IP30_RAW_SWIN_BASE(widget);
@ -93,15 +107,31 @@ static void bridge_platform_create(int widget, int masterwid)
bd->io.flags = IORESOURCE_IO; bd->io.flags = IORESOURCE_IO;
bd->io_offset = IP30_SWIN_BASE(widget); bd->io_offset = IP30_SWIN_BASE(widget);
platform_device_add_data(pdev, bd, sizeof(*bd)); if (platform_device_add_data(pdev_bd, bd, sizeof(*bd))) {
pr_warn("xtalk:%x bridge failed to add platform data.\n", widget);
goto err_put_pdev_bd;
}
if (platform_device_add(pdev_bd)) {
pr_warn("xtalk:%x bridge failed to add platform device.\n", widget);
goto err_put_pdev_bd;
}
/* platform_device_add_data() duplicates the data */ /* platform_device_add_data() duplicates the data */
kfree(bd); kfree(bd);
platform_device_add(pdev);
pr_info("xtalk:%x bridge widget\n", widget); pr_info("xtalk:%x bridge widget\n", widget);
return; return;
no_mem: err_put_pdev_bd:
pr_warn("xtalk:%x bridge create out of memory\n", widget); platform_device_put(pdev_bd);
err_kfree_bd:
kfree(bd);
err_unregister_pdev_wd:
platform_device_unregister(pdev_wd);
return;
err_put_pdev_wd:
platform_device_put(pdev_wd);
err_kfree_wd:
kfree(wd);
return;
} }
static unsigned int __init xbow_widget_active(s8 wid) static unsigned int __init xbow_widget_active(s8 wid)