public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: ben@fluff.org.uk
To: linux-kernel@vger.kernel.org
Cc: drzeus-mmc@drzeus.cx, Christer Weinigel <christer@weinigel.se>,
	Ben Dooks <ben-linux@fluff.org>
Subject: [patch 3/5] s3cmci: Support transfers which are not multiple of 32 bits.
Date: Wed, 15 Oct 2008 00:17:17 +0100	[thread overview]
Message-ID: <20081014231810.337018575@fluff.org.uk> (raw)
In-Reply-To: 20081014231714.739345038@fluff.org.uk

[-- Attachment #1: thirdparty/christer-mmc-byte-alignment.patch --]
[-- Type: text/plain, Size: 6890 bytes --]

From: Christer Weinigel <christer@weinigel.se>

To be able to do SDIO the s3cmci driver has to support non-word-sized
transfers.  Change pio_words into pio_bytes and fix up all the places
where it is used.  

This variant of the patch will not overrun the buffer when reading an
odd number of bytes.  When writing, this variant will still read past
the end of the buffer, but since the driver can't support non-word-
aligned transfers anyway, this should not be a problem, since a
word-aligned transfer will never cross a page boundary.

This has been tested with a CSR SDIO Bluetooth Type A device on a
Samsung S3C24A0 processor.

Signed-off-by: Christer Weinigel <christer@weinigel.se>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>

Index: linux-2.6.27-rc5-quilt1/drivers/mmc/host/s3cmci.c
===================================================================
--- linux-2.6.27-rc5-quilt1.orig/drivers/mmc/host/s3cmci.c	2008-09-04 11:35:38.000000000 +0100
+++ linux-2.6.27-rc5-quilt1/drivers/mmc/host/s3cmci.c	2008-09-08 16:23:58.000000000 +0100
@@ -190,7 +190,7 @@ static inline void clear_imask(struct s3
 }
 
 static inline int get_data_buffer(struct s3cmci_host *host,
-				  u32 *words, u32 **pointer)
+				  u32 *bytes, u32 **pointer)
 {
 	struct scatterlist *sg;
 
@@ -207,7 +207,7 @@ static inline int get_data_buffer(struct
 	}
 	sg = &host->mrq->data->sg[host->pio_sgptr];
 
-	*words = sg->length >> 2;
+	*bytes = sg->length;
 	*pointer = sg_virt(sg);
 
 	host->pio_sgptr++;
@@ -223,7 +223,7 @@ static inline u32 fifo_count(struct s3cm
 	u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
 
 	fifostat &= S3C2410_SDIFSTA_COUNTMASK;
-	return fifostat >> 2;
+	return fifostat;
 }
 
 static inline u32 fifo_free(struct s3cmci_host *host)
@@ -231,13 +231,14 @@ static inline u32 fifo_free(struct s3cmc
 	u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
 
 	fifostat &= S3C2410_SDIFSTA_COUNTMASK;
-	return (63 - fifostat) >> 2;
+	return 63 - fifostat;
 }
 
 static void do_pio_read(struct s3cmci_host *host)
 {
 	int res;
 	u32 fifo;
+	u32 fifo_words;
 	void __iomem *from_ptr;
 
 	/* write real prescaler to host, it might be set slow to fix */
@@ -246,8 +247,8 @@ static void do_pio_read(struct s3cmci_ho
 	from_ptr = host->base + host->sdidata;
 
 	while ((fifo = fifo_count(host))) {
-		if (!host->pio_words) {
-			res = get_data_buffer(host, &host->pio_words,
+		if (!host->pio_bytes) {
+			res = get_data_buffer(host, &host->pio_bytes,
 					      &host->pio_ptr);
 			if (res) {
 				host->pio_active = XFER_NONE;
@@ -260,26 +261,45 @@ static void do_pio_read(struct s3cmci_ho
 
 			dbg(host, dbg_pio,
 			    "pio_read(): new target: [%i]@[%p]\n",
-			    host->pio_words, host->pio_ptr);
+			    host->pio_bytes, host->pio_ptr);
 		}
 
 		dbg(host, dbg_pio,
 		    "pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n",
-		    fifo, host->pio_words,
+		    fifo, host->pio_bytes,
 		    readl(host->base + S3C2410_SDIDCNT));
 
-		if (fifo > host->pio_words)
-			fifo = host->pio_words;
+		/* If we have reached the end of the block, we can
+		 * read a word and get 1 to 3 bytes.  If we in the
+		 * middle of the block, we have to read full words,
+		 * otherwise we will write garbage, so round down to
+		 * an even multiple of 4. */
+		if (fifo >= host->pio_bytes)
+			fifo = host->pio_bytes;
+		else
+			fifo -= fifo & 3;
 
-		host->pio_words -= fifo;
+		host->pio_bytes -= fifo;
 		host->pio_count += fifo;
 
-		while (fifo--)
+		fifo_words = fifo >> 2;
+		while (fifo_words--)
 			*(host->pio_ptr++) = readl(from_ptr);
+
+		if (fifo & 3) {
+			u32 n = fifo & 3;
+			u32 data = readl(from_ptr);
+			u8 *p = (u8 *)host->pio_ptr;
+
+			while (n--) {
+				*p++ = data;
+				data >>= 8;
+			}
+		}
 	}
 
-	if (!host->pio_words) {
-		res = get_data_buffer(host, &host->pio_words, &host->pio_ptr);
+	if (!host->pio_bytes) {
+		res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr);
 		if (res) {
 			dbg(host, dbg_pio,
 			    "pio_read(): complete (no more buffers).\n");
@@ -303,8 +323,8 @@ static void do_pio_write(struct s3cmci_h
 	to_ptr = host->base + host->sdidata;
 
 	while ((fifo = fifo_free(host))) {
-		if (!host->pio_words) {
-			res = get_data_buffer(host, &host->pio_words,
+		if (!host->pio_bytes) {
+			res = get_data_buffer(host, &host->pio_bytes,
 							&host->pio_ptr);
 			if (res) {
 				dbg(host, dbg_pio,
@@ -316,16 +336,23 @@ static void do_pio_write(struct s3cmci_h
 
 			dbg(host, dbg_pio,
 			    "pio_write(): new source: [%i]@[%p]\n",
-			    host->pio_words, host->pio_ptr);
+			    host->pio_bytes, host->pio_ptr);
 
 		}
 
-		if (fifo > host->pio_words)
-			fifo = host->pio_words;
+		/* If we have reached the end of the block, we have to
+		 * write exactly the remaining number of bytes.  If we
+		 * in the middle of the block, we have to write full
+		 * words, so round down to an even multiple of 4. */
+		if (fifo >= host->pio_bytes)
+			fifo = host->pio_bytes;
+		else
+			fifo -= fifo & 3;
 
-		host->pio_words -= fifo;
+		host->pio_bytes -= fifo;
 		host->pio_count += fifo;
 
+		fifo = (fifo + 3) >> 2;
 		while (fifo--)
 			writel(*(host->pio_ptr++), to_ptr);
 	}
@@ -350,9 +377,9 @@ static void pio_tasklet(unsigned long da
 		clear_imask(host);
 		if (host->pio_active != XFER_NONE) {
 			dbg(host, dbg_err, "unfinished %s "
-			    "- pio_count:[%u] pio_words:[%u]\n",
+			    "- pio_count:[%u] pio_bytes:[%u]\n",
 			    (host->pio_active == XFER_READ) ? "read" : "write",
-			    host->pio_count, host->pio_words);
+			    host->pio_count, host->pio_bytes);
 
 			if (host->mrq->data)
 				host->mrq->data->error = -EINVAL;
@@ -813,11 +840,10 @@ static int s3cmci_setup_data(struct s3cm
 		/* We cannot deal with unaligned blocks with more than
 		 * one block being transfered. */
 
-		if (data->blocks > 1)
+		if (data->blocks > 1) {
+			pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz);
 			return -EINVAL;
-
-		/* No support yet for non-word block transfers. */
-		return -EINVAL;
+		}
 	}
 
 	while (readl(host->base + S3C2410_SDIDSTA) &
@@ -897,7 +923,7 @@ static int s3cmci_prepare_pio(struct s3c
 	BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
 
 	host->pio_sgptr = 0;
-	host->pio_words = 0;
+	host->pio_bytes = 0;
 	host->pio_count = 0;
 	host->pio_active = rw ? XFER_WRITE : XFER_READ;
 
Index: linux-2.6.27-rc5-quilt1/drivers/mmc/host/s3cmci.h
===================================================================
--- linux-2.6.27-rc5-quilt1.orig/drivers/mmc/host/s3cmci.h	2008-09-04 11:35:38.000000000 +0100
+++ linux-2.6.27-rc5-quilt1/drivers/mmc/host/s3cmci.h	2008-09-08 16:23:58.000000000 +0100
@@ -51,7 +51,7 @@ struct s3cmci_host {
 	int			dma_complete;
 
 	u32			pio_sgptr;
-	u32			pio_words;
+	u32			pio_bytes;
 	u32			pio_count;
 	u32			*pio_ptr;
 #define XFER_NONE 0

-- 
Ben (ben@fluff.org, http://www.fluff.org/)

  'a smiley only costs 4 bytes'

  parent reply	other threads:[~2008-10-14 23:19 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-10-14 23:17 [patch 0/5] S3C24XX SD/MMC updates for 2.6.28-rc1 ben
2008-10-14 23:17 ` [patch 1/5] s3cmci: Make general protocol errors less noisy ben
2008-10-14 23:17 ` [patch 2/5] s3cmci: cpufreq support ben
2008-10-14 23:17 ` ben [this message]
2008-10-14 23:17 ` [patch 4/5] s3cmci: fix continual accesses to host->pio_ptr ben
2008-10-14 23:17 ` [patch 5/5] s3cmci: Add Ben Dooks/Simtec Electronics to header & copyright ben
2008-10-15 16:06 ` [patch 0/5] S3C24XX SD/MMC updates for 2.6.28-rc1 Pierre Ossman
  -- strict thread matches above, loose matches on Subject: below --
2008-10-10 10:32 [patch 0/5] MMC: S3C24XX updates for s3cmci driver Ben Dooks
2008-10-10 10:32 ` [patch 3/5] s3cmci: Support transfers which are not multiple of 32 bits Ben Dooks

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20081014231810.337018575@fluff.org.uk \
    --to=ben@fluff.org.uk \
    --cc=ben-linux@fluff.org \
    --cc=christer@weinigel.se \
    --cc=drzeus-mmc@drzeus.cx \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox