From 4fe16897c59882420d66f2d503106653d026ed6c Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Wed, 16 Jul 2008 18:29:11 +0200 Subject: pxamci: trivial fix of DMA alignment register bit clearing Signed-off-by: Karl Beldan Acked-by: Eric Miao Signed-off-by: Pierre Ossman --- drivers/mmc/host/pxamci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc/host') 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; } -- cgit v1.2.3 From d2f2761bb75ee365077b52c7e73a6e5164d3efa0 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 17 Jul 2008 11:54:01 +0100 Subject: s3cmci: fixes for section mismatch warnings Fix the naming of various functions in the s3cmc driver to stop triggering section mismatch warnings. Signed-off-by: Ben Dooks Signed-off-by: Pierre Ossman --- drivers/mmc/host/s3cmci.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 6a1e4994b72..8904bb39df6 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1355,17 +1355,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,28 +1392,28 @@ 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), .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), .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), .suspend = s3cmci_suspend, .resume = s3cmci_resume, @@ -1422,17 +1422,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); -- cgit v1.2.3 From dd8572af68229a65b6716b286395ad7f5e2ecc48 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Thu, 17 Jul 2008 13:07:28 +0200 Subject: au1xmmc: suspend/resume implementation Basic suspend/resume support: disable peripheral on suspend and reinit on resume. Tested on Au1200. Signed-off-by: Manuel Lauss Signed-off-by: Pierre Ossman --- drivers/mmc/host/au1xmmc.c | 54 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'drivers/mmc/host') 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, -- cgit v1.2.3 From 907b2cd6dbbdfd6a4be7908f57b1498dfabc880e Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 17 Jul 2008 15:32:54 +0100 Subject: s3cmci: ensure host stopped on machine shutdown Ensure that the s3cmci host controller is turned off when the machine is shutdown, otherwise we end up leaving the card powered and processing insertion and removal events after the system prints "System halted." Signed-off-by: Ben Dooks Signed-off-by: Pierre Ossman --- drivers/mmc/host/s3cmci.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 8904bb39df6..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); @@ -1397,6 +1406,7 @@ static struct platform_driver s3cmci_2410_driver = { .driver.owner = THIS_MODULE, .probe = s3cmci_2410_probe, .remove = __devexit_p(s3cmci_remove), + .shutdown = s3cmci_shutdown, .suspend = s3cmci_suspend, .resume = s3cmci_resume, }; @@ -1406,6 +1416,7 @@ static struct platform_driver s3cmci_2412_driver = { .driver.owner = THIS_MODULE, .probe = s3cmci_2412_probe, .remove = __devexit_p(s3cmci_remove), + .shutdown = s3cmci_shutdown, .suspend = s3cmci_suspend, .resume = s3cmci_resume, }; @@ -1415,6 +1426,7 @@ static struct platform_driver s3cmci_2440_driver = { .driver.owner = THIS_MODULE, .probe = s3cmci_2440_probe, .remove = __devexit_p(s3cmci_remove), + .shutdown = s3cmci_shutdown, .suspend = s3cmci_suspend, .resume = s3cmci_resume, }; -- cgit v1.2.3 From 6cefd05f35177ad5d22d44519c680cf43f2ac86d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2008 00:45:15 +0200 Subject: sdhci: add warnings for bad buffers in ADMA path The ADMA code path assumes that the 3 byte alignment fix doesn't cross a page boundary. I'm not convinced this is worth supporting, but at least print a warning in the off chance we'll actually see such a request. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 17701c3da73..b27c1a28a7c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -389,6 +389,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 +511,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); -- cgit v1.2.3 From 719a61b452ff74cf81a96e4212748d9d63bcc924 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 22 Jul 2008 13:23:23 +0200 Subject: sdhci: fix bad warning from commit c8b3e02 Commit c8b3e02 renamed a variable, but missed one reference to it inside a WARN_ON, causing it to incorrectly trigger. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index b27c1a28a7c..8b1f412144c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -689,7 +689,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); } -- cgit v1.2.3 From 7659150c60839a2bd31f74e866374abb9be17e43 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2008 00:32:11 +0200 Subject: sdhci: highmem capable PIO routines Improve the PIO handling so that it can service highmem pages. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 163 +++++++++++++++++++++-------------------------- drivers/mmc/host/sdhci.h | 7 +- 2 files changed, 75 insertions(+), 95 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8b1f412144c..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; } @@ -713,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) */ @@ -1583,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 */ -- cgit v1.2.3 From 1685a03e98b7e9b83e0aa692c1cc470b3aa37597 Mon Sep 17 00:00:00 2001 From: Jan Nikitenko Date: Thu, 24 Jul 2008 01:27:07 +0200 Subject: mmc_spi: put signals to low power off fix The original intention was to write a zero byte to mmc to force spi signals to low when doing power off. Somehow the spi_w8r8 call got there so a read followed the write of single zero byte. This patch changes that to simple write of zero byte without the following read. This way the power off is more reliable and completely sufficient. Signed-off-by: Jan Nikitenko Signed-off-by: David Brownell Signed-off-by: Pierre Ossman --- drivers/mmc/host/mmc_spi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 41cc63360e4..7503b81374e 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1076,6 +1076,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) */ if (canpower && ios->power_mode == MMC_POWER_OFF) { int mres; + u8 nullbyte = 0; host->spi->mode &= ~(SPI_CPOL|SPI_CPHA); mres = spi_setup(host->spi); @@ -1083,7 +1084,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) dev_dbg(&host->spi->dev, "switch to SPI mode 0 failed\n"); - if (spi_w8r8(host->spi, 0x00) < 0) + if (spi_write(host->spi, &nullbyte, 1) < 0) dev_dbg(&host->spi->dev, "put spi signals to low failed\n"); -- cgit v1.2.3 From 0c7ad106e779549792deb307242dece6f3499bb9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 25 Jul 2008 19:44:35 -0700 Subject: drivers/mmc/host/sdhci.h needs scatterlist.h alpha: drivers/mmc/host/sdhci.h:242: error: field 'sg_miter' has incomplete type Cc: Pierre Ossman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/sdhci.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index a06bf8b8934..e354faee5df 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -9,6 +9,8 @@ * your option) any later version. */ +#include + /* * Controller registers */ -- cgit v1.2.3 From 8d8bb39b9eba32dd70e87fd5ad5c5dd4ba118e06 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 25 Jul 2008 19:44:49 -0700 Subject: dma-mapping: add the device argument to dma_mapping_error() Add per-device dma_mapping_ops support for CONFIG_X86_64 as POWER architecture does: This enables us to cleanly fix the Calgary IOMMU issue that some devices are not behind the IOMMU (http://lkml.org/lkml/2008/5/8/423). I think that per-device dma_mapping_ops support would be also helpful for KVM people to support PCI passthrough but Andi thinks that this makes it difficult to support the PCI passthrough (see the above thread). So I CC'ed this to KVM camp. Comments are appreciated. A pointer to dma_mapping_ops to struct dev_archdata is added. If the pointer is non NULL, DMA operations in asm/dma-mapping.h use it. If it's NULL, the system-wide dma_ops pointer is used as before. If it's useful for KVM people, I plan to implement a mechanism to register a hook called when a new pci (or dma capable) device is created (it works with hot plugging). It enables IOMMUs to set up an appropriate dma_mapping_ops per device. The major obstacle is that dma_mapping_error doesn't take a pointer to the device unlike other DMA operations. So x86 can't have dma_mapping_ops per device. Note all the POWER IOMMUs use the same dma_mapping_error function so this is not a problem for POWER but x86 IOMMUs use different dma_mapping_error functions. The first patch adds the device argument to dma_mapping_error. The patch is trivial but large since it touches lots of drivers and dma-mapping.h in all the architecture. This patch: dma_mapping_error() doesn't take a pointer to the device unlike other DMA operations. So we can't have dma_mapping_ops per device. Note that POWER already has dma_mapping_ops per device but all the POWER IOMMUs use the same dma_mapping_error function. x86 IOMMUs use device argument. [akpm@linux-foundation.org: fix sge] [akpm@linux-foundation.org: fix svc_rdma] [akpm@linux-foundation.org: build fix] [akpm@linux-foundation.org: fix bnx2x] [akpm@linux-foundation.org: fix s2io] [akpm@linux-foundation.org: fix pasemi_mac] [akpm@linux-foundation.org: fix sdhci] [akpm@linux-foundation.org: build fix] [akpm@linux-foundation.org: fix sparc] [akpm@linux-foundation.org: fix ibmvscsi] Signed-off-by: FUJITA Tomonori Cc: Muli Ben-Yehuda Cc: Andi Kleen Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Avi Kivity Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/sdhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c3a5db72ddd..5f95e10229b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -337,7 +337,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, host->align_addr = dma_map_single(mmc_dev(host->mmc), host->align_buffer, 128 * 4, direction); - if (dma_mapping_error(host->align_addr)) + if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) goto fail; BUG_ON(host->align_addr & 0x3); @@ -439,7 +439,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, host->adma_addr = dma_map_single(mmc_dev(host->mmc), host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE); - if (dma_mapping_error(host->align_addr)) + if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) goto unmap_entries; BUG_ON(host->adma_addr & 0x3); -- cgit v1.2.3 From 322069c9df1fd4da269b2a57d78f753684962523 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 9 Jul 2008 16:03:13 +0300 Subject: imxmmc: remove DEBUG definition Removed DEBUG #define #undef, because module is automaticaly compiled with -DDEBUG when CONFIG_MMC_DEBUG is defined. Currently it just generates compiler warning about redefinition. Signed-off-by: Paulius Zaleckas Acked-by: Pavel Pisa Signed-off-by: Pierre Ossman --- drivers/mmc/host/imxmmc.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 5e880c0f134..77493339303 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -26,12 +26,6 @@ * */ -#ifdef CONFIG_MMC_DEBUG -#define DEBUG -#else -#undef DEBUG -#endif - #include #include #include -- cgit v1.2.3 From 5fc63dfba8a016caf832572aeaa90abef82f0ba0 Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 9 Jul 2008 16:03:17 +0300 Subject: imxmmc: fix platform resources Fixup platform resources handling. Signed-off-by: Paulius Zaleckas Acked-by: Pavel Pisa Signed-off-by: Pierre Ossman --- drivers/mmc/host/imxmmc.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 77493339303..9cda12fba9a 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -901,26 +901,6 @@ static const struct mmc_host_ops imxmci_ops = { .get_ro = imxmci_get_ro, }; -static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr) -{ - int i; - - for (i = 0; i < dev->num_resources; i++) - if (dev->resource[i].flags == mask && nr-- == 0) - return &dev->resource[i]; - return NULL; -} - -static int platform_device_irq(struct platform_device *dev, int nr) -{ - int i; - - for (i = 0; i < dev->num_resources; i++) - if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0) - return dev->resource[i].start; - return NO_IRQ; -} - static void imxmci_check_status(unsigned long data) { struct imxmci_host *host = (struct imxmci_host *)data; @@ -956,13 +936,12 @@ static int imxmci_probe(struct platform_device *pdev) printk(KERN_INFO "i.MX mmc driver\n"); - r = platform_device_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_device_irq(pdev, 0); - if (!r || irq == NO_IRQ) + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!r || irq < 0) return -ENXIO; - r = request_mem_region(r->start, 0x100, "IMXMCI"); - if (!r) + if (!request_mem_region(r->start, 0x100, pdev->name)) return -EBUSY; mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev); @@ -1067,7 +1046,7 @@ out: } if (mmc) mmc_free_host(mmc); - release_resource(r); + release_mem_region(r->start, 0x100); return ret; } @@ -1096,7 +1075,7 @@ static int imxmci_remove(struct platform_device *pdev) clk_disable(host->clk); clk_put(host->clk); - release_resource(host->res); + release_mem_region(host->res->start, 0x100); mmc_free_host(mmc); } -- cgit v1.2.3 From c5d5e9c40fc6cabedd5fdc7441e6e9d37f5c9bba Mon Sep 17 00:00:00 2001 From: Paulius Zaleckas Date: Wed, 9 Jul 2008 16:03:20 +0300 Subject: imxmmc: fix crash when no platform data is provided Don't crash if no platform data is provided. In this case assume that card is present. Signed-off-by: Paulius Zaleckas Acked-by: Pavel Pisa Signed-off-by: Pierre Ossman --- drivers/mmc/host/imxmmc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 9cda12fba9a..f61406da65d 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -905,7 +905,8 @@ static void imxmci_check_status(unsigned long data) { struct imxmci_host *host = (struct imxmci_host *)data; - if( host->pdata->card_present(mmc_dev(host->mmc)) != host->present ) { + if (host->pdata && host->pdata->card_present && + host->pdata->card_present(mmc_dev(host->mmc)) != host->present) { host->present ^= 1; dev_info(mmc_dev(host->mmc), "card %s\n", host->present ? "inserted" : "removed"); @@ -968,6 +969,8 @@ static int imxmci_probe(struct platform_device *pdev) host->mmc = mmc; host->dma_allocated = 0; host->pdata = pdev->dev.platform_data; + if (!host->pdata) + dev_warn(&pdev->dev, "No platform data provided!\n"); spin_lock_init(&host->lock); host->res = r; @@ -1020,7 +1023,11 @@ static int imxmci_probe(struct platform_device *pdev) if (ret) goto out; - host->present = host->pdata->card_present(mmc_dev(mmc)); + if (host->pdata && host->pdata->card_present) + host->present = host->pdata->card_present(mmc_dev(mmc)); + else /* if there is no way to detect assume that card is present */ + host->present = 1; + init_timer(&host->timer); host->timer.data = (unsigned long)host; host->timer.function = imxmci_check_status; -- cgit v1.2.3 From deec9ae31e6079551ce9260d29a4cf83e5b19a83 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 24 Jul 2008 14:18:59 +0200 Subject: atmel-mci: debugfs support Create additional files under the host's debugfs directory containing additional host-specific debug information. Signed-off-by: Haavard Skinnemoen Signed-off-by: Pierre Ossman --- drivers/mmc/host/atmel-mci-regs.h | 2 + drivers/mmc/host/atmel-mci.c | 189 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index a9a5657706c..26bd80e6503 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -82,6 +82,8 @@ # define MCI_OVRE ( 1 << 30) /* RX Overrun Error */ # define MCI_UNRE ( 1 << 31) /* TX Underrun Error */ +#define MCI_REGS_SIZE 0x100 + /* Register access macros */ #define mci_readl(port,reg) \ __raw_readl((port)->regs + MCI_##reg) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index cce873c5a14..b68381f7bfd 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -9,6 +9,7 @@ */ #include #include +#include #include #include #include @@ -16,6 +17,8 @@ #include #include #include +#include +#include #include @@ -88,6 +91,188 @@ struct atmel_mci { #define atmci_clear_pending(host, event) \ clear_bit(event, &host->pending_events) +/* + * The debugfs stuff below is mostly optimized away when + * CONFIG_DEBUG_FS is not set. + */ +static int atmci_req_show(struct seq_file *s, void *v) +{ + struct atmel_mci *host = s->private; + struct mmc_request *mrq = host->mrq; + struct mmc_command *cmd; + struct mmc_command *stop; + struct mmc_data *data; + + /* Make sure we get a consistent snapshot */ + spin_lock_irq(&host->mmc->lock); + + if (mrq) { + cmd = mrq->cmd; + data = mrq->data; + stop = mrq->stop; + + if (cmd) + seq_printf(s, + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", + cmd->opcode, cmd->arg, cmd->flags, + cmd->resp[0], cmd->resp[1], cmd->resp[2], + cmd->resp[2], cmd->error); + if (data) + seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", + data->bytes_xfered, data->blocks, + data->blksz, data->flags, data->error); + if (stop) + seq_printf(s, + "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", + stop->opcode, stop->arg, stop->flags, + stop->resp[0], stop->resp[1], stop->resp[2], + stop->resp[2], stop->error); + } + + spin_unlock_irq(&host->mmc->lock); + + return 0; +} + +static int atmci_req_open(struct inode *inode, struct file *file) +{ + return single_open(file, atmci_req_show, inode->i_private); +} + +static const struct file_operations atmci_req_fops = { + .owner = THIS_MODULE, + .open = atmci_req_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void atmci_show_status_reg(struct seq_file *s, + const char *regname, u32 value) +{ + static const char *sr_bit[] = { + [0] = "CMDRDY", + [1] = "RXRDY", + [2] = "TXRDY", + [3] = "BLKE", + [4] = "DTIP", + [5] = "NOTBUSY", + [8] = "SDIOIRQA", + [9] = "SDIOIRQB", + [16] = "RINDE", + [17] = "RDIRE", + [18] = "RCRCE", + [19] = "RENDE", + [20] = "RTOE", + [21] = "DCRCE", + [22] = "DTOE", + [30] = "OVRE", + [31] = "UNRE", + }; + unsigned int i; + + seq_printf(s, "%s:\t0x%08x", regname, value); + for (i = 0; i < ARRAY_SIZE(sr_bit); i++) { + if (value & (1 << i)) { + if (sr_bit[i]) + seq_printf(s, " %s", sr_bit[i]); + else + seq_puts(s, " UNKNOWN"); + } + } + seq_putc(s, '\n'); +} + +static int atmci_regs_show(struct seq_file *s, void *v) +{ + struct atmel_mci *host = s->private; + u32 *buf; + + buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Grab a more or less consistent snapshot */ + spin_lock_irq(&host->mmc->lock); + memcpy_fromio(buf, host->regs, MCI_REGS_SIZE); + spin_unlock_irq(&host->mmc->lock); + + seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n", + buf[MCI_MR / 4], + buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "", + buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "", + buf[MCI_MR / 4] & 0xff); + seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]); + seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]); + seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]); + seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", + buf[MCI_BLKR / 4], + buf[MCI_BLKR / 4] & 0xffff, + (buf[MCI_BLKR / 4] >> 16) & 0xffff); + + /* Don't read RSPR and RDR; it will consume the data there */ + + atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]); + atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]); + + return 0; +} + +static int atmci_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, atmci_regs_show, inode->i_private); +} + +static const struct file_operations atmci_regs_fops = { + .owner = THIS_MODULE, + .open = atmci_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void atmci_init_debugfs(struct atmel_mci *host) +{ + struct mmc_host *mmc; + struct dentry *root; + struct dentry *node; + struct resource *res; + + mmc = host->mmc; + root = mmc->debugfs_root; + if (!root) + return; + + node = debugfs_create_file("regs", S_IRUSR, root, host, + &atmci_regs_fops); + if (IS_ERR(node)) + return; + if (!node) + goto err; + + res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); + node->d_inode->i_size = res->end - res->start + 1; + + node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops); + if (!node) + goto err; + + node = debugfs_create_x32("pending_events", S_IRUSR, root, + (u32 *)&host->pending_events); + if (!node) + goto err; + + node = debugfs_create_x32("completed_events", S_IRUSR, root, + (u32 *)&host->completed_events); + if (!node) + goto err; + + return; + +err: + dev_err(&host->pdev->dev, + "failed to initialize debugfs for controller\n"); +} static void atmci_enable(struct atmel_mci *host) { @@ -905,6 +1090,8 @@ static int __init atmci_probe(struct platform_device *pdev) "Atmel MCI controller at 0x%08lx irq %d\n", host->mapbase, irq); + atmci_init_debugfs(host); + return 0; err_request_irq: @@ -923,6 +1110,8 @@ static int __exit atmci_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (host) { + /* Debugfs stuff is cleaned up by mmc core */ + if (host->detect_pin >= 0) { int pin = host->detect_pin; -- cgit v1.2.3