Prechádzať zdrojové kódy

fw/diskcache.c: writeback cache

Change from write-through to writeback cache.
H. Peter Anvin 3 rokov pred
rodič
commit
a42b824c80

BIN
fpga/output_files/max80.jbc


BIN
fpga/output_files/max80.jic


BIN
fpga/output_files/max80.pof


BIN
fpga/output_files/max80.sof


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4661 - 4661
fw/boot.mif


+ 67 - 14
fw/diskcache.c

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

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov