]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/musb/musbhsdma.c
ARM: OMAP: MUSB: DMA interrupt locking fix
[linux-2.6-omap-h63xx.git] / drivers / usb / musb / musbhsdma.c
index 48e5531888d4088386f6a8b9768b307c202d742b..589ca80a64e50ef943ef65854b47345f51577131 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * MUSB OTG driver internal DMA controller support
+ * MUSB OTG driver - support for Mentor's DMA controller
  *
  * Copyright 2005 Mentor Graphics Corporation
  * Copyright (C) 2005-2007 by Texas Instruments
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-
-/*
- * Implementation for the DMA controller within the MUSBMHDRC.
- */
-
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include "musbdefs.h"
+#include "musb_core.h"
 
 #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
 #include "omap2430.h"
 #endif
 
-#define MGC_O_HSDMA_BASE               0x200
-#define MGC_O_HSDMA_INTR               (MGC_O_HSDMA_BASE + 0)
-#define MGC_O_HSDMA_CONTROL            0x4
-#define MGC_O_HSDMA_ADDRESS            0x8
-#define MGC_O_HSDMA_COUNT              0xc
+#define MUSB_HSDMA_BASE                0x200
+#define MUSB_HSDMA_INTR                (MUSB_HSDMA_BASE + 0)
+#define MUSB_HSDMA_CONTROL             0x4
+#define MUSB_HSDMA_ADDRESS             0x8
+#define MUSB_HSDMA_COUNT               0xc
 
-#define MGC_HSDMA_CHANNEL_OFFSET(_bChannel, _offset)           \
-               (MGC_O_HSDMA_BASE + (_bChannel << 4) + _offset)
+#define MUSB_HSDMA_CHANNEL_OFFSET(_bChannel, _offset)          \
+               (MUSB_HSDMA_BASE + (_bChannel << 4) + _offset)
 
 /* control register (16-bit): */
 #define MUSB_HSDMA_ENABLE_SHIFT                0
 #define MUSB_HSDMA_BUSERROR_SHIFT              8
 #define MUSB_HSDMA_BURSTMODE_SHIFT             9
 #define MUSB_HSDMA_BURSTMODE           (3 << MUSB_HSDMA_BURSTMODE_SHIFT)
-#define MGC_HSDMA_BURSTMODE_UNSPEC     0
-#define MGC_HSDMA_BURSTMODE_INCR4      1
-#define MGC_HSDMA_BURSTMODE_INCR8      2
-#define MGC_HSDMA_BURSTMODE_INCR16     3
+#define MUSB_HSDMA_BURSTMODE_UNSPEC    0
+#define MUSB_HSDMA_BURSTMODE_INCR4     1
+#define MUSB_HSDMA_BURSTMODE_INCR8     2
+#define MUSB_HSDMA_BURSTMODE_INCR16    3
 
-#define MGC_HSDMA_CHANNELS             8
+#define MUSB_HSDMA_CHANNELS            8
 
 struct musb_dma_controller;
 
@@ -84,11 +79,11 @@ struct musb_dma_channel {
 
 struct musb_dma_controller {
        struct dma_controller           Controller;
-       struct musb_dma_channel         aChannel[MGC_HSDMA_CHANNELS];
-       void                            *pDmaPrivate;
-       void __iomem                    *pCoreBase;
-       u8                              bChannelCount;
-       u8                              bmUsedChannels;
+       struct musb_dma_channel         aChannel[MUSB_HSDMA_CHANNELS];
+       void                            *pDmaPrivate;
+       void __iomem                    *pCoreBase;
+       u8                              bChannelCount;
+       u8                              bmUsedChannels;
        u8                              irq;
 };
 
@@ -112,9 +107,9 @@ static int dma_controller_stop(struct dma_controller *c)
                dev_err(musb->controller,
                        "Stopping DMA controller while channel active\n");
 
-               for (bBit = 0; bBit < MGC_HSDMA_CHANNELS; bBit++) {
+               for (bBit = 0; bBit < MUSB_HSDMA_CHANNELS; bBit++) {
                        if (controller->bmUsedChannels & (1 << bBit)) {
-                               pChannel = &(controller->aChannel[bBit].Channel);
+                               pChannel = &controller->aChannel[bBit].Channel;
                                dma_channel_release(pChannel);
 
                                if (!controller->bmUsedChannels)
@@ -125,7 +120,7 @@ static int dma_controller_stop(struct dma_controller *c)
        return 0;
 }
 
-static struct dma_channeldma_channel_allocate(struct dma_controller *c,
+static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
                                struct musb_hw_ep *hw_ep, u8 transmit)
 {
        u8 bBit;
@@ -134,7 +129,7 @@ static struct dma_channel* dma_channel_allocate(struct dma_controller *c,
        struct musb_dma_controller *controller =
                        container_of(c, struct musb_dma_controller, Controller);
 
-       for (bBit = 0; bBit < MGC_HSDMA_CHANNELS; bBit++) {
+       for (bBit = 0; bBit < MUSB_HSDMA_CHANNELS; bBit++) {
                if (!(controller->bmUsedChannels & (1 << bBit))) {
                        controller->bmUsedChannels |= (1 << bBit);
                        pImplChannel = &(controller->aChannel[bBit]);
@@ -182,42 +177,43 @@ static void configure_channel(struct dma_channel *pChannel,
        u16 csr = 0;
 
        DBG(4, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
-           pChannel, packet_sz, dma_addr, len, mode);
+                       pChannel, packet_sz, dma_addr, len, mode);
 
        if (mode) {
                csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
-               if (len < packet_sz) {
-                       return FALSE;
-               }
+               BUG_ON(len < packet_sz);
+
                if (packet_sz >= 64) {
-                       csr |=
-                           MGC_HSDMA_BURSTMODE_INCR16 << MUSB_HSDMA_BURSTMODE_SHIFT;
+                       csr |= MUSB_HSDMA_BURSTMODE_INCR16
+                                       << MUSB_HSDMA_BURSTMODE_SHIFT;
                } else if (packet_sz >= 32) {
-                       csr |=
-                           MGC_HSDMA_BURSTMODE_INCR8 << MUSB_HSDMA_BURSTMODE_SHIFT;
+                       csr |= MUSB_HSDMA_BURSTMODE_INCR8
+                                       << MUSB_HSDMA_BURSTMODE_SHIFT;
                } else if (packet_sz >= 16) {
-                       csr |=
-                           MGC_HSDMA_BURSTMODE_INCR4 << MUSB_HSDMA_BURSTMODE_SHIFT;
+                       csr |= MUSB_HSDMA_BURSTMODE_INCR4
+                                       << MUSB_HSDMA_BURSTMODE_SHIFT;
                }
        }
 
        csr |= (pImplChannel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT)
                | (1 << MUSB_HSDMA_ENABLE_SHIFT)
                | (1 << MUSB_HSDMA_IRQENABLE_SHIFT)
-               | (pImplChannel->transmit ? (1 << MUSB_HSDMA_TRANSMIT_SHIFT) : 0);
+               | (pImplChannel->transmit
+                               ? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
+                               : 0);
 
        /* address/count */
        musb_writel(mbase,
-                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_ADDRESS),
-                   dma_addr);
+               MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
+               dma_addr);
        musb_writel(mbase,
-                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_COUNT),
-                   len);
+               MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
+               len);
 
        /* control (this should start things) */
        musb_writew(mbase,
-                   MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL),
-                   csr);
+               MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
+               csr);
 }
 
 static int dma_channel_program(struct dma_channel * pChannel,
@@ -241,14 +237,12 @@ static int dma_channel_program(struct dma_channel * pChannel,
        pImplChannel->wMaxPacketSize = packet_sz;
        pChannel->status = MUSB_DMA_STATUS_BUSY;
 
-       if ((mode == 1) && (len >= packet_sz)) {
-               configure_channel(pChannel, packet_sz, 1, dma_addr,
-                                 len);
-       } else
-               configure_channel(pChannel, packet_sz, 0, dma_addr,
-                                 len);
+       if ((mode == 1) && (len >= packet_sz))
+               configure_channel(pChannel, packet_sz, 1, dma_addr, len);
+       else
+               configure_channel(pChannel, packet_sz, 0, dma_addr, len);
 
-       return TRUE;
+       return true;
 }
 
 static int dma_channel_abort(struct dma_channel *pChannel)
@@ -268,8 +262,8 @@ static int dma_channel_abort(struct dma_channel *pChannel)
                                 MUSB_TXCSR_DMAENAB |
                                 MUSB_TXCSR_DMAMODE);
                        musb_writew(mbase,
-                                       MUSB_EP_OFFSET(pImplChannel->epnum,MUSB_TXCSR),
-                                       csr);
+                               MUSB_EP_OFFSET(pImplChannel->epnum,MUSB_TXCSR),
+                               csr);
                }
                else {
                        csr = musb_readw(mbase,
@@ -278,16 +272,19 @@ static int dma_channel_abort(struct dma_channel *pChannel)
                                 MUSB_RXCSR_DMAENAB |
                                 MUSB_RXCSR_DMAMODE);
                        musb_writew(mbase,
-                                       MUSB_EP_OFFSET(pImplChannel->epnum,MUSB_RXCSR),
-                                       csr);
+                               MUSB_EP_OFFSET(pImplChannel->epnum,MUSB_RXCSR),
+                               csr);
                }
 
                musb_writew(mbase,
-                  MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_CONTROL), 0);
+                       MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_CONTROL),
+                       0);
                musb_writel(mbase,
-                  MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_ADDRESS), 0);
+                       MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_ADDRESS),
+                       0);
                musb_writel(mbase,
-                  MGC_HSDMA_CHANNEL_OFFSET(bChannel, MGC_O_HSDMA_COUNT), 0);
+                       MUSB_HSDMA_CHANNEL_OFFSET(bChannel, MUSB_HSDMA_COUNT),
+                       0);
 
                pChannel->status = MUSB_DMA_STATUS_FREE;
        }
@@ -299,6 +296,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
        struct musb_dma_controller *controller =
                (struct musb_dma_controller *)private_data;
        struct musb_dma_channel *pImplChannel;
+       struct musb *musb = controller->pDmaPrivate;
        u8 *mbase = controller->pCoreBase;
        struct dma_channel *pChannel;
        u8 bChannel;
@@ -306,38 +304,41 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
        u32 dwAddress;
        u8 int_hsdma;
        irqreturn_t retval = IRQ_NONE;
+       unsigned long flags;
+
+       spin_lock_irqsave(&musb->lock, flags);
 
-       int_hsdma = musb_readb(mbase, MGC_O_HSDMA_INTR);
+       int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
        if (!int_hsdma)
                goto done;
 
-       for (bChannel = 0; bChannel < MGC_HSDMA_CHANNELS; bChannel++) {
+       for (bChannel = 0; bChannel < MUSB_HSDMA_CHANNELS; bChannel++) {
                if (int_hsdma & (1 << bChannel)) {
                        pImplChannel = (struct musb_dma_channel *)
                                        &(controller->aChannel[bChannel]);
                        pChannel = &pImplChannel->Channel;
 
                        csr = musb_readw(mbase,
-                                      MGC_HSDMA_CHANNEL_OFFSET(bChannel,
-                                                       MGC_O_HSDMA_CONTROL));
+                                       MUSB_HSDMA_CHANNEL_OFFSET(bChannel,
+                                                       MUSB_HSDMA_CONTROL));
 
-                       if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) {
+                       if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT))
                                pImplChannel->Channel.status =
-                                   MUSB_DMA_STATUS_BUS_ABORT;
-                       else {
+                                       MUSB_DMA_STATUS_BUS_ABORT;
+                       else {
                                dwAddress = musb_readl(mbase,
-                                               MGC_HSDMA_CHANNEL_OFFSET(
+                                               MUSB_HSDMA_CHANNEL_OFFSET(
                                                        bChannel,
-                                                       MGC_O_HSDMA_ADDRESS));
-                               pChannel->actual_len =
-                                   dwAddress - pImplChannel->dwStartAddress;
+                                                       MUSB_HSDMA_ADDRESS));
+                               pChannel->actual_len = dwAddress
+                                       - pImplChannel->dwStartAddress;
 
                                DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
-                                   pChannel, pImplChannel->dwStartAddress,
-                                   dwAddress, pChannel->actual_len,
-                                   pImplChannel->len,
-                                   (pChannel->actual_len <
-                                       pImplChannel->len) ?
+                                       pChannel, pImplChannel->dwStartAddress,
+                                       dwAddress, pChannel->actual_len,
+                                       pImplChannel->len,
+                                       (pChannel->actual_len
+                                               < pImplChannel->len) ?
                                        "=> reconfig 0": "=> complete");
 
                                u8 devctl = musb_readb(mbase,
@@ -347,20 +348,21 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
 
                                /* completed */
                                if ((devctl & MUSB_DEVCTL_HM)
-                                   && (pImplChannel->transmit)
-                                   && ((pChannel->desired_mode == 0)
-                                       || (pChannel->actual_len &
+                                       && (pImplChannel->transmit)
+                                       && ((pChannel->desired_mode == 0)
+                                           || (pChannel->actual_len &
                                            (pImplChannel->wMaxPacketSize - 1)))
-                                  ) {
+                                        ) {
                                        /* Send out the packet */
                                        musb_ep_select(mbase,
                                                pImplChannel->epnum);
-                                       musb_writew(mbase,
-                                               MUSB_EP_OFFSET(pImplChannel->epnum,MUSB_TXCSR),
+                                       musb_writew(mbase, MUSB_EP_OFFSET(
+                                                       pImplChannel->epnum,
+                                                       MUSB_TXCSR),
                                                MUSB_TXCSR_TXPKTRDY);
                                } else
                                        musb_dma_completion(
-                                               controller->pDmaPrivate,
+                                               musb,
                                                pImplChannel->epnum,
                                                pImplChannel->transmit);
                        }
@@ -368,6 +370,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
        }
        retval = IRQ_HANDLED;
 done:
+       spin_unlock_irqrestore(&musb->lock, flags);
        return retval;
 }
 
@@ -403,7 +406,7 @@ dma_controller_create(struct musb *musb, void __iomem *pCoreBase)
                                GFP_KERNEL)))
                return NULL;
 
-       controller->bChannelCount = MGC_HSDMA_CHANNELS;
+       controller->bChannelCount = MUSB_HSDMA_CHANNELS;
        controller->pDmaPrivate = musb;
        controller->pCoreBase = pCoreBase;