diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-23 12:04:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-23 12:04:34 -0700 |
commit | 20b7997e8abdf338dcc27fb4f1333c4973a7f113 (patch) | |
tree | d060f0ba9940781ca2351c09f4638640584052a5 /drivers/mmc/host | |
parent | 5554b35933245e95710d709175e14c02cbc956a4 (diff) | |
parent | 7659150c60839a2bd31f74e866374abb9be17e43 (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.c | 54 | ||||
-rw-r--r-- | drivers/mmc/host/pxamci.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/s3cmci.c | 50 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 167 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 7 |
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 */ |