mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 21:25:19 -05:00
MMC driver: More flexible background copy & bitswap concept, using global variables - slightly less read latency when both partial and full blocks are involved. Some code cleanup.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6393 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
4e2cee1ece
commit
1ba26b8a60
1 changed files with 63 additions and 54 deletions
|
|
@ -128,6 +128,11 @@ struct block_cache_entry {
|
||||||
static struct block_cache_entry block_cache[NUMCACHES];
|
static struct block_cache_entry block_cache[NUMCACHES];
|
||||||
static int current_cache = 0;
|
static int current_cache = 0;
|
||||||
|
|
||||||
|
/* globals for background copy and swap */
|
||||||
|
static const unsigned char *bcs_src = NULL;
|
||||||
|
static unsigned char *bcs_dest = NULL;
|
||||||
|
static unsigned long bcs_len = 0;
|
||||||
|
|
||||||
static tCardInfo card_info[2];
|
static tCardInfo card_info[2];
|
||||||
#ifndef HAVE_MULTIVOLUME
|
#ifndef HAVE_MULTIVOLUME
|
||||||
static int current_card = 0;
|
static int current_card = 0;
|
||||||
|
|
@ -152,12 +157,9 @@ static unsigned char poll_busy(long timeout);
|
||||||
static int send_cmd(int cmd, unsigned long parameter, unsigned char *response);
|
static int send_cmd(int cmd, unsigned long parameter, unsigned char *response);
|
||||||
static int receive_cxd(unsigned char *buf);
|
static int receive_cxd(unsigned char *buf);
|
||||||
static int initialize_card(int card_no);
|
static int initialize_card(int card_no);
|
||||||
static void swapcopy(void *dst, const void *src, unsigned long size);
|
static void bg_copy_swap(void);
|
||||||
static int receive_block(unsigned char *inbuf, unsigned char *swapbuf,
|
static int receive_block(unsigned char *inbuf, int size, long timeout);
|
||||||
int size, long timeout);
|
static int send_block(int size, unsigned char start_token, long timeout);
|
||||||
static void swapcopy_block(const unsigned char *buf, int size);
|
|
||||||
static int send_block(const unsigned char *nextbuf, int size,
|
|
||||||
unsigned char start_token, long timeout);
|
|
||||||
static int cache_block(IF_MV2(int drive,) unsigned long blocknum,
|
static int cache_block(IF_MV2(int drive,) unsigned long blocknum,
|
||||||
int size, long timeout);
|
int size, long timeout);
|
||||||
static void mmc_tick(void);
|
static void mmc_tick(void);
|
||||||
|
|
@ -546,16 +548,32 @@ tCardInfo *mmc_card_info(int card_no)
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swapcopy(void *dst, const void *src, unsigned long size)
|
/* copy and swap in the background. If destination is NULL, use the next
|
||||||
|
* block cache entry */
|
||||||
|
static void bg_copy_swap(void)
|
||||||
{
|
{
|
||||||
memcpy(dst, src, size);
|
if (!bcs_len)
|
||||||
bitswap(dst, size);
|
return;
|
||||||
|
|
||||||
|
if (!bcs_dest)
|
||||||
|
{
|
||||||
|
current_cache = (current_cache + 1) % NUMCACHES; /* next cache */
|
||||||
|
block_cache[current_cache].inuse = false;
|
||||||
|
bcs_dest = block_cache[current_cache].data + 2;
|
||||||
|
}
|
||||||
|
if (bcs_src)
|
||||||
|
{
|
||||||
|
memcpy(bcs_dest, bcs_src, bcs_len);
|
||||||
|
bcs_src += bcs_len;
|
||||||
|
}
|
||||||
|
bitswap(bcs_dest, bcs_len);
|
||||||
|
bcs_dest += bcs_len;
|
||||||
|
bcs_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Receive one block with dma, possibly swapping the previously received
|
/* Receive one block with dma, possibly swapping the previously received
|
||||||
* block in the background */
|
* block in the background */
|
||||||
static int receive_block(unsigned char *inbuf, unsigned char *swapbuf,
|
static int receive_block(unsigned char *inbuf, int size, long timeout)
|
||||||
int size, long timeout)
|
|
||||||
{
|
{
|
||||||
if (poll_byte(timeout) != DT_START_BLOCK)
|
if (poll_byte(timeout) != DT_START_BLOCK)
|
||||||
{
|
{
|
||||||
|
|
@ -582,8 +600,7 @@ static int receive_block(unsigned char *inbuf, unsigned char *swapbuf,
|
||||||
* the second one is lost because of the SCI overrun. However, this
|
* the second one is lost because of the SCI overrun. However, this
|
||||||
* behaviour conveniently discards the crc. */
|
* behaviour conveniently discards the crc. */
|
||||||
|
|
||||||
if (swapbuf != NULL) /* bitswap previous block */
|
bg_copy_swap();
|
||||||
bitswap(swapbuf, size);
|
|
||||||
yield(); /* be nice */
|
yield(); /* be nice */
|
||||||
|
|
||||||
while (!(CHCR2 & 0x0002)); /* wait for end of DMA */
|
while (!(CHCR2 & 0x0002)); /* wait for end of DMA */
|
||||||
|
|
@ -592,22 +609,13 @@ static int receive_block(unsigned char *inbuf, unsigned char *swapbuf,
|
||||||
serial_mode = SER_DISABLED;
|
serial_mode = SER_DISABLED;
|
||||||
|
|
||||||
write_transfer(dummy, 1); /* send trailer */
|
write_transfer(dummy, 1); /* send trailer */
|
||||||
|
last_disk_activity = current_tick;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copies one block into the next-current block cache, then bitswaps */
|
|
||||||
static void swapcopy_block(const unsigned char *buf, int size)
|
|
||||||
{
|
|
||||||
current_cache = (current_cache + 1) % NUMCACHES; /* next cache */
|
|
||||||
|
|
||||||
block_cache[current_cache].inuse = false;
|
|
||||||
swapcopy(block_cache[current_cache].data + 2, buf, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send one block with dma from the current block cache, possibly preparing
|
/* Send one block with dma from the current block cache, possibly preparing
|
||||||
* the next block within the next block cache in the background. */
|
* the next block within the next block cache in the background. */
|
||||||
static int send_block(const unsigned char *nextbuf, int size,
|
static int send_block(int size, unsigned char start_token, long timeout)
|
||||||
unsigned char start_token, long timeout)
|
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
unsigned char *curbuf = block_cache[current_cache].data;
|
unsigned char *curbuf = block_cache[current_cache].data;
|
||||||
|
|
@ -629,8 +637,7 @@ static int send_block(const unsigned char *nextbuf, int size,
|
||||||
DMAOR = 0x0001;
|
DMAOR = 0x0001;
|
||||||
SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */
|
SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */
|
||||||
|
|
||||||
if (nextbuf != NULL) /* prepare next sector */
|
bg_copy_swap();
|
||||||
swapcopy_block(nextbuf, size);
|
|
||||||
yield(); /* be nice */
|
yield(); /* be nice */
|
||||||
|
|
||||||
while (!(CHCR2 & 0x0002)); /* wait for end of DMA */
|
while (!(CHCR2 & 0x0002)); /* wait for end of DMA */
|
||||||
|
|
@ -642,6 +649,7 @@ static int send_block(const unsigned char *nextbuf, int size,
|
||||||
rc = -1;
|
rc = -1;
|
||||||
|
|
||||||
write_transfer(dummy, 1);
|
write_transfer(dummy, 1);
|
||||||
|
last_disk_activity = current_tick;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
@ -662,6 +670,7 @@ static int cache_block(IF_MV2(int drive,) unsigned long blocknum,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
current_cache = i;
|
current_cache = i;
|
||||||
|
bg_copy_swap();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -672,8 +681,7 @@ static int cache_block(IF_MV2(int drive,) unsigned long blocknum,
|
||||||
return rc * 10 - 1;
|
return rc * 10 - 1;
|
||||||
|
|
||||||
block_cache[current_cache].inuse = false;
|
block_cache[current_cache].inuse = false;
|
||||||
rc = receive_block(block_cache[current_cache].data + 2, NULL,
|
rc = receive_block(block_cache[current_cache].data + 2, size, timeout);
|
||||||
size, timeout);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc * 10 - 2;
|
return rc * 10 - 2;
|
||||||
|
|
||||||
|
|
@ -682,7 +690,6 @@ static int cache_block(IF_MV2(int drive,) unsigned long blocknum,
|
||||||
#endif
|
#endif
|
||||||
block_cache[current_cache].blocknum = blocknum;
|
block_cache[current_cache].blocknum = blocknum;
|
||||||
block_cache[current_cache].inuse = true;
|
block_cache[current_cache].inuse = true;
|
||||||
last_disk_activity = current_tick;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -697,7 +704,6 @@ int ata_read_sectors(IF_MV2(int drive,)
|
||||||
unsigned long c_addr, c_end_addr;
|
unsigned long c_addr, c_end_addr;
|
||||||
unsigned long c_block, c_end_block;
|
unsigned long c_block, c_end_block;
|
||||||
unsigned char response;
|
unsigned char response;
|
||||||
void *inbuf_prev = NULL;
|
|
||||||
tCardInfo *card;
|
tCardInfo *card;
|
||||||
|
|
||||||
c_addr = start * SECTOR_SIZE;
|
c_addr = start * SECTOR_SIZE;
|
||||||
|
|
@ -727,6 +733,7 @@ int ata_read_sectors(IF_MV2(int drive,)
|
||||||
offset = c_addr & (blocksize - 1);
|
offset = c_addr & (blocksize - 1);
|
||||||
c_block = c_addr >> card->block_exp;
|
c_block = c_addr >> card->block_exp;
|
||||||
c_end_block = c_end_addr >> card->block_exp;
|
c_end_block = c_end_addr >> card->block_exp;
|
||||||
|
bcs_dest = inbuf;
|
||||||
|
|
||||||
if (offset) /* first partial block */
|
if (offset) /* first partial block */
|
||||||
{
|
{
|
||||||
|
|
@ -739,7 +746,8 @@ int ata_read_sectors(IF_MV2(int drive,)
|
||||||
rc = rc * 10 - 3;
|
rc = rc * 10 - 3;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
swapcopy(inbuf, block_cache[current_cache].data + 2 + offset, len);
|
bcs_src = block_cache[current_cache].data + 2 + offset;
|
||||||
|
bcs_len = len;
|
||||||
inbuf += len;
|
inbuf += len;
|
||||||
c_addr += len;
|
c_addr += len;
|
||||||
c_block++;
|
c_block++;
|
||||||
|
|
@ -764,15 +772,14 @@ int ata_read_sectors(IF_MV2(int drive,)
|
||||||
}
|
}
|
||||||
while (c_block < c_end_block)
|
while (c_block < c_end_block)
|
||||||
{
|
{
|
||||||
rc = receive_block(inbuf, inbuf_prev, blocksize,
|
rc = receive_block(inbuf, blocksize, card->read_timeout);
|
||||||
card->read_timeout);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
rc = rc * 10 - 5;
|
rc = rc * 10 - 5;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
last_disk_activity = current_tick;
|
bcs_src = NULL;
|
||||||
inbuf_prev = inbuf;
|
bcs_len = blocksize;
|
||||||
inbuf += blocksize;
|
inbuf += blocksize;
|
||||||
c_addr += blocksize;
|
c_addr += blocksize;
|
||||||
c_block++;
|
c_block++;
|
||||||
|
|
@ -786,7 +793,6 @@ int ata_read_sectors(IF_MV2(int drive,)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bitswap(inbuf_prev, blocksize);
|
|
||||||
}
|
}
|
||||||
if (c_addr < c_end_addr) /* last partial block */
|
if (c_addr < c_end_addr) /* last partial block */
|
||||||
{
|
{
|
||||||
|
|
@ -797,9 +803,10 @@ int ata_read_sectors(IF_MV2(int drive,)
|
||||||
rc = rc * 10 - 7;
|
rc = rc * 10 - 7;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
swapcopy(inbuf, block_cache[current_cache].data + 2,
|
bcs_src = block_cache[current_cache].data + 2;
|
||||||
c_end_addr - c_addr);
|
bcs_len = c_end_addr - c_addr;
|
||||||
}
|
}
|
||||||
|
bg_copy_swap();
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
||||||
|
|
@ -854,6 +861,7 @@ int ata_write_sectors(IF_MV2(int drive,)
|
||||||
offset = c_addr & (blocksize - 1);
|
offset = c_addr & (blocksize - 1);
|
||||||
c_block = c_addr >> card->block_exp;
|
c_block = c_addr >> card->block_exp;
|
||||||
c_end_block = c_end_addr >> card->block_exp;
|
c_end_block = c_end_addr >> card->block_exp;
|
||||||
|
bcs_src = buf;
|
||||||
|
|
||||||
/* Special case: first block is trimmed at both ends. May only happen
|
/* Special case: first block is trimmed at both ends. May only happen
|
||||||
* if (blocksize > 2 * sectorsize), i.e. blocksize == 2048 */
|
* if (blocksize > 2 * sectorsize), i.e. blocksize == 2048 */
|
||||||
|
|
@ -881,21 +889,22 @@ int ata_write_sectors(IF_MV2(int drive,)
|
||||||
unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset);
|
unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset);
|
||||||
|
|
||||||
rc = cache_block(IF_MV2(drive,) c_block, blocksize,
|
rc = cache_block(IF_MV2(drive,) c_block, blocksize,
|
||||||
card->read_timeout);
|
card->read_timeout);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
rc = rc * 10 - 2;
|
rc = rc * 10 - 2;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
swapcopy(block_cache[current_cache].data + 2 + offset, buf, len);
|
bcs_dest = block_cache[current_cache].data + 2 + offset;
|
||||||
buf += len;
|
bcs_len = len;
|
||||||
c_addr -= offset;
|
c_addr -= offset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
swapcopy_block(buf, blocksize);
|
bcs_dest = NULL; /* next block cache */
|
||||||
buf += blocksize;
|
bcs_len = blocksize;
|
||||||
}
|
}
|
||||||
|
bg_copy_swap();
|
||||||
rc = send_cmd(write_cmd, c_addr, &response);
|
rc = send_cmd(write_cmd, c_addr, &response);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
|
|
@ -906,24 +915,23 @@ int ata_write_sectors(IF_MV2(int drive,)
|
||||||
|
|
||||||
while (c_block < c_end_block)
|
while (c_block < c_end_block)
|
||||||
{
|
{
|
||||||
rc = send_block(buf, blocksize, start_token, card->write_timeout);
|
bcs_dest = NULL; /* next block cache */
|
||||||
|
bcs_len = blocksize;
|
||||||
|
rc = send_block(blocksize, start_token, card->write_timeout);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
rc = rc * 10 - 4;
|
rc = rc * 10 - 4;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
last_disk_activity = current_tick;
|
|
||||||
buf += blocksize;
|
|
||||||
c_addr += blocksize;
|
c_addr += blocksize;
|
||||||
c_block++;
|
c_block++;
|
||||||
}
|
}
|
||||||
rc = send_block(NULL, blocksize, start_token, card->write_timeout);
|
rc = send_block(blocksize, start_token, card->write_timeout);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
rc = rc * 10 - 5;
|
rc = rc * 10 - 5;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
last_disk_activity = current_tick;
|
|
||||||
c_addr += blocksize;
|
c_addr += blocksize;
|
||||||
/* c_block++ was done early */
|
/* c_block++ was done early */
|
||||||
|
|
||||||
|
|
@ -944,15 +952,16 @@ int ata_write_sectors(IF_MV2(int drive,)
|
||||||
rc = rc * 10 - 6;
|
rc = rc * 10 - 6;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
swapcopy(block_cache[current_cache].data + 2, buf,
|
bcs_dest = block_cache[current_cache].data + 2;
|
||||||
c_end_addr - c_addr);
|
bcs_len = c_end_addr - c_addr;
|
||||||
|
bg_copy_swap();
|
||||||
rc = send_cmd(CMD_WRITE_BLOCK, c_addr, &response);
|
rc = send_cmd(CMD_WRITE_BLOCK, c_addr, &response);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
rc = rc * 10 - 7;
|
rc = rc * 10 - 7;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
rc = send_block(NULL, blocksize, DT_START_BLOCK, card->write_timeout);
|
rc = send_block(blocksize, DT_START_BLOCK, card->write_timeout);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
rc = rc * 10 - 8;
|
rc = rc * 10 - 8;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue