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 }