aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/mmci.c60
-rw-r--r--drivers/mmc/host/mmci.h35
2 files changed, 39 insertions, 56 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 4917af96bae1..d63d7565f896 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -26,7 +26,6 @@
26#include <linux/amba/mmci.h> 26#include <linux/amba/mmci.h>
27#include <linux/regulator/consumer.h> 27#include <linux/regulator/consumer.h>
28 28
29#include <asm/cacheflush.h>
30#include <asm/div64.h> 29#include <asm/div64.h>
31#include <asm/io.h> 30#include <asm/io.h>
32#include <asm/sizes.h> 31#include <asm/sizes.h>
@@ -98,6 +97,18 @@ static void mmci_stop_data(struct mmci_host *host)
98 host->data = NULL; 97 host->data = NULL;
99} 98}
100 99
100static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
101{
102 unsigned int flags = SG_MITER_ATOMIC;
103
104 if (data->flags & MMC_DATA_READ)
105 flags |= SG_MITER_TO_SG;
106 else
107 flags |= SG_MITER_FROM_SG;
108
109 sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
110}
111
101static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) 112static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
102{ 113{
103 unsigned int datactrl, timeout, irqmask; 114 unsigned int datactrl, timeout, irqmask;
@@ -210,8 +221,17 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
210 * We hit an error condition. Ensure that any data 221 * We hit an error condition. Ensure that any data
211 * partially written to a page is properly coherent. 222 * partially written to a page is properly coherent.
212 */ 223 */
213 if (host->sg_len && data->flags & MMC_DATA_READ) 224 if (data->flags & MMC_DATA_READ) {
214 flush_dcache_page(sg_page(host->sg_ptr)); 225 struct sg_mapping_iter *sg_miter = &host->sg_miter;
226 unsigned long flags;
227
228 local_irq_save(flags);
229 if (sg_miter_next(sg_miter)) {
230 flush_dcache_page(sg_miter->page);
231 sg_miter_stop(sg_miter);
232 }
233 local_irq_restore(flags);
234 }
215 } 235 }
216 if (status & MCI_DATAEND) { 236 if (status & MCI_DATAEND) {
217 mmci_stop_data(host); 237 mmci_stop_data(host);
@@ -314,15 +334,18 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
314static irqreturn_t mmci_pio_irq(int irq, void *dev_id) 334static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
315{ 335{
316 struct mmci_host *host = dev_id; 336 struct mmci_host *host = dev_id;
337 struct sg_mapping_iter *sg_miter = &host->sg_miter;
317 void __iomem *base = host->base; 338 void __iomem *base = host->base;
339 unsigned long flags;
318 u32 status; 340 u32 status;
319 341
320 status = readl(base + MMCISTATUS); 342 status = readl(base + MMCISTATUS);
321 343
322 dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); 344 dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
323 345
346 local_irq_save(flags);
347
324 do { 348 do {
325 unsigned long flags;
326 unsigned int remain, len; 349 unsigned int remain, len;
327 char *buffer; 350 char *buffer;
328 351
@@ -336,11 +359,11 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
336 if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) 359 if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
337 break; 360 break;
338 361
339 /* 362 if (!sg_miter_next(sg_miter))
340 * Map the current scatter buffer. 363 break;
341 */ 364
342 buffer = mmci_kmap_atomic(host, &flags) + host->sg_off; 365 buffer = sg_miter->addr;
343 remain = host->sg_ptr->length - host->sg_off; 366 remain = sg_miter->length;
344 367
345 len = 0; 368 len = 0;
346 if (status & MCI_RXACTIVE) 369 if (status & MCI_RXACTIVE)
@@ -348,31 +371,24 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
348 if (status & MCI_TXACTIVE) 371 if (status & MCI_TXACTIVE)
349 len = mmci_pio_write(host, buffer, remain, status); 372 len = mmci_pio_write(host, buffer, remain, status);
350 373
351 /* 374 sg_miter->consumed = len;
352 * Unmap the buffer.
353 */
354 mmci_kunmap_atomic(host, buffer, &flags);
355 375
356 host->sg_off += len;
357 host->size -= len; 376 host->size -= len;
358 remain -= len; 377 remain -= len;
359 378
360 if (remain) 379 if (remain)
361 break; 380 break;
362 381
363 /*
364 * If we were reading, and we have completed this
365 * page, ensure that the data cache is coherent.
366 */
367 if (status & MCI_RXACTIVE) 382 if (status & MCI_RXACTIVE)
368 flush_dcache_page(sg_page(host->sg_ptr)); 383 flush_dcache_page(sg_miter->page);
369
370 if (!mmci_next_sg(host))
371 break;
372 384
373 status = readl(base + MMCISTATUS); 385 status = readl(base + MMCISTATUS);
374 } while (1); 386 } while (1);
375 387
388 sg_miter_stop(sg_miter);
389
390 local_irq_restore(flags);
391
376 /* 392 /*
377 * If we're nearing the end of the read, switch to 393 * If we're nearing the end of the read, switch to
378 * "any data available" mode. 394 * "any data available" mode.
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index d77062e5e3af..7cb24ab1eecc 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -171,42 +171,9 @@ struct mmci_host {
171 struct timer_list timer; 171 struct timer_list timer;
172 unsigned int oldstat; 172 unsigned int oldstat;
173 173
174 unsigned int sg_len;
175
176 /* pio stuff */ 174 /* pio stuff */
177 struct scatterlist *sg_ptr; 175 struct sg_mapping_iter sg_miter;
178 unsigned int sg_off;
179 unsigned int size; 176 unsigned int size;
180 struct regulator *vcc; 177 struct regulator *vcc;
181}; 178};
182 179
183static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
184{
185 /*
186 * Ideally, we want the higher levels to pass us a scatter list.
187 */
188 host->sg_len = data->sg_len;
189 host->sg_ptr = data->sg;
190 host->sg_off = 0;
191}
192
193static inline int mmci_next_sg(struct mmci_host *host)
194{
195 host->sg_ptr++;
196 host->sg_off = 0;
197 return --host->sg_len;
198}
199
200static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
201{
202 struct scatterlist *sg = host->sg_ptr;
203
204 local_irq_save(*flags);
205 return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
206}
207
208static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
209{
210 kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
211 local_irq_restore(*flags);
212}