linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 01/12] mmci: use sg_miter API to fix multi-page sg handling
@ 2010-06-22  9:17 Rabin Vincent
  2010-06-22  9:17 ` [PATCH 02/12] mmci: fix multi block transfers Rabin Vincent
                   ` (12 more replies)
  0 siblings, 13 replies; 37+ messages in thread
From: Rabin Vincent @ 2010-06-22  9:17 UTC (permalink / raw)
  To: linux-arm-kernel

The mmci driver's SG list iteration logic assumes that each SG entry
spans only one page, and only maps and flushes one page of the sg.  This
is not a valid assumption.  Fix it by converting the driver to the
sg_miter API, which correctly handles sgs which span multiple pages.
Cache flushing is handled inside the sg_miter API implementation.

Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
---
 drivers/mmc/host/mmci.c |   55 ++++++++++++++++++++++------------------------
 drivers/mmc/host/mmci.h |   35 +-----------------------------
 2 files changed, 27 insertions(+), 63 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 4917af9..683516b 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -26,7 +26,6 @@
 #include <linux/amba/mmci.h>
 #include <linux/regulator/consumer.h>
 
-#include <asm/cacheflush.h>
 #include <asm/div64.h>
 #include <asm/io.h>
 #include <asm/sizes.h>
@@ -98,6 +97,18 @@ static void mmci_stop_data(struct mmci_host *host)
 	host->data = NULL;
 }
 
+static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
+{
+	unsigned int flags = SG_MITER_ATOMIC;
+
+	if (data->flags & MMC_DATA_READ)
+		flags |= SG_MITER_TO_SG;
+	else
+		flags |= SG_MITER_FROM_SG;
+
+	sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+}
+
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 {
 	unsigned int datactrl, timeout, irqmask;
@@ -205,13 +216,6 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
 		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
 			data->error = -EIO;
 		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(sg_page(host->sg_ptr));
 	}
 	if (status & MCI_DATAEND) {
 		mmci_stop_data(host);
@@ -314,15 +318,18 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
 static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 {
 	struct mmci_host *host = dev_id;
+	struct sg_mapping_iter *sg_miter = &host->sg_miter;
 	void __iomem *base = host->base;
+	unsigned long flags;
 	u32 status;
 
 	status = readl(base + MMCISTATUS);
 
 	dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
 
+	local_irq_save(flags);
+
 	do {
-		unsigned long flags;
 		unsigned int remain, len;
 		char *buffer;
 
@@ -336,11 +343,11 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 		if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
 			break;
 
-		/*
-		 * Map the current scatter buffer.
-		 */
-		buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
-		remain = host->sg_ptr->length - host->sg_off;
+		if (!sg_miter_next(sg_miter))
+			break;
+
+		buffer = sg_miter->addr;
+		remain = sg_miter->length;
 
 		len = 0;
 		if (status & MCI_RXACTIVE)
@@ -348,31 +355,21 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 		if (status & MCI_TXACTIVE)
 			len = mmci_pio_write(host, buffer, remain, status);
 
-		/*
-		 * Unmap the buffer.
-		 */
-		mmci_kunmap_atomic(host, buffer, &flags);
+		sg_miter->consumed = len;
 
-		host->sg_off += len;
 		host->size -= len;
 		remain -= len;
 
 		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(sg_page(host->sg_ptr));
-
-		if (!mmci_next_sg(host))
-			break;
-
 		status = readl(base + MMCISTATUS);
 	} while (1);
 
+	sg_miter_stop(sg_miter);
+
+	local_irq_restore(flags);
+
 	/*
 	 * If we're nearing the end of the read, switch to
 	 * "any data available" mode.
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index d77062e..7cb24ab 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -171,42 +171,9 @@ struct mmci_host {
 	struct timer_list	timer;
 	unsigned int		oldstat;
 
-	unsigned int		sg_len;
-
 	/* pio stuff */
-	struct scatterlist	*sg_ptr;
-	unsigned int		sg_off;
+	struct sg_mapping_iter	sg_miter;
 	unsigned int		size;
 	struct regulator	*vcc;
 };
 
-static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
-{
-	/*
-	 * Ideally, we want the higher levels to pass us a scatter list.
-	 */
-	host->sg_len = data->sg_len;
-	host->sg_ptr = data->sg;
-	host->sg_off = 0;
-}
-
-static inline int mmci_next_sg(struct mmci_host *host)
-{
-	host->sg_ptr++;
-	host->sg_off = 0;
-	return --host->sg_len;
-}
-
-static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
-{
-	struct scatterlist *sg = host->sg_ptr;
-
-	local_irq_save(*flags);
-	return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
-}
-
-static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
-{
-	kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
-	local_irq_restore(*flags);
-}
-- 
1.7.0

^ permalink raw reply related	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2010-10-19 12:52 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-22  9:17 [PATCH 01/12] mmci: use sg_miter API to fix multi-page sg handling Rabin Vincent
2010-06-22  9:17 ` [PATCH 02/12] mmci: fix multi block transfers Rabin Vincent
2010-07-29 13:18   ` Russell King - ARM Linux
2010-07-29 13:31     ` Colin Tuckley
2010-07-29 13:36       ` Russell King - ARM Linux
2010-07-29 13:42         ` Colin Tuckley
2010-07-29 13:55           ` Russell King - ARM Linux
2010-07-29 14:14             ` Russell King - ARM Linux
2010-06-22  9:17 ` [PATCH 03/12] mmci: let core poll for card detection Rabin Vincent
2010-06-22  9:17 ` [PATCH 04/12] mmci: allow the card detect status not to be inverted Rabin Vincent
2010-07-29 12:34   ` Russell King - ARM Linux
2010-07-29 13:53     ` Linus Walleij
2010-07-29 14:20       ` Russell King - ARM Linux
2010-08-05  6:14         ` Rabin VINCENT
2010-08-05  9:25           ` Russell King - ARM Linux
2010-08-09 10:37             ` Rabin VINCENT
2010-08-09 11:25               ` Russell King - ARM Linux
2010-06-22  9:17 ` [PATCH 05/12] mmci: support card detection interrupts Rabin Vincent
2010-06-22  9:17 ` [PATCH 06/12] mmci: allow neither ->status nor gpio_cd to be specified Rabin Vincent
2010-06-22  9:17 ` [PATCH 07/12] mmci: pass power_mode to the translate_vdd callback Rabin Vincent
2010-06-22 22:03   ` Linus Walleij
2010-06-24  8:27     ` Rabin VINCENT
2010-06-24  8:56       ` Linus WALLEIJ
2010-07-19 12:57   ` [PATCHv2 " Rabin Vincent
2010-06-22  9:17 ` [PATCH 08/12] mmci: add variant data and default MCICLOCK support Rabin Vincent
2010-06-22  9:17 ` [PATCH 09/12] mmci: enable hardware flow control on Ux500 variants Rabin Vincent
2010-06-22  9:17 ` [PATCH 10/12] mmci: support larger MMCIDATALENGTH register Rabin Vincent
2010-06-22  9:17 ` [PATCH 11/12] mmci: support different FIFO sizes Rabin Vincent
2010-06-22  9:17 ` [PATCH 12/12] mmci: support variants with only one irq Rabin Vincent
2010-09-23 20:04   ` Linus Walleij
2010-10-11  0:06   ` [PATCHv2] mmci: work " Rabin Vincent
2010-10-11  9:13     ` Linus Walleij
2010-10-11  9:44     ` Russell King - ARM Linux
2010-10-11 11:10       ` Linus Walleij
2010-10-19 12:52       ` Linus Walleij
2010-07-07 20:34 ` [PATCH 01/12] mmci: use sg_miter API to fix multi-page sg handling Linus Walleij
2010-07-19 13:23 ` [PATCHv2 " Rabin Vincent

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).