Skip to content

Commit f22de97

Browse files
sylvioalvesfabiobaltieri
authored andcommitted
soc: esp32: riscv: fix interrupt allocator
Current interrupt allocator is not taking into account reserved areas. In case of esp32c6, Wi-Fi isn't properly configured, causing instability or even non-functional feature. This adds the reserved area ranges for all risc-v based SoC and unify the slot finding based on interrupt source. Signed-off-by: Sylvio Alves <[email protected]>
1 parent fff5004 commit f22de97

File tree

3 files changed

+110
-124
lines changed

3 files changed

+110
-124
lines changed
Lines changed: 103 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
2+
* Copyright (c) 2021-2025 Espressif Systems (Shanghai) Co., Ltd.
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -19,10 +19,8 @@
1919
#include <zephyr/sw_isr_table.h>
2020
#include <riscv/interrupt.h>
2121

22-
#define ESP32C3_INTC_DEFAULT_PRIO 15
23-
2422
#include <zephyr/logging/log.h>
25-
LOG_MODULE_REGISTER(intc_esp32c3, CONFIG_LOG_DEFAULT_LEVEL);
23+
LOG_MODULE_REGISTER(intc_esp32, CONFIG_LOG_DEFAULT_LEVEL);
2624

2725
/*
2826
* Define this to debug the choices made when allocating the interrupt. This leads to much debugging
@@ -35,132 +33,118 @@ LOG_MODULE_REGISTER(intc_esp32c3, CONFIG_LOG_DEFAULT_LEVEL);
3533
# define INTC_LOG(...) do {} while (0)
3634
#endif
3735

38-
#define ESP32C3_INTC_DEFAULT_PRIORITY 15
39-
#define ESP32C3_INTC_DEFAULT_THRESHOLD 1
40-
#define ESP32C3_INTC_DISABLED_SLOT 31
41-
#define ESP32C3_INTC_SRCS_PER_IRQ 2
42-
#define ESP32C3_INTC_AVAILABLE_IRQS 30
36+
#define ESP32_INTC_DEFAULT_PRIORITY 15
37+
#define ESP32_INTC_DEFAULT_THRESHOLD 1
38+
#define ESP32_INTC_DISABLED_SLOT 31
39+
#define ESP32_INTC_SRCS_PER_IRQ 2
4340

41+
/* Define maximum interrupt sources per SoC */
4442
#if defined(CONFIG_SOC_SERIES_ESP32C6)
45-
46-
#define IRQ_NA 0xFF /* IRQ not available */
47-
#define IRQ_FREE 0xFE
48-
49-
#define ESP32C6_INTC_SRCS_PER_IRQ 2
50-
#define ESP32C6_INTC_AVAILABLE_IRQS 31
51-
52-
/* Interrupt overview for ESP32C6:
53-
* - 0, 3, 4, and 7 are used by the CPU for core-local interrupts (CLINT)
54-
* - 1 is used for Wi-Fi in Espressif HAL
55-
* - 2, 5, 6, 8 .. 31 are available for Zephyr
56-
* - 31 is reserved for disabled interrupts
43+
/*
44+
* Interrupt reserved mask
45+
* 0 is reserved
46+
* 1 is for Wi-Fi
47+
* 3, 4 and 7 are unavailable for PULP CPU as they are bound to Core-Local Interrupts (CLINT)
48+
*/
49+
#define RSVD_MASK (BIT(0) | BIT(1) | BIT(3) | BIT(4) | BIT(7))
50+
#define ESP_INTC_AVAILABLE_IRQS 31
51+
#else
52+
/*
53+
* Interrupt reserved mask
54+
* 1 is for Wi-Fi
5755
*/
58-
static uint8_t esp_intr_irq_alloc[ESP32C6_INTC_AVAILABLE_IRQS][ESP32C6_INTC_SRCS_PER_IRQ] = {
59-
[0] = {IRQ_NA, IRQ_NA},
60-
[1] = {IRQ_NA, IRQ_NA},
61-
[2] = {IRQ_FREE, IRQ_FREE},
62-
[3] = {IRQ_NA, IRQ_NA},
63-
[4] = {IRQ_NA, IRQ_NA},
64-
[5 ... 6] = {IRQ_FREE, IRQ_FREE},
65-
[7] = {IRQ_NA, IRQ_NA},
66-
[8 ... 30] = {IRQ_FREE, IRQ_FREE}
67-
};
56+
#define RSVD_MASK (BIT(0) | BIT(1))
57+
#define ESP_INTC_AVAILABLE_IRQS 30
6858
#endif
6959

70-
#define STATUS_MASK_NUM 3
60+
/* Single array for IRQ allocation */
61+
static uint8_t esp_intr_irq_alloc[ESP_INTC_AVAILABLE_IRQS * ESP32_INTC_SRCS_PER_IRQ];
7162

72-
static uint32_t esp_intr_enabled_mask[STATUS_MASK_NUM] = {0, 0, 0};
63+
#define ESP_INTR_IDX(irq, slot) ((irq % ESP_INTC_AVAILABLE_IRQS) * ESP32_INTC_SRCS_PER_IRQ + slot)
64+
65+
#define STATUS_MASK_NUM 3
7366

74-
#if defined(CONFIG_SOC_SERIES_ESP32C2) || defined(CONFIG_SOC_SERIES_ESP32C3)
67+
static uint32_t esp_intr_enabled_mask[STATUS_MASK_NUM] = {0, 0, 0};
7568

7669
static uint32_t esp_intr_find_irq_for_source(uint32_t source)
7770
{
78-
/* in general case, each 2 sources goes routed to
79-
* 1 IRQ line.
80-
*/
81-
uint32_t irq = (source / ESP32C3_INTC_SRCS_PER_IRQ);
82-
83-
if (irq > ESP32C3_INTC_AVAILABLE_IRQS) {
84-
INTC_LOG("Clamping the source: %d no more IRQs available", source);
85-
irq = ESP32C3_INTC_AVAILABLE_IRQS;
86-
} else if (irq == 0) {
87-
irq = 1;
71+
if (source >= ETS_MAX_INTR_SOURCE) {
72+
return IRQ_NA;
8873
}
8974

90-
INTC_LOG("Found IRQ: %d for source: %d", irq, source);
75+
uint32_t irq = source / ESP32_INTC_SRCS_PER_IRQ;
9176

92-
return irq;
93-
}
77+
/* Check if the derived IRQ is usable first */
78+
for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) {
79+
int idx = ESP_INTR_IDX(irq, j);
9480

95-
#elif defined(CONFIG_SOC_SERIES_ESP32C6)
81+
/* Ensure idx is within a valid range */
82+
if (idx >= ARRAY_SIZE(esp_intr_irq_alloc)) {
83+
continue;
84+
}
9685

97-
static uint32_t esp_intr_find_irq_for_source(uint32_t source)
98-
{
99-
uint32_t irq = IRQ_NA;
100-
uint32_t irq_free = IRQ_NA;
101-
uint8_t *irq_ptr = NULL;
102-
103-
/* First allocate one source per IRQ, then two
104-
* if there are more sources than free IRQs
105-
*/
106-
for (int j = 0; j < ESP32C6_INTC_SRCS_PER_IRQ; j++) {
107-
for (int i = 0; i < ESP32C6_INTC_AVAILABLE_IRQS; i++) {
108-
/* Find first free slot but keep searching to see
109-
* if source is already associated to an IRQ
110-
*/
111-
if (esp_intr_irq_alloc[i][j] == source) {
112-
/* Source is already associated to an IRQ */
113-
irq = i;
114-
goto found;
115-
} else if ((irq_free == IRQ_NA) && (esp_intr_irq_alloc[i][j] == IRQ_FREE)) {
116-
irq_free = i;
117-
irq_ptr = &esp_intr_irq_alloc[i][j];
118-
}
86+
/* If source is already assigned, return the IRQ */
87+
if (esp_intr_irq_alloc[idx] == source) {
88+
return irq;
11989
}
120-
}
12190

122-
if (irq_ptr != NULL) {
123-
*irq_ptr = (uint8_t)source;
124-
irq = irq_free;
125-
} else {
126-
return IRQ_NA;
91+
/* If slot is free, allocate it */
92+
if (esp_intr_irq_alloc[idx] == IRQ_FREE) {
93+
esp_intr_irq_alloc[idx] = source;
94+
return irq;
95+
}
12796
}
12897

129-
found:
130-
INTC_LOG("Found IRQ: %d for source: %d", irq, source);
98+
/* If derived IRQ is full, search for another available IRQ */
99+
for (irq = 0; irq < ESP_INTC_AVAILABLE_IRQS; irq++) {
100+
if (RSVD_MASK & (1U << irq)) {
101+
continue;
102+
}
103+
for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) {
104+
int idx = ESP_INTR_IDX(irq, j);
131105

132-
return irq;
133-
}
106+
/* Ensure idx is within a valid range */
107+
if (idx >= ARRAY_SIZE(esp_intr_irq_alloc)) {
108+
continue;
109+
}
134110

135-
#endif
111+
/* If source is already assigned, return this IRQ */
112+
if (esp_intr_irq_alloc[idx] == source) {
113+
return irq;
114+
}
136115

137-
void esp_intr_initialize(void)
138-
{
139-
/* IRQ 31 is reserved for disabled interrupts,
140-
* so route all sources to it
141-
*/
142-
for (int i = 0 ; i < ESP32C3_INTC_AVAILABLE_IRQS + 2; i++) {
143-
irq_disable(i);
116+
/* If slot is free, allocate it */
117+
if (esp_intr_irq_alloc[idx] == IRQ_FREE) {
118+
esp_intr_irq_alloc[idx] = source;
119+
return irq;
120+
}
121+
}
144122
}
145123

124+
/* No available slot found */
125+
return IRQ_NA;
126+
}
127+
128+
void esp_intr_initialize(void)
129+
{
146130
for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) {
147-
esp_rom_intr_matrix_set(0, i, ESP32C3_INTC_DISABLED_SLOT);
131+
esp_rom_intr_matrix_set(0, i, ESP32_INTC_DISABLED_SLOT);
148132
}
149133

150-
#if defined(CONFIG_SOC_SERIES_ESP32C6)
151-
/* Clear up IRQ allocation */
152-
for (int j = 0; j < ESP32C6_INTC_SRCS_PER_IRQ; j++) {
153-
for (int i = 0; i < ESP32C6_INTC_AVAILABLE_IRQS; i++) {
154-
/* screen out reserved IRQs */
155-
if (esp_intr_irq_alloc[i][j] != IRQ_NA) {
156-
esp_intr_irq_alloc[i][j] = IRQ_FREE;
134+
for (int irq = 0; irq < ESP_INTC_AVAILABLE_IRQS; irq++) {
135+
for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) {
136+
int idx = ESP_INTR_IDX(irq, j);
137+
138+
if (RSVD_MASK & (1U << irq)) {
139+
esp_intr_irq_alloc[idx] = IRQ_NA;
140+
} else {
141+
esp_intr_irq_alloc[idx] = IRQ_FREE;
157142
}
158143
}
159144
}
160-
#endif
161145

162-
/* set global esp32c3's INTC masking level */
163-
esprv_intc_int_set_threshold(ESP32C3_INTC_DEFAULT_THRESHOLD);
146+
/* set global INTC masking level */
147+
esprv_intc_int_set_threshold(ESP32_INTC_DEFAULT_THRESHOLD);
164148
}
165149

166150
int esp_intr_alloc(int source,
@@ -181,21 +165,19 @@ int esp_intr_alloc(int source,
181165
}
182166

183167
uint32_t key = irq_lock();
168+
uint32_t irq = esp_intr_find_irq_for_source(source);
169+
170+
if (irq == IRQ_NA) {
171+
irq_unlock(key);
172+
return -ENOMEM;
173+
}
184174

185175
irq_connect_dynamic(source,
186-
ESP32C3_INTC_DEFAULT_PRIORITY,
176+
ESP32_INTC_DEFAULT_PRIORITY,
187177
handler,
188178
arg,
189179
0);
190180

191-
if (source < 32) {
192-
esp_intr_enabled_mask[0] |= (1 << source);
193-
} else if (source < 64) {
194-
esp_intr_enabled_mask[1] |= (1 << (source - 32));
195-
} else if (source < 96) {
196-
esp_intr_enabled_mask[2] |= (1 << (source - 64));
197-
}
198-
199181
INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
200182
esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
201183

@@ -215,19 +197,20 @@ int esp_intr_disable(int source)
215197

216198
esp_rom_intr_matrix_set(0,
217199
source,
218-
ESP32C3_INTC_DISABLED_SLOT);
200+
ESP32_INTC_DISABLED_SLOT);
219201

220-
#if defined(CONFIG_SOC_SERIES_ESP32C6)
221-
for (int j = 0; j < ESP32C6_INTC_SRCS_PER_IRQ; j++) {
222-
for (int i = 0; i < ESP32C6_INTC_AVAILABLE_IRQS; i++) {
223-
if (esp_intr_irq_alloc[i][j] == source) {
224-
esp_intr_irq_alloc[i][j] = IRQ_FREE;
225-
goto freed;
202+
for (int i = 0; i < ESP_INTC_AVAILABLE_IRQS; i++) {
203+
if (RSVD_MASK & (1U << i)) {
204+
continue;
205+
}
206+
for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) {
207+
int idx = ESP_INTR_IDX(i, j);
208+
209+
if (esp_intr_irq_alloc[idx] == source) {
210+
esp_intr_irq_alloc[idx] = IRQ_FREE;
226211
}
227212
}
228213
}
229-
freed:
230-
#endif
231214

232215
if (source < 32) {
233216
esp_intr_enabled_mask[0] &= ~(1 << source);
@@ -254,12 +237,10 @@ int esp_intr_enable(int source)
254237
uint32_t key = irq_lock();
255238
uint32_t irq = esp_intr_find_irq_for_source(source);
256239

257-
#if defined(CONFIG_SOC_SERIES_ESP32C6)
258240
if (irq == IRQ_NA) {
259241
irq_unlock(key);
260242
return -ENOMEM;
261243
}
262-
#endif
263244

264245
esp_rom_intr_matrix_set(0, source, irq);
265246

@@ -274,7 +255,7 @@ int esp_intr_enable(int source)
274255
INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
275256
esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
276257

277-
esprv_intc_int_set_priority(irq, ESP32C3_INTC_DEFAULT_PRIO);
258+
esprv_intc_int_set_priority(irq, ESP32_INTC_DEFAULT_PRIORITY);
278259
esprv_intc_int_set_type(irq, INTR_TYPE_LEVEL);
279260
esprv_intc_int_enable(1 << irq);
280261

@@ -290,7 +271,7 @@ uint32_t esp_intr_get_enabled_intmask(int status_mask_number)
290271

291272
if (status_mask_number < STATUS_MASK_NUM) {
292273
return esp_intr_enabled_mask[status_mask_number];
293-
} else {
294-
return 0; /* error */
295274
}
275+
276+
return 0;
296277
}

include/zephyr/drivers/interrupt_controller/intc_esp32c3.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \
4141
ESP_INTR_FLAG_NMI)
4242

43+
#define IRQ_NA 0xFF /* IRQ not available */
44+
#define IRQ_FREE 0xFE /* IRQ available for use */
45+
4346
/*
4447
* Get the interrupt flags from the supplied priority.
4548
*/

soc/espressif/esp32c6/soc_irq.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ int arch_irq_is_enabled(unsigned int irq)
5353
uint32_t soc_intr_get_next_source(void)
5454
{
5555
uint32_t status;
56-
uint32_t source;
56+
uint32_t source = IRQ_NA;
5757

5858
/* Status register for interrupt sources 0 ~ 31 */
5959
status = REG_READ(INTMTX_CORE0_INT_STATUS_REG_0_REG) &
@@ -77,7 +77,9 @@ uint32_t soc_intr_get_next_source(void)
7777
status = REG_READ(INTMTX_CORE0_INT_STATUS_REG_2_REG) &
7878
esp_intr_get_enabled_intmask(2);
7979

80-
source = (__builtin_ffs(status) - 1 + ESP32C6_INTSTATUS_REG2_THRESHOLD);
80+
if (status) {
81+
source = (__builtin_ffs(status) - 1 + ESP32C6_INTSTATUS_REG2_THRESHOLD);
82+
}
8183

8284
ret:
8385
return source;

0 commit comments

Comments
 (0)