Commit 6527cc27 authored by Alexey Khoroshilov's avatar Alexey Khoroshilov Committed by Felipe Balbi

usb: gadget: amd5536udc: fix error handling in udc_pci_probe()

If a failure happens early in udc_pci_probe(), error handling code
just kfree(dev) and returns. The patch adds proper resource
deallocations in udc_pci_probe() itself,
since udc_pci_remove() is not suitabe to be called so early
in initialization process.

By the way, iounmap(dev->regs) is replaced by iounmap(dev->virt_addr)
in udc_pci_remove() for clarity.

Found by Linux Driver Verification project (linuxtesting.org).
Signed-off-by: default avatarAlexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 88ccdbd5
...@@ -3138,8 +3138,8 @@ static void udc_pci_remove(struct pci_dev *pdev) ...@@ -3138,8 +3138,8 @@ static void udc_pci_remove(struct pci_dev *pdev)
writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
if (dev->irq_registered) if (dev->irq_registered)
free_irq(pdev->irq, dev); free_irq(pdev->irq, dev);
if (dev->regs) if (dev->virt_addr)
iounmap(dev->regs); iounmap(dev->virt_addr);
if (dev->mem_region) if (dev->mem_region)
release_mem_region(pci_resource_start(pdev, 0), release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0)); pci_resource_len(pdev, 0));
...@@ -3226,17 +3226,13 @@ static int udc_pci_probe( ...@@ -3226,17 +3226,13 @@ static int udc_pci_probe(
/* init */ /* init */
dev = kzalloc(sizeof(struct udc), GFP_KERNEL); dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
if (!dev) { if (!dev)
retval = -ENOMEM; return -ENOMEM;
goto finished;
}
/* pci setup */ /* pci setup */
if (pci_enable_device(pdev) < 0) { if (pci_enable_device(pdev) < 0) {
kfree(dev);
dev = NULL;
retval = -ENODEV; retval = -ENODEV;
goto finished; goto err_pcidev;
} }
dev->active = 1; dev->active = 1;
...@@ -3246,28 +3242,22 @@ static int udc_pci_probe( ...@@ -3246,28 +3242,22 @@ static int udc_pci_probe(
if (!request_mem_region(resource, len, name)) { if (!request_mem_region(resource, len, name)) {
dev_dbg(&pdev->dev, "pci device used already\n"); dev_dbg(&pdev->dev, "pci device used already\n");
kfree(dev);
dev = NULL;
retval = -EBUSY; retval = -EBUSY;
goto finished; goto err_memreg;
} }
dev->mem_region = 1; dev->mem_region = 1;
dev->virt_addr = ioremap_nocache(resource, len); dev->virt_addr = ioremap_nocache(resource, len);
if (dev->virt_addr == NULL) { if (dev->virt_addr == NULL) {
dev_dbg(&pdev->dev, "start address cannot be mapped\n"); dev_dbg(&pdev->dev, "start address cannot be mapped\n");
kfree(dev);
dev = NULL;
retval = -EFAULT; retval = -EFAULT;
goto finished; goto err_ioremap;
} }
if (!pdev->irq) { if (!pdev->irq) {
dev_err(&pdev->dev, "irq not set\n"); dev_err(&pdev->dev, "irq not set\n");
kfree(dev);
dev = NULL;
retval = -ENODEV; retval = -ENODEV;
goto finished; goto err_irq;
} }
spin_lock_init(&dev->lock); spin_lock_init(&dev->lock);
...@@ -3283,10 +3273,8 @@ static int udc_pci_probe( ...@@ -3283,10 +3273,8 @@ static int udc_pci_probe(
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq); dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
kfree(dev);
dev = NULL;
retval = -EBUSY; retval = -EBUSY;
goto finished; goto err_irq;
} }
dev->irq_registered = 1; dev->irq_registered = 1;
...@@ -3314,8 +3302,17 @@ static int udc_pci_probe( ...@@ -3314,8 +3302,17 @@ static int udc_pci_probe(
return 0; return 0;
finished: finished:
if (dev) udc_pci_remove(pdev);
udc_pci_remove(pdev); return retval;
err_irq:
iounmap(dev->virt_addr);
err_ioremap:
release_mem_region(resource, len);
err_memreg:
pci_disable_device(pdev);
err_pcidev:
kfree(dev);
return retval; return retval;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment