aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorTerry Barnaby <terry@beam.ltd.uk>2013-04-08 12:05:47 -0400
committerChris Ball <cjb@laptop.org>2013-04-08 12:05:47 -0400
commitbdbc5d0c60f3e9de3eeccf1c1a18bdc11dca62cc (patch)
tree1c20e5a4c777bf3295bd98710ed7277030b42154 /drivers/mmc
parent836dc2fe89c968c10cada87e0dfae6626f8f9da3 (diff)
mmc: atmel-mci: pio hang on block errors
The driver is doing, by default, multi-block reads. When a block error occurs, card/block.c instigates a single block read: "mmcblk0: retrying using single block read". It leaves the sg chain intact and just changes the length attribute for the first sg entry and the overall sg_len parameter. When atmci_read_data_pio is called to read the single block of data it ignores the sg_len and expects to read more than 512 bytes as it sees there are multiple items in the sg list. No more data comes as the controller has only been commanded to get one block. Signed-off-by: Terry Barnaby <terry@beam.ltd.uk> Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com> Cc: stable <stable@vger.kernel.org> # 3.2+ Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/atmel-mci.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 10f8b7358e57..e75774f72606 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -178,6 +178,7 @@ struct atmel_mci {
178 void __iomem *regs; 178 void __iomem *regs;
179 179
180 struct scatterlist *sg; 180 struct scatterlist *sg;
181 unsigned int sg_len;
181 unsigned int pio_offset; 182 unsigned int pio_offset;
182 unsigned int *buffer; 183 unsigned int *buffer;
183 unsigned int buf_size; 184 unsigned int buf_size;
@@ -892,6 +893,7 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
892 data->error = -EINPROGRESS; 893 data->error = -EINPROGRESS;
893 894
894 host->sg = data->sg; 895 host->sg = data->sg;
896 host->sg_len = data->sg_len;
895 host->data = data; 897 host->data = data;
896 host->data_chan = NULL; 898 host->data_chan = NULL;
897 899
@@ -1826,7 +1828,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
1826 if (offset == sg->length) { 1828 if (offset == sg->length) {
1827 flush_dcache_page(sg_page(sg)); 1829 flush_dcache_page(sg_page(sg));
1828 host->sg = sg = sg_next(sg); 1830 host->sg = sg = sg_next(sg);
1829 if (!sg) 1831 host->sg_len--;
1832 if (!sg || !host->sg_len)
1830 goto done; 1833 goto done;
1831 1834
1832 offset = 0; 1835 offset = 0;
@@ -1839,7 +1842,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
1839 1842
1840 flush_dcache_page(sg_page(sg)); 1843 flush_dcache_page(sg_page(sg));
1841 host->sg = sg = sg_next(sg); 1844 host->sg = sg = sg_next(sg);
1842 if (!sg) 1845 host->sg_len--;
1846 if (!sg || !host->sg_len)
1843 goto done; 1847 goto done;
1844 1848
1845 offset = 4 - remaining; 1849 offset = 4 - remaining;
@@ -1890,7 +1894,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
1890 nbytes += 4; 1894 nbytes += 4;
1891 if (offset == sg->length) { 1895 if (offset == sg->length) {
1892 host->sg = sg = sg_next(sg); 1896 host->sg = sg = sg_next(sg);
1893 if (!sg) 1897 host->sg_len--;
1898 if (!sg || !host->sg_len)
1894 goto done; 1899 goto done;
1895 1900
1896 offset = 0; 1901 offset = 0;
@@ -1904,7 +1909,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
1904 nbytes += remaining; 1909 nbytes += remaining;
1905 1910
1906 host->sg = sg = sg_next(sg); 1911 host->sg = sg = sg_next(sg);
1907 if (!sg) { 1912 host->sg_len--;
1913 if (!sg || !host->sg_len) {
1908 atmci_writel(host, ATMCI_TDR, value); 1914 atmci_writel(host, ATMCI_TDR, value);
1909 goto done; 1915 goto done;
1910 } 1916 }