Merge branch 'fixes' of http://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 30 Dec 2011 21:45:34 +0000 (13:45 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 30 Dec 2011 21:45:34 +0000 (13:45 -0800)
* 'fixes' of http://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-2.6-arm:
  ARM: 7237/1: PL330: Fix driver freeze
  ARM: 7197/1: errata: Remove SMP dependency for erratum 751472
  ARM: 7196/1: errata: Remove SMP dependency for erratum 720789
  ARM: 7220/1: mmc: mmci: Fixup error handling for dma
  ARM: 7214/1: mmc: mmci: Fixup handling of MCI_STARTBITERR

arch/arm/Kconfig
arch/arm/common/pl330.c
arch/arm/mm/proc-v7.S
drivers/mmc/host/mmci.c

index 776d76b..b259c7c 100644 (file)
@@ -1246,7 +1246,7 @@ config PL310_ERRATA_588369
 
 config ARM_ERRATA_720789
        bool "ARM errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID"
-       depends on CPU_V7 && SMP
+       depends on CPU_V7
        help
          This option enables the workaround for the 720789 Cortex-A9 (prior to
          r2p0) erratum. A faulty ASID can be sent to the other CPUs for the
@@ -1282,7 +1282,7 @@ config ARM_ERRATA_743622
 
 config ARM_ERRATA_751472
        bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation"
-       depends on CPU_V7 && SMP
+       depends on CPU_V7
        help
          This option enables the workaround for the 751472 Cortex-A9 (prior
          to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the
index f407a6b..8d8df74 100644 (file)
  */
 #define MCODE_BUFF_PER_REQ     256
 
-/*
- * Mark a _pl330_req as free.
- * We do it by writing DMAEND as the first instruction
- * because no valid request is going to have DMAEND as
- * its first instruction to execute.
- */
-#define MARK_FREE(req) do { \
-                               _emit_END(0, (req)->mc_cpu); \
-                               (req)->mc_len = 0; \
-                       } while (0)
-
 /* If the _pl330_req is available to the client */
 #define IS_FREE(req)   (*((u8 *)((req)->mc_cpu)) == CMD_DMAEND)
 
@@ -301,8 +290,10 @@ struct pl330_thread {
        struct pl330_dmac *dmac;
        /* Only two at a time */
        struct _pl330_req req[2];
-       /* Index of the last submitted request */
+       /* Index of the last enqueued request */
        unsigned lstenq;
+       /* Index of the last submitted request or -1 if the DMA is stopped */
+       int req_running;
 };
 
 enum pl330_dmac_state {
@@ -778,6 +769,22 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd,
        writel(0, regs + DBGCMD);
 }
 
+/*
+ * Mark a _pl330_req as free.
+ * We do it by writing DMAEND as the first instruction
+ * because no valid request is going to have DMAEND as
+ * its first instruction to execute.
+ */
+static void mark_free(struct pl330_thread *thrd, int idx)
+{
+       struct _pl330_req *req = &thrd->req[idx];
+
+       _emit_END(0, req->mc_cpu);
+       req->mc_len = 0;
+
+       thrd->req_running = -1;
+}
+
 static inline u32 _state(struct pl330_thread *thrd)
 {
        void __iomem *regs = thrd->dmac->pinfo->base;
@@ -836,31 +843,6 @@ static inline u32 _state(struct pl330_thread *thrd)
        }
 }
 
-/* If the request 'req' of thread 'thrd' is currently active */
-static inline bool _req_active(struct pl330_thread *thrd,
-               struct _pl330_req *req)
-{
-       void __iomem *regs = thrd->dmac->pinfo->base;
-       u32 buf = req->mc_bus, pc = readl(regs + CPC(thrd->id));
-
-       if (IS_FREE(req))
-               return false;
-
-       return (pc >= buf && pc <= buf + req->mc_len) ? true : false;
-}
-
-/* Returns 0 if the thread is inactive, ID of active req + 1 otherwise */
-static inline unsigned _thrd_active(struct pl330_thread *thrd)
-{
-       if (_req_active(thrd, &thrd->req[0]))
-               return 1; /* First req active */
-
-       if (_req_active(thrd, &thrd->req[1]))
-               return 2; /* Second req active */
-
-       return 0;
-}
-
 static void _stop(struct pl330_thread *thrd)
 {
        void __iomem *regs = thrd->dmac->pinfo->base;
@@ -892,17 +874,22 @@ static bool _trigger(struct pl330_thread *thrd)
        struct _arg_GO go;
        unsigned ns;
        u8 insn[6] = {0, 0, 0, 0, 0, 0};
+       int idx;
 
        /* Return if already ACTIVE */
        if (_state(thrd) != PL330_STATE_STOPPED)
                return true;
 
-       if (!IS_FREE(&thrd->req[1 - thrd->lstenq]))
-               req = &thrd->req[1 - thrd->lstenq];
-       else if (!IS_FREE(&thrd->req[thrd->lstenq]))
-               req = &thrd->req[thrd->lstenq];
-       else
-               req = NULL;
+       idx = 1 - thrd->lstenq;
+       if (!IS_FREE(&thrd->req[idx]))
+               req = &thrd->req[idx];
+       else {
+               idx = thrd->lstenq;
+               if (!IS_FREE(&thrd->req[idx]))
+                       req = &thrd->req[idx];
+               else
+                       req = NULL;
+       }
 
        /* Return if no request */
        if (!req || !req->r)
@@ -933,6 +920,8 @@ static bool _trigger(struct pl330_thread *thrd)
        /* Only manager can execute GO */
        _execute_DBGINSN(thrd, insn, true);
 
+       thrd->req_running = idx;
+
        return true;
 }
 
@@ -1382,8 +1371,8 @@ static void pl330_dotask(unsigned long data)
 
                        thrd->req[0].r = NULL;
                        thrd->req[1].r = NULL;
-                       MARK_FREE(&thrd->req[0]);
-                       MARK_FREE(&thrd->req[1]);
+                       mark_free(thrd, 0);
+                       mark_free(thrd, 1);
 
                        /* Clear the reset flag */
                        pl330->dmac_tbd.reset_chan &= ~(1 << i);
@@ -1461,14 +1450,12 @@ int pl330_update(const struct pl330_info *pi)
 
                        thrd = &pl330->channels[id];
 
-                       active = _thrd_active(thrd);
-                       if (!active) /* Aborted */
+                       active = thrd->req_running;
+                       if (active == -1) /* Aborted */
                                continue;
 
-                       active -= 1;
-
                        rqdone = &thrd->req[active];
-                       MARK_FREE(rqdone);
+                       mark_free(thrd, active);
 
                        /* Get going again ASAP */
                        _start(thrd);
@@ -1509,7 +1496,7 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
        struct pl330_thread *thrd = ch_id;
        struct pl330_dmac *pl330;
        unsigned long flags;
-       int ret = 0, active;
+       int ret = 0, active = thrd->req_running;
 
        if (!thrd || thrd->free || thrd->dmac->state == DYING)
                return -EINVAL;
@@ -1525,28 +1512,24 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
 
                thrd->req[0].r = NULL;
                thrd->req[1].r = NULL;
-               MARK_FREE(&thrd->req[0]);
-               MARK_FREE(&thrd->req[1]);
+               mark_free(thrd, 0);
+               mark_free(thrd, 1);
                break;
 
        case PL330_OP_ABORT:
-               active = _thrd_active(thrd);
-
                /* Make sure the channel is stopped */
                _stop(thrd);
 
                /* ABORT is only for the active req */
-               if (!active)
+               if (active == -1)
                        break;
 
-               active--;
-
                thrd->req[active].r = NULL;
-               MARK_FREE(&thrd->req[active]);
+               mark_free(thrd, active);
 
                /* Start the next */
        case PL330_OP_START:
-               if (!_thrd_active(thrd) && !_start(thrd))
+               if ((active == -1) && !_start(thrd))
                        ret = -EIO;
                break;
 
@@ -1587,14 +1570,13 @@ int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus)
        else
                pstatus->faulting = false;
 
-       active = _thrd_active(thrd);
+       active = thrd->req_running;
 
-       if (!active) {
+       if (active == -1) {
                /* Indicate that the thread is not running */
                pstatus->top_req = NULL;
                pstatus->wait_req = NULL;
        } else {
-               active--;
                pstatus->top_req = thrd->req[active].r;
                pstatus->wait_req = !IS_FREE(&thrd->req[1 - active])
                                        ? thrd->req[1 - active].r : NULL;
@@ -1659,9 +1641,9 @@ void *pl330_request_channel(const struct pl330_info *pi)
                                thrd->free = false;
                                thrd->lstenq = 1;
                                thrd->req[0].r = NULL;
-                               MARK_FREE(&thrd->req[0]);
+                               mark_free(thrd, 0);
                                thrd->req[1].r = NULL;
-                               MARK_FREE(&thrd->req[1]);
+                               mark_free(thrd, 1);
                                break;
                        }
                }
@@ -1767,14 +1749,14 @@ static inline void _reset_thread(struct pl330_thread *thrd)
        thrd->req[0].mc_bus = pl330->mcode_bus
                                + (thrd->id * pi->mcbufsz);
        thrd->req[0].r = NULL;
-       MARK_FREE(&thrd->req[0]);
+       mark_free(thrd, 0);
 
        thrd->req[1].mc_cpu = thrd->req[0].mc_cpu
                                + pi->mcbufsz / 2;
        thrd->req[1].mc_bus = thrd->req[0].mc_bus
                                + pi->mcbufsz / 2;
        thrd->req[1].r = NULL;
-       MARK_FREE(&thrd->req[1]);
+       mark_free(thrd, 1);
 }
 
 static int dmac_alloc_threads(struct pl330_dmac *pl330)
index 2c559ac..e70a737 100644 (file)
@@ -363,11 +363,13 @@ __v7_setup:
        orreq   r10, r10, #1 << 6               @ set bit #6
        mcreq   p15, 0, r10, c15, c0, 1         @ write diagnostic register
 #endif
-#ifdef CONFIG_ARM_ERRATA_751472
-       cmp     r6, #0x30                       @ present prior to r3p0
+#if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP)
+       ALT_SMP(cmp r6, #0x30)                  @ present prior to r3p0
+       ALT_UP_B(1f)
        mrclt   p15, 0, r10, c15, c0, 1         @ read diagnostic register
        orrlt   r10, r10, #1 << 11              @ set bit #11
        mcrlt   p15, 0, r10, c15, c0, 1         @ write diagnostic register
+1:
 #endif
 
 3:     mov     r10, #0
index 50b5f99..0726e59 100644 (file)
@@ -675,7 +675,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
              unsigned int status)
 {
        /* First check for errors */
-       if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+       if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
+                     MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
                u32 remain, success;
 
                /* Terminate the DMA transfer */
@@ -754,8 +755,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
        }
 
        if (!cmd->data || cmd->error) {
-               if (host->data)
+               if (host->data) {
+                       /* Terminate the DMA transfer */
+                       if (dma_inprogress(host))
+                               mmci_dma_data_error(host);
                        mmci_stop_data(host);
+               }
                mmci_request_end(host, cmd->mrq);
        } else if (!(cmd->data->flags & MMC_DATA_READ)) {
                mmci_start_data(host, cmd->data);
@@ -955,8 +960,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
                dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
 
                data = host->data;
-               if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
-                             MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
+               if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
+                             MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
+                             MCI_DATABLOCKEND) && data)
                        mmci_data_irq(host, data, status);
 
                cmd = host->cmd;