hli_api.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <string.h>
  7. #include "esp_log.h"
  8. #include "esp_heap_caps.h"
  9. #include "xtensa/core-macros.h"
  10. #include "soc/dport_reg.h"
  11. #include "hli_api.h"
  12. #include "freertos/FreeRTOS.h"
  13. #include "freertos/queue.h"
  14. #if CONFIG_BTDM_CTRL_HLI
  15. #define HLI_MAX_HANDLERS 4
  16. typedef struct {
  17. intr_handler_t handler;
  18. void* arg;
  19. uint32_t intr_reg;
  20. uint32_t intr_mask;
  21. } hli_handler_info_t;
  22. typedef struct {
  23. #define CUSTOMER_TYPE_REQUEST (0)
  24. #define CUSTOMER_TYPE_RELEASE (1)
  25. struct {
  26. uint32_t cb_type;
  27. union {
  28. int (* request)(uint32_t, uint32_t, uint32_t);
  29. int (* release)(uint32_t);
  30. } cb;
  31. } customer_cb;
  32. uint32_t arg0, arg1, arg2;
  33. } customer_swisr_t;
  34. static void IRAM_ATTR customer_swisr_handle(customer_swisr_t *cus_swisr)
  35. {
  36. if (cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_REQUEST) {
  37. if (cus_swisr->customer_cb.cb.request != NULL) {
  38. cus_swisr->customer_cb.cb.request(cus_swisr->arg0, cus_swisr->arg1, cus_swisr->arg2);
  39. }
  40. } else if(cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_RELEASE) {
  41. if (cus_swisr->customer_cb.cb.release != NULL) {
  42. cus_swisr->customer_cb.cb.release(cus_swisr->arg0);
  43. }
  44. }
  45. }
  46. static DRAM_ATTR hli_handler_info_t s_hli_handlers[HLI_MAX_HANDLERS];
  47. esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask)
  48. {
  49. for (hli_handler_info_t* hip = s_hli_handlers;
  50. hip < s_hli_handlers + HLI_MAX_HANDLERS;
  51. ++hip) {
  52. if (hip->handler == NULL) {
  53. hip->arg = arg;
  54. hip->intr_reg = intr_reg;
  55. hip->intr_mask = intr_mask;
  56. hip->handler = handler; /* set last, indicates the entry as valid */
  57. return ESP_OK;
  58. }
  59. }
  60. return ESP_ERR_NO_MEM;
  61. }
  62. void IRAM_ATTR hli_c_handler(void)
  63. {
  64. bool handled = false;
  65. /* Iterate over registered interrupt handlers,
  66. * and check if the expected mask is present in the interrupt status register.
  67. */
  68. for (hli_handler_info_t* hip = s_hli_handlers;
  69. hip < s_hli_handlers + HLI_MAX_HANDLERS;
  70. ++hip) {
  71. if (hip->handler == NULL) {
  72. continue;
  73. }
  74. uint32_t reg = hip->intr_reg;
  75. uint32_t val;
  76. if (reg == 0) { /* special case for CPU internal interrupts */
  77. val = XTHAL_GET_INTERRUPT();
  78. } else {
  79. /* "reg" might not be in DPORT, but this will work in any case */
  80. val = DPORT_REG_READ(reg);
  81. }
  82. if ((val & hip->intr_mask) != 0) {
  83. handled = true;
  84. (*hip->handler)(hip->arg);
  85. }
  86. }
  87. if (!handled) {
  88. /* no handler found, it is OK in this case. */
  89. }
  90. }
  91. uint32_t IRAM_ATTR hli_intr_disable(void)
  92. {
  93. /* disable level 4 and below */
  94. return XTOS_SET_INTLEVEL(XCHAL_DEBUGLEVEL - 2);
  95. }
  96. void IRAM_ATTR hli_intr_restore(uint32_t state)
  97. {
  98. XTOS_RESTORE_JUST_INTLEVEL(state);
  99. }
  100. #define HLI_META_QUEUE_SIZE 16
  101. #define HLI_QUEUE_MAX_ELEM_SIZE 32
  102. #define HLI_QUEUE_SW_INT_NUM 29
  103. #define HLI_QUEUE_FLAG_SEMAPHORE BIT(0)
  104. #define HLI_QUEUE_FLAG_CUSTOMER BIT(1)
  105. static DRAM_ATTR struct hli_queue_t *s_meta_queue_ptr = NULL;
  106. static intr_handle_t ret_handle;
  107. static inline char* IRAM_ATTR wrap_ptr(hli_queue_handle_t queue, char *ptr)
  108. {
  109. return (ptr == queue->bufend) ? queue->buf : ptr;
  110. }
  111. static inline bool IRAM_ATTR queue_empty(hli_queue_handle_t queue)
  112. {
  113. return queue->begin == queue->end;
  114. }
  115. static inline bool IRAM_ATTR queue_full(hli_queue_handle_t queue)
  116. {
  117. return wrap_ptr(queue, queue->end + queue->elem_size) == queue->begin;
  118. }
  119. static void IRAM_ATTR queue_isr_handler(void* arg)
  120. {
  121. int do_yield = pdFALSE;
  122. XTHAL_SET_INTCLEAR(BIT(HLI_QUEUE_SW_INT_NUM));
  123. hli_queue_handle_t queue;
  124. while (hli_queue_get(s_meta_queue_ptr, &queue)) {
  125. static DRAM_ATTR char scratch[HLI_QUEUE_MAX_ELEM_SIZE];
  126. while (hli_queue_get(queue, scratch)) {
  127. int res = pdPASS;
  128. if ((queue->flags & HLI_QUEUE_FLAG_CUSTOMER) != 0) {
  129. customer_swisr_handle((customer_swisr_t *)scratch);
  130. } else if ((queue->flags & HLI_QUEUE_FLAG_SEMAPHORE) != 0) {
  131. res = xSemaphoreGiveFromISR((SemaphoreHandle_t) queue->downstream, &do_yield);
  132. } else {
  133. res = xQueueSendFromISR(queue->downstream, scratch, &do_yield);
  134. }
  135. if (res == pdFAIL) {
  136. /* Failed to send to downstream queue, it is OK in this case. */
  137. }
  138. }
  139. }
  140. if (do_yield) {
  141. portYIELD_FROM_ISR();
  142. }
  143. }
  144. /* Notify the level 3 handler that an element is added to the given hli queue.
  145. * Do this by placing the queue handle onto s_meta_queue, and raising a SW interrupt.
  146. *
  147. * This function must be called with HL interrupts disabled!
  148. */
  149. static void IRAM_ATTR queue_signal(hli_queue_handle_t queue)
  150. {
  151. /* See if the queue is already in s_meta_queue, before adding */
  152. bool found = false;
  153. const hli_queue_handle_t *end = (hli_queue_handle_t*) s_meta_queue_ptr->end;
  154. hli_queue_handle_t *item = (hli_queue_handle_t*) s_meta_queue_ptr->begin;
  155. for (;item != end; item = (hli_queue_handle_t*) wrap_ptr(s_meta_queue_ptr, (char*) (item + 1))) {
  156. if (*item == queue) {
  157. found = true;
  158. break;
  159. }
  160. }
  161. if (!found) {
  162. bool res = hli_queue_put(s_meta_queue_ptr, &queue);
  163. if (!res) {
  164. esp_rom_printf(DRAM_STR("Fatal error in queue_signal: s_meta_queue full\n"));
  165. abort();
  166. }
  167. XTHAL_SET_INTSET(BIT(HLI_QUEUE_SW_INT_NUM));
  168. }
  169. }
  170. static void queue_init(hli_queue_handle_t queue, size_t buf_size, size_t elem_size, QueueHandle_t downstream)
  171. {
  172. queue->elem_size = elem_size;
  173. queue->begin = queue->buf;
  174. queue->end = queue->buf;
  175. queue->bufend = queue->buf + buf_size;
  176. queue->downstream = downstream;
  177. queue->flags = 0;
  178. }
  179. void hli_queue_setup(void)
  180. {
  181. if (s_meta_queue_ptr == NULL) {
  182. s_meta_queue_ptr = hli_queue_create(HLI_META_QUEUE_SIZE, sizeof(void*), NULL);
  183. ESP_ERROR_CHECK(esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, ESP_INTR_FLAG_IRAM, queue_isr_handler, NULL, &ret_handle));
  184. xt_ints_on(BIT(HLI_QUEUE_SW_INT_NUM));
  185. }
  186. }
  187. void hli_queue_shutdown(void)
  188. {
  189. if (s_meta_queue_ptr != NULL) {
  190. hli_queue_delete(s_meta_queue_ptr);
  191. s_meta_queue_ptr = NULL;
  192. esp_intr_free(ret_handle);
  193. xt_ints_off(BIT(HLI_QUEUE_SW_INT_NUM));
  194. }
  195. }
  196. hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
  197. {
  198. const size_t buf_elem = nelem + 1;
  199. if (elem_size > HLI_QUEUE_MAX_ELEM_SIZE) {
  200. return NULL;
  201. }
  202. size_t buf_size = buf_elem * elem_size;
  203. hli_queue_handle_t res = (hli_queue_handle_t) heap_caps_malloc(sizeof(struct hli_queue_t) + buf_size,
  204. MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
  205. if (res == NULL) {
  206. return NULL;
  207. }
  208. queue_init(res, buf_size, elem_size, downstream);
  209. return res;
  210. }
  211. hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
  212. {
  213. hli_queue_handle_t res = hli_queue_create(nelem, elem_size, (QueueHandle_t) downstream);
  214. if (res == NULL) {
  215. return NULL;
  216. }
  217. res->flags |= HLI_QUEUE_FLAG_CUSTOMER;
  218. return res;
  219. }
  220. hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream)
  221. {
  222. const size_t elem_size = 1;
  223. hli_queue_handle_t res = hli_queue_create(max_count, elem_size, (QueueHandle_t) downstream);
  224. if (res == NULL) {
  225. return NULL;
  226. }
  227. res->flags |= HLI_QUEUE_FLAG_SEMAPHORE;
  228. return res;
  229. }
  230. void hli_queue_delete(hli_queue_handle_t queue)
  231. {
  232. free(queue);
  233. }
  234. bool IRAM_ATTR hli_queue_get(hli_queue_handle_t queue, void* out)
  235. {
  236. uint32_t int_state = hli_intr_disable();
  237. bool res = false;
  238. if (!queue_empty(queue)) {
  239. memcpy(out, queue->begin, queue->elem_size);
  240. queue->begin = wrap_ptr(queue, queue->begin + queue->elem_size);
  241. res = true;
  242. }
  243. hli_intr_restore(int_state);
  244. return res;
  245. }
  246. bool IRAM_ATTR hli_queue_put(hli_queue_handle_t queue, const void* data)
  247. {
  248. uint32_t int_state = hli_intr_disable();
  249. bool res = false;
  250. bool was_empty = queue_empty(queue);
  251. if (!queue_full(queue)) {
  252. memcpy(queue->end, data, queue->elem_size);
  253. queue->end = wrap_ptr(queue, queue->end + queue->elem_size);
  254. if (was_empty && queue != s_meta_queue_ptr) {
  255. queue_signal(queue);
  256. }
  257. res = true;
  258. }
  259. hli_intr_restore(int_state);
  260. return res;
  261. }
  262. bool IRAM_ATTR hli_semaphore_give(hli_queue_handle_t queue)
  263. {
  264. uint8_t data = 0;
  265. return hli_queue_put(queue, &data);
  266. }
  267. #endif /* CONFIG_BTDM_CTRL_HLI */