[PATCH] usb: gadget: aspeed_udc: fix probe error cleanup
Jiawen Liu <[email protected]> Sun, 26 Jul 2026 09:52:15 +0400
| Newsgroups | org.ozlabs.lists.linux-aspeed,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-usb |
|---|---|
| Message-ID | <[email protected]> |
ast_udc_probe() jumps to one shared error label for failures after driver data is installed. That label calls ast_udc_remove(), but remove assumes that the gadget has been registered successfully and that later probe resources are initialized. For example, failures before usb_add_gadget_udc() can call usb_del_gadget_udc() through ast_udc_remove() even though gadget->udc has not been set up by the UDC core. Failures before or after DMA allocation also take the same remove-style path. Use staged probe error labels instead: free the endpoint DMA buffer only after it has been allocated, and disable the clock only after it has been enabled. While doing this, also handle dma_alloc_coherent() failure explicitly. Signed-off-by: Jiawen Liu <[email protected]> --- drivers/usb/gadget/udc/aspeed_udc.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c index 75f9c831b21a..877a9f7539f7 100644 --- a/drivers/usb/gadget/udc/aspeed_udc.c +++ b/drivers/usb/gadget/udc/aspeed_udc.c @@ -1474,6 +1474,7 @@ static int ast_udc_probe(struct platform_device *pdev) enum usb_device_speed max_speed; struct device *dev = &pdev->dev; struct ast_udc_dev *udc; + size_t ep0_buf_size; int rc; udc = devm_kzalloc(&pdev->dev, sizeof(struct ast_udc_dev), GFP_KERNEL); @@ -1516,10 +1517,14 @@ static int ast_udc_probe(struct platform_device *pdev) /* * Allocate DMA buffers for all EPs in one chunk */ + ep0_buf_size = AST_UDC_EP_DMA_SIZE * AST_UDC_NUM_ENDPOINTS; udc->ep0_buf = dma_alloc_coherent(&pdev->dev, - AST_UDC_EP_DMA_SIZE * - AST_UDC_NUM_ENDPOINTS, + ep0_buf_size, &udc->ep0_buf_dma, GFP_KERNEL); + if (!udc->ep0_buf) { + rc = -ENOMEM; + goto err_disable_clk; + } udc->gadget.speed = USB_SPEED_UNKNOWN; udc->gadget.max_speed = USB_SPEED_HIGH; @@ -1550,20 +1555,20 @@ static int ast_udc_probe(struct platform_device *pdev) udc->irq = platform_get_irq(pdev, 0); if (udc->irq < 0) { rc = udc->irq; - goto err; + goto err_free_ep0_buf; } rc = devm_request_irq(&pdev->dev, udc->irq, ast_udc_isr, 0, KBUILD_MODNAME, udc); if (rc) { dev_err(&pdev->dev, "Failed to request interrupt\n"); - goto err; + goto err_free_ep0_buf; } rc = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (rc) { dev_err(&pdev->dev, "Failed to add gadget udc\n"); - goto err; + goto err_free_ep0_buf; } dev_info(&pdev->dev, "Initialized udc in USB%s mode\n", @@ -1571,9 +1576,15 @@ static int ast_udc_probe(struct platform_device *pdev) return 0; +err_free_ep0_buf: + dma_free_coherent(&pdev->dev, + ep0_buf_size, udc->ep0_buf, + udc->ep0_buf_dma); + udc->ep0_buf = NULL; +err_disable_clk: + clk_disable_unprepare(udc->clk); err: dev_err(&pdev->dev, "Failed to udc probe, rc:0x%x\n", rc); - ast_udc_remove(pdev); return rc; } -- 2.34.1