diff options
Diffstat (limited to 'drivers/mmc/wbsd.c')
-rw-r--r-- | drivers/mmc/wbsd.c | 131 |
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 @@ /* * 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); } |