mmc: msm_sdcc: Fix scatterlist processing in PIO mode

sg_miter_next() does not place byte alignment restrictions on
sgl lengths. However, SDCC FIFO must be accessed in multiples
of 4 bytes, requiring rounding which can cause data corruption.

For example, an sgl of length 481 is decribed below:
	struct scatterlist sgl;
	sgl.page_link = 0xXXXX_XXXX;
	sgl.length    = 481;
	sgl.offset    = 3821;

First call to sg_miter_next():
	Sgl length returned = (PAGE_SIZE - 3821) = 275 bytes
	Driver rounds this length to multiple of 4 = 276 bytes

Next call to sg_miter_next():
	Sgl length returned = (481 - 275) = 206 bytes
	Driver rounds this length to 208 bytes

On a write, the extra byte written to the FIFO during the first
276 byte chunk is assumed valid. The next call writes 208 bytes,
but the last 3 bytes (276 + 208 - 481) including 1 valid byte,
are ignored, as the controller uses the MCI_DATA_LENGTH register
to figure out that it only needs to write a total of 481 bytes.

To fix the data corruption in cases as above, a 4 byte bounce
buffer is used realign buffer access to the FIFO, such that 4 byte
multiples are written until the last buffer chunk.

Note that in a simple case where all 481 bytes lie within a page,
the driver rounds the length to 484, but the MCI_DATA_LENGTH
register enusres only 481 bytes are actually written.

Change-Id: I164bae2df4857017b35857e465d753b9dc9edf6a
Signed-off-by: Oluwafemi Adeyemi <aadeyemi@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 319d721..8a728f2 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -281,9 +281,10 @@
 };
 
 struct msmsdcc_pio_data {
-	struct scatterlist	*sg;
-	unsigned int		sg_len;
-	unsigned int		sg_off;
+	struct sg_mapping_iter		sg_miter;
+	char				bounce_buf[4];
+	/* valid bytes in bounce_buf */
+	int				bounce_buf_len;
 };
 
 struct msmsdcc_curr_req {
@@ -361,7 +362,7 @@
 	struct msmsdcc_sps_data sps;
 	bool			is_dma_mode;
 	bool			is_sps_mode;
-	struct sg_mapping_iter sg_miter;
+	struct msmsdcc_pio_data	pio;
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 	struct early_suspend early_suspend;