/ components / esp_system / intr_alloc.c
intr_alloc.c
  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  
  7  //     http://www.apache.org/licenses/LICENSE-2.0
  8  //
  9  // Unless required by applicable law or agreed to in writing, software
 10  // distributed under the License is distributed on an "AS IS" BASIS,
 11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  // See the License for the specific language governing permissions and
 13  // limitations under the License.
 14  
 15  #include "sdkconfig.h"
 16  #include <stdint.h>
 17  #include <stdio.h>
 18  #include <stdlib.h>
 19  #include <stdbool.h>
 20  #include <string.h>
 21  #include <esp_types.h>
 22  #include <limits.h>
 23  #include <assert.h>
 24  #include "freertos/FreeRTOS.h"
 25  #include "freertos/task.h"
 26  #include "esp_err.h"
 27  #include "esp_log.h"
 28  #include "esp_intr_alloc.h"
 29  #include "esp_attr.h"
 30  #include "hal/cpu_hal.h"
 31  #include "hal/interrupt_controller_hal.h"
 32  
 33  #if !CONFIG_FREERTOS_UNICORE
 34  #include "esp_ipc.h"
 35  #endif
 36  
 37  static const char* TAG = "intr_alloc";
 38  
 39  #define ETS_INTERNAL_TIMER0_INTR_NO 6
 40  #define ETS_INTERNAL_TIMER1_INTR_NO 15
 41  #define ETS_INTERNAL_TIMER2_INTR_NO 16
 42  #define ETS_INTERNAL_SW0_INTR_NO 7
 43  #define ETS_INTERNAL_SW1_INTR_NO 29
 44  #define ETS_INTERNAL_PROFILING_INTR_NO 11
 45  
 46  /*
 47  Define this to debug the choices made when allocating the interrupt. This leads to much debugging
 48  output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
 49  being triggered, that is why it is separate from the normal LOG* scheme.
 50  */
 51  //define DEBUG_INT_ALLOC_DECISIONS
 52  #ifdef DEBUG_INT_ALLOC_DECISIONS
 53  # define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__)
 54  #else
 55  # define ALCHLOG(...) do {} while (0)
 56  #endif
 57  
 58  typedef struct shared_vector_desc_t shared_vector_desc_t;
 59  typedef struct vector_desc_t vector_desc_t;
 60  
 61  struct shared_vector_desc_t {
 62      int disabled: 1;
 63      int source: 8;
 64      volatile uint32_t *statusreg;
 65      uint32_t statusmask;
 66      intr_handler_t isr;
 67      void *arg;
 68      shared_vector_desc_t *next;
 69  };
 70  
 71  #define VECDESC_FL_RESERVED     (1<<0)
 72  #define VECDESC_FL_INIRAM       (1<<1)
 73  #define VECDESC_FL_SHARED       (1<<2)
 74  #define VECDESC_FL_NONSHARED    (1<<3)
 75  
 76  //Pack using bitfields for better memory use
 77  struct vector_desc_t {
 78      int flags: 16;                          //OR of VECDESC_FLAG_* defines
 79      unsigned int cpu: 1;
 80      unsigned int intno: 5;
 81      int source: 8;                          //Interrupt mux flags, used when not shared
 82      shared_vector_desc_t *shared_vec_info;  //used when VECDESC_FL_SHARED
 83      vector_desc_t *next;
 84  };
 85  
 86  struct intr_handle_data_t {
 87      vector_desc_t *vector_desc;
 88      shared_vector_desc_t *shared_vector_desc;
 89  };
 90  
 91  typedef struct non_shared_isr_arg_t non_shared_isr_arg_t;
 92  
 93  struct non_shared_isr_arg_t {
 94      intr_handler_t isr;
 95      void *isr_arg;
 96      int source;
 97  };
 98  
 99  //Linked list of vector descriptions, sorted by cpu.intno value
100  static vector_desc_t *vector_desc_head = NULL;
101  
102  //This bitmask has an 1 if the int should be disabled when the flash is disabled.
103  static uint32_t non_iram_int_mask[SOC_CPU_CORES_NUM];
104  
105  //This bitmask has 1 in it if the int was disabled using esp_intr_noniram_disable.
106  static uint32_t non_iram_int_disabled[SOC_CPU_CORES_NUM];
107  static bool non_iram_int_disabled_flag[SOC_CPU_CORES_NUM];
108  
109  #if CONFIG_SYSVIEW_ENABLE
110  extern uint32_t port_switch_flag[];
111  #endif
112  
113  static portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
114  
115  //Inserts an item into vector_desc list so that the list is sorted
116  //with an incrementing cpu.intno value.
117  static void insert_vector_desc(vector_desc_t *to_insert)
118  {
119      vector_desc_t *vd=vector_desc_head;
120      vector_desc_t *prev=NULL;
121      while(vd!=NULL) {
122          if (vd->cpu > to_insert->cpu) break;
123          if (vd->cpu == to_insert->cpu && vd->intno >= to_insert->intno) break;
124          prev=vd;
125          vd=vd->next;
126      }
127      if ((vector_desc_head==NULL) || (prev==NULL)) {
128          //First item
129          to_insert->next = vd;
130          vector_desc_head=to_insert;
131      } else {
132          prev->next=to_insert;
133          to_insert->next=vd;
134      }
135  }
136  
137  //Returns a vector_desc entry for an intno/cpu, or NULL if none exists.
138  static vector_desc_t *find_desc_for_int(int intno, int cpu)
139  {
140      vector_desc_t *vd=vector_desc_head;
141      while(vd!=NULL) {
142          if (vd->cpu==cpu && vd->intno==intno) break;
143          vd=vd->next;
144      }
145      return vd;
146  }
147  
148  //Returns a vector_desc entry for an intno/cpu.
149  //Either returns a preexisting one or allocates a new one and inserts
150  //it into the list. Returns NULL on malloc fail.
151  static vector_desc_t *get_desc_for_int(int intno, int cpu)
152  {
153      vector_desc_t *vd=find_desc_for_int(intno, cpu);
154      if (vd==NULL) {
155          vector_desc_t *newvd=heap_caps_malloc(sizeof(vector_desc_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
156          if (newvd==NULL) return NULL;
157          memset(newvd, 0, sizeof(vector_desc_t));
158          newvd->intno=intno;
159          newvd->cpu=cpu;
160          insert_vector_desc(newvd);
161          return newvd;
162      } else {
163          return vd;
164      }
165  }
166  
167  //Returns a vector_desc entry for an source, the cpu parameter is used to tell GPIO_INT and GPIO_NMI from different CPUs
168  static vector_desc_t * find_desc_for_source(int source, int cpu)
169  {
170      vector_desc_t *vd=vector_desc_head;
171      while(vd!=NULL) {
172          if ( !(vd->flags & VECDESC_FL_SHARED) ) {
173              if ( vd->source == source && cpu == vd->cpu ) break;
174          } else if ( vd->cpu == cpu ) {
175              // check only shared vds for the correct cpu, otherwise skip
176              bool found = false;
177              shared_vector_desc_t *svd = vd->shared_vec_info;
178              assert(svd != NULL );
179              while(svd) {
180                  if ( svd->source == source ) {
181                      found = true;
182                      break;
183                  }
184                  svd = svd->next;
185              }
186              if ( found ) break;
187          }
188          vd=vd->next;
189      }
190      return vd;
191  }
192  
193  esp_err_t esp_intr_mark_shared(int intno, int cpu, bool is_int_ram)
194  {
195      if (intno>31) return ESP_ERR_INVALID_ARG;
196      if (cpu>=SOC_CPU_CORES_NUM) return ESP_ERR_INVALID_ARG;
197  
198      portENTER_CRITICAL(&spinlock);
199      vector_desc_t *vd=get_desc_for_int(intno, cpu);
200      if (vd==NULL) {
201          portEXIT_CRITICAL(&spinlock);
202          return ESP_ERR_NO_MEM;
203      }
204      vd->flags=VECDESC_FL_SHARED;
205      if (is_int_ram) vd->flags|=VECDESC_FL_INIRAM;
206      portEXIT_CRITICAL(&spinlock);
207  
208      return ESP_OK;
209  }
210  
211  esp_err_t esp_intr_reserve(int intno, int cpu)
212  {
213      if (intno>31) return ESP_ERR_INVALID_ARG;
214      if (cpu>=SOC_CPU_CORES_NUM) return ESP_ERR_INVALID_ARG;
215  
216      portENTER_CRITICAL(&spinlock);
217      vector_desc_t *vd=get_desc_for_int(intno, cpu);
218      if (vd==NULL) {
219          portEXIT_CRITICAL(&spinlock);
220          return ESP_ERR_NO_MEM;
221      }
222      vd->flags=VECDESC_FL_RESERVED;
223      portEXIT_CRITICAL(&spinlock);
224  
225      return ESP_OK;
226  }
227  
228  static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force)
229  {
230      //Check if interrupt is not reserved by design
231      int x = vd->intno;
232      if (interrupt_controller_hal_get_cpu_desc_flags(x, cpu)==INTDESC_RESVD) {
233          ALCHLOG("....Unusable: reserved");
234          return false;
235      }
236      if (interrupt_controller_hal_get_cpu_desc_flags(x, cpu)==INTDESC_SPECIAL && force==-1) {
237          ALCHLOG("....Unusable: special-purpose int");
238          return false;
239      }
240      //Check if the interrupt level is acceptable
241      if (!(flags&(1<<interrupt_controller_hal_get_level(x)))) {
242          ALCHLOG("....Unusable: incompatible level");
243          return false;
244      }
245      //check if edge/level type matches what we want
246      if (((flags&ESP_INTR_FLAG_EDGE) && (interrupt_controller_hal_get_type(x)==INTTP_LEVEL)) ||
247              (((!(flags&ESP_INTR_FLAG_EDGE)) && (interrupt_controller_hal_get_type(x)==INTTP_EDGE)))) {
248          ALCHLOG("....Unusable: incompatible trigger type");
249          return false;
250      }
251      //check if interrupt is reserved at runtime
252      if (vd->flags&VECDESC_FL_RESERVED)  {
253          ALCHLOG("....Unusable: reserved at runtime.");
254          return false;
255      }
256  
257      //Ints can't be both shared and non-shared.
258      assert(!((vd->flags&VECDESC_FL_SHARED)&&(vd->flags&VECDESC_FL_NONSHARED)));
259      //check if interrupt already is in use by a non-shared interrupt
260      if (vd->flags&VECDESC_FL_NONSHARED) {
261          ALCHLOG("....Unusable: already in (non-shared) use.");
262          return false;
263      }
264      // check shared interrupt flags
265      if (vd->flags&VECDESC_FL_SHARED ) {
266          if (flags&ESP_INTR_FLAG_SHARED) {
267              bool in_iram_flag=((flags&ESP_INTR_FLAG_IRAM)!=0);
268              bool desc_in_iram_flag=((vd->flags&VECDESC_FL_INIRAM)!=0);
269              //Bail out if int is shared, but iram property doesn't match what we want.
270              if ((vd->flags&VECDESC_FL_SHARED) && (desc_in_iram_flag!=in_iram_flag))  {
271                  ALCHLOG("....Unusable: shared but iram prop doesn't match");
272                  return false;
273              }
274          } else {
275              //We need an unshared IRQ; can't use shared ones; bail out if this is shared.
276              ALCHLOG("...Unusable: int is shared, we need non-shared.");
277              return false;
278          }
279      } else if (interrupt_controller_hal_has_handler(x, cpu)) {
280          //Check if interrupt already is allocated by interrupt_controller_hal_set_int_handler
281          ALCHLOG("....Unusable: already allocated");
282          return false;
283      }
284  
285      return true;
286  }
287  
288  //Locate a free interrupt compatible with the flags given.
289  //The 'force' argument can be -1, or 0-31 to force checking a certain interrupt.
290  //When a CPU is forced, the INTDESC_SPECIAL marked interrupts are also accepted.
291  static int get_available_int(int flags, int cpu, int force, int source)
292  {
293      int x;
294      int best=-1;
295      int bestLevel=9;
296      int bestSharedCt=INT_MAX;
297  
298      //Default vector desc, for vectors not in the linked list
299      vector_desc_t empty_vect_desc;
300      memset(&empty_vect_desc, 0, sizeof(vector_desc_t));
301  
302      //Level defaults to any low/med interrupt
303      if (!(flags&ESP_INTR_FLAG_LEVELMASK)) flags|=ESP_INTR_FLAG_LOWMED;
304  
305      ALCHLOG("get_available_int: try to find existing. Cpu: %d, Source: %d", cpu, source);
306      vector_desc_t *vd = find_desc_for_source(source, cpu);
307      if ( vd ) {
308          // if existing vd found, don't need to search any more.
309          ALCHLOG("get_avalible_int: existing vd found. intno: %d", vd->intno);
310          if ( force != -1 && force != vd->intno ) {
311              ALCHLOG("get_avalible_int: intr forced but not matach existing. existing intno: %d, force: %d", vd->intno, force);
312          } else if ( !is_vect_desc_usable(vd, flags, cpu, force) ) {
313              ALCHLOG("get_avalible_int: existing vd invalid.");
314          } else {
315              best = vd->intno;
316          }
317          return best;
318      }
319      if (force!=-1) {
320          ALCHLOG("get_available_int: try to find force. Cpu: %d, Source: %d, Force: %d", cpu, source, force);
321          //if force assigned, don't need to search any more.
322          vd = find_desc_for_int(force, cpu);
323          if (vd == NULL ) {
324              //if existing vd not found, just check the default state for the intr.
325              empty_vect_desc.intno = force;
326              vd = &empty_vect_desc;
327          }
328          if ( is_vect_desc_usable(vd, flags, cpu, force) ) {
329              best = vd->intno;
330          } else {
331              ALCHLOG("get_avalible_int: forced vd invalid.");
332          }
333          return best;
334      }
335  
336      ALCHLOG("get_free_int: start looking. Current cpu: %d", cpu);
337      //No allocated handlers as well as forced intr, iterate over the 32 possible interrupts
338      for (x=0; x<32; x++) {
339          //Grab the vector_desc for this vector.
340          vd=find_desc_for_int(x, cpu);
341          if (vd==NULL) {
342              empty_vect_desc.intno = x;
343              vd=&empty_vect_desc;
344          }
345  
346          ALCHLOG("Int %d reserved %d level %d %s hasIsr %d",
347              x, interrupt_controller_hal_get_cpu_desc_flags(x,cpu)==INTDESC_RESVD, interrupt_controller_hal_get_level(x),
348              interrupt_controller_hal_get_type(x)==INTTP_LEVEL?"LEVEL":"EDGE", interrupt_controller_hal_has_handler(x, cpu));
349  
350          if ( !is_vect_desc_usable(vd, flags, cpu, force) ) continue;
351  
352          if (flags&ESP_INTR_FLAG_SHARED) {
353              //We're allocating a shared int.
354  
355              //See if int already is used as a shared interrupt.
356              if (vd->flags&VECDESC_FL_SHARED) {
357                  //We can use this already-marked-as-shared interrupt. Count the already attached isrs in order to see
358                  //how useful it is.
359                  int no=0;
360                  shared_vector_desc_t *svdesc=vd->shared_vec_info;
361                  while (svdesc!=NULL) {
362                      no++;
363                      svdesc=svdesc->next;
364                  }
365                  if (no<bestSharedCt || bestLevel>interrupt_controller_hal_get_level(x)) {
366                      //Seems like this shared vector is both okay and has the least amount of ISRs already attached to it.
367                      best=x;
368                      bestSharedCt=no;
369                      bestLevel=interrupt_controller_hal_get_level(x);
370                      ALCHLOG("...int %d more usable as a shared int: has %d existing vectors", x, no);
371                  } else {
372                      ALCHLOG("...worse than int %d", best);
373                  }
374              } else {
375                  if (best==-1) {
376                      //We haven't found a feasible shared interrupt yet. This one is still free and usable, even if
377                      //not marked as shared.
378                      //Remember it in case we don't find any other shared interrupt that qualifies.
379                      if (bestLevel>interrupt_controller_hal_get_level(x)) {
380                          best=x;
381                          bestLevel=interrupt_controller_hal_get_level(x);
382                          ALCHLOG("...int %d usable as a new shared int", x);
383                      }
384                  } else {
385                      ALCHLOG("...already have a shared int");
386                  }
387              }
388          } else {
389              //Seems this interrupt is feasible. Select it and break out of the loop; no need to search further.
390              if (bestLevel>interrupt_controller_hal_get_level(x)) {
391                  best=x;
392                  bestLevel=interrupt_controller_hal_get_level(x);
393              } else {
394                  ALCHLOG("...worse than int %d", best);
395              }
396          }
397      }
398      ALCHLOG("get_available_int: using int %d", best);
399  
400      //Okay, by now we have looked at all potential interrupts and hopefully have selected the best one in best.
401      return best;
402  }
403  
404  //Common shared isr handler. Chain-call all ISRs.
405  static void IRAM_ATTR shared_intr_isr(void *arg)
406  {
407      vector_desc_t *vd=(vector_desc_t*)arg;
408      shared_vector_desc_t *sh_vec=vd->shared_vec_info;
409      portENTER_CRITICAL_ISR(&spinlock);
410      while(sh_vec) {
411          if (!sh_vec->disabled) {
412              if ((sh_vec->statusreg == NULL) || (*sh_vec->statusreg & sh_vec->statusmask)) {
413  #if CONFIG_SYSVIEW_ENABLE
414                  traceISR_ENTER(sh_vec->source+ETS_INTERNAL_INTR_SOURCE_OFF);
415  #endif
416                  sh_vec->isr(sh_vec->arg);
417  #if CONFIG_SYSVIEW_ENABLE
418                  // check if we will return to scheduler or to interrupted task after ISR
419                  if (!port_switch_flag[cpu_hal_get_core_id()]) {
420                      traceISR_EXIT();
421                  }
422  #endif
423              }
424          }
425          sh_vec=sh_vec->next;
426      }
427      portEXIT_CRITICAL_ISR(&spinlock);
428  }
429  
430  #if CONFIG_SYSVIEW_ENABLE
431  //Common non-shared isr handler wrapper.
432  static void IRAM_ATTR non_shared_intr_isr(void *arg)
433  {
434      non_shared_isr_arg_t *ns_isr_arg=(non_shared_isr_arg_t*)arg;
435      portENTER_CRITICAL_ISR(&spinlock);
436      traceISR_ENTER(ns_isr_arg->source+ETS_INTERNAL_INTR_SOURCE_OFF);
437      // FIXME: can we call ISR and check port_switch_flag after releasing spinlock?
438      // when CONFIG_SYSVIEW_ENABLE = 0 ISRs for non-shared IRQs are called without spinlock
439      ns_isr_arg->isr(ns_isr_arg->isr_arg);
440      // check if we will return to scheduler or to interrupted task after ISR
441      if (!port_switch_flag[cpu_hal_get_core_id()]) {
442          traceISR_EXIT();
443      }
444      portEXIT_CRITICAL_ISR(&spinlock);
445  }
446  #endif
447  
448  //We use ESP_EARLY_LOG* here because this can be called before the scheduler is running.
449  esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusreg, uint32_t intrstatusmask, intr_handler_t handler,
450                                          void *arg, intr_handle_t *ret_handle)
451  {
452      intr_handle_data_t *ret=NULL;
453      int force=-1;
454      ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): checking args", cpu_hal_get_core_id());
455      //Shared interrupts should be level-triggered.
456      if ((flags&ESP_INTR_FLAG_SHARED) && (flags&ESP_INTR_FLAG_EDGE)) return ESP_ERR_INVALID_ARG;
457      //You can't set an handler / arg for a non-C-callable interrupt.
458      if ((flags&ESP_INTR_FLAG_HIGH) && (handler)) return ESP_ERR_INVALID_ARG;
459      //Shared ints should have handler and non-processor-local source
460      if ((flags&ESP_INTR_FLAG_SHARED) && (!handler || source<0)) return ESP_ERR_INVALID_ARG;
461      //Statusreg should have a mask
462      if (intrstatusreg && !intrstatusmask) return ESP_ERR_INVALID_ARG;
463      //If the ISR is marked to be IRAM-resident, the handler must not be in the cached region
464      //ToDo: if we are to allow placing interrupt handlers into the 0x400c0000—0x400c2000 region,
465      //we need to make sure the interrupt is connected to the CPU0.
466      //CPU1 does not have access to the RTC fast memory through this region.
467      if ((flags&ESP_INTR_FLAG_IRAM) &&
468              (ptrdiff_t) handler >= SOC_RTC_IRAM_HIGH &&
469              (ptrdiff_t) handler < SOC_RTC_DATA_LOW ) {
470          return ESP_ERR_INVALID_ARG;
471      }
472  
473      //Default to prio 1 for shared interrupts. Default to prio 1, 2 or 3 for non-shared interrupts.
474      if ((flags&ESP_INTR_FLAG_LEVELMASK)==0) {
475          if (flags&ESP_INTR_FLAG_SHARED) {
476              flags|=ESP_INTR_FLAG_LEVEL1;
477          } else {
478              flags|=ESP_INTR_FLAG_LOWMED;
479          }
480      }
481      ESP_EARLY_LOGV(TAG, "esp_intr_alloc_intrstatus (cpu %d): Args okay. Resulting flags 0x%X", cpu_hal_get_core_id(), flags);
482  
483      //Check 'special' interrupt sources. These are tied to one specific interrupt, so we
484      //have to force get_free_int to only look at that.
485      if (source==ETS_INTERNAL_TIMER0_INTR_SOURCE) force=ETS_INTERNAL_TIMER0_INTR_NO;
486      if (source==ETS_INTERNAL_TIMER1_INTR_SOURCE) force=ETS_INTERNAL_TIMER1_INTR_NO;
487      if (source==ETS_INTERNAL_TIMER2_INTR_SOURCE) force=ETS_INTERNAL_TIMER2_INTR_NO;
488      if (source==ETS_INTERNAL_SW0_INTR_SOURCE) force=ETS_INTERNAL_SW0_INTR_NO;
489      if (source==ETS_INTERNAL_SW1_INTR_SOURCE) force=ETS_INTERNAL_SW1_INTR_NO;
490      if (source==ETS_INTERNAL_PROFILING_INTR_SOURCE) force=ETS_INTERNAL_PROFILING_INTR_NO;
491  
492      //Allocate a return handle. If we end up not needing it, we'll free it later on.
493      ret=heap_caps_malloc(sizeof(intr_handle_data_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
494      if (ret==NULL) return ESP_ERR_NO_MEM;
495  
496      portENTER_CRITICAL(&spinlock);
497      int cpu=cpu_hal_get_core_id();
498      //See if we can find an interrupt that matches the flags.
499      int intr=get_available_int(flags, cpu, force, source);
500      if (intr==-1) {
501          //None found. Bail out.
502          portEXIT_CRITICAL(&spinlock);
503          free(ret);
504          return ESP_ERR_NOT_FOUND;
505      }
506      //Get an int vector desc for int.
507      vector_desc_t *vd=get_desc_for_int(intr, cpu);
508      if (vd==NULL) {
509          portEXIT_CRITICAL(&spinlock);
510          free(ret);
511          return ESP_ERR_NO_MEM;
512      }
513  
514      //Allocate that int!
515      if (flags&ESP_INTR_FLAG_SHARED) {
516          //Populate vector entry and add to linked list.
517          shared_vector_desc_t *sh_vec=malloc(sizeof(shared_vector_desc_t));
518          if (sh_vec==NULL) {
519              portEXIT_CRITICAL(&spinlock);
520              free(ret);
521              return ESP_ERR_NO_MEM;
522          }
523          memset(sh_vec, 0, sizeof(shared_vector_desc_t));
524          sh_vec->statusreg=(uint32_t*)intrstatusreg;
525          sh_vec->statusmask=intrstatusmask;
526          sh_vec->isr=handler;
527          sh_vec->arg=arg;
528          sh_vec->next=vd->shared_vec_info;
529          sh_vec->source=source;
530          sh_vec->disabled=0;
531          vd->shared_vec_info=sh_vec;
532          vd->flags|=VECDESC_FL_SHARED;
533          //(Re-)set shared isr handler to new value.
534          xt_set_interrupt_handler(intr, shared_intr_isr, vd);
535      } else {
536          //Mark as unusable for other interrupt sources. This is ours now!
537          vd->flags=VECDESC_FL_NONSHARED;
538          if (handler) {
539  #if CONFIG_SYSVIEW_ENABLE
540              non_shared_isr_arg_t *ns_isr_arg=malloc(sizeof(non_shared_isr_arg_t));
541              if (!ns_isr_arg) {
542                  portEXIT_CRITICAL(&spinlock);
543                  free(ret);
544                  return ESP_ERR_NO_MEM;
545              }
546              ns_isr_arg->isr=handler;
547              ns_isr_arg->isr_arg=arg;
548              ns_isr_arg->source=source;
549              interrupt_controller_hal_set_int_handler(intr, non_shared_intr_isr, ns_isr_arg);
550  #else
551              interrupt_controller_hal_set_int_handler(intr, handler, arg);
552  #endif
553          }
554          if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr);
555          vd->source=source;
556      }
557      if (flags&ESP_INTR_FLAG_IRAM) {
558          vd->flags|=VECDESC_FL_INIRAM;
559          non_iram_int_mask[cpu]&=~(1<<intr);
560      } else {
561          vd->flags&=~VECDESC_FL_INIRAM;
562          non_iram_int_mask[cpu]|=(1<<intr);
563      }
564      if (source>=0) {
565          intr_matrix_set(cpu, source, intr);
566      }
567  
568      //Fill return handle data.
569      ret->vector_desc=vd;
570      ret->shared_vector_desc=vd->shared_vec_info;
571  
572      //Enable int at CPU-level;
573      ESP_INTR_ENABLE(intr);
574  
575      //If interrupt has to be started disabled, do that now; ints won't be enabled for real until the end
576      //of the critical section.
577      if (flags&ESP_INTR_FLAG_INTRDISABLED) {
578          esp_intr_disable(ret);
579      }
580  
581      portEXIT_CRITICAL(&spinlock);
582  
583      //Fill return handle if needed, otherwise free handle.
584      if (ret_handle!=NULL) {
585          *ret_handle=ret;
586      } else {
587          free(ret);
588      }
589  
590      ESP_EARLY_LOGD(TAG, "Connected src %d to int %d (cpu %d)", source, intr, cpu);
591      return ESP_OK;
592  }
593  
594  esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, intr_handle_t *ret_handle)
595  {
596      /*
597        As an optimization, we can create a table with the possible interrupt status registers and masks for every single
598        source there is. We can then add code here to look up an applicable value and pass that to the
599        esp_intr_alloc_intrstatus function.
600      */
601      return esp_intr_alloc_intrstatus(source, flags, 0, 0, handler, arg, ret_handle);
602  }
603  
604  esp_err_t IRAM_ATTR esp_intr_set_in_iram(intr_handle_t handle, bool is_in_iram)
605  {
606      if (!handle) return ESP_ERR_INVALID_ARG;
607      vector_desc_t *vd = handle->vector_desc;
608      if (vd->flags & VECDESC_FL_SHARED) {
609        return ESP_ERR_INVALID_ARG;
610      }
611      portENTER_CRITICAL(&spinlock);
612      uint32_t mask = (1 << vd->intno);
613      if (is_in_iram) {
614          vd->flags |= VECDESC_FL_INIRAM;
615          non_iram_int_mask[vd->cpu] &= ~mask;
616      } else {
617          vd->flags &= ~VECDESC_FL_INIRAM;
618          non_iram_int_mask[vd->cpu] |= mask;
619      }
620      portEXIT_CRITICAL(&spinlock);
621      return ESP_OK;
622  }
623  
624  #if !CONFIG_FREERTOS_UNICORE
625  static void esp_intr_free_cb(void *arg)
626  {
627      (void)esp_intr_free((intr_handle_t)arg);
628  }
629  #endif /* !CONFIG_FREERTOS_UNICORE */
630  
631  esp_err_t esp_intr_free(intr_handle_t handle)
632  {
633      bool free_shared_vector=false;
634      if (!handle) return ESP_ERR_INVALID_ARG;
635  
636  #if !CONFIG_FREERTOS_UNICORE
637      //Assign this routine to the core where this interrupt is allocated on.
638      if (handle->vector_desc->cpu!=cpu_hal_get_core_id()) {
639          esp_err_t ret = esp_ipc_call_blocking(handle->vector_desc->cpu, &esp_intr_free_cb, (void *)handle);
640          return ret == ESP_OK ? ESP_OK : ESP_FAIL;
641      }
642  #endif /* !CONFIG_FREERTOS_UNICORE */
643  
644      portENTER_CRITICAL(&spinlock);
645      esp_intr_disable(handle);
646      if (handle->vector_desc->flags&VECDESC_FL_SHARED) {
647          //Find and kill the shared int
648          shared_vector_desc_t *svd=handle->vector_desc->shared_vec_info;
649          shared_vector_desc_t *prevsvd=NULL;
650          assert(svd); //should be something in there for a shared int
651          while (svd!=NULL) {
652              if (svd==handle->shared_vector_desc) {
653                  //Found it. Now kill it.
654                  if (prevsvd) {
655                      prevsvd->next=svd->next;
656                  } else {
657                      handle->vector_desc->shared_vec_info=svd->next;
658                  }
659                  free(svd);
660                  break;
661              }
662              prevsvd=svd;
663              svd=svd->next;
664          }
665          //If nothing left, disable interrupt.
666          if (handle->vector_desc->shared_vec_info==NULL) free_shared_vector=true;
667          ESP_EARLY_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");
668      }
669  
670      if ((handle->vector_desc->flags&VECDESC_FL_NONSHARED) || free_shared_vector) {
671          ESP_EARLY_LOGV(TAG, "esp_intr_free: Disabling int, killing handler");
672  #if CONFIG_SYSVIEW_ENABLE
673          if (!free_shared_vector) {
674              void *isr_arg = interrupt_controller_hal_get_int_handler_arg(handle->vector_desc->intno);
675              if (isr_arg) {
676                  free(isr_arg);
677              }
678          }
679  #endif
680          //Reset to normal handler:
681          interrupt_controller_hal_set_int_handler(handle->vector_desc->intno, NULL, (void*)((int)handle->vector_desc->intno));
682          //Theoretically, we could free the vector_desc... not sure if that's worth the few bytes of memory
683          //we save.(We can also not use the same exit path for empty shared ints anymore if we delete
684          //the desc.) For now, just mark it as free.
685          handle->vector_desc->flags&=!(VECDESC_FL_NONSHARED|VECDESC_FL_RESERVED);
686          //Also kill non_iram mask bit.
687          non_iram_int_mask[handle->vector_desc->cpu]&=~(1<<(handle->vector_desc->intno));
688      }
689      portEXIT_CRITICAL(&spinlock);
690      free(handle);
691      return ESP_OK;
692  }
693  
694  int esp_intr_get_intno(intr_handle_t handle)
695  {
696      return handle->vector_desc->intno;
697  }
698  
699  int esp_intr_get_cpu(intr_handle_t handle)
700  {
701      return handle->vector_desc->cpu;
702  }
703  
704  /*
705   Interrupt disabling strategy:
706   If the source is >=0 (meaning a muxed interrupt), we disable it by muxing the interrupt to a non-connected
707   interrupt. If the source is <0 (meaning an internal, per-cpu interrupt), we disable it using ESP_INTR_DISABLE.
708   This allows us to, for the muxed CPUs, disable an int from the other core. It also allows disabling shared
709   interrupts.
710   */
711  
712  //Muxing an interrupt source to interrupt 6, 7, 11, 15, 16 or 29 cause the interrupt to effectively be disabled.
713  #define INT_MUX_DISABLED_INTNO 6
714  
715  esp_err_t IRAM_ATTR esp_intr_enable(intr_handle_t handle)
716  {
717      if (!handle) return ESP_ERR_INVALID_ARG;
718      portENTER_CRITICAL_SAFE(&spinlock);
719      int source;
720      if (handle->shared_vector_desc) {
721          handle->shared_vector_desc->disabled=0;
722          source=handle->shared_vector_desc->source;
723      } else {
724          source=handle->vector_desc->source;
725      }
726      if (source >= 0) {
727          //Disabled using int matrix; re-connect to enable
728          intr_matrix_set(handle->vector_desc->cpu, source, handle->vector_desc->intno);
729      } else {
730          //Re-enable using cpu int ena reg
731          if (handle->vector_desc->cpu!=cpu_hal_get_core_id()) return ESP_ERR_INVALID_ARG; //Can only enable these ints on this cpu
732          ESP_INTR_ENABLE(handle->vector_desc->intno);
733      }
734      portEXIT_CRITICAL_SAFE(&spinlock);
735      return ESP_OK;
736  }
737  
738  esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle)
739  {
740      if (!handle) return ESP_ERR_INVALID_ARG;
741      portENTER_CRITICAL_SAFE(&spinlock);
742      int source;
743      bool disabled = 1;
744      if (handle->shared_vector_desc) {
745          handle->shared_vector_desc->disabled=1;
746          source=handle->shared_vector_desc->source;
747  
748          shared_vector_desc_t *svd=handle->vector_desc->shared_vec_info;
749          assert( svd != NULL );
750          while( svd ) {
751              if ( svd->source == source && svd->disabled == 0 ) {
752                  disabled = 0;
753                  break;
754              }
755              svd = svd->next;
756          }
757      } else {
758          source=handle->vector_desc->source;
759      }
760  
761      if (source >= 0) {
762          if ( disabled ) {
763              //Disable using int matrix
764              intr_matrix_set(handle->vector_desc->cpu, source, INT_MUX_DISABLED_INTNO);
765          }
766      } else {
767          //Disable using per-cpu regs
768          if (handle->vector_desc->cpu!=cpu_hal_get_core_id()) {
769              portEXIT_CRITICAL_SAFE(&spinlock);
770              return ESP_ERR_INVALID_ARG; //Can only enable these ints on this cpu
771          }
772          ESP_INTR_DISABLE(handle->vector_desc->intno);
773      }
774      portEXIT_CRITICAL_SAFE(&spinlock);
775      return ESP_OK;
776  }
777  
778  void IRAM_ATTR esp_intr_noniram_disable(void)
779  {
780      uint32_t oldint;
781      int cpu=cpu_hal_get_core_id();
782      uint32_t intmask=~non_iram_int_mask[cpu];
783      if (non_iram_int_disabled_flag[cpu]) abort();
784      non_iram_int_disabled_flag[cpu]=true;
785      oldint = interrupt_controller_hal_disable_int_mask(intmask);
786      //Save which ints we did disable
787      non_iram_int_disabled[cpu]=oldint&non_iram_int_mask[cpu];
788  }
789  
790  void IRAM_ATTR esp_intr_noniram_enable(void)
791  {
792      int cpu=cpu_hal_get_core_id();
793      int intmask=non_iram_int_disabled[cpu];
794      if (!non_iram_int_disabled_flag[cpu]) abort();
795      non_iram_int_disabled_flag[cpu]=false;
796      interrupt_controller_hal_enable_int_mask(intmask);
797  }
798  
799  //These functions are provided in ROM, but the ROM-based functions use non-multicore-capable
800  //virtualized interrupt levels. Thus, we disable them in the ld file and provide working
801  //equivalents here.
802  
803  
804  void IRAM_ATTR ets_isr_unmask(unsigned int mask) {
805      interrupt_controller_hal_enable_interrupts(mask);
806  }
807  
808  void IRAM_ATTR ets_isr_mask(unsigned int mask) {
809      interrupt_controller_hal_disable_interrupts(mask);
810  }
811  
812  void esp_intr_enable_source(int inum) 
813  {
814      interrupt_controller_hal_enable_interrupts(1 << inum);
815  }
816  
817  void esp_intr_disable_source(int inum)
818  {
819      interrupt_controller_hal_disable_interrupts(1 << inum);
820  }