diff options
author | Alex Dubov <oakad@yahoo.com> | 2007-04-13 13:04:38 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-05-01 07:04:12 -0400 |
commit | 14d836e7499c53a1f6a65086c3d11600e871a971 (patch) | |
tree | 37d1cb767422bd498a13654ecabd6f891b27b0e3 /drivers/mmc | |
parent | dc87c3985e9b442c60994308a96f887579addc39 (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')
-rw-r--r-- | drivers/mmc/mmc_block.c | 16 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 24 | ||||
-rw-r--r-- | drivers/mmc/sdhci.h | 4 | ||||
-rw-r--r-- | drivers/mmc/wbsd.c | 131 | ||||
-rw-r--r-- | drivers/mmc/wbsd.h | 4 |
5 files changed, 50 insertions, 129 deletions
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 86439a0bb271..95b0da6abe87 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c | |||
@@ -223,7 +223,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) | |||
223 | struct mmc_blk_data *md = mq->data; | 223 | struct mmc_blk_data *md = mq->data; |
224 | struct mmc_card *card = md->queue.card; | 224 | struct mmc_card *card = md->queue.card; |
225 | struct mmc_blk_request brq; | 225 | struct mmc_blk_request brq; |
226 | int ret = 1; | 226 | int ret = 1, sg_pos, data_size; |
227 | 227 | ||
228 | if (mmc_card_claim_host(card)) | 228 | if (mmc_card_claim_host(card)) |
229 | goto flush_queue; | 229 | goto flush_queue; |
@@ -283,6 +283,20 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) | |||
283 | brq.data.sg = mq->sg; | 283 | brq.data.sg = mq->sg; |
284 | brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg); | 284 | brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg); |
285 | 285 | ||
286 | if (brq.data.blocks != | ||
287 | (req->nr_sectors >> (md->block_bits - 9))) { | ||
288 | data_size = brq.data.blocks * brq.data.blksz; | ||
289 | for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) { | ||
290 | data_size -= mq->sg[sg_pos].length; | ||
291 | if (data_size <= 0) { | ||
292 | mq->sg[sg_pos].length += data_size; | ||
293 | sg_pos++; | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | brq.data.sg_len = sg_pos; | ||
298 | } | ||
299 | |||
286 | mmc_wait_for_req(card->host, &brq.mrq); | 300 | mmc_wait_for_req(card->host, &brq.mrq); |
287 | if (brq.cmd.error) { | 301 | if (brq.cmd.error) { |
288 | printk(KERN_ERR "%s: error %d sending read/write command\n", | 302 | printk(KERN_ERR "%s: error %d sending read/write command\n", |
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index d749f08601b8..587dccf95f8e 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver | 2 | * linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver |
3 | * | 3 | * |
4 | * Copyright (C) 2005-2006 Pierre Ossman, All Rights Reserved. | 4 | * Copyright (C) 2005-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 |
@@ -247,14 +247,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host) | |||
247 | chunk_remain = min(blksize, 4); | 247 | chunk_remain = min(blksize, 4); |
248 | } | 248 | } |
249 | 249 | ||
250 | size = min(host->size, host->remain); | 250 | size = min(host->remain, chunk_remain); |
251 | size = min(size, chunk_remain); | ||
252 | 251 | ||
253 | chunk_remain -= size; | 252 | chunk_remain -= size; |
254 | blksize -= size; | 253 | blksize -= size; |
255 | host->offset += size; | 254 | host->offset += size; |
256 | host->remain -= size; | 255 | host->remain -= size; |
257 | host->size -= size; | 256 | |
258 | while (size) { | 257 | while (size) { |
259 | *buffer = data & 0xFF; | 258 | *buffer = data & 0xFF; |
260 | buffer++; | 259 | buffer++; |
@@ -289,14 +288,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host) | |||
289 | buffer = sdhci_sg_to_buffer(host) + host->offset; | 288 | buffer = sdhci_sg_to_buffer(host) + host->offset; |
290 | 289 | ||
291 | while (blksize) { | 290 | while (blksize) { |
292 | size = min(host->size, host->remain); | 291 | size = min(host->remain, chunk_remain); |
293 | size = min(size, chunk_remain); | ||
294 | 292 | ||
295 | chunk_remain -= size; | 293 | chunk_remain -= size; |
296 | blksize -= size; | 294 | blksize -= size; |
297 | host->offset += size; | 295 | host->offset += size; |
298 | host->remain -= size; | 296 | host->remain -= size; |
299 | host->size -= size; | 297 | |
300 | while (size) { | 298 | while (size) { |
301 | data >>= 8; | 299 | data >>= 8; |
302 | data |= (u32)*buffer << 24; | 300 | data |= (u32)*buffer << 24; |
@@ -325,7 +323,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host) | |||
325 | 323 | ||
326 | BUG_ON(!host->data); | 324 | BUG_ON(!host->data); |
327 | 325 | ||
328 | if (host->size == 0) | 326 | if (host->num_sg == 0) |
329 | return; | 327 | return; |
330 | 328 | ||
331 | if (host->data->flags & MMC_DATA_READ) | 329 | if (host->data->flags & MMC_DATA_READ) |
@@ -339,10 +337,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host) | |||
339 | else | 337 | else |
340 | sdhci_write_block_pio(host); | 338 | sdhci_write_block_pio(host); |
341 | 339 | ||
342 | if (host->size == 0) | 340 | if (host->num_sg == 0) |
343 | break; | 341 | break; |
344 | |||
345 | BUG_ON(host->num_sg == 0); | ||
346 | } | 342 | } |
347 | 343 | ||
348 | DBG("PIO transfer complete.\n"); | 344 | DBG("PIO transfer complete.\n"); |
@@ -408,8 +404,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) | |||
408 | 404 | ||
409 | writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS); | 405 | writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS); |
410 | } else { | 406 | } else { |
411 | host->size = data->blksz * data->blocks; | ||
412 | |||
413 | host->cur_sg = data->sg; | 407 | host->cur_sg = data->sg; |
414 | host->num_sg = data->sg_len; | 408 | host->num_sg = data->sg_len; |
415 | 409 | ||
@@ -473,10 +467,6 @@ static void sdhci_finish_data(struct sdhci_host *host) | |||
473 | "though there were blocks left.\n", | 467 | "though there were blocks left.\n", |
474 | mmc_hostname(host->mmc)); | 468 | mmc_hostname(host->mmc)); |
475 | data->error = MMC_ERR_FAILED; | 469 | data->error = MMC_ERR_FAILED; |
476 | } else if (host->size != 0) { | ||
477 | printk(KERN_ERR "%s: %d bytes were left untransferred.\n", | ||
478 | mmc_hostname(host->mmc), host->size); | ||
479 | data->error = MMC_ERR_FAILED; | ||
480 | } | 470 | } |
481 | 471 | ||
482 | DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered); | 472 | DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered); |
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h index e324f0a623dc..7400f4bc114f 100644 --- a/drivers/mmc/sdhci.h +++ b/drivers/mmc/sdhci.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver | 2 | * linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Pierre Ossman, All Rights Reserved. | 4 | * Copyright (C) 2005-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 |
@@ -187,8 +187,6 @@ struct sdhci_host { | |||
187 | int offset; /* Offset into current sg */ | 187 | int offset; /* Offset into current sg */ |
188 | int remain; /* Bytes left in current */ | 188 | int remain; /* Bytes left in current */ |
189 | 189 | ||
190 | int size; /* Remaining bytes in transfer */ | ||
191 | |||
192 | char slot_descr[20]; /* Name for reservations */ | 190 | char slot_descr[20]; /* Name for reservations */ |
193 | 191 | ||
194 | int irq; /* Device IRQ */ | 192 | int irq; /* Device IRQ */ |
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 | ||
279 | static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) | 279 | static 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 | ||
323 | static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) | 296 | static 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 | } |
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h index d06718b0e2ab..6fb4fa423219 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/wbsd.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver | 2 | * linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2005 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 |
@@ -158,8 +158,6 @@ struct wbsd_host | |||
158 | unsigned int offset; /* Offset into current entry */ | 158 | unsigned int offset; /* Offset into current entry */ |
159 | unsigned int remain; /* Data left in curren entry */ | 159 | unsigned int remain; /* Data left in curren entry */ |
160 | 160 | ||
161 | int size; /* Total size of transfer */ | ||
162 | |||
163 | char* dma_buffer; /* ISA DMA buffer */ | 161 | char* dma_buffer; /* ISA DMA buffer */ |
164 | dma_addr_t dma_addr; /* Physical address for same */ | 162 | dma_addr_t dma_addr; /* Physical address for same */ |
165 | 163 | ||