usb: amd5536udc: fixed shared interrupt bug and warning oops
authorThomas Dahlmann <dahlmann.thomas@arcor.de>
Tue, 17 Nov 2009 22:18:27 +0000 (14:18 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 1 Dec 2009 00:43:15 +0000 (16:43 -0800)
- fixed shared interrupt bug reported by Vadim Lobanov
 - fixed possible warning oops on driver unload when connected
 - prevent interrupt flood in PIO mode ("modprobe amd5536udc use_dma=0")
   when using gadget ether

Signed-off-by: Thomas Dahlmann <dahlmann.thomas@arcor.de>
Cc: Robert Richter <robert.richter@amd.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: stable <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/gadget/amd5536udc.c

index d5b65962dd36a0bf9050cd61c51140979f9ca3d2..731150d4b1d9d0e646e34ca03f7cbaa0ac85e398 100644 (file)
@@ -1213,7 +1213,12 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
                                tmp &= AMD_UNMASK_BIT(ep->num);
                                writel(tmp, &dev->regs->ep_irqmsk);
                        }
-               }
+               } else if (ep->in) {
+                               /* enable ep irq */
+                               tmp = readl(&dev->regs->ep_irqmsk);
+                               tmp &= AMD_UNMASK_BIT(ep->num);
+                               writel(tmp, &dev->regs->ep_irqmsk);
+                       }
 
        } else if (ep->dma) {
 
@@ -2005,18 +2010,17 @@ __acquires(dev->lock)
 {
        int tmp;
 
-       /* empty queues and init hardware */
-       udc_basic_init(dev);
-       for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
-               empty_req_queue(&dev->ep[tmp]);
-       }
-
        if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
                spin_unlock(&dev->lock);
                driver->disconnect(&dev->gadget);
                spin_lock(&dev->lock);
        }
-       /* init */
+
+       /* empty queues and init hardware */
+       udc_basic_init(dev);
+       for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
+               empty_req_queue(&dev->ep[tmp]);
+
        udc_setup_endpoints(dev);
 }
 
@@ -2472,6 +2476,13 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
                                }
                        }
 
+               } else if (!use_dma && ep->in) {
+                       /* disable interrupt */
+                       tmp = readl(
+                               &dev->regs->ep_irqmsk);
+                       tmp |= AMD_BIT(ep->num);
+                       writel(tmp,
+                               &dev->regs->ep_irqmsk);
                }
        }
        /* clear status bits */
@@ -3279,6 +3290,17 @@ static int udc_pci_probe(
                goto finished;
        }
 
+       spin_lock_init(&dev->lock);
+       /* udc csr registers base */
+       dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+       /* dev registers base */
+       dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+       /* ep registers base */
+       dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+       /* fifo's base */
+       dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+       dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
        if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
                dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
                kfree(dev);
@@ -3331,7 +3353,6 @@ static int udc_probe(struct udc *dev)
        udc_pollstall_timer.data = 0;
 
        /* device struct setup */
-       spin_lock_init(&dev->lock);
        dev->gadget.ops = &udc_ops;
 
        dev_set_name(&dev->gadget.dev, "gadget");
@@ -3340,16 +3361,6 @@ static int udc_probe(struct udc *dev)
        dev->gadget.name = name;
        dev->gadget.is_dualspeed = 1;
 
-       /* udc csr registers base */
-       dev->csr = dev->virt_addr + UDC_CSR_ADDR;
-       /* dev registers base */
-       dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
-       /* ep registers base */
-       dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
-       /* fifo's base */
-       dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
-       dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
-
        /* init registers, interrupts, ... */
        startup_registers(dev);