diff options
author | David Vrabel <david.vrabel@csr.com> | 2007-08-08 17:24:21 +0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 23:21:32 +0400 |
commit | eb6594689226663968ef0a9fd71ec5e1e4e04f9c (patch) | |
tree | d523962b81a2b5f4a55543d4342daaaebc5d5162 /drivers/mmc/core/sdio_io.c | |
parent | 9a08f82b3cc522f727ace580a2aaee5402435bc8 (diff) | |
download | linux-eb6594689226663968ef0a9fd71ec5e1e4e04f9c.tar.xz |
sdio: extend sdio_readsb() and friends to handle any length of buffer
Extend sdio_readsb(), sdio_writesb(), sdio_memcpy_fromio(), and
sdio_memcpy_toio() to handle any length of buffer by splitting the transfer
into several IO_RW_EXTENDED commands. Typically, a transfer would be split
into a single block mode transfer followed by a byte mode transfer for the
remainder but we also handle lack of block mode support and the block size
being greater than 512 (the maximum byte mode transfer size).
host->max_seg_size <= host->max_req_size so there's no need to check both
when determining the maximum data size for a single command.
Signed-off-by: David Vrabel <david.vrabel@csr.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/sdio_io.c')
-rw-r--r-- | drivers/mmc/core/sdio_io.c | 93 |
1 files changed, 73 insertions, 20 deletions
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index c2bad1195e3b..34b085d4024a 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -189,6 +189,67 @@ int sdio_set_block_size(struct sdio_func *func, unsigned blksz) EXPORT_SYMBOL_GPL(sdio_set_block_size); +/* Split an arbitrarily sized data transfer into several + * IO_RW_EXTENDED commands. */ +static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, + unsigned addr, int incr_addr, u8 *buf, unsigned size) +{ + unsigned remainder = size; + unsigned max_blocks; + int ret; + + /* Do the bulk of the transfer using block mode (if supported). */ + if (func->card->cccr.multi_block) { + /* Blocks per command is limited by host count, host transfer + * size (we only use a single sg entry) and the maximum for + * IO_RW_EXTENDED of 511 blocks. */ + max_blocks = min(min( + func->card->host->max_blk_count, + func->card->host->max_seg_size / func->cur_blksize), + 511u); + + while (remainder > func->cur_blksize) { + unsigned blocks; + + blocks = remainder / func->cur_blksize; + if (blocks > max_blocks) + blocks = max_blocks; + size = blocks * func->cur_blksize; + + ret = mmc_io_rw_extended(func->card, write, + func->num, addr, incr_addr, buf, + blocks, func->cur_blksize); + if (ret) + return ret; + + remainder -= size; + buf += size; + if (incr_addr) + addr += size; + } + } + + /* Write the remainder using byte mode. */ + while (remainder > 0) { + size = remainder; + if (size > func->cur_blksize) + size = func->cur_blksize; + if (size > 512) + size = 512; /* maximum size for byte mode */ + + ret = mmc_io_rw_extended(func->card, write, func->num, addr, + incr_addr, buf, 1, size); + if (ret) + return ret; + + remainder -= size; + buf += size; + if (incr_addr) + addr += size; + } + return 0; +} + /** * sdio_readb - read a single byte from a SDIO function * @func: SDIO function to access @@ -252,15 +313,13 @@ EXPORT_SYMBOL_GPL(sdio_writeb); * @addr: address to begin reading from * @count: number of bytes to read * - * Reads up to 512 bytes from the address space of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Reads from the address space of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_memcpy_fromio(struct sdio_func *func, void *dst, unsigned int addr, int count) { - return mmc_io_rw_extended(func->card, 0, func->num, addr, 0, dst, - count); + return sdio_io_rw_ext_helper(func, 0, addr, 1, dst, count); } EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); @@ -271,15 +330,13 @@ EXPORT_SYMBOL_GPL(sdio_memcpy_fromio); * @src: buffer that contains the data to write * @count: number of bytes to write * - * Writes up to 512 bytes to the address space of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Writes to the address space of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, void *src, int count) { - return mmc_io_rw_extended(func->card, 1, func->num, addr, 0, src, - count); + return sdio_io_rw_ext_helper(func, 1, addr, 1, src, count); } EXPORT_SYMBOL_GPL(sdio_memcpy_toio); @@ -290,15 +347,13 @@ EXPORT_SYMBOL_GPL(sdio_memcpy_toio); * @addr: address of (single byte) FIFO * @count: number of bytes to read * - * Reads up to 512 bytes from the specified FIFO of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Reads from the specified FIFO of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, int count) { - return mmc_io_rw_extended(func->card, 0, func->num, addr, 1, dst, - count); + return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count); } EXPORT_SYMBOL_GPL(sdio_readsb); @@ -310,15 +365,13 @@ EXPORT_SYMBOL_GPL(sdio_readsb); * @src: buffer that contains the data to write * @count: number of bytes to write * - * Writes up to 512 bytes to the specified FIFO of a given SDIO - * function. Return value indicates if the transfer succeeded or - * not. + * Writes to the specified FIFO of a given SDIO function. Return + * value indicates if the transfer succeeded or not. */ int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, int count) { - return mmc_io_rw_extended(func->card, 1, func->num, addr, 1, src, - count); + return sdio_io_rw_ext_helper(func, 1, addr, 0, src, count); } EXPORT_SYMBOL_GPL(sdio_writesb); |