summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@nxp.com>2020-08-21 05:55:47 +0300
committerFelipe Balbi <balbi@kernel.org>2020-10-02 09:57:42 +0300
commit6b7778924c70dad395f6aa843d641e799590f890 (patch)
treed25fcc1fce26d163a1c98a2c67df2c211f1279ac
parent9b719c7119e77e8ddeefe4772c554d2863579c2b (diff)
downloadlinux-6b7778924c70dad395f6aa843d641e799590f890.tar.xz
usb: cdns3: gadget: fix possible memory leak
If cdns3_gadget_start is failed, it never frees cdns3_device structure. Meanwhile, there is no release function for gadget device, it causes there is no sync with driver core. To fix this, we add release function for gadget device, and free cdns3_device structure at there. Meanwhile, With the new UDC core APIs, we could work with driver core better to handle memory leak issue. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Peter Chen <peter.chen@nxp.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
-rw-r--r--drivers/usb/cdns3/gadget.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
index d3f079af4a00..26ba41700672 100644
--- a/drivers/usb/cdns3/gadget.c
+++ b/drivers/usb/cdns3/gadget.c
@@ -2989,6 +2989,14 @@ err:
return -ENOMEM;
}
+static void cdns3_gadget_release(struct device *dev)
+{
+ struct cdns3_device *priv_dev = container_of(dev,
+ struct cdns3_device, gadget.dev);
+
+ kfree(priv_dev);
+}
+
void cdns3_gadget_exit(struct cdns3 *cdns)
{
struct cdns3_device *priv_dev;
@@ -2999,7 +3007,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns)
pm_runtime_mark_last_busy(cdns->dev);
pm_runtime_put_autosuspend(cdns->dev);
- usb_del_gadget_udc(&priv_dev->gadget);
+ usb_del_gadget(&priv_dev->gadget);
devm_free_irq(cdns->dev, cdns->dev_irq, priv_dev);
cdns3_free_all_eps(priv_dev);
@@ -3020,7 +3028,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns)
priv_dev->setup_dma);
kfree(priv_dev->zlp_buf);
- kfree(priv_dev);
+ usb_put_gadget(&priv_dev->gadget);
cdns->gadget_dev = NULL;
cdns3_drd_gadget_off(cdns);
}
@@ -3035,6 +3043,8 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
if (!priv_dev)
return -ENOMEM;
+ usb_initialize_gadget(cdns->dev, &priv_dev->gadget,
+ cdns3_gadget_release);
cdns->gadget_dev = priv_dev;
priv_dev->sysdev = cdns->dev;
priv_dev->dev = cdns->dev;
@@ -3122,10 +3132,9 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
}
/* add USB gadget device */
- ret = usb_add_gadget_udc(priv_dev->dev, &priv_dev->gadget);
+ ret = usb_add_gadget(&priv_dev->gadget);
if (ret < 0) {
- dev_err(priv_dev->dev,
- "Failed to register USB device controller\n");
+ dev_err(priv_dev->dev, "Failed to add gadget\n");
goto err4;
}
@@ -3138,6 +3147,7 @@ err3:
err2:
cdns3_free_all_eps(priv_dev);
err1:
+ usb_put_gadget(&priv_dev->gadget);
cdns->gadget_dev = NULL;
return ret;
}