fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / mmc / mmci.c
index 3a5f6ac..ccfe656 100644 (file)
@@ -7,7 +7,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/protocol.h>
+#include <linux/amba/bus.h>
+#include <linux/clk.h>
 
+#include <asm/cacheflush.h>
+#include <asm/div64.h>
 #include <asm/io.h>
-#include <asm/irq.h>
 #include <asm/scatterlist.h>
-#include <asm/hardware/amba.h>
-#include <asm/hardware/clock.h>
+#include <asm/sizes.h>
 #include <asm/mach/mmc.h>
 
 #include "mmci.h"
 
 #define DRIVER_NAME "mmci-pl18x"
 
-#ifdef CONFIG_MMC_DEBUG
 #define DBG(host,fmt,args...)  \
-       pr_debug("%s: %s: " fmt, host->mmc->host_name, __func__ , args)
-#else
-#define DBG(host,fmt,args...)  do { } while (0)
-#endif
+       pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
 
 static unsigned int fmax = 515633;
 
@@ -45,6 +42,8 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
 {
        writel(0, host->base + MMCICOMMAND);
 
+       BUG_ON(host->data);
+
        host->mrq = NULL;
        host->cmd = NULL;
 
@@ -70,29 +69,42 @@ static void mmci_stop_data(struct mmci_host *host)
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 {
        unsigned int datactrl, timeout, irqmask;
+       unsigned long long clks;
        void __iomem *base;
+       int blksz_bits;
 
        DBG(host, "blksz %04x blks %04x flags %08x\n",
-           1 << data->blksz_bits, data->blocks, data->flags);
+           data->blksz, data->blocks, data->flags);
 
        host->data = data;
-       host->size = data->blocks << data->blksz_bits;
+       host->size = data->blksz;
        host->data_xfered = 0;
 
        mmci_init_sg(host, data);
 
-       timeout = data->timeout_clks +
-                 ((unsigned long long)data->timeout_ns * host->cclk) /
-                  1000000000ULL;
+       clks = (unsigned long long)data->timeout_ns * host->cclk;
+       do_div(clks, 1000000000UL);
+
+       timeout = data->timeout_clks + (unsigned int)clks;
 
        base = host->base;
        writel(timeout, base + MMCIDATATIMER);
        writel(host->size, base + MMCIDATALENGTH);
 
-       datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
+       blksz_bits = ffs(data->blksz) - 1;
+       BUG_ON(1 << blksz_bits != data->blksz);
+
+       datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
        if (data->flags & MMC_DATA_READ) {
                datactrl |= MCI_DPSM_DIRECTION;
                irqmask = MCI_RXFIFOHALFFULLMASK;
+
+               /*
+                * If we have less than a FIFOSIZE of bytes to transfer,
+                * trigger a PIO interrupt as soon as any data is available.
+                */
+               if (host->size < MCI_FIFOSIZE)
+                       irqmask |= MCI_RXDATAAVLBLMASK;
        } else {
                /*
                 * We don't actually need to include "FIFO empty" here
@@ -120,15 +132,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
        }
 
        c |= cmd->opcode | MCI_CPSM_ENABLE;
-       switch (cmd->flags & MMC_RSP_MASK) {
-       case MMC_RSP_NONE:
-       default:
-               break;
-       case MMC_RSP_LONG:
-               c |= MCI_CPSM_LONGRSP;
-       case MMC_RSP_SHORT:
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136)
+                       c |= MCI_CPSM_LONGRSP;
                c |= MCI_CPSM_RESPONSE;
-               break;
        }
        if (/*interrupt*/0)
                c |= MCI_CPSM_INTERRUPT;
@@ -144,7 +151,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
              unsigned int status)
 {
        if (status & MCI_DATABLOCKEND) {
-               host->data_xfered += 1 << data->blksz_bits;
+               host->data_xfered += data->blksz;
        }
        if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
                if (status & MCI_DATACRCFAIL)
@@ -154,6 +161,13 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
                else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
                        data->error = MMC_ERR_FIFO;
                status |= MCI_DATAEND;
+
+               /*
+                * We hit an error condition.  Ensure that any data
+                * partially written to a page is properly coherent.
+                */
+               if (host->sg_len && data->flags & MMC_DATA_READ)
+                       flush_dcache_page(host->sg_ptr->page);
        }
        if (status & MCI_DATAEND) {
                mmci_stop_data(host);
@@ -186,6 +200,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
        }
 
        if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+               if (host->data)
+                       mmci_stop_data(host);
                mmci_request_end(host, cmd->mrq);
        } else if (!(cmd->data->flags & MMC_DATA_READ)) {
                mmci_start_data(host, cmd->data);
@@ -249,7 +265,7 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
 /*
  * PIO data transfer IRQ handler.
  */
-static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 {
        struct mmci_host *host = dev_id;
        void __iomem *base = host->base;
@@ -289,7 +305,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
                /*
                 * Unmap the buffer.
                 */
-               mmci_kunmap_atomic(host, &flags);
+               mmci_kunmap_atomic(host, buffer, &flags);
 
                host->sg_off += len;
                host->size -= len;
@@ -298,6 +314,13 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
                if (remain)
                        break;
 
+               /*
+                * If we were reading, and we have completed this
+                * page, ensure that the data cache is coherent.
+                */
+               if (status & MCI_RXACTIVE)
+                       flush_dcache_page(host->sg_ptr->page);
+
                if (!mmci_next_sg(host))
                        break;
 
@@ -328,7 +351,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
 /*
  * Handle completion of command and data transfers.
  */
-static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmci_irq(int irq, void *dev_id)
 {
        struct mmci_host *host = dev_id;
        u32 status;
@@ -386,9 +409,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct mmci_host *host = mmc_priv(mmc);
        u32 clk = 0, pwr = 0;
 
-       DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n",
-           ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
-
        if (ios->clock) {
                if (ios->clock >= host->mclk) {
                        clk = MCI_CLK_BYPASS;
@@ -427,7 +447,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 }
 
-static struct mmc_host_ops mmci_ops = {
+static const struct mmc_host_ops mmci_ops = {
        .request        = mmci_request,
        .set_ios        = mmci_set_ios,
 };
@@ -439,7 +459,7 @@ static void mmci_check_status(unsigned long data)
 
        status = host->plat->status(mmc_dev(host->mmc));
        if (status ^ host->oldstat)
-               mmc_detect_change(host->mmc);
+               mmc_detect_change(host->mmc, 0);
 
        host->oldstat = status;
        mod_timer(&host->timer, jiffies + HZ);
@@ -476,13 +496,9 @@ static int mmci_probe(struct amba_device *dev, void *id)
                goto host_free;
        }
 
-       ret = clk_use(host->clk);
-       if (ret)
-               goto clk_free;
-
        ret = clk_enable(host->clk);
        if (ret)
-               goto clk_unuse;
+               goto clk_free;
 
        host->plat = plat;
        host->mclk = clk_get_rate(host->clk);
@@ -497,6 +513,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
        mmc->f_min = (host->mclk + 511) / 512;
        mmc->f_max = min(host->mclk, fmax);
        mmc->ocr_avail = plat->ocr_mask;
+       mmc->caps = MMC_CAP_MULTIWRITE;
 
        /*
         * We can do SGIO
@@ -523,11 +540,11 @@ static int mmci_probe(struct amba_device *dev, void *id)
        writel(0, host->base + MMCIMASK1);
        writel(0xfff, host->base + MMCICLEAR);
 
-       ret = request_irq(dev->irq[0], mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host);
+       ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
        if (ret)
                goto unmap;
 
-       ret = request_irq(dev->irq[1], mmci_pio_irq, SA_SHIRQ, DRIVER_NAME " (pio)", host);
+       ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
        if (ret)
                goto irq0_free;
 
@@ -537,9 +554,9 @@ static int mmci_probe(struct amba_device *dev, void *id)
 
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n",
-               mmc->host_name, amba_rev(dev), amba_config(dev),
-               dev->res.start, dev->irq[0], dev->irq[1]);
+       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
+               mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
+               (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
 
        init_timer(&host->timer);
        host->timer.data = (unsigned long)host;
@@ -555,8 +572,6 @@ static int mmci_probe(struct amba_device *dev, void *id)
        iounmap(host->base);
  clk_disable:
        clk_disable(host->clk);
- clk_unuse:
-       clk_unuse(host->clk);
  clk_free:
        clk_put(host->clk);
  host_free:
@@ -591,7 +606,6 @@ static int mmci_remove(struct amba_device *dev)
 
                iounmap(host->base);
                clk_disable(host->clk);
-               clk_unuse(host->clk);
                clk_put(host->clk);
 
                mmc_free_host(mmc);