2
0

diskcache.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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 __attribute__((const)) struct dll *hash_slot(block_t block)
  46. {
  47. uint64_t m;
  48. uint32_t hash;
  49. m = UINT64_C(0x34f1f85d) * block;
  50. hash = (m >> 32) + m;
  51. return &cache_hash[hash % CACHE_BLOCKS];
  52. }
  53. static struct cache_block *disk_cache_find(block_t block)
  54. {
  55. struct dll *hp, *bhp;
  56. struct cache_block *bp;
  57. hp = hash_slot(block);
  58. for (bhp = hp->next; bhp != hp; bhp = bhp->next) {
  59. bp = container_of(bhp, struct cache_block, hash);
  60. if (bp->block == block)
  61. return bp;
  62. }
  63. return NULL;
  64. }
  65. static void invalidate_block(struct cache_block *bp)
  66. {
  67. dll_remove(&bp->hash);
  68. dll_insert_head(&free_list, &bp->hash);
  69. bp->block = NO_BLOCK;
  70. dll_demote(&lru_list, &bp->lru);
  71. }
  72. static struct cache_block *disk_cache_get(block_t block, bool do_read)
  73. {
  74. const sector_t size = sdc.lbasize;
  75. struct cache_block *bp;
  76. bp = disk_cache_find(block);
  77. if (!bp) {
  78. /* Block not in cache, need to get it */
  79. sector_t sector = block << CACHE_BLOCK_BITS;
  80. int sectors = CACHE_BLOCK_SECTORS;
  81. if (sector >= size)
  82. return NULL;
  83. if (sector + sectors > size)
  84. sectors = size - sectors; /* Truncated final block */
  85. /* Get the oldest block */
  86. bp = container_of(lru_list.prev, struct cache_block, lru);
  87. invalidate_block(bp);
  88. if (do_read &&
  89. sdcard_read_sectors(bp->data, sector, sectors) != sectors)
  90. return NULL;
  91. bp->block = block;
  92. dll_insert_head(hash_slot(block), &bp->hash);
  93. }
  94. dll_promote(&lru_list, &bp->lru);
  95. return bp;
  96. }
  97. /* --------------------------------------------------------------------------
  98. * Interface to fatfs
  99. * ------------------------------------------------------------------------- */
  100. DRESULT disk_initialize(BYTE drive)
  101. {
  102. if (drive != 0)
  103. return STA_NOINIT;
  104. disk_cache_init();
  105. return sdcard_init();
  106. }
  107. static FATFS sd_fs;
  108. int disk_init(void)
  109. {
  110. FRESULT rv;
  111. char label[128];
  112. uint32_t volid, freeclust;
  113. FATFS *fs;
  114. rv = f_mount(&sd_fs, "", 1);
  115. if (rv != FR_OK) {
  116. con_printf("sdcard: no volume found\n");
  117. return -1;
  118. }
  119. label[0] = '\0';
  120. volid = 0;
  121. f_getlabel("", label, &volid);
  122. con_printf("sdcard: volume found, label \"%s\", volid %08x\n", label, volid);
  123. freeclust = 0;
  124. f_getfree("", &freeclust, &fs);
  125. con_printf("sdcard: %u/%u clusters free, clusters = %u bytes\n",
  126. freeclust, fs->n_fatent - 2, fs->csize << 9);
  127. mount_abcdrives();
  128. return 0;
  129. }
  130. DRESULT disk_ioctl(BYTE drive, BYTE command, void *buffer)
  131. {
  132. if (drive != 0)
  133. return STA_NOINIT;
  134. switch (command) {
  135. case CTRL_SYNC:
  136. return RES_OK;
  137. case GET_SECTOR_SIZE:
  138. *(WORD *)buffer = 512;
  139. return RES_OK;
  140. case GET_SECTOR_COUNT:
  141. *(DWORD *)buffer = sdc.lbasize;
  142. return RES_OK;
  143. case GET_BLOCK_SIZE:
  144. *(DWORD *)buffer = 1; /* XXX */
  145. return RES_OK;
  146. default:
  147. return RES_PARERR;
  148. }
  149. }
  150. DRESULT disk_read(BYTE drive, BYTE *buffer,
  151. LBA_t sectornumber, UINT sectorcount)
  152. {
  153. (void)drive;
  154. if (!sectorcount)
  155. return RES_OK;
  156. block_t block = sectornumber >> CACHE_BLOCK_BITS;
  157. block_t last = (sectornumber + sectorcount - 1) >> CACHE_BLOCK_BITS;
  158. size_t offset = (sectornumber & (CACHE_BLOCK_SECTORS-1)) << SECTOR_SHIFT;
  159. size_t len = sectorcount << SECTOR_SHIFT;
  160. while (block <= last) {
  161. struct cache_block *bp = disk_cache_get(block, true);
  162. if (!bp)
  163. return RES_ERROR;
  164. size_t bytes = min(CACHE_BLOCK_SIZE - offset, len);
  165. memcpy(buffer, bp->data + offset, bytes);
  166. len -= bytes;
  167. block++;
  168. offset = 0;
  169. }
  170. return RES_OK;
  171. }
  172. DRESULT disk_write(BYTE drive, const BYTE *buffer, LBA_t sectornumber,
  173. UINT sectorcount)
  174. {
  175. (void)drive;
  176. if (!sectorcount)
  177. return RES_OK;
  178. block_t block = sectornumber >> CACHE_BLOCK_BITS;
  179. block_t last = (sectornumber + sectorcount - 1) >> CACHE_BLOCK_BITS;
  180. size_t offset = (sectornumber & (CACHE_BLOCK_SECTORS-1)) << SECTOR_SHIFT;
  181. size_t len = sectorcount << SECTOR_SHIFT;
  182. size_t size = sdc.lbasize;
  183. while (block <= last) {
  184. struct cache_block *bp = disk_cache_get(block, !!offset);
  185. if (!bp)
  186. return RES_ERROR;
  187. size_t bytes = min(CACHE_BLOCK_SIZE - offset, len);
  188. memcpy(bp->data + offset, buffer, bytes);
  189. sector_t sector = block << CACHE_BLOCK_BITS;
  190. int sectors = CACHE_BLOCK_SECTORS;
  191. if (sector + sectors > size)
  192. sectors = size - sectors; /* Truncated final block */
  193. if (sdcard_write_sectors(bp->data, block << CACHE_BLOCK_BITS,
  194. sectors) != sectors) {
  195. invalidate_block(bp);
  196. return RES_ERROR;
  197. }
  198. len -= bytes;
  199. block++;
  200. offset = 0;
  201. }
  202. return RES_OK;
  203. }
  204. DWORD get_fattime(void)
  205. {
  206. return SYSCLOCK_DATETIME; /* Already in FAT format */
  207. }