usb: gadget: amd5536udc: fix error handling in udc_pci_probe()
authorAlexey Khoroshilov <khoroshilov@ispras.ru>
Sat, 5 Sep 2015 22:11:51 +0000 (01:11 +0300)
committerFelipe Balbi <balbi@ti.com>
Mon, 14 Sep 2015 15:14:51 +0000 (10:14 -0500)
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: Alexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/udc/amd5536udc.c

index fdacddb..175ca93 100644 (file)
@@ -3138,8 +3138,8 @@ static void udc_pci_remove(struct pci_dev *pdev)
        writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
        if (dev->irq_registered)
                free_irq(pdev->irq, dev);
-       if (dev->regs)
-               iounmap(dev->regs);
+       if (dev->virt_addr)
+               iounmap(dev->virt_addr);
        if (dev->mem_region)
                release_mem_region(pci_resource_start(pdev, 0),
                                pci_resource_len(pdev, 0));
@@ -3226,17 +3226,13 @@ static int udc_pci_probe(
 
        /* init */
        dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
-       if (!dev) {
-               retval = -ENOMEM;
-               goto finished;
-       }
+       if (!dev)
+               return -ENOMEM;
 
        /* pci setup */
        if (pci_enable_device(pdev) < 0) {
-               kfree(dev);
-               dev = NULL;
                retval = -ENODEV;
-               goto finished;
+               goto err_pcidev;
        }
        dev->active = 1;
 
@@ -3246,28 +3242,22 @@ static int udc_pci_probe(
 
        if (!request_mem_region(resource, len, name)) {
                dev_dbg(&pdev->dev, "pci device used already\n");
-               kfree(dev);
-               dev = NULL;
                retval = -EBUSY;
-               goto finished;
+               goto err_memreg;
        }
        dev->mem_region = 1;
 
        dev->virt_addr = ioremap_nocache(resource, len);
        if (dev->virt_addr == NULL) {
                dev_dbg(&pdev->dev, "start address cannot be mapped\n");
-               kfree(dev);
-               dev = NULL;
                retval = -EFAULT;
-               goto finished;
+               goto err_ioremap;
        }
 
        if (!pdev->irq) {
                dev_err(&pdev->dev, "irq not set\n");
-               kfree(dev);
-               dev = NULL;
                retval = -ENODEV;
-               goto finished;
+               goto err_irq;
        }
 
        spin_lock_init(&dev->lock);
@@ -3283,10 +3273,8 @@ static int udc_pci_probe(
 
        if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
                dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
-               kfree(dev);
-               dev = NULL;
                retval = -EBUSY;
-               goto finished;
+               goto err_irq;
        }
        dev->irq_registered = 1;
 
@@ -3314,8 +3302,17 @@ static int udc_pci_probe(
                return 0;
 
 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;
 }