diff options
author | Thomas Dahlmann <dahlmann.thomas@arcor.de> | 2009-11-17 14:18:27 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-08 10:22:13 -0800 |
commit | 774430b67775145d69362ca807d5f25db019919e (patch) | |
tree | ef8f66adb3feb4dea588026f08f91721c1e8ae50 | |
parent | 41e0b0605826e299a981e2da61e631efe171f4af (diff) | |
download | linux-stable-774430b67775145d69362ca807d5f25db019919e.tar.gz linux-stable-774430b67775145d69362ca807d5f25db019919e.tar.bz2 linux-stable-774430b67775145d69362ca807d5f25db019919e.zip |
usb: amd5536udc: fixed shared interrupt bug and warning oops
commit c5deb832d7a3f9618b09e6eeaa91a1a845c90c65 upstream.
- 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>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/gadget/amd5536udc.c | 49 |
1 files changed, 30 insertions, 19 deletions
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 77352ccc245e..fb0976643a2f 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -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); } @@ -2478,6 +2482,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 */ @@ -3285,6 +3296,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); @@ -3337,7 +3359,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"); @@ -3346,16 +3367,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); |