aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/wbsd.c
diff options
context:
space:
mode:
authorAlex Dubov <oakad@yahoo.com>2007-04-13 13:04:38 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-05-01 07:04:12 -0400
commit14d836e7499c53a1f6a65086c3d11600e871a971 (patch)
tree37d1cb767422bd498a13654ecabd6f891b27b0e3 /drivers/mmc/wbsd.c
parentdc87c3985e9b442c60994308a96f887579addc39 (diff)
mmc: cull sg list to match mmc request size
mmc layer may introduce additional (compared to block layer) limits on request size. Culling of the sg list to match adjusted request size simplifies the handling of such cases in the low level driver, allowing it to skip block count checks while processing sg entries. (fixes for wbsd and sdhci by Pierre Ossman) Signed-off-by: Alex Dubov <oakad@yahoo.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/wbsd.c')
-rw-r--r--drivers/mmc/wbsd.c131
1 files changed, 26 insertions, 105 deletions
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 05ccfc43168f..7a3e32ec46b8 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver 2 * linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
3 * 3 *
4 * Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved. 4 * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -278,90 +278,36 @@ static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
278 278
279static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) 279static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
280{ 280{
281 unsigned int len, i, size; 281 unsigned int len, i;
282 struct scatterlist *sg; 282 struct scatterlist *sg;
283 char *dmabuf = host->dma_buffer; 283 char *dmabuf = host->dma_buffer;
284 char *sgbuf; 284 char *sgbuf;
285 285
286 size = host->size;
287
288 sg = data->sg; 286 sg = data->sg;
289 len = data->sg_len; 287 len = data->sg_len;
290 288
291 /*
292 * Just loop through all entries. Size might not
293 * be the entire list though so make sure that
294 * we do not transfer too much.
295 */
296 for (i = 0; i < len; i++) { 289 for (i = 0; i < len; i++) {
297 sgbuf = page_address(sg[i].page) + sg[i].offset; 290 sgbuf = page_address(sg[i].page) + sg[i].offset;
298 if (size < sg[i].length) 291 memcpy(dmabuf, sgbuf, sg[i].length);
299 memcpy(dmabuf, sgbuf, size);
300 else
301 memcpy(dmabuf, sgbuf, sg[i].length);
302 dmabuf += sg[i].length; 292 dmabuf += sg[i].length;
303
304 if (size < sg[i].length)
305 size = 0;
306 else
307 size -= sg[i].length;
308
309 if (size == 0)
310 break;
311 } 293 }
312
313 /*
314 * Check that we didn't get a request to transfer
315 * more data than can fit into the SG list.
316 */
317
318 BUG_ON(size != 0);
319
320 host->size -= size;
321} 294}
322 295
323static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) 296static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
324{ 297{
325 unsigned int len, i, size; 298 unsigned int len, i;
326 struct scatterlist *sg; 299 struct scatterlist *sg;
327 char *dmabuf = host->dma_buffer; 300 char *dmabuf = host->dma_buffer;
328 char *sgbuf; 301 char *sgbuf;
329 302
330 size = host->size;
331
332 sg = data->sg; 303 sg = data->sg;
333 len = data->sg_len; 304 len = data->sg_len;
334 305
335 /*
336 * Just loop through all entries. Size might not
337 * be the entire list though so make sure that
338 * we do not transfer too much.
339 */
340 for (i = 0; i < len; i++) { 306 for (i = 0; i < len; i++) {
341 sgbuf = page_address(sg[i].page) + sg[i].offset; 307 sgbuf = page_address(sg[i].page) + sg[i].offset;
342 if (size < sg[i].length) 308 memcpy(sgbuf, dmabuf, sg[i].length);
343 memcpy(sgbuf, dmabuf, size);
344 else
345 memcpy(sgbuf, dmabuf, sg[i].length);
346 dmabuf += sg[i].length; 309 dmabuf += sg[i].length;
347
348 if (size < sg[i].length)
349 size = 0;
350 else
351 size -= sg[i].length;
352
353 if (size == 0)
354 break;
355 } 310 }
356
357 /*
358 * Check that we didn't get a request to transfer
359 * more data than can fit into the SG list.
360 */
361
362 BUG_ON(size != 0);
363
364 host->size -= size;
365} 311}
366 312
367/* 313/*
@@ -484,7 +430,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
484 /* 430 /*
485 * Handle excessive data. 431 * Handle excessive data.
486 */ 432 */
487 if (data->bytes_xfered == host->size) 433 if (host->num_sg == 0)
488 return; 434 return;
489 435
490 buffer = wbsd_sg_to_buffer(host) + host->offset; 436 buffer = wbsd_sg_to_buffer(host) + host->offset;
@@ -514,31 +460,14 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
514 data->bytes_xfered++; 460 data->bytes_xfered++;
515 461
516 /* 462 /*
517 * Transfer done?
518 */
519 if (data->bytes_xfered == host->size)
520 return;
521
522 /*
523 * End of scatter list entry? 463 * End of scatter list entry?
524 */ 464 */
525 if (host->remain == 0) { 465 if (host->remain == 0) {
526 /* 466 /*
527 * Get next entry. Check if last. 467 * Get next entry. Check if last.
528 */ 468 */
529 if (!wbsd_next_sg(host)) { 469 if (!wbsd_next_sg(host))
530 /*
531 * We should never reach this point.
532 * It means that we're trying to
533 * transfer more blocks than can fit
534 * into the scatter list.
535 */
536 BUG_ON(1);
537
538 host->size = data->bytes_xfered;
539
540 return; 470 return;
541 }
542 471
543 buffer = wbsd_sg_to_buffer(host); 472 buffer = wbsd_sg_to_buffer(host);
544 } 473 }
@@ -550,7 +479,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
550 * hardware problem. The chip doesn't trigger 479 * hardware problem. The chip doesn't trigger
551 * FIFO threshold interrupts properly. 480 * FIFO threshold interrupts properly.
552 */ 481 */
553 if ((host->size - data->bytes_xfered) < 16) 482 if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
554 tasklet_schedule(&host->fifo_tasklet); 483 tasklet_schedule(&host->fifo_tasklet);
555} 484}
556 485
@@ -564,7 +493,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
564 * Check that we aren't being called after the 493 * Check that we aren't being called after the
565 * entire buffer has been transfered. 494 * entire buffer has been transfered.
566 */ 495 */
567 if (data->bytes_xfered == host->size) 496 if (host->num_sg == 0)
568 return; 497 return;
569 498
570 buffer = wbsd_sg_to_buffer(host) + host->offset; 499 buffer = wbsd_sg_to_buffer(host) + host->offset;
@@ -594,31 +523,14 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
594 data->bytes_xfered++; 523 data->bytes_xfered++;
595 524
596 /* 525 /*
597 * Transfer done?
598 */
599 if (data->bytes_xfered == host->size)
600 return;
601
602 /*
603 * End of scatter list entry? 526 * End of scatter list entry?
604 */ 527 */
605 if (host->remain == 0) { 528 if (host->remain == 0) {
606 /* 529 /*
607 * Get next entry. Check if last. 530 * Get next entry. Check if last.
608 */ 531 */
609 if (!wbsd_next_sg(host)) { 532 if (!wbsd_next_sg(host))
610 /*
611 * We should never reach this point.
612 * It means that we're trying to
613 * transfer more blocks than can fit
614 * into the scatter list.
615 */
616 BUG_ON(1);
617
618 host->size = data->bytes_xfered;
619
620 return; 533 return;
621 }
622 534
623 buffer = wbsd_sg_to_buffer(host); 535 buffer = wbsd_sg_to_buffer(host);
624 } 536 }
@@ -638,6 +550,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
638 u16 blksize; 550 u16 blksize;
639 u8 setup; 551 u8 setup;
640 unsigned long dmaflags; 552 unsigned long dmaflags;
553 unsigned int size;
641 554
642 DBGF("blksz %04x blks %04x flags %08x\n", 555 DBGF("blksz %04x blks %04x flags %08x\n",
643 data->blksz, data->blocks, data->flags); 556 data->blksz, data->blocks, data->flags);
@@ -647,7 +560,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
647 /* 560 /*
648 * Calculate size. 561 * Calculate size.
649 */ 562 */
650 host->size = data->blocks * data->blksz; 563 size = data->blocks * data->blksz;
651 564
652 /* 565 /*
653 * Check timeout values for overflow. 566 * Check timeout values for overflow.
@@ -705,8 +618,8 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
705 /* 618 /*
706 * The buffer for DMA is only 64 kB. 619 * The buffer for DMA is only 64 kB.
707 */ 620 */
708 BUG_ON(host->size > 0x10000); 621 BUG_ON(size > 0x10000);
709 if (host->size > 0x10000) { 622 if (size > 0x10000) {
710 data->error = MMC_ERR_INVALID; 623 data->error = MMC_ERR_INVALID;
711 return; 624 return;
712 } 625 }
@@ -729,7 +642,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
729 else 642 else
730 set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40); 643 set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
731 set_dma_addr(host->dma, host->dma_addr); 644 set_dma_addr(host->dma, host->dma_addr);
732 set_dma_count(host->dma, host->size); 645 set_dma_count(host->dma, size);
733 646
734 enable_dma(host->dma); 647 enable_dma(host->dma);
735 release_dma_lock(dmaflags); 648 release_dma_lock(dmaflags);
@@ -812,6 +725,10 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
812 count = get_dma_residue(host->dma); 725 count = get_dma_residue(host->dma);
813 release_dma_lock(dmaflags); 726 release_dma_lock(dmaflags);
814 727
728 data->bytes_xfered = host->mrq->data->blocks *
729 host->mrq->data->blksz - count;
730 data->bytes_xfered -= data->bytes_xfered % data->blksz;
731
815 /* 732 /*
816 * Any leftover data? 733 * Any leftover data?
817 */ 734 */
@@ -820,7 +737,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
820 "%d bytes left.\n", 737 "%d bytes left.\n",
821 mmc_hostname(host->mmc), count); 738 mmc_hostname(host->mmc), count);
822 739
823 data->error = MMC_ERR_FAILED; 740 if (data->error == MMC_ERR_NONE)
741 data->error = MMC_ERR_FAILED;
824 } else { 742 } else {
825 /* 743 /*
826 * Transfer data from DMA buffer to 744 * Transfer data from DMA buffer to
@@ -828,8 +746,11 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
828 */ 746 */
829 if (data->flags & MMC_DATA_READ) 747 if (data->flags & MMC_DATA_READ)
830 wbsd_dma_to_sg(host, data); 748 wbsd_dma_to_sg(host, data);
749 }
831 750
832 data->bytes_xfered = host->size; 751 if (data->error != MMC_ERR_NONE) {
752 if (data->bytes_xfered)
753 data->bytes_xfered -= data->blksz;
833 } 754 }
834 } 755 }
835 756
@@ -1167,7 +1088,7 @@ static void wbsd_tasklet_fifo(unsigned long param)
1167 /* 1088 /*
1168 * Done? 1089 * Done?
1169 */ 1090 */
1170 if (host->size == data->bytes_xfered) { 1091 if (host->num_sg == 0) {
1171 wbsd_write_index(host, WBSD_IDX_FIFOEN, 0); 1092 wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
1172 tasklet_schedule(&host->finish_tasklet); 1093 tasklet_schedule(&host->finish_tasklet);
1173 } 1094 }