aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc/wbsd.c
diff options
context:
space:
mode:
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 05ccfc43168..7a3e32ec46b 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
*
- * Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* 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)
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
{
- unsigned int len, i, size;
+ unsigned int len, i;
struct scatterlist *sg;
char *dmabuf = host->dma_buffer;
char *sgbuf;
- size = host->size;
-
sg = data->sg;
len = data->sg_len;
- /*
- * Just loop through all entries. Size might not
- * be the entire list though so make sure that
- * we do not transfer too much.
- */
for (i = 0; i < len; i++) {
sgbuf = page_address(sg[i].page) + sg[i].offset;
- if (size < sg[i].length)
- memcpy(dmabuf, sgbuf, size);
- else
- memcpy(dmabuf, sgbuf, sg[i].length);
+ memcpy(dmabuf, sgbuf, sg[i].length);
dmabuf += sg[i].length;
-
- if (size < sg[i].length)
- size = 0;
- else
- size -= sg[i].length;
-
- if (size == 0)
- break;
}
-
- /*
- * Check that we didn't get a request to transfer
- * more data than can fit into the SG list.
- */
-
- BUG_ON(size != 0);
-
- host->size -= size;
}
static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
{
- unsigned int len, i, size;
+ unsigned int len, i;
struct scatterlist *sg;
char *dmabuf = host->dma_buffer;
char *sgbuf;
- size = host->size;
-
sg = data->sg;
len = data->sg_len;
- /*
- * Just loop through all entries. Size might not
- * be the entire list though so make sure that
- * we do not transfer too much.
- */
for (i = 0; i < len; i++) {
sgbuf = page_address(sg[i].page) + sg[i].offset;
- if (size < sg[i].length)
- memcpy(sgbuf, dmabuf, size);
- else
- memcpy(sgbuf, dmabuf, sg[i].length);
+ memcpy(sgbuf, dmabuf, sg[i].length);
dmabuf += sg[i].length;
-
- if (size < sg[i].length)
- size = 0;
- else
- size -= sg[i].length;
-
- if (size == 0)
- break;
}
-
- /*
- * Check that we didn't get a request to transfer
- * more data than can fit into the SG list.
- */
-
- BUG_ON(size != 0);
-
- host->size -= size;
}
/*
@@ -484,7 +430,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
/*
* Handle excessive data.
*/
- if (data->bytes_xfered == host->size)
+ if (host->num_sg == 0)
return;
buffer = wbsd_sg_to_buffer(host) + host->offset;
@@ -514,31 +460,14 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
data->bytes_xfered++;
/*
- * Transfer done?
- */
- if (data->bytes_xfered == host->size)
- return;
-
- /*
* End of scatter list entry?
*/
if (host->remain == 0) {
/*
* Get next entry. Check if last.
*/
- if (!wbsd_next_sg(host)) {
- /*
- * We should never reach this point.
- * It means that we're trying to
- * transfer more blocks than can fit
- * into the scatter list.
- */
- BUG_ON(1);
-
- host->size = data->bytes_xfered;
-
+ if (!wbsd_next_sg(host))
return;
- }
buffer = wbsd_sg_to_buffer(host);
}
@@ -550,7 +479,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
* hardware problem. The chip doesn't trigger
* FIFO threshold interrupts properly.
*/
- if ((host->size - data->bytes_xfered) < 16)
+ if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
tasklet_schedule(&host->fifo_tasklet);
}
@@ -564,7 +493,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
* Check that we aren't being called after the
* entire buffer has been transfered.
*/
- if (data->bytes_xfered == host->size)
+ if (host->num_sg == 0)
return;
buffer = wbsd_sg_to_buffer(host) + host->offset;
@@ -594,31 +523,14 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
data->bytes_xfered++;
/*
- * Transfer done?
- */
- if (data->bytes_xfered == host->size)
- return;
-
- /*
* End of scatter list entry?
*/
if (host->remain == 0) {
/*
* Get next entry. Check if last.
*/
- if (!wbsd_next_sg(host)) {
- /*
- * We should never reach this point.
- * It means that we're trying to
- * transfer more blocks than can fit
- * into the scatter list.
- */
- BUG_ON(1);
-
- host->size = data->bytes_xfered;
-
+ if (!wbsd_next_sg(host))
return;
- }
buffer = wbsd_sg_to_buffer(host);
}
@@ -638,6 +550,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
u16 blksize;
u8 setup;
unsigned long dmaflags;
+ unsigned int size;
DBGF("blksz %04x blks %04x flags %08x\n",
data->blksz, data->blocks, data->flags);
@@ -647,7 +560,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
/*
* Calculate size.
*/
- host->size = data->blocks * data->blksz;
+ size = data->blocks * data->blksz;
/*
* Check timeout values for overflow.
@@ -705,8 +618,8 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
/*
* The buffer for DMA is only 64 kB.
*/
- BUG_ON(host->size > 0x10000);
- if (host->size > 0x10000) {
+ BUG_ON(size > 0x10000);
+ if (size > 0x10000) {
data->error = MMC_ERR_INVALID;
return;
}
@@ -729,7 +642,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
else
set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
set_dma_addr(host->dma, host->dma_addr);
- set_dma_count(host->dma, host->size);
+ set_dma_count(host->dma, size);
enable_dma(host->dma);
release_dma_lock(dmaflags);
@@ -812,6 +725,10 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
count = get_dma_residue(host->dma);
release_dma_lock(dmaflags);
+ data->bytes_xfered = host->mrq->data->blocks *
+ host->mrq->data->blksz - count;
+ data->bytes_xfered -= data->bytes_xfered % data->blksz;
+
/*
* Any leftover data?
*/
@@ -820,7 +737,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
"%d bytes left.\n",
mmc_hostname(host->mmc), count);
- data->error = MMC_ERR_FAILED;
+ if (data->error == MMC_ERR_NONE)
+ data->error = MMC_ERR_FAILED;
} else {
/*
* Transfer data from DMA buffer to
@@ -828,8 +746,11 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
*/
if (data->flags & MMC_DATA_READ)
wbsd_dma_to_sg(host, data);
+ }
- data->bytes_xfered = host->size;
+ if (data->error != MMC_ERR_NONE) {
+ if (data->bytes_xfered)
+ data->bytes_xfered -= data->blksz;
}
}
@@ -1167,7 +1088,7 @@ static void wbsd_tasklet_fifo(unsigned long param)
/*
* Done?
*/
- if (host->size == data->bytes_xfered) {
+ if (host->num_sg == 0) {
wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
tasklet_schedule(&host->finish_tasklet);
}