diskcache.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Simple disk cache; write-through for now
  3. */
  4. #include "fw.h"
  5. #include "list.h"
  6. #include "sdcard.h"
  7. #include "systime.h"
  8. #include "console.h"
  9. #define CACHE_BLOCKS 512
  10. #define CACHE_BLOCK_BITS 5
  11. #define CACHE_BLOCK_SECTORS (1 << CACHE_BLOCK_BITS)
  12. #define CACHE_BLOCK_SIZE (SECTOR_SIZE << CACHE_BLOCK_BITS)
  13. #define CACHE_HASH_SIZE (CACHE_BLOCKS*2)
  14. typedef sector_t block_t;
  15. #define NO_BLOCK ((block_t)(-1))
  16. struct cache_block {
  17. struct dll hash; /* Link in hash chain or free list */
  18. struct dll lru; /* Link in LRU chain */
  19. block_t block; /* Physical block index */
  20. char data[CACHE_BLOCK_SIZE];
  21. };
  22. static struct dll __dram_noinit cache_hash[CACHE_HASH_SIZE];
  23. static struct cache_block __dram_noinit disk_cache[CACHE_BLOCKS];
  24. static struct dll lru_list;
  25. static struct dll free_list;
  26. static void disk_cache_init(void)
  27. {
  28. struct cache_block *bp, *bep;
  29. struct dll *hp, *hep;
  30. dll_init(&free_list);
  31. dll_init(&lru_list);
  32. bp = disk_cache;
  33. bep = bp + CACHE_BLOCKS;
  34. while (bp < bep) {
  35. dll_insert_head(&free_list, &bp->hash);
  36. dll_insert_head(&lru_list, &bp->lru);
  37. bp->block = NO_BLOCK;
  38. bp++;
  39. }
  40. hp = cache_hash;
  41. hep = hp + CACHE_HASH_SIZE;
  42. while (hp < hep)
  43. dll_init(hp++);
  44. }
  45. static inline struct dll *hash_slot(block_t block)
  46. {
  47. return &cache_hash[(0x34f1f85d * block) % CACHE_BLOCKS];
  48. }
  49. static struct cache_block *disk_cache_find(block_t block)
  50. {
  51. struct dll *hp, *bhp;
  52. struct cache_block *bp;
  53. hp = hash_slot(block);
  54. for (bhp = hp->next; bhp != hp; bhp = bhp->next) {
  55. bp = container_of(bhp, struct cache_block, hash);
  56. if (bp->block == block)
  57. return bp;
  58. }
  59. return NULL;
  60. }
  61. static void invalidate_block(struct cache_block *bp)
  62. {
  63. dll_remove(&bp->hash);
  64. dll_insert_head(&free_list, &bp->hash);
  65. bp->block = NO_BLOCK;
  66. dll_demote(&lru_list, &bp->lru);
  67. }
  68. static struct cache_block *disk_cache_get(block_t block, bool do_read)
  69. {
  70. const sector_t size = sdc.lbasize;
  71. struct cache_block *bp;
  72. bp = disk_cache_find(block);
  73. if (!bp) {
  74. /* Block not in cache, need to get it */
  75. sector_t sector = block << CACHE_BLOCK_BITS;
  76. int sectors = CACHE_BLOCK_SECTORS;
  77. if (sector >= size)
  78. return NULL;
  79. if (sector + sectors > size)
  80. sectors = size - sectors; /* Truncated final block */
  81. /* Get the oldest block */
  82. bp = container_of(lru_list.prev, struct cache_block, lru);
  83. invalidate_block(bp);
  84. if (do_read &&
  85. sdcard_read_sectors(bp->data, sector, sectors) != sectors)
  86. return NULL;
  87. bp->block = block;
  88. dll_insert_head(hash_slot(block), &bp->hash);
  89. }
  90. dll_promote(&lru_list, &bp->lru);
  91. return bp;
  92. }
  93. /* --------------------------------------------------------------------------
  94. * Interface to fatfs
  95. * ------------------------------------------------------------------------- */
  96. DRESULT disk_initialize(BYTE drive)
  97. {
  98. if (drive != 0)
  99. return STA_NOINIT;
  100. disk_cache_init();
  101. return sdcard_init();
  102. }
  103. static FATFS sd_fs;
  104. int disk_init(void)
  105. {
  106. FRESULT rv;
  107. char label[128];
  108. uint32_t volid, freeclust;
  109. FATFS *fs;
  110. rv = f_mount(&sd_fs, "", 1);
  111. if (rv != FR_OK) {
  112. con_printf("sdcard: no volume found\n");
  113. return -1;
  114. }
  115. label[0] = '\0';
  116. volid = 0;
  117. f_getlabel("", label, &volid);
  118. con_printf("sdcard: volume found, label \"%s\", volid %08x\n", label, volid);
  119. freeclust = 0;
  120. f_getfree("", &freeclust, &fs);
  121. con_printf("sdcard: %u/%u clusters free, clusters = %u bytes\n",
  122. freeclust, fs->n_fatent - 2, fs->csize << 9);
  123. mount_abcdrives();
  124. return 0;
  125. }
  126. DRESULT disk_ioctl(BYTE drive, BYTE command, void *buffer)
  127. {
  128. if (drive != 0)
  129. return STA_NOINIT;
  130. switch (command) {
  131. case CTRL_SYNC:
  132. return RES_OK;
  133. case GET_SECTOR_SIZE:
  134. *(WORD *)buffer = 512;
  135. return RES_OK;
  136. case GET_SECTOR_COUNT:
  137. *(DWORD *)buffer = sdc.lbasize;
  138. return RES_OK;
  139. case GET_BLOCK_SIZE:
  140. *(DWORD *)buffer = 1; /* XXX */
  141. return RES_OK;
  142. default:
  143. return RES_PARERR;
  144. }
  145. }
  146. DRESULT disk_read(BYTE drive, BYTE *buffer,
  147. LBA_t sectornumber, UINT sectorcount)
  148. {
  149. (void)drive;
  150. if (!sectorcount)
  151. return RES_OK;
  152. block_t block = sectornumber >> CACHE_BLOCK_BITS;
  153. block_t last = (sectornumber + sectorcount - 1) >> CACHE_BLOCK_BITS;
  154. size_t offset = (sectornumber & (CACHE_BLOCK_SECTORS-1)) << SECTOR_SHIFT;
  155. size_t len = sectorcount << SECTOR_SHIFT;
  156. while (block <= last) {
  157. struct cache_block *bp = disk_cache_get(block, true);
  158. if (!bp)
  159. return RES_ERROR;
  160. size_t bytes = min(CACHE_BLOCK_SIZE - offset, len);
  161. memcpy(buffer, bp->data + offset, bytes);
  162. len -= bytes;
  163. block++;
  164. offset = 0;
  165. }
  166. return RES_OK;
  167. }
  168. DRESULT disk_write(BYTE drive, const BYTE *buffer, LBA_t sectornumber,
  169. UINT sectorcount)
  170. {
  171. (void)drive;
  172. if (!sectorcount)
  173. return RES_OK;
  174. block_t block = sectornumber >> CACHE_BLOCK_BITS;
  175. block_t last = (sectornumber + sectorcount - 1) >> CACHE_BLOCK_BITS;
  176. size_t offset = (sectornumber & (CACHE_BLOCK_SECTORS-1)) << SECTOR_SHIFT;
  177. size_t len = sectorcount << SECTOR_SHIFT;
  178. size_t size = sdc.lbasize;
  179. while (block <= last) {
  180. struct cache_block *bp = disk_cache_get(block, !!offset);
  181. if (!bp)
  182. return RES_ERROR;
  183. size_t bytes = min(CACHE_BLOCK_SIZE - offset, len);
  184. memcpy(bp->data + offset, buffer, bytes);
  185. sector_t sector = block << CACHE_BLOCK_BITS;
  186. int sectors = CACHE_BLOCK_SECTORS;
  187. if (sector + sectors > size)
  188. sectors = size - sectors; /* Truncated final block */
  189. if (sdcard_write_sectors(bp->data, block << CACHE_BLOCK_BITS,
  190. sectors) != sectors) {
  191. invalidate_block(bp);
  192. return RES_ERROR;
  193. }
  194. len -= bytes;
  195. block++;
  196. offset = 0;
  197. }
  198. return RES_OK;
  199. }
  200. DWORD get_fattime(void)
  201. {
  202. return SYSCLOCK_DATETIME; /* Already in FAT format */
  203. }