|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Simple disk cache; write-through for now
|
|
|
+ * Simple disk cache
|
|
|
*/
|
|
|
|
|
|
#include "fw.h"
|
|
@@ -8,7 +8,7 @@
|
|
|
#include "systime.h"
|
|
|
#include "console.h"
|
|
|
|
|
|
-#define CACHE_BLOCKS 512
|
|
|
+#define CACHE_BLOCKS 1024
|
|
|
#define CACHE_BLOCK_BITS 5
|
|
|
#define CACHE_BLOCK_SECTORS (1 << CACHE_BLOCK_BITS)
|
|
|
#define CACHE_BLOCK_SIZE (SECTOR_SIZE << CACHE_BLOCK_BITS)
|
|
@@ -22,9 +22,13 @@ struct cache_block {
|
|
|
struct dll hash; /* Link in hash chain or free list */
|
|
|
struct dll lru; /* Link in LRU chain */
|
|
|
block_t block; /* Physical block index */
|
|
|
+ unsigned int flags; /* Status flags */
|
|
|
char data[CACHE_BLOCK_SIZE];
|
|
|
};
|
|
|
|
|
|
+#define FL_VALID 1
|
|
|
+#define FL_DIRTY 2
|
|
|
+
|
|
|
static struct dll __dram_noinit cache_hash[CACHE_HASH_SIZE];
|
|
|
static struct cache_block __dram_noinit disk_cache[CACHE_BLOCKS];
|
|
|
|
|
@@ -45,6 +49,7 @@ static void disk_cache_init(void)
|
|
|
dll_insert_head(&free_list, &bp->hash);
|
|
|
dll_insert_head(&lru_list, &bp->lru);
|
|
|
bp->block = NO_BLOCK;
|
|
|
+ bp->flags = 0;
|
|
|
bp++;
|
|
|
}
|
|
|
|
|
@@ -86,9 +91,58 @@ static void invalidate_block(struct cache_block *bp)
|
|
|
dll_remove(&bp->hash);
|
|
|
dll_insert_head(&free_list, &bp->hash);
|
|
|
bp->block = NO_BLOCK;
|
|
|
+ bp->flags = 0;
|
|
|
dll_demote(&lru_list, &bp->lru);
|
|
|
}
|
|
|
|
|
|
+static DRESULT sync_block(struct cache_block *bp)
|
|
|
+{
|
|
|
+ if (bp->flags == (FL_DIRTY|FL_VALID)) {
|
|
|
+ sector_t sector = bp->block << CACHE_BLOCK_BITS;
|
|
|
+ sector_t size = sdc.lbasize;
|
|
|
+ sector_t sectors = min(CACHE_BLOCK_SIZE, size - sector);
|
|
|
+
|
|
|
+ if (sdcard_write_sectors(bp->data, sector, sectors) != (int)sectors) {
|
|
|
+ invalidate_block(bp); /* Or...? */
|
|
|
+ return RES_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
+ bp->flags = FL_VALID;
|
|
|
+ }
|
|
|
+
|
|
|
+ return RES_OK;
|
|
|
+}
|
|
|
+
|
|
|
+static DRESULT clear_block(struct cache_block *bp)
|
|
|
+{
|
|
|
+ DRESULT rv;
|
|
|
+
|
|
|
+ rv = sync_block(bp);
|
|
|
+ if (rv != RES_OK)
|
|
|
+ return rv;
|
|
|
+
|
|
|
+ invalidate_block(bp);
|
|
|
+ return RES_OK;
|
|
|
+}
|
|
|
+
|
|
|
+static DRESULT sync_all(void)
|
|
|
+{
|
|
|
+ DRESULT rv = RES_OK;
|
|
|
+ struct dll *bhp;
|
|
|
+ struct cache_block *bp;
|
|
|
+
|
|
|
+ for (bhp = lru_list.next; bhp != &lru_list; bhp = bhp->next) {
|
|
|
+ bp = container_of(bhp, struct cache_block, hash);
|
|
|
+
|
|
|
+ if (bp->flags == (FL_VALID|FL_DIRTY)) {
|
|
|
+ if (sync_block(bp))
|
|
|
+ rv = RES_ERROR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
static struct cache_block *disk_cache_get(block_t block, bool do_read)
|
|
|
{
|
|
|
const sector_t size = sdc.lbasize;
|
|
@@ -109,11 +163,14 @@ static struct cache_block *disk_cache_get(block_t block, bool do_read)
|
|
|
|
|
|
/* Get the oldest block */
|
|
|
bp = container_of(lru_list.prev, struct cache_block, lru);
|
|
|
- invalidate_block(bp);
|
|
|
+ clear_block(bp);
|
|
|
|
|
|
- if (do_read &&
|
|
|
- sdcard_read_sectors(bp->data, sector, sectors) != sectors)
|
|
|
- return NULL;
|
|
|
+ if (do_read) {
|
|
|
+ if (sdcard_read_sectors(bp->data, sector, sectors) != sectors)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ bp->flags = FL_VALID;
|
|
|
+ }
|
|
|
|
|
|
bp->block = block;
|
|
|
dll_insert_head(hash_slot(block), &bp->hash);
|
|
@@ -176,15 +233,15 @@ DRESULT disk_ioctl(BYTE drive, BYTE command, void *buffer)
|
|
|
|
|
|
switch (command) {
|
|
|
case CTRL_SYNC:
|
|
|
- return RES_OK;
|
|
|
+ return sync_all();
|
|
|
case GET_SECTOR_SIZE:
|
|
|
- *(WORD *)buffer = 512;
|
|
|
+ *(WORD *)buffer = SECTOR_SIZE;
|
|
|
return RES_OK;
|
|
|
case GET_SECTOR_COUNT:
|
|
|
*(DWORD *)buffer = sdc.lbasize;
|
|
|
return RES_OK;
|
|
|
case GET_BLOCK_SIZE:
|
|
|
- *(DWORD *)buffer = 1; /* XXX */
|
|
|
+ *(DWORD *)buffer = CACHE_BLOCK_SECTORS;
|
|
|
return RES_OK;
|
|
|
default:
|
|
|
return RES_PARERR;
|
|
@@ -246,11 +303,7 @@ DRESULT disk_write(BYTE drive, const BYTE *buffer, LBA_t sectornumber,
|
|
|
return RES_ERROR;
|
|
|
|
|
|
memcpy(bp->data + offset, buffer, bytes);
|
|
|
-
|
|
|
- if (sdcard_write_sectors(bp->data, sector, sectors) != sectors) {
|
|
|
- invalidate_block(bp);
|
|
|
- return RES_ERROR;
|
|
|
- }
|
|
|
+ bp->flags = FL_VALID | FL_DIRTY;
|
|
|
|
|
|
len -= bytes;
|
|
|
block++;
|