summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-23 12:04:34 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-23 12:04:34 -0700
commit20b7997e8abdf338dcc27fb4f1333c4973a7f113 (patch)
treed060f0ba9940781ca2351c09f4638640584052a5 /drivers/mmc/host
parent5554b35933245e95710d709175e14c02cbc956a4 (diff)
parent7659150c60839a2bd31f74e866374abb9be17e43 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: sdhci: highmem capable PIO routines sg: reimplement sg mapping iterator mmc_test: print message when attaching to card mmc: Remove Russell as primecell mci maintainer mmc_block: bounce buffer highmem support sdhci: fix bad warning from commit c8b3e02 sdhci: add warnings for bad buffers in ADMA path mmc_test: test oversized sg lists mmc_test: highmem tests s3cmci: ensure host stopped on machine shutdown au1xmmc: suspend/resume implementation s3cmci: fixes for section mismatch warnings pxamci: trivial fix of DMA alignment register bit clearing
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/au1xmmc.c54
-rw-r--r--drivers/mmc/host/pxamci.c2
-rw-r--r--drivers/mmc/host/s3cmci.c50
-rw-r--r--drivers/mmc/host/sdhci.c167
-rw-r--r--drivers/mmc/host/sdhci.h7
5 files changed, 152 insertions, 128 deletions
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 3f15eb20489..99b20917cc0 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -1043,7 +1043,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
goto out6;
}
- platform_set_drvdata(pdev, mmc);
+ platform_set_drvdata(pdev, host);
printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X"
" (mode=%s)\n", pdev->id, host->iobase,
@@ -1087,13 +1087,10 @@ out0:
static int __devexit au1xmmc_remove(struct platform_device *pdev)
{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct au1xmmc_host *host;
-
- if (mmc) {
- host = mmc_priv(mmc);
+ struct au1xmmc_host *host = platform_get_drvdata(pdev);
- mmc_remove_host(mmc);
+ if (host) {
+ mmc_remove_host(host->mmc);
#ifdef CONFIG_LEDS_CLASS
if (host->platdata && host->platdata->led)
@@ -1101,8 +1098,8 @@ static int __devexit au1xmmc_remove(struct platform_device *pdev)
#endif
if (host->platdata && host->platdata->cd_setup &&
- !(mmc->caps & MMC_CAP_NEEDS_POLL))
- host->platdata->cd_setup(mmc, 0);
+ !(host->mmc->caps & MMC_CAP_NEEDS_POLL))
+ host->platdata->cd_setup(host->mmc, 0);
au_writel(0, HOST_ENABLE(host));
au_writel(0, HOST_CONFIG(host));
@@ -1122,16 +1119,49 @@ static int __devexit au1xmmc_remove(struct platform_device *pdev)
release_resource(host->ioarea);
kfree(host->ioarea);
- mmc_free_host(mmc);
+ mmc_free_host(host->mmc);
+ platform_set_drvdata(pdev, NULL);
}
return 0;
}
+#ifdef CONFIG_PM
+static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct au1xmmc_host *host = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = mmc_suspend_host(host->mmc, state);
+ if (ret)
+ return ret;
+
+ au_writel(0, HOST_CONFIG2(host));
+ au_writel(0, HOST_CONFIG(host));
+ au_writel(0xffffffff, HOST_STATUS(host));
+ au_writel(0, HOST_ENABLE(host));
+ au_sync();
+
+ return 0;
+}
+
+static int au1xmmc_resume(struct platform_device *pdev)
+{
+ struct au1xmmc_host *host = platform_get_drvdata(pdev);
+
+ au1xmmc_reset_controller(host);
+
+ return mmc_resume_host(host->mmc);
+}
+#else
+#define au1xmmc_suspend NULL
+#define au1xmmc_resume NULL
+#endif
+
static struct platform_driver au1xmmc_driver = {
.probe = au1xmmc_probe,
.remove = au1xmmc_remove,
- .suspend = NULL,
- .resume = NULL,
+ .suspend = au1xmmc_suspend,
+ .resume = au1xmmc_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index d39f5973886..a8e18fe5307 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -177,7 +177,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
if (dalgn)
DALGN |= (1 << host->dma);
else
- DALGN &= (1 << host->dma);
+ DALGN &= ~(1 << host->dma);
DDADR(host->dma) = host->sg_dma;
DCSR(host->dma) = DCSR_RUN;
}
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 6a1e4994b72..be550c26da6 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1331,21 +1331,30 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
return ret;
}
+static void s3cmci_shutdown(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct s3cmci_host *host = mmc_priv(mmc);
+
+ if (host->irq_cd >= 0)
+ free_irq(host->irq_cd, host);
+
+ mmc_remove_host(mmc);
+ clk_disable(host->clk);
+}
+
static int __devexit s3cmci_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct s3cmci_host *host = mmc_priv(mmc);
- mmc_remove_host(mmc);
+ s3cmci_shutdown(pdev);
- clk_disable(host->clk);
clk_put(host->clk);
tasklet_disable(&host->pio_tasklet);
s3c2410_dma_free(S3CMCI_DMA, &s3cmci_dma_client);
- if (host->irq_cd >= 0)
- free_irq(host->irq_cd, host);
free_irq(host->irq, host);
iounmap(host->base);
@@ -1355,17 +1364,17 @@ static int __devexit s3cmci_remove(struct platform_device *pdev)
return 0;
}
-static int __devinit s3cmci_probe_2410(struct platform_device *dev)
+static int __devinit s3cmci_2410_probe(struct platform_device *dev)
{
return s3cmci_probe(dev, 0);
}
-static int __devinit s3cmci_probe_2412(struct platform_device *dev)
+static int __devinit s3cmci_2412_probe(struct platform_device *dev)
{
return s3cmci_probe(dev, 1);
}
-static int __devinit s3cmci_probe_2440(struct platform_device *dev)
+static int __devinit s3cmci_2440_probe(struct platform_device *dev)
{
return s3cmci_probe(dev, 1);
}
@@ -1392,29 +1401,32 @@ static int s3cmci_resume(struct platform_device *dev)
#endif /* CONFIG_PM */
-static struct platform_driver s3cmci_driver_2410 = {
+static struct platform_driver s3cmci_2410_driver = {
.driver.name = "s3c2410-sdi",
.driver.owner = THIS_MODULE,
- .probe = s3cmci_probe_2410,
+ .probe = s3cmci_2410_probe,
.remove = __devexit_p(s3cmci_remove),
+ .shutdown = s3cmci_shutdown,
.suspend = s3cmci_suspend,
.resume = s3cmci_resume,
};
-static struct platform_driver s3cmci_driver_2412 = {
+static struct platform_driver s3cmci_2412_driver = {
.driver.name = "s3c2412-sdi",
.driver.owner = THIS_MODULE,
- .probe = s3cmci_probe_2412,
+ .probe = s3cmci_2412_probe,
.remove = __devexit_p(s3cmci_remove),
+ .shutdown = s3cmci_shutdown,
.suspend = s3cmci_suspend,
.resume = s3cmci_resume,
};
-static struct platform_driver s3cmci_driver_2440 = {
+static struct platform_driver s3cmci_2440_driver = {
.driver.name = "s3c2440-sdi",
.driver.owner = THIS_MODULE,
- .probe = s3cmci_probe_2440,
+ .probe = s3cmci_2440_probe,
.remove = __devexit_p(s3cmci_remove),
+ .shutdown = s3cmci_shutdown,
.suspend = s3cmci_suspend,
.resume = s3cmci_resume,
};
@@ -1422,17 +1434,17 @@ static struct platform_driver s3cmci_driver_2440 = {
static int __init s3cmci_init(void)
{
- platform_driver_register(&s3cmci_driver_2410);
- platform_driver_register(&s3cmci_driver_2412);
- platform_driver_register(&s3cmci_driver_2440);
+ platform_driver_register(&s3cmci_2410_driver);
+ platform_driver_register(&s3cmci_2412_driver);
+ platform_driver_register(&s3cmci_2440_driver);
return 0;
}
static void __exit s3cmci_exit(void)
{
- platform_driver_unregister(&s3cmci_driver_2410);
- platform_driver_unregister(&s3cmci_driver_2412);
- platform_driver_unregister(&s3cmci_driver_2440);
+ platform_driver_unregister(&s3cmci_2410_driver);
+ platform_driver_unregister(&s3cmci_2412_driver);
+ platform_driver_unregister(&s3cmci_2440_driver);
}
module_init(s3cmci_init);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 17701c3da73..c3a5db72ddd 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -173,119 +173,95 @@ static void sdhci_led_control(struct led_classdev *led,
* *
\*****************************************************************************/
-static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
-{
- return sg_virt(host->cur_sg);
-}
-
-static inline int sdhci_next_sg(struct sdhci_host* host)
-{
- /*
- * Skip to next SG entry.
- */
- host->cur_sg++;
- host->num_sg--;
-
- /*
- * Any entries left?
- */
- if (host->num_sg > 0) {
- host->offset = 0;
- host->remain = host->cur_sg->length;
- }
-
- return host->num_sg;
-}
-
static void sdhci_read_block_pio(struct sdhci_host *host)
{
- int blksize, chunk_remain;
- u32 data;
- char *buffer;
- int size;
+ unsigned long flags;
+ size_t blksize, len, chunk;
+ u32 scratch;
+ u8 *buf;
DBG("PIO reading\n");
blksize = host->data->blksz;
- chunk_remain = 0;
- data = 0;
+ chunk = 0;
- buffer = sdhci_sg_to_buffer(host) + host->offset;
+ local_irq_save(flags);
while (blksize) {
- if (chunk_remain == 0) {
- data = readl(host->ioaddr + SDHCI_BUFFER);
- chunk_remain = min(blksize, 4);
- }
+ if (!sg_miter_next(&host->sg_miter))
+ BUG();
- size = min(host->remain, chunk_remain);
+ len = min(host->sg_miter.length, blksize);
- chunk_remain -= size;
- blksize -= size;
- host->offset += size;
- host->remain -= size;
+ blksize -= len;
+ host->sg_miter.consumed = len;
- while (size) {
- *buffer = data & 0xFF;
- buffer++;
- data >>= 8;
- size--;
- }
+ buf = host->sg_miter.addr;
- if (host->remain == 0) {
- if (sdhci_next_sg(host) == 0) {
- BUG_ON(blksize != 0);
- return;
+ while (len) {
+ if (chunk == 0) {
+ scratch = readl(host->ioaddr + SDHCI_BUFFER);
+ chunk = 4;
}
- buffer = sdhci_sg_to_buffer(host);
+
+ *buf = scratch & 0xFF;
+
+ buf++;
+ scratch >>= 8;
+ chunk--;
+ len--;
}
}
+
+ sg_miter_stop(&host->sg_miter);
+
+ local_irq_restore(flags);
}
static void sdhci_write_block_pio(struct sdhci_host *host)
{
- int blksize, chunk_remain;
- u32 data;
- char *buffer;
- int bytes, size;
+ unsigned long flags;
+ size_t blksize, len, chunk;
+ u32 scratch;
+ u8 *buf;
DBG("PIO writing\n");
blksize = host->data->blksz;
- chunk_remain = 4;
- data = 0;
+ chunk = 0;
+ scratch = 0;
- bytes = 0;
- buffer = sdhci_sg_to_buffer(host) + host->offset;
+ local_irq_save(flags);
while (blksize) {
- size = min(host->remain, chunk_remain);
-
- chunk_remain -= size;
- blksize -= size;
- host->offset += size;
- host->remain -= size;
-
- while (size) {
- data >>= 8;
- data |= (u32)*buffer << 24;
- buffer++;
- size--;
- }
+ if (!sg_miter_next(&host->sg_miter))
+ BUG();
- if (chunk_remain == 0) {
- writel(data, host->ioaddr + SDHCI_BUFFER);
- chunk_remain = min(blksize, 4);
- }
+ len = min(host->sg_miter.length, blksize);
+
+ blksize -= len;
+ host->sg_miter.consumed = len;
+
+ buf = host->sg_miter.addr;
- if (host->remain == 0) {
- if (sdhci_next_sg(host) == 0) {
- BUG_ON(blksize != 0);
- return;
+ while (len) {
+ scratch |= (u32)*buf << (chunk * 8);
+
+ buf++;
+ chunk++;
+ len--;
+
+ if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
+ writel(scratch, host->ioaddr + SDHCI_BUFFER);
+ chunk = 0;
+ scratch = 0;
}
- buffer = sdhci_sg_to_buffer(host);
}
}
+
+ sg_miter_stop(&host->sg_miter);
+
+ local_irq_restore(flags);
}
static void sdhci_transfer_pio(struct sdhci_host *host)
@@ -294,7 +270,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
BUG_ON(!host->data);
- if (host->num_sg == 0)
+ if (host->blocks == 0)
return;
if (host->data->flags & MMC_DATA_READ)
@@ -308,7 +284,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
else
sdhci_write_block_pio(host);
- if (host->num_sg == 0)
+ host->blocks--;
+ if (host->blocks == 0)
break;
}
@@ -389,6 +366,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
if (offset) {
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags);
+ WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
memcpy(align, buffer, offset);
sdhci_kunmap_atomic(buffer, &flags);
}
@@ -510,6 +488,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
size = 4 - (sg_dma_address(sg) & 0x3);
buffer = sdhci_kmap_atomic(sg, &flags);
+ WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
memcpy(buffer, align, size);
sdhci_kunmap_atomic(buffer, &flags);
@@ -687,7 +666,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
WARN_ON(1);
host->flags &= ~SDHCI_USE_DMA;
} else {
- WARN_ON(count != 1);
+ WARN_ON(sg_cnt != 1);
writel(sg_dma_address(data->sg),
host->ioaddr + SDHCI_DMA_ADDRESS);
}
@@ -711,11 +690,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
}
if (!(host->flags & SDHCI_REQ_USE_DMA)) {
- host->cur_sg = data->sg;
- host->num_sg = data->sg_len;
-
- host->offset = 0;
- host->remain = host->cur_sg->length;
+ sg_miter_start(&host->sg_miter,
+ data->sg, data->sg_len, SG_MITER_ATOMIC);
+ host->blocks = data->blocks;
}
/* We do not handle DMA boundaries, so set it to max (512 KiB) */
@@ -1581,9 +1558,15 @@ int sdhci_add_host(struct sdhci_host *host)
}
}
- /* XXX: Hack to get MMC layer to avoid highmem */
- if (!(host->flags & SDHCI_USE_DMA))
- mmc_dev(host->mmc)->dma_mask = NULL;
+ /*
+ * If we use DMA, then it's up to the caller to set the DMA
+ * mask, but PIO does not need the hw shim so we set a new
+ * mask here in that case.
+ */
+ if (!(host->flags & SDHCI_USE_DMA)) {
+ host->dma_mask = DMA_BIT_MASK(64);
+ mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
+ }
host->max_clk =
(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 5bb35528176..a06bf8b8934 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -212,6 +212,7 @@ struct sdhci_host {
/* Internal data */
struct mmc_host *mmc; /* MMC structure */
+ u64 dma_mask; /* custom DMA mask */
#ifdef CONFIG_LEDS_CLASS
struct led_classdev led; /* LED control */
@@ -238,10 +239,8 @@ struct sdhci_host {
struct mmc_data *data; /* Current data request */
unsigned int data_early:1; /* Data finished before cmd */
- struct scatterlist *cur_sg; /* We're working on this */
- int num_sg; /* Entries left */
- int offset; /* Offset into current sg */
- int remain; /* Bytes left in current */
+ struct sg_mapping_iter sg_miter; /* SG state for PIO */
+ unsigned int blocks; /* remaining PIO blocks */
int sg_count; /* Mapped sg entries */