intr_alloc.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include "sdkconfig.h"
  14. #include <stdint.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <stdbool.h>
  18. #include <string.h>
  19. #include "freertos/FreeRTOS.h"
  20. #include "freertos/task.h"
  21. #include <esp_types.h>
  22. #include "esp_err.h"
  23. #include "esp_log.h"
  24. #include "esp_intr.h"
  25. #include "esp_attr.h"
  26. #include "esp_intr_alloc.h"
  27. #include <limits.h>
  28. #include <assert.h>
  29. static const char* TAG = "intr_alloc";
  30. #define ETS_INTERNAL_TIMER0_INTR_NO 6
  31. #define ETS_INTERNAL_TIMER1_INTR_NO 15
  32. #define ETS_INTERNAL_TIMER2_INTR_NO 16
  33. #define ETS_INTERNAL_SW0_INTR_NO 7
  34. #define ETS_INTERNAL_SW1_INTR_NO 29
  35. #define ETS_INTERNAL_PROFILING_INTR_NO 11
  36. /*
  37. Define this to debug the choices made when allocating the interrupt. This leads to much debugging
  38. output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
  39. being triggered, that is why it is separate from the normal LOG* scheme.
  40. */
  41. //define DEBUG_INT_ALLOC_DECISIONS
  42. #ifdef DEBUG_INT_ALLOC_DECISIONS
  43. # define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__)
  44. #else
  45. # define ALCHLOG(...) do {} while (0)
  46. #endif
  47. typedef enum {
  48. INTDESC_NORMAL=0,
  49. INTDESC_RESVD,
  50. INTDESC_SPECIAL //for xtensa timers / software ints
  51. } int_desc_flag_t;
  52. typedef enum {
  53. INTTP_LEVEL=0,
  54. INTTP_EDGE,
  55. INTTP_NA
  56. } int_type_t;
  57. typedef struct {
  58. int level;
  59. int_type_t type;
  60. int_desc_flag_t cpuflags[2];
  61. } int_desc_t;
  62. //We should mark the interrupt for the timer used by FreeRTOS as reserved. The specific timer
  63. //is selectable using menuconfig; we use these cpp bits to convert that into something we can use in
  64. //the table below.
  65. #if CONFIG_FREERTOS_CORETIMER_0
  66. #define INT6RES INTDESC_RESVD
  67. #else
  68. #define INT6RES INTDESC_SPECIAL
  69. #endif
  70. #if CONFIG_FREERTOS_CORETIMER_1
  71. #define INT15RES INTDESC_RESVD
  72. #else
  73. #define INT15RES INTDESC_SPECIAL
  74. #endif
  75. //This is basically a software-readable version of the interrupt usage table in include/soc/soc.h
  76. const static int_desc_t int_desc[32]={
  77. { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //0
  78. { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //1
  79. { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //2
  80. { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //3
  81. { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_NORMAL} }, //4
  82. { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_NORMAL} }, //5
  83. { 1, INTTP_NA, {INT6RES, INT6RES } }, //6
  84. { 1, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //7
  85. { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //8
  86. { 1, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //9 //FRC1
  87. { 1, INTTP_EDGE , {INTDESC_RESVD, INTDESC_RESVD } }, //10 //FRC2
  88. { 3, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //11
  89. { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //12
  90. { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //13
  91. { 7, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //14, NMI
  92. { 3, INTTP_NA, {INT15RES, INT15RES } }, //15
  93. { 5, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL} }, //16
  94. { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //17
  95. { 1, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //18
  96. { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //19
  97. { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //20
  98. { 2, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //21
  99. { 3, INTTP_EDGE, {INTDESC_RESVD, INTDESC_NORMAL} }, //22
  100. { 3, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //23
  101. { 4, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_NORMAL} }, //24
  102. { 4, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //25
  103. { 5, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //26
  104. { 3, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //27
  105. { 4, INTTP_EDGE, {INTDESC_NORMAL, INTDESC_NORMAL} }, //28
  106. { 3, INTTP_NA, {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //29
  107. { 4, INTTP_EDGE, {INTDESC_RESVD, INTDESC_RESVD } }, //30
  108. { 5, INTTP_LEVEL, {INTDESC_RESVD, INTDESC_RESVD } }, //31
  109. };
  110. typedef struct shared_vector_desc_t shared_vector_desc_t;
  111. typedef struct vector_desc_t vector_desc_t;
  112. struct shared_vector_desc_t {
  113. int disabled: 1;
  114. int source: 8;
  115. volatile uint32_t *statusreg;
  116. uint32_t statusmask;
  117. intr_handler_t isr;
  118. void *arg;
  119. shared_vector_desc_t *next;
  120. };
  121. #define VECDESC_FL_RESERVED (1<<0)
  122. #define VECDESC_FL_INIRAM (1<<1)
  123. #define VECDESC_FL_SHARED (1<<2)
  124. #define VECDESC_FL_NONSHARED (1<<3)
  125. //Pack using bitfields for better memory use
  126. struct vector_desc_t {
  127. int flags: 16; //OR of VECDESC_FLAG_* defines
  128. unsigned int cpu: 1;
  129. unsigned int intno: 5;
  130. int source: 8; //Interrupt mux flags, used when not shared
  131. shared_vector_desc_t *shared_vec_info; //used when VECDESC_FL_SHARED
  132. vector_desc_t *next;
  133. };
  134. struct intr_handle_data_t {
  135. vector_desc_t *vector_desc;
  136. shared_vector_desc_t *shared_vector_desc;
  137. };
  138. //Linked list of vector descriptions, sorted by cpu.intno value
  139. static vector_desc_t *vector_desc_head;
  140. //This bitmask has an 1 if the int should be disabled when the flash is disabled.
  141. static uint32_t non_iram_int_mask[portNUM_PROCESSORS];
  142. //This bitmask has 1 in it if the int was disabled using esp_intr_noniram_disable.
  143. static uint32_t non_iram_int_disabled[portNUM_PROCESSORS];
  144. static bool non_iram_int_disabled_flag[portNUM_PROCESSORS];
  145. static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
  146. //Inserts an item into vector_desc list so that the list is sorted
  147. //with an incrementing cpu.intno value.
  148. static void insert_vector_desc(vector_desc_t *to_insert)
  149. {
  150. vector_desc_t *vd=vector_desc_head;
  151. vector_desc_t *prev=NULL;
  152. while(vd!=NULL) {
  153. if (vd->cpu > to_insert->cpu) break;
  154. if (vd->cpu == to_insert->cpu && vd->intno >= to_insert->intno) break;
  155. prev=vd;
  156. vd=vd->next;
  157. }
  158. if (vd==NULL && prev==NULL) {
  159. //First item
  160. vector_desc_head=to_insert;
  161. vector_desc_head->next=NULL;
  162. } else {
  163. prev->next=to_insert;
  164. to_insert->next=vd;
  165. }
  166. }
  167. //Returns a vector_desc entry for an intno/cpu, or NULL if none exists.
  168. static vector_desc_t *find_desc_for_int(int intno, int cpu)
  169. {
  170. vector_desc_t *vd=vector_desc_head;
  171. while(vd!=NULL) {
  172. if (vd->cpu==cpu && vd->intno==intno) break;
  173. vd=vd->next;
  174. }
  175. return vd;
  176. }
  177. //Returns a vector_desc entry for an intno/cpu.
  178. //Either returns a preexisting one or allocates a new one and inserts
  179. //it into the list. Returns NULL on malloc fail.
  180. static vector_desc_t *get_desc_for_int(int intno, int cpu)
  181. {
  182. vector_desc_t *vd=find_desc_for_int(intno, cpu);
  183. if (vd==NULL) {
  184. vector_desc_t *newvd=malloc(sizeof(vector_desc_t));
  185. if (newvd==NULL) return NULL;
  186. memset(newvd, 0, sizeof(vector_desc_t));
  187. newvd->intno=intno;
  188. newvd->cpu=cpu;
  189. insert_vector_desc(newvd);
  190. return newvd;
  191. } else {
  192. return vd;
  193. }
  194. }
  195. esp_err_t esp_intr_mark_shared(int intno, int cpu, bool is_int_ram)
  196. {
  197. if (intno>31) return ESP_ERR_INVALID_ARG;
  198. if (cpu>=portNUM_PROCESSORS) return ESP_ERR_INVALID_ARG;
  199. portENTER_CRITICAL(&spinlock);
  200. vector_desc_t *vd=get_desc_for_int(intno, cpu);
  201. if (vd==NULL) {
  202. portEXIT_CRITICAL(&spinlock);
  203. return ESP_ERR_NO_MEM;
  204. }
  205. vd->flags=VECDESC_FL_SHARED;
  206. if (is_int_ram) vd->flags|=VECDESC_FL_INIRAM;
  207. portEXIT_CRITICAL(&spinlock);
  208. return ESP_OK;
  209. }
  210. esp_err_t esp_intr_reserve(int intno, int cpu)
  211. {
  212. if (intno>31) return ESP_ERR_INVALID_ARG;
  213. if (cpu>=portNUM_PROCESSORS) return ESP_ERR_INVALID_ARG;
  214. portENTER_CRITICAL(&spinlock);
  215. vector_desc_t *vd=get_desc_for_int(intno, cpu);
  216. if (vd==NULL) {
  217. portEXIT_CRITICAL(&spinlock);
  218. return ESP_ERR_NO_MEM;
  219. }
  220. vd->flags=VECDESC_FL_RESERVED;
  221. portEXIT_CRITICAL(&spinlock);
  222. return ESP_OK;
  223. }
  224. //Interrupt handler table and unhandled uinterrupt routine. Duplicated
  225. //from xtensa_intr.c... it's supposed to be private, but we need to look
  226. //into it in order to see if someone allocated an int using
  227. //xt_set_interrupt_handler.
  228. typedef struct xt_handler_table_entry {
  229. void * handler;
  230. void * arg;
  231. } xt_handler_table_entry;
  232. extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS];
  233. extern void xt_unhandled_interrupt(void * arg);
  234. //Returns true if handler for interrupt is not the default unhandled interrupt handler
  235. static bool int_has_handler(int intr, int cpu)
  236. {
  237. return (_xt_interrupt_table[intr*portNUM_PROCESSORS+cpu].handler != xt_unhandled_interrupt);
  238. }
  239. //Locate a free interrupt compatible with the flags given.
  240. //The 'force' argument can be -1, or 0-31 to force checking a certain interrupt.
  241. //When a CPU is forced, the INTDESC_SPECIAL marked interrupts are also accepted.
  242. static int get_free_int(int flags, int cpu, int force)
  243. {
  244. int x;
  245. int best=-1;
  246. int bestLevel=9;
  247. int bestSharedCt=INT_MAX;
  248. //Default vector desc, for vectors not in the linked list
  249. vector_desc_t empty_vect_desc;
  250. memset(&empty_vect_desc, 0, sizeof(vector_desc_t));
  251. //Level defaults to any low/med interrupt
  252. if (!(flags&ESP_INTR_FLAG_LEVELMASK)) flags|=ESP_INTR_FLAG_LOWMED;
  253. ALCHLOG(TAG, "get_free_int: start looking. Current cpu: %d", cpu);
  254. //Iterate over the 32 possible interrupts
  255. for (x=0; x<32; x++) {
  256. //Grab the vector_desc for this vector.
  257. vector_desc_t *vd=find_desc_for_int(x, cpu);
  258. if (vd==NULL) vd=&empty_vect_desc;
  259. //See if we have a forced interrupt; if so, bail out if this is not it.
  260. if (force!=-1 && force!=x) {
  261. ALCHLOG(TAG, "Ignoring int %d: forced to %d", x, force);
  262. continue;
  263. }
  264. ALCHLOG(TAG, "Int %d reserved %d level %d %s hasIsr %d",
  265. x, int_desc[x].cpuflags[cpu]==INTDESC_RESVD, int_desc[x].level,
  266. int_desc[x].type==INTTP_LEVEL?"LEVEL":"EDGE", int_has_handler(x, cpu));
  267. //Check if interrupt is not reserved by design
  268. if (int_desc[x].cpuflags[cpu]==INTDESC_RESVD) {
  269. ALCHLOG(TAG, "....Unusable: reserved");
  270. continue;
  271. }
  272. if (int_desc[x].cpuflags[cpu]==INTDESC_SPECIAL && force==-1) {
  273. ALCHLOG(TAG, "....Unusable: special-purpose int");
  274. continue;
  275. }
  276. //Check if the interrupt level is acceptable
  277. if (!(flags&(1<<int_desc[x].level))) {
  278. ALCHLOG(TAG, "....Unusable: incompatible level");
  279. continue;
  280. }
  281. //check if edge/level type matches what we want
  282. if (((flags&ESP_INTR_FLAG_EDGE) && (int_desc[x].type==INTTP_LEVEL)) ||
  283. (((!(flags&ESP_INTR_FLAG_EDGE)) && (int_desc[x].type==INTTP_EDGE)))) {
  284. ALCHLOG(TAG, "....Unusable: incompatible trigger type");
  285. continue;
  286. }
  287. //Check if interrupt already is allocated by xt_set_interrupt_handler
  288. if (int_has_handler(x, cpu) && !(vd->flags&VECDESC_FL_SHARED)) {
  289. ALCHLOG(TAG, "....Unusable: already allocated");
  290. continue;
  291. }
  292. //Ints can't be both shared and non-shared.
  293. assert(!((vd->flags&VECDESC_FL_SHARED)&&(vd->flags&VECDESC_FL_NONSHARED)));
  294. //check if interrupt is reserved at runtime
  295. if (vd->flags&VECDESC_FL_RESERVED) {
  296. ALCHLOG(TAG, "....Unusable: reserved at runtime.");
  297. continue;
  298. }
  299. //check if interrupt already is in use by a non-shared interrupt
  300. if (vd->flags&VECDESC_FL_NONSHARED) {
  301. ALCHLOG(TAG, "....Unusable: already in (non-shared) use.");
  302. continue;
  303. }
  304. if (flags&ESP_INTR_FLAG_SHARED) {
  305. //We're allocating a shared int.
  306. bool in_iram_flag=((flags&ESP_INTR_FLAG_IRAM)!=0);
  307. bool desc_in_iram_flag=((vd->flags&VECDESC_FL_INIRAM)!=0);
  308. //Bail out if int is shared, but iram property doesn't match what we want.
  309. if ((vd->flags&VECDESC_FL_SHARED) && (desc_in_iram_flag!=in_iram_flag)) {
  310. ALCHLOG(TAG, "....Unusable: shared but iram prop doesn't match");
  311. continue;
  312. }
  313. //See if int already is used as a shared interrupt.
  314. if (vd->flags&VECDESC_FL_SHARED) {
  315. //We can use this already-marked-as-shared interrupt. Count the already attached isrs in order to see
  316. //how useful it is.
  317. int no=0;
  318. shared_vector_desc_t *svdesc=vd->shared_vec_info;
  319. while (svdesc!=NULL) {
  320. no++;
  321. svdesc=svdesc->next;
  322. }
  323. if (no<bestSharedCt || bestLevel>int_desc[x].level) {
  324. //Seems like this shared vector is both okay and has the least amount of ISRs already attached to it.
  325. best=x;
  326. bestSharedCt=no;
  327. bestLevel=int_desc[x].level;
  328. ALCHLOG(TAG, "...int %d more usable as a shared int: has %d existing vectors", x, no);
  329. } else {
  330. ALCHLOG(TAG, "...worse than int %d", best);
  331. }
  332. } else {
  333. if (best==-1) {
  334. //We haven't found a feasible shared interrupt yet. This one is still free and usable, even if
  335. //not marked as shared.
  336. //Remember it in case we don't find any other shared interrupt that qualifies.
  337. if (bestLevel>int_desc[x].level) {
  338. best=x;
  339. bestLevel=int_desc[x].level;
  340. ALCHLOG(TAG, "...int %d usable as a new shared int", x);
  341. }
  342. } else {
  343. ALCHLOG(TAG, "...already have a shared int");
  344. }
  345. }
  346. } else {
  347. //We need an unshared IRQ; can't use shared ones; bail out if this is shared.
  348. if (vd->flags&VECDESC_FL_SHARED) {
  349. ALCHLOG(TAG, "...Unusable: int is shared, we need non-shared.");
  350. continue;
  351. }
  352. //Seems this interrupt is feasible. Select it and break out of the loop; no need to search further.
  353. if (bestLevel>int_desc[x].level) {
  354. best=x;
  355. bestLevel=int_desc[x].level;
  356. } else {
  357. ALCHLOG(TAG, "...worse than int %d", best);
  358. }
  359. }
  360. }
  361. ALCHLOG(TAG, "get_free_int: using int %d", best);
  362. //Okay, by now we have looked at all potential interrupts and hopefully have selected the best one in best.
  363. return best;
  364. }
  365. //Common shared isr handler. Chain-call all ISRs.
  366. static void IRAM_ATTR shared_intr_isr(void *arg)
  367. {
  368. vector_desc_t *vd=(vector_desc_t*)arg;
  369. shared_vector_desc_t *sh_vec=vd->shared_vec_info;
  370. portENTER_CRITICAL(&spinlock);
  371. while(sh_vec) {
  372. if (!sh_vec->disabled) {
  373. if ((sh_vec->statusreg == NULL) || (*sh_vec->statusreg & sh_vec->statusmask)) {
  374. sh_vec->isr(sh_vec->arg);
  375. }
  376. }
  377. sh_vec=sh_vec->next;
  378. }
  379. portEXIT_CRITICAL(&spinlock);
  380. }
  381. //We use ESP_EARLY_LOG* here because this can be called before the scheduler is running.
  382. esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusreg, uint32_t intrstatusmask, intr_handler_t handler,
  383. void *arg, intr_handle_t *ret_handle)
  384. {
  385. intr_handle_data_t *ret=NULL;
  386. int force=-1;
  387. ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): checking args", xPortGetCoreID());
  388. //Shared interrupts should be level-triggered.
  389. if ((flags&ESP_INTR_FLAG_SHARED) && (flags&ESP_INTR_FLAG_EDGE)) return ESP_ERR_INVALID_ARG;
  390. //You can't set an handler / arg for a non-C-callable interrupt.
  391. if ((flags&ESP_INTR_FLAG_HIGH) && (handler)) return ESP_ERR_INVALID_ARG;
  392. //Shared ints should have handler and non-processor-local source
  393. if ((flags&ESP_INTR_FLAG_SHARED) && (!handler || source<0)) return ESP_ERR_INVALID_ARG;
  394. //Statusreg should have a mask
  395. if (intrstatusreg && !intrstatusmask) return ESP_ERR_INVALID_ARG;
  396. //If the ISR is marked to be IRAM-resident, the handler must not be in the cached region
  397. if ((flags&ESP_INTR_FLAG_IRAM) &&
  398. (ptrdiff_t) handler >= 0x400C0000 &&
  399. (ptrdiff_t) handler < 0x50000000 ) {
  400. return ESP_ERR_INVALID_ARG;
  401. }
  402. //Default to prio 1 for shared interrupts. Default to prio 1, 2 or 3 for non-shared interrupts.
  403. if ((flags&ESP_INTR_FLAG_LEVELMASK)==0) {
  404. if (flags&ESP_INTR_FLAG_SHARED) {
  405. flags|=ESP_INTR_FLAG_LEVEL1;
  406. } else {
  407. flags|=ESP_INTR_FLAG_LOWMED;
  408. }
  409. }
  410. ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): Args okay. Resulting flags 0x%X", xPortGetCoreID(), flags);
  411. //Check 'special' interrupt sources. These are tied to one specific interrupt, so we
  412. //have to force get_free_int to only look at that.
  413. if (source==ETS_INTERNAL_TIMER0_INTR_SOURCE) force=ETS_INTERNAL_TIMER0_INTR_NO;
  414. if (source==ETS_INTERNAL_TIMER1_INTR_SOURCE) force=ETS_INTERNAL_TIMER1_INTR_NO;
  415. if (source==ETS_INTERNAL_TIMER2_INTR_SOURCE) force=ETS_INTERNAL_TIMER2_INTR_NO;
  416. if (source==ETS_INTERNAL_SW0_INTR_SOURCE) force=ETS_INTERNAL_SW0_INTR_NO;
  417. if (source==ETS_INTERNAL_SW1_INTR_SOURCE) force=ETS_INTERNAL_SW1_INTR_NO;
  418. if (source==ETS_INTERNAL_PROFILING_INTR_SOURCE) force=ETS_INTERNAL_PROFILING_INTR_NO;
  419. //Allocate a return handle. If we end up not needing it, we'll free it later on.
  420. ret=malloc(sizeof(intr_handle_data_t));
  421. if (ret==NULL) return ESP_ERR_NO_MEM;
  422. portENTER_CRITICAL(&spinlock);
  423. int cpu=xPortGetCoreID();
  424. //See if we can find an interrupt that matches the flags.
  425. int intr=get_free_int(flags, cpu, force);
  426. if (intr==-1) {
  427. //None found. Bail out.
  428. portEXIT_CRITICAL(&spinlock);
  429. free(ret);
  430. return ESP_ERR_NOT_FOUND;
  431. }
  432. //Get an int vector desc for int.
  433. vector_desc_t *vd=get_desc_for_int(intr, cpu);
  434. if (vd==NULL) {
  435. portEXIT_CRITICAL(&spinlock);
  436. free(ret);
  437. return ESP_ERR_NO_MEM;
  438. }
  439. //Allocate that int!
  440. if (flags&ESP_INTR_FLAG_SHARED) {
  441. //Populate vector entry and add to linked list.
  442. shared_vector_desc_t *sh_vec=malloc(sizeof(shared_vector_desc_t));
  443. if (sh_vec==NULL) {
  444. portEXIT_CRITICAL(&spinlock);
  445. free(ret);
  446. return ESP_ERR_NO_MEM;
  447. }
  448. memset(sh_vec, 0, sizeof(shared_vector_desc_t));
  449. sh_vec->statusreg=(uint32_t*)intrstatusreg;
  450. sh_vec->statusmask=intrstatusmask;
  451. sh_vec->isr=handler;
  452. sh_vec->arg=arg;
  453. sh_vec->next=vd->shared_vec_info;
  454. sh_vec->source=source;
  455. sh_vec->disabled=0;
  456. vd->shared_vec_info=sh_vec;
  457. vd->flags|=VECDESC_FL_SHARED;
  458. //(Re-)set shared isr handler to new value.
  459. xt_set_interrupt_handler(intr, shared_intr_isr, vd);
  460. } else {
  461. //Mark as unusable for other interrupt sources. This is ours now!
  462. vd->flags=VECDESC_FL_NONSHARED;
  463. if (handler) {
  464. xt_set_interrupt_handler(intr, handler, arg);
  465. }
  466. if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr);
  467. vd->source=source;
  468. }
  469. if (flags&ESP_INTR_FLAG_IRAM) {
  470. vd->flags|=VECDESC_FL_INIRAM;
  471. non_iram_int_mask[cpu]&=~(1<<intr);
  472. } else {
  473. vd->flags&=~VECDESC_FL_INIRAM;
  474. non_iram_int_mask[cpu]|=(1<<intr);
  475. }
  476. if (source>=0) {
  477. intr_matrix_set(cpu, source, intr);
  478. }
  479. //Fill return handle data.
  480. ret->vector_desc=vd;
  481. ret->shared_vector_desc=vd->shared_vec_info;
  482. //Enable int at CPU-level;
  483. ESP_INTR_ENABLE(intr);
  484. //If interrupt has to be started disabled, do that now; ints won't be enabled for real until the end
  485. //of the critical section.
  486. if (flags&ESP_INTR_FLAG_INTRDISABLED) {
  487. esp_intr_disable(ret);
  488. }
  489. portEXIT_CRITICAL(&spinlock);
  490. //Fill return handle if needed, otherwise free handle.
  491. if (ret_handle!=NULL) {
  492. *ret_handle=ret;
  493. } else {
  494. free(ret);
  495. }
  496. ESP_EARLY_LOGD(TAG, "Connected src %d to int %d (cpu %d)", source, intr, cpu);
  497. return ESP_OK;
  498. }
  499. esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, intr_handle_t *ret_handle)
  500. {
  501. /*
  502. As an optimization, we can create a table with the possible interrupt status registers and masks for every single
  503. source there is. We can then add code here to look up an applicable value and pass that to the
  504. esp_intr_alloc_intrstatus function.
  505. */
  506. return esp_intr_alloc_intrstatus(source, flags, 0, 0, handler, arg, ret_handle);
  507. }
  508. esp_err_t esp_intr_free(intr_handle_t handle)
  509. {
  510. bool free_shared_vector=false;
  511. if (!handle) return ESP_ERR_INVALID_ARG;
  512. //This routine should be called from the interrupt the task is scheduled on.
  513. if (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG;
  514. portENTER_CRITICAL(&spinlock);
  515. esp_intr_disable(handle);
  516. if (handle->vector_desc->flags&VECDESC_FL_SHARED) {
  517. //Find and kill the shared int
  518. shared_vector_desc_t *svd=handle->vector_desc->shared_vec_info;
  519. shared_vector_desc_t *prevsvd=NULL;
  520. assert(svd); //should be something in there for a shared int
  521. while (svd!=NULL) {
  522. if (svd==handle->shared_vector_desc) {
  523. //Found it. Now kill it.
  524. if (prevsvd) {
  525. prevsvd->next=svd->next;
  526. } else {
  527. handle->vector_desc->shared_vec_info=svd->next;
  528. }
  529. free(svd);
  530. break;
  531. }
  532. prevsvd=svd;
  533. svd=svd->next;
  534. }
  535. //If nothing left, disable interrupt.
  536. if (handle->vector_desc->shared_vec_info==NULL) free_shared_vector=true;
  537. ESP_LOGV(TAG, "esp_intr_free: Deleting shared int: %s. Shared int is %s", svd?"not found or last one":"deleted", free_shared_vector?"empty now.":"still in use");
  538. }
  539. if ((handle->vector_desc->flags&VECDESC_FL_NONSHARED) || free_shared_vector) {
  540. ESP_LOGV(TAG, "esp_intr_free: Disabling int, killing handler");
  541. //Reset to normal handler
  542. xt_set_interrupt_handler(handle->vector_desc->intno, xt_unhandled_interrupt, (void*)((int)handle->vector_desc->intno));
  543. //Theoretically, we could free the vector_desc... not sure if that's worth the few bytes of memory
  544. //we save.(We can also not use the same exit path for empty shared ints anymore if we delete
  545. //the desc.) For now, just mark it as free.
  546. handle->vector_desc->flags&=!(VECDESC_FL_NONSHARED|VECDESC_FL_RESERVED);
  547. //Also kill non_iram mask bit.
  548. non_iram_int_mask[handle->vector_desc->cpu]&=~(1<<(handle->vector_desc->intno));
  549. }
  550. portEXIT_CRITICAL(&spinlock);
  551. free(handle);
  552. return ESP_OK;
  553. }
  554. int esp_intr_get_intno(intr_handle_t handle)
  555. {
  556. return handle->vector_desc->intno;
  557. }
  558. int esp_intr_get_cpu(intr_handle_t handle)
  559. {
  560. return handle->vector_desc->cpu;
  561. }
  562. /*
  563. Interrupt disabling strategy:
  564. If the source is >=0 (meaning a muxed interrupt), we disable it by muxing the interrupt to a non-connected
  565. interrupt. If the source is <0 (meaning an internal, per-cpu interrupt), we disable it using ESP_INTR_DISABLE.
  566. This allows us to, for the muxed CPUs, disable an int from the other core. It also allows disabling shared
  567. interrupts.
  568. */
  569. //Muxing an interrupt source to interrupt 6, 7, 11, 15, 16 or 29 cause the interrupt to effectively be disabled.
  570. #define INT_MUX_DISABLED_INTNO 6
  571. esp_err_t IRAM_ATTR esp_intr_enable(intr_handle_t handle)
  572. {
  573. if (!handle) return ESP_ERR_INVALID_ARG;
  574. portENTER_CRITICAL(&spinlock);
  575. int source;
  576. if (handle->shared_vector_desc) {
  577. handle->shared_vector_desc->disabled=0;
  578. source=handle->shared_vector_desc->source;
  579. } else {
  580. source=handle->vector_desc->source;
  581. }
  582. if (source >= 0) {
  583. //Disabled using int matrix; re-connect to enable
  584. intr_matrix_set(handle->vector_desc->cpu, source, handle->vector_desc->intno);
  585. } else {
  586. //Re-enable using cpu int ena reg
  587. if (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; //Can only enable these ints on this cpu
  588. ESP_INTR_ENABLE(handle->vector_desc->intno);
  589. }
  590. portEXIT_CRITICAL(&spinlock);
  591. return ESP_OK;
  592. }
  593. esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle)
  594. {
  595. if (!handle) return ESP_ERR_INVALID_ARG;
  596. portENTER_CRITICAL(&spinlock);
  597. int source;
  598. if (handle->shared_vector_desc) {
  599. handle->shared_vector_desc->disabled=1;
  600. source=handle->shared_vector_desc->source;
  601. } else {
  602. source=handle->vector_desc->source;
  603. }
  604. if (source >= 0) {
  605. //Disable using int matrix
  606. intr_matrix_set(handle->vector_desc->cpu, source, INT_MUX_DISABLED_INTNO);
  607. } else {
  608. //Disable using per-cpu regs
  609. if (handle->vector_desc->cpu!=xPortGetCoreID()) {
  610. portEXIT_CRITICAL(&spinlock);
  611. return ESP_ERR_INVALID_ARG; //Can only enable these ints on this cpu
  612. }
  613. ESP_INTR_DISABLE(handle->vector_desc->intno);
  614. }
  615. portEXIT_CRITICAL(&spinlock);
  616. return ESP_OK;
  617. }
  618. void IRAM_ATTR esp_intr_noniram_disable()
  619. {
  620. int oldint;
  621. int cpu=xPortGetCoreID();
  622. int intmask=~non_iram_int_mask[cpu];
  623. if (non_iram_int_disabled_flag[cpu]) abort();
  624. non_iram_int_disabled_flag[cpu]=true;
  625. asm volatile (
  626. "movi %0,0\n"
  627. "xsr %0,INTENABLE\n" //disable all ints first
  628. "rsync\n"
  629. "and a3,%0,%1\n" //mask ints that need disabling
  630. "wsr a3,INTENABLE\n" //write back
  631. "rsync\n"
  632. :"=&r"(oldint):"r"(intmask):"a3");
  633. //Save which ints we did disable
  634. non_iram_int_disabled[cpu]=oldint&non_iram_int_mask[cpu];
  635. }
  636. void IRAM_ATTR esp_intr_noniram_enable()
  637. {
  638. int cpu=xPortGetCoreID();
  639. int intmask=non_iram_int_disabled[cpu];
  640. if (!non_iram_int_disabled_flag[cpu]) abort();
  641. non_iram_int_disabled_flag[cpu]=false;
  642. asm volatile (
  643. "movi a3,0\n"
  644. "xsr a3,INTENABLE\n"
  645. "rsync\n"
  646. "or a3,a3,%0\n"
  647. "wsr a3,INTENABLE\n"
  648. "rsync\n"
  649. ::"r"(intmask):"a3");
  650. }
  651. //These functions are provided in ROM, but the ROM-based functions use non-multicore-capable
  652. //virtualized interrupt levels. Thus, we disable them in the ld file and provide working
  653. //equivalents here.
  654. void IRAM_ATTR ets_isr_unmask(unsigned int mask) {
  655. xt_ints_on(mask);
  656. }
  657. void IRAM_ATTR ets_isr_mask(unsigned int mask) {
  658. xt_ints_off(mask);
  659. }