fstorage.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. */
  12. #include "fstorage.h"
  13. #include "fstorage_config.h"
  14. #include "fstorage_internal_defs.h"
  15. #include <stdint.h>
  16. #include <string.h>
  17. #include <stdbool.h>
  18. #include "nrf_error.h"
  19. #include "nrf_soc.h"
  20. static uint8_t m_flags; // fstorage status flags.
  21. static fs_op_queue_t m_queue; // Queue of requested operations.
  22. static uint8_t m_retry_count; // Number of times the last flash operation was retried.
  23. // Sends events to the application.
  24. static void send_event(fs_op_t const * const p_op, fs_ret_t result)
  25. {
  26. fs_evt_t evt;
  27. memset(&evt, 0x00, sizeof(fs_evt_t));
  28. switch (p_op->op_code)
  29. {
  30. case FS_OP_STORE:
  31. evt.id = FS_EVT_STORE;
  32. evt.store.p_data = p_op->store.p_dest;
  33. evt.store.length_words = p_op->store.length_words;
  34. break;
  35. case FS_OP_ERASE:
  36. evt.id = FS_EVT_ERASE;
  37. evt.erase.first_page = p_op->erase.page - p_op->erase.pages_erased;
  38. evt.erase.last_page = p_op->erase.page;
  39. break;
  40. default:
  41. // Should not happen.
  42. break;
  43. }
  44. p_op->p_config->callback(&evt, result);
  45. }
  46. // Checks that a configuration is non-NULL and within section variable bounds.
  47. static bool check_config(fs_config_t const * const config)
  48. {
  49. if ((config != NULL) &&
  50. (FS_SECTION_VARS_START_ADDR <= (uint32_t)config) &&
  51. (FS_SECTION_VARS_END_ADDR > (uint32_t)config))
  52. {
  53. return true;
  54. }
  55. return false;
  56. }
  57. // Executes a store operation.
  58. static uint32_t store_execute(fs_op_t const * const p_op)
  59. {
  60. uint16_t chunk_len;
  61. if ((p_op->store.length_words - p_op->store.offset) < FS_MAX_WRITE_SIZE_WORDS)
  62. {
  63. chunk_len = p_op->store.length_words - p_op->store.offset;
  64. }
  65. else
  66. {
  67. chunk_len = FS_MAX_WRITE_SIZE_WORDS;
  68. }
  69. return sd_flash_write((uint32_t*)p_op->store.p_dest + p_op->store.offset,
  70. (uint32_t*)p_op->store.p_src + p_op->store.offset,
  71. chunk_len);
  72. }
  73. // Executes an erase operation.
  74. static uint32_t erase_execute(fs_op_t const * const p_op)
  75. {
  76. return sd_flash_page_erase(p_op->erase.page);
  77. }
  78. // Advances the queue, wrapping around if necessary.
  79. // If no elements are left in the queue, clears the FS_FLAG_PROCESSING flag.
  80. static void queue_advance(void)
  81. {
  82. if (--m_queue.count == 0)
  83. {
  84. m_flags &= ~FS_FLAG_PROCESSING;
  85. }
  86. if (++m_queue.rp == FS_QUEUE_SIZE)
  87. {
  88. m_queue.rp = 0;
  89. }
  90. }
  91. // Processes the current element in the queue. If the queue is empty, does nothing.
  92. static void queue_process(void)
  93. {
  94. uint32_t ret;
  95. fs_op_t * const p_op = &m_queue.op[m_queue.rp];
  96. if (m_queue.count > 0)
  97. {
  98. switch (p_op->op_code)
  99. {
  100. case FS_OP_STORE:
  101. ret = store_execute(p_op);
  102. break;
  103. case FS_OP_ERASE:
  104. ret = erase_execute(p_op);
  105. break;
  106. default:
  107. ret = FS_ERR_INTERNAL;
  108. break;
  109. }
  110. // There is a pending flash operation which was not initiated by this module.
  111. // Stop processing the queue and wait for a system event.
  112. if (ret == NRF_ERROR_BUSY)
  113. {
  114. m_flags &= ~FS_FLAG_PROCESSING;
  115. m_flags |= FS_FLAG_FLASH_REQ_PENDING;
  116. }
  117. else if (ret != NRF_SUCCESS)
  118. {
  119. // An error has occurred.
  120. send_event(p_op, FS_ERR_INTERNAL);
  121. }
  122. else
  123. {
  124. // Operation is executing.
  125. }
  126. }
  127. }
  128. // Starts processing the queue if there are no pending flash operations, both inside and
  129. // outside this module. Returns immediately otherwise.
  130. static void queue_start(void)
  131. {
  132. if (!(m_flags & FS_FLAG_PROCESSING) &&
  133. !(m_flags & FS_FLAG_FLASH_REQ_PENDING))
  134. {
  135. m_flags |= FS_FLAG_PROCESSING;
  136. queue_process();
  137. }
  138. }
  139. // Flash operation success callback handler. Keeps track of the progress of an operation.
  140. // If it has finished, advances the queue and notifies the application.
  141. static void on_operation_success(fs_op_t * const p_op)
  142. {
  143. m_retry_count = 0;
  144. switch (p_op->op_code)
  145. {
  146. case FS_OP_STORE:
  147. {
  148. uint16_t chunk_len;
  149. if ((p_op->store.length_words - p_op->store.offset) < FS_MAX_WRITE_SIZE_WORDS)
  150. {
  151. chunk_len = p_op->store.length_words - p_op->store.offset;
  152. }
  153. else
  154. {
  155. chunk_len = FS_MAX_WRITE_SIZE_WORDS;
  156. }
  157. p_op->store.offset += chunk_len;
  158. if (p_op->store.offset == p_op->store.length_words)
  159. {
  160. // The operation has finished.
  161. send_event(p_op, FS_SUCCESS);
  162. queue_advance();
  163. }
  164. }
  165. break;
  166. case FS_OP_ERASE:
  167. {
  168. p_op->erase.page++;
  169. p_op->erase.pages_erased++;
  170. if (p_op->erase.pages_erased == p_op->erase.pages_to_erase)
  171. {
  172. send_event(p_op, FS_SUCCESS);
  173. queue_advance();
  174. }
  175. }
  176. break;
  177. default:
  178. // Should not happen.
  179. break;
  180. }
  181. }
  182. // Flash operation failure callback handler. If the maximum number of retries has
  183. // been reached, notifies the application and advances the queue.
  184. static void on_operation_failure(fs_op_t const * const p_op)
  185. {
  186. if (++m_retry_count > FS_OP_MAX_RETRIES)
  187. {
  188. m_retry_count = 0;
  189. send_event(p_op, FS_ERR_OPERATION_TIMEOUT);
  190. queue_advance();
  191. }
  192. }
  193. // Retrieves a pointer to the next free element in the queue.
  194. // Additionally, increases the number of elements stored in the queue.
  195. static bool queue_get_next_free(fs_op_t ** p_op)
  196. {
  197. uint32_t idx;
  198. if (m_queue.count == FS_QUEUE_SIZE)
  199. {
  200. return false;
  201. }
  202. idx = ((m_queue.rp + m_queue.count) < FS_QUEUE_SIZE) ?
  203. (m_queue.rp + m_queue.count) : 0;
  204. m_queue.count++;
  205. // Zero the element so that unassigned fields will be zero.
  206. memset(&m_queue.op[idx], 0x00, sizeof(fs_op_t));
  207. *p_op = &m_queue.op[idx];
  208. return true;
  209. }
  210. fs_ret_t fs_init(void)
  211. {
  212. uint32_t const users = FS_SECTION_VARS_COUNT;
  213. uint32_t const * p_current_end = FS_PAGE_END_ADDR;
  214. uint32_t index_max = 0x00;
  215. uint32_t index_last = 0xFFFFFFFF;
  216. if (m_flags & FS_FLAG_INITIALIZED)
  217. {
  218. return FS_SUCCESS;
  219. }
  220. #if 0
  221. // Check for configurations with duplicate priority.
  222. for (uint32_t i = 0; i < users; i++)
  223. {
  224. for (uint32_t j = i + 1; j < users; j++)
  225. {
  226. fs_config_t const * const p_config_i = FS_SECTION_VARS_GET(i);
  227. fs_config_t const * const p_config_j = FS_SECTION_VARS_GET(j);
  228. if (p_config_i->page_order == p_config_j->page_order)
  229. {
  230. // Error.
  231. return FS_ERR_INVALID_CFG;
  232. }
  233. }
  234. }
  235. #endif
  236. // Assign pages to registered users, beginning with the ones with the highest
  237. // priority, which will be assigned pages with the highest memory address.
  238. for (uint32_t i = 0; i < users; i++)
  239. {
  240. uint8_t max_priority = 0x00;
  241. for (uint32_t j = 0; j < users; j++)
  242. {
  243. fs_config_t * const p_config = FS_SECTION_VARS_GET(j);
  244. // Skip the one assigned during last iteration.
  245. if (j == index_last)
  246. {
  247. continue;
  248. }
  249. if (p_config->priority >= max_priority)
  250. {
  251. max_priority = p_config->priority;
  252. index_max = j;
  253. }
  254. }
  255. fs_config_t * const p_config = FS_SECTION_VARS_GET(index_max);
  256. p_config->p_end_addr = p_current_end;
  257. p_config->p_start_addr = p_current_end - (p_config->num_pages * FS_PAGE_SIZE_WORDS);
  258. p_current_end = p_config->p_start_addr;
  259. index_last = index_max;
  260. }
  261. m_flags |= FS_FLAG_INITIALIZED;
  262. return FS_SUCCESS;
  263. }
  264. fs_ret_t fs_store(fs_config_t const * const p_config,
  265. uint32_t const * const p_dest,
  266. uint32_t const * const p_src,
  267. uint16_t const length_words)
  268. {
  269. fs_op_t * p_op;
  270. if (!(m_flags & FS_FLAG_INITIALIZED))
  271. {
  272. return FS_ERR_NOT_INITIALIZED;
  273. }
  274. if (!check_config(p_config))
  275. {
  276. return FS_ERR_INVALID_CFG;
  277. }
  278. if ((p_src == NULL) || (p_dest == NULL))
  279. {
  280. return FS_ERR_NULL_ARG;
  281. }
  282. // Check that both pointers are word aligned.
  283. if (((uint32_t)p_src & 0x03) ||
  284. ((uint32_t)p_dest & 0x03))
  285. {
  286. return FS_ERR_UNALIGNED_ADDR;
  287. }
  288. // Check that the operation doesn't go outside the client's memory boundaries.
  289. if ((p_config->p_start_addr > p_dest) ||
  290. (p_config->p_end_addr < (p_dest + length_words)))
  291. {
  292. return FS_ERR_INVALID_ADDR;
  293. }
  294. if (length_words == 0)
  295. {
  296. return FS_ERR_INVALID_ARG;
  297. }
  298. if (!queue_get_next_free(&p_op))
  299. {
  300. return FS_ERR_QUEUE_FULL;
  301. }
  302. // Initialize the operation.
  303. p_op->p_config = p_config;
  304. p_op->op_code = FS_OP_STORE;
  305. p_op->store.p_src = p_src;
  306. p_op->store.p_dest = p_dest;
  307. p_op->store.length_words = length_words;
  308. queue_start();
  309. return FS_SUCCESS;
  310. }
  311. fs_ret_t fs_erase(fs_config_t const * const p_config,
  312. uint32_t const * const p_page_addr,
  313. uint16_t const num_pages)
  314. {
  315. fs_op_t * p_op;
  316. if (!(m_flags & FS_FLAG_INITIALIZED))
  317. {
  318. return FS_ERR_NOT_INITIALIZED;
  319. }
  320. if (!check_config(p_config))
  321. {
  322. return FS_ERR_INVALID_CFG;
  323. }
  324. if (p_page_addr == NULL)
  325. {
  326. return FS_ERR_NULL_ARG;
  327. }
  328. // Check that the page is aligned to a page boundary.
  329. if (((uint32_t)p_page_addr % FS_PAGE_SIZE) != 0)
  330. {
  331. return FS_ERR_UNALIGNED_ADDR;
  332. }
  333. // Check that the operation doesn't go outside the client's memory boundaries.
  334. if ((p_page_addr < p_config->p_start_addr) ||
  335. (p_page_addr + (FS_PAGE_SIZE_WORDS * num_pages) > p_config->p_end_addr))
  336. {
  337. return FS_ERR_INVALID_ADDR;
  338. }
  339. if (num_pages == 0)
  340. {
  341. return FS_ERR_INVALID_ARG;
  342. }
  343. if (!queue_get_next_free(&p_op))
  344. {
  345. return FS_ERR_QUEUE_FULL;
  346. }
  347. // Initialize the operation.
  348. p_op->p_config = p_config;
  349. p_op->op_code = FS_OP_ERASE;
  350. p_op->erase.page = ((uint32_t)p_page_addr / FS_PAGE_SIZE);
  351. p_op->erase.pages_to_erase = num_pages;
  352. queue_start();
  353. return FS_SUCCESS;
  354. }
  355. fs_ret_t fs_queued_op_count_get(uint32_t * const p_op_count)
  356. {
  357. if (p_op_count == NULL)
  358. {
  359. return FS_ERR_NULL_ARG;
  360. }
  361. *p_op_count = m_queue.count;
  362. return FS_SUCCESS;
  363. }
  364. void fs_sys_event_handler(uint32_t sys_evt)
  365. {
  366. fs_op_t * const p_op = &m_queue.op[m_queue.rp];
  367. if (m_flags & FS_FLAG_PROCESSING)
  368. {
  369. // A flash operation was initiated by this module. Handle the result.
  370. switch (sys_evt)
  371. {
  372. case NRF_EVT_FLASH_OPERATION_SUCCESS:
  373. on_operation_success(p_op);
  374. break;
  375. case NRF_EVT_FLASH_OPERATION_ERROR:
  376. on_operation_failure(p_op);
  377. break;
  378. }
  379. }
  380. else if ((m_flags & FS_FLAG_FLASH_REQ_PENDING))
  381. {
  382. // A flash operation was initiated outside this module.
  383. // A callback which indicates that it has finished was received.
  384. m_flags &= ~FS_FLAG_FLASH_REQ_PENDING;
  385. // If there are any elements left in the queue, set FS_FLAG_PROCESSING.
  386. if (m_queue.count > 0)
  387. {
  388. m_flags |= FS_FLAG_PROCESSING;
  389. }
  390. }
  391. // Resume processing the queue, if necessary.
  392. queue_process();
  393. }