diff options
| author | Jens Arnold <amiconn@rockbox.org> | 2005-04-28 20:47:55 +0000 |
|---|---|---|
| committer | Jens Arnold <amiconn@rockbox.org> | 2005-04-28 20:47:55 +0000 |
| commit | 74875ef37ebe70c1ed54c6eb75cf3cf218dfc212 (patch) | |
| tree | 687e1ffa39316dc8d6a7a1ae57f72d41ab2c799f /firmware | |
| parent | 238bea737050f22007a06035cdd78c96beb50f06 (diff) | |
| download | rockbox-74875ef37ebe70c1ed54c6eb75cf3cf218dfc212.zip rockbox-74875ef37ebe70c1ed54c6eb75cf3cf218dfc212.tar.gz rockbox-74875ef37ebe70c1ed54c6eb75cf3cf218dfc212.tar.bz2 rockbox-74875ef37ebe70c1ed54c6eb75cf3cf218dfc212.tar.xz | |
Speed optimisations: (1) Read, write: Use single/multiple block commands depending on the block count. (2) Write: Combine first partial sector transfer (after caching) & main loop into one block-transfer sequence.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6381 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
| -rw-r--r-- | firmware/drivers/ata_mmc.c | 125 |
1 files changed, 72 insertions, 53 deletions
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c index 3c24287..606bb0c 100644 --- a/firmware/drivers/ata_mmc.c +++ b/firmware/drivers/ata_mmc.c @@ -744,16 +744,19 @@ int ata_read_sectors(IF_MV2(int drive,) c_addr += len; c_block++; } - /* some cards don't like reading the very last sector with - * CMD_READ_MULTIPLE_BLOCK, so make sure this sector is always - * read with CMD_READ_SINGLE_BLOCK. This is caught by the 'last - * partial block' read. */ + /* some cards don't like reading the very last block with + * CMD_READ_MULTIPLE_BLOCK, so make sure this block is always + * read with CMD_READ_SINGLE_BLOCK. Let the 'last partial block' + * read catch this. */ if (c_end_block == card->numblocks) c_end_block--; if (c_block < c_end_block) { - rc = send_cmd(CMD_READ_MULTIPLE_BLOCK, c_addr, &response); + int read_cmd = (c_end_block - c_block > 1) ? + CMD_READ_MULTIPLE_BLOCK : CMD_READ_SINGLE_BLOCK; + + rc = send_cmd(read_cmd, c_addr, &response); if (rc) { rc = rc * 10 - 4; @@ -774,11 +777,14 @@ int ata_read_sectors(IF_MV2(int drive,) c_addr += blocksize; c_block++; } - rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); - if (rc) + if (read_cmd == CMD_READ_MULTIPLE_BLOCK) { - rc = rc * 10 - 6; - goto error; + rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); + if (rc) + { + rc = rc * 10 - 6; + goto error; + } } bitswap(inbuf_prev, blocksize); } @@ -848,81 +854,94 @@ int ata_write_sectors(IF_MV2(int drive,) offset = c_addr & (blocksize - 1); c_block = c_addr >> card->block_exp; c_end_block = c_end_addr >> card->block_exp; - - if (offset) /* first partial block */ - { - unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset); - rc = cache_block(IF_MV2(drive,) c_block, blocksize, - card->read_timeout); - if (rc) + /* Special case: first block is trimmed at both ends. May only happen + * if (blocksize > 2 * sectorsize), i.e. blocksize == 2048 */ + if ((c_block == c_end_block) && offset) + c_end_block++; + + if (c_block < c_end_block) + { + int write_cmd; + unsigned char start_token; + + if (c_end_block - c_block > 1) { - rc = rc * 10 - 2; - goto error; + write_cmd = CMD_WRITE_MULTIPLE_BLOCK; + start_token = DT_START_WRITE_MULTIPLE; } - swapcopy(block_cache[current_cache].data + 2 + offset, buf, len); - rc = send_cmd(CMD_WRITE_BLOCK, c_addr - offset, &response); - if (rc) + else { - rc = rc * 10 - 3; - goto error; + write_cmd = CMD_WRITE_BLOCK; + start_token = DT_START_BLOCK; } - buf += len; - rc = send_block(NULL, blocksize, DT_START_BLOCK, card->write_timeout); - if (rc) + + if (offset) { - rc = rc * 10 - 4; - goto error; + unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset); + + rc = cache_block(IF_MV2(drive,) c_block, blocksize, + card->read_timeout); + if (rc) + { + rc = rc * 10 - 2; + goto error; + } + swapcopy(block_cache[current_cache].data + 2 + offset, buf, len); + buf += len; + c_addr -= offset; } - c_addr += len; - c_block++; - } - if (c_block < c_end_block) - { - swapcopy_block(buf, blocksize); - rc = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, c_addr, &response); + else + { + swapcopy_block(buf, blocksize); + buf += blocksize; + } + rc = send_cmd(write_cmd, c_addr, &response); if (rc) { - rc = rc * 10 - 5; + rc = rc * 10 - 3; goto error; } - while (c_block < c_end_block - 1) + c_block++; /* early increment to simplify the loop */ + + while (c_block < c_end_block) { - buf += blocksize; - rc = send_block(buf, blocksize, DT_START_WRITE_MULTIPLE, - card->write_timeout); + rc = send_block(buf, blocksize, start_token, card->write_timeout); if (rc) { - rc = rc * 10 - 6; + rc = rc * 10 - 4; goto error; } last_disk_activity = current_tick; + buf += blocksize; c_addr += blocksize; c_block++; } - buf += blocksize; - rc = send_block(NULL, blocksize, DT_START_WRITE_MULTIPLE, - card->write_timeout); + rc = send_block(NULL, blocksize, start_token, card->write_timeout); if (rc) { - rc = rc * 10 - 7; + rc = rc * 10 - 5; goto error; } last_disk_activity = current_tick; c_addr += blocksize; - c_block++; - - response = DT_STOP_TRAN; - write_transfer(&response, 1); - poll_busy(card->write_timeout); + /* c_block++ was done early */ + + if (write_cmd == CMD_WRITE_MULTIPLE_BLOCK) + { + response = DT_STOP_TRAN; + write_transfer(&response, 1); + poll_busy(card->write_timeout); + } } + if (c_addr < c_end_addr) /* last partial block */ { rc = cache_block(IF_MV2(drive,) c_block, blocksize, card->read_timeout); if (rc) { - rc = rc * 10 - 8; + rc = rc * 10 - 6; goto error; } swapcopy(block_cache[current_cache].data + 2, buf, @@ -930,13 +949,13 @@ int ata_write_sectors(IF_MV2(int drive,) rc = send_cmd(CMD_WRITE_BLOCK, c_addr, &response); if (rc) { - rc = rc * 10 - 9; + rc = rc * 10 - 7; goto error; } rc = send_block(NULL, blocksize, DT_START_BLOCK, card->write_timeout); if (rc) { - rc = rc * 10 - 9; + rc = rc * 10 - 8; goto error; } } |