diff options
-rw-r--r-- | drivers/mmc/host/mmci.c | 60 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 35 |
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 | ||
100 | static 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 | |||
101 | static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) | 112 | static 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 | |||
314 | static irqreturn_t mmci_pio_irq(int irq, void *dev_id) | 334 | static 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 | ||
183 | static 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 | |||
193 | static 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 | |||
200 | static 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 | |||
208 | static 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 | } | ||