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:
Jens Arnold 2005-05-02 00:33:01 +00:00
parent 4e2cee1ece
commit 1ba26b8a60

View file

@ -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;