risc-v/espressif: support marking interrupt as running from IRAM

This commit is contained in:
Filipe Cavalcanti 2024-09-12 11:11:43 -03:00 committed by Petro Karashchenko
parent 7acb298f26
commit a876f00e2a
6 changed files with 284 additions and 7 deletions

View file

@ -1200,6 +1200,19 @@ config ESPRESSIF_SPI_TEST_MODE
endmenu # SPI configuration
menu "Interrupt Configuration"
config ESPRESSIF_IRAM_ISR_DEBUG
bool "Enable debugging of the IRAM-enabled interrupts"
default n
---help---
This option enables keeping track of the IRAM-enabled interrupts by
registering its execution when non-IRAM interrupts are disabled. It
keeps track of the IRQ executed and register how many times since
boot it was executed. Generally used for testing.
endmenu
menu "SPI Flash Configuration"
choice ESPRESSIF_FLASH_MODE

View file

@ -78,6 +78,11 @@
#define NO_CPUINT ETS_INVALID_INUM
/* Masks for interrupt type used on esp_setup_irq */
#define ESP_CPUINT_IRAM_MASK (1 << 1)
#define ESP_CPUINT_TRIGGER_MASK (1 << 0)
/****************************************************************************
* Private Types
****************************************************************************/
@ -130,6 +135,14 @@ static uint32_t non_iram_int_mask[CONFIG_ESPRESSIF_NUM_CPUS];
static uint32_t non_iram_int_disabled[CONFIG_ESPRESSIF_NUM_CPUS];
static bool non_iram_int_disabled_flag[CONFIG_ESPRESSIF_NUM_CPUS];
#ifdef CONFIG_ESPRESSIF_IRAM_ISR_DEBUG
/* The g_iram_count keeps track of how many times such an IRQ ran when the
* non-IRAM interrupts were disabled.
*/
static uint64_t g_iram_count[NR_IRQS];
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
@ -273,6 +286,33 @@ static void esp_cpuint_initialize(void)
memset(g_cpuint_map, 0, sizeof(g_cpuint_map));
}
#ifdef CONFIG_ESPRESSIF_IRAM_ISR_DEBUG
/****************************************************************************
* Name: esp_iram_interrupt_record
*
* Description:
* This function keeps track of the IRQs that ran when non-IRAM interrupts
* are disabled and enables debugging of the IRAM-enabled interrupts.
*
* Input Parameters:
* irq - The IRQ associated with a CPU interrupt
*
* Returned Value:
* None.
*
****************************************************************************/
IRAM_ATTR void esp_irq_iram_interrupt_record(int irq)
{
irqstate_t flags = enter_critical_section();
g_iram_count[irq]++;
leave_critical_section(flags);
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -464,7 +504,7 @@ void esp_route_intr(int source, int cpuint, irq_priority_t priority,
*
****************************************************************************/
int esp_setup_irq(int source, irq_priority_t priority, irq_trigger_t type)
int esp_setup_irq(int source, irq_priority_t priority, int type)
{
irqstate_t irqstate;
int irq;
@ -492,7 +532,17 @@ int esp_setup_irq(int source, irq_priority_t priority, irq_trigger_t type)
PANIC();
}
esp_route_intr(source, cpuint, priority, type);
esp_route_intr(source, cpuint, priority, (type & ESP_CPUINT_TRIGGER_MASK));
if ((type & ESP_CPUINT_IRAM_MASK) == ESP_IRQ_IRAM)
{
esp_irq_set_iram_isr(irq);
irqinfo("source %d marked IRAM (irq=%d)\n", source, irq);
}
else
{
esp_irq_unset_iram_isr(irq);
}
leave_critical_section(irqstate);
@ -557,6 +607,7 @@ IRAM_ATTR void *riscv_dispatch_irq(uintreg_t mcause, uintreg_t *regs)
int irq;
bool is_irq = (RISCV_IRQ_BIT & mcause) != 0;
bool is_edge = false;
uint32_t cpu = esp_cpu_get_core_id();
if (is_irq)
{
@ -568,7 +619,18 @@ IRAM_ATTR void *riscv_dispatch_irq(uintreg_t mcause, uintreg_t *regs)
irq = g_cpuint_map[cpuint].irq;
is_edge = esprv_intc_int_get_type(cpuint) == INTR_TYPE_EDGE;
#ifdef CONFIG_ESPRESSIF_IRAM_ISR_DEBUG
/* Check if non-IRAM interrupts are disabled */
if (esp_irq_noniram_status(cpu) == 0)
{
/* Sum-up the IRAM-enabled counter associated with the IRQ */
esp_irq_iram_interrupt_record(irq);
}
#endif
is_edge = esprv_intc_int_get_type(cpuint) == INTR_TYPE_LEVEL;
if (is_edge)
{
/* Clear edge interrupts. */
@ -626,7 +688,7 @@ irqstate_t up_irq_enable(void)
*
****************************************************************************/
void IRAM_ATTR esp_intr_noniram_disable(void)
void esp_intr_noniram_disable(void)
{
uint32_t oldint;
irqstate_t irqstate;
@ -666,7 +728,7 @@ void IRAM_ATTR esp_intr_noniram_disable(void)
*
****************************************************************************/
void IRAM_ATTR esp_intr_noniram_enable(void)
void esp_intr_noniram_enable(void)
{
irqstate_t irqstate;
uint32_t cpu;
@ -686,6 +748,27 @@ void IRAM_ATTR esp_intr_noniram_enable(void)
leave_critical_section(irqstate);
}
/****************************************************************************
* Name: esp_irq_noniram_status
*
* Description:
* Get the current status of non-IRAM interrupts on a specific CPU core
*
* Input Parameters:
* cpu - The CPU to check the non-IRAM interrupts state
*
* Returned Value:
* true if non-IRAM interrupts are enabled, false otherwise.
*
****************************************************************************/
bool esp_irq_noniram_status(int cpu)
{
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
return !non_iram_int_disabled_flag[cpu];
}
/****************************************************************************
* Name: esp_get_irq
*
@ -731,3 +814,89 @@ void esp_set_irq(int irq, int cpuint)
CPUINT_ASSIGN(g_cpuint_map[cpuint], irq);
g_irq_map[irq] = cpuint;
}
/****************************************************************************
* Name: esp_irq_set_iram_isr
*
* Description:
* Set the ISR associated to an IRQ as a IRAM-enabled ISR.
*
* Input Parameters:
* irq - The associated IRQ to set
*
* Returned Value:
* OK on success; A negated errno value on failure.
*
****************************************************************************/
int esp_irq_set_iram_isr(int irq)
{
uint32_t cpu = esp_cpu_get_core_id();
int cpuint = g_irq_map[irq];
if (cpuint == IRQ_UNMAPPED)
{
return -EINVAL;
}
non_iram_int_mask[cpu] &= ~(1 << cpuint);
return OK;
}
/****************************************************************************
* Name: esp_irq_unset_iram_isr
*
* Description:
* Set the ISR associated to an IRQ as a non-IRAM ISR.
*
* Input Parameters:
* irq - The associated IRQ to set
*
* Returned Value:
* OK on success; A negated errno value on failure.
*
****************************************************************************/
int esp_irq_unset_iram_isr(int irq)
{
uint32_t cpu = esp_cpu_get_core_id();
int cpuint = g_irq_map[irq];
if (cpuint == IRQ_UNMAPPED)
{
return -EINVAL;
}
non_iram_int_mask[cpu] |= (1 << cpuint);
return OK;
}
/****************************************************************************
* Name: esp_get_iram_interrupt_records
*
* Description:
* This function copies the vector that keeps track of the IRQs that ran
* when non-IRAM interrupts were disabled.
*
* Input Parameters:
*
* irq_count - A previously allocated pointer to store the counter of the
* interrupts that ran when non-IRAM interrupts were disabled.
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_ESPRESSIF_IRAM_ISR_DEBUG
void esp_get_iram_interrupt_records(uint64_t *irq_count)
{
irqstate_t flags = enter_critical_section();
memcpy(irq_count, &g_iram_count, sizeof(uint64_t) * NR_IRQS);
leave_critical_section(flags);
}
#endif

View file

@ -45,6 +45,15 @@ extern "C"
#define EXTERN extern
#endif
/* CPU interrupt flags.
* esp_setup_irq() will check bit 1 for IRAM requirement and
* bit 0 for trigger type.
*
* OR'ed values of irq_trigger_e and irq_iram_e define interrupt type.
* | IRAM | TRIGGER |
* Bits | 1 | 0 |
*/
/* CPU interrupt trigger types */
typedef enum irq_trigger_e
@ -53,6 +62,14 @@ typedef enum irq_trigger_e
ESP_IRQ_TRIGGER_EDGE = 1, /* Edge-triggered interrupts */
} irq_trigger_t;
/* CPU interrupt IRAM enabled */
typedef enum irq_iram_e
{
ESP_IRQ_NON_IRAM = (0 << 1), /* Non-IRAM interrupt */
ESP_IRQ_IRAM = (1 << 1), /* IRAM interrupt */
} irq_iram_t;
/* CPU interrupt priority levels */
typedef enum irq_priority_e
@ -119,7 +136,7 @@ void esp_route_intr(int source, int cpuint, irq_priority_t priority,
*
****************************************************************************/
int esp_setup_irq(int source, irq_priority_t priority, irq_trigger_t type);
int esp_setup_irq(int source, irq_priority_t priority, int type);
/****************************************************************************
* Name: esp_teardown_irq
@ -213,6 +230,73 @@ int esp_get_irq(int cpuint);
void esp_set_irq(int irq, int cpuint);
/****************************************************************************
* Name: esp_irq_set_iram_isr
*
* Description:
* Set the ISR associated to an IRQ as a IRAM-enabled ISR.
*
* Input Parameters:
* irq - The associated IRQ to set
*
* Returned Value:
* OK on success; A negated errno value on failure.
*
****************************************************************************/
int esp_irq_set_iram_isr(int irq);
/****************************************************************************
* Name: esp32s3_irq_unset_iram_isr
*
* Description:
* Set the ISR associated to an IRQ as a non-IRAM ISR.
*
* Input Parameters:
* irq - The associated IRQ to set
*
* Returned Value:
* OK on success; A negated errno value on failure.
*
****************************************************************************/
int esp_irq_unset_iram_isr(int irq);
/****************************************************************************
* Name: esp_irq_noniram_status
*
* Description:
* Get the current status of non-IRAM interrupts on a specific CPU core
*
* Input Parameters:
* cpu - The CPU to check the non-IRAM interrupts state
*
* Returned Value:
* true if non-IRAM interrupts are enabled, false otherwise.
*
****************************************************************************/
bool esp_irq_noniram_status(int cpu);
/****************************************************************************
* Name: esp_get_iram_interrupt_records
*
* Description:
* This function copies the vector that keeps track of the IRQs that ran
* when non-IRAM interrupts were disabled.
*
* Input Parameters:
*
* irq_count - A previously allocated pointer to store the counter of the
* interrupts that ran when non-IRAM interrupts were disabled.
*
* Returned Value:
* None
*
****************************************************************************/
void esp_get_iram_interrupt_records(uint64_t *irq_count);
#undef EXTERN
#if defined(__cplusplus)
}

View file

@ -73,6 +73,8 @@ SECTIONS
*libsched.a:irq_dispatch.*(.text .text.* .literal .literal.*)
*libarch.a:*(.text.esprv_intc_int_get_type .literal.esprv_intc_int_get_type)
*libarch.a:*riscv_doirq.*(.text .text.* .literal .literal.*)
*libarch.a:*brownout.*(.text .text.* .literal .literal.*)
*libarch.a:*cpu.*(.text .text.* .literal .literal.*)
*libarch.a:*gpio_hal.*(.text .text.* .literal .literal.*)
@ -188,6 +190,8 @@ SECTIONS
*libsched.a:irq_dispatch.*(.rodata .rodata.*)
*libarch.a:*(.rodata.esprv_intc_int_get_type)
*libarch.a:*riscv_doirq.*(.rodata .rodata.*)
*libarch.a:*brownout.*(.rodata .rodata.*)
*libarch.a:*cpu.*(.rodata .rodata.*)
*libarch.a:*gpio_hal.*(.rodata .rodata.*)

View file

@ -73,6 +73,8 @@ SECTIONS
*libsched.a:irq_dispatch.*(.text .text.* .literal .literal.*)
*libarch.a:*(.text.esprv_intc_int_get_type .literal.esprv_intc_int_get_type)
*libarch.a:*riscv_doirq.*(.text .text.* .literal .literal.*)
*libarch.a:*brownout.*(.text .text.* .literal .literal.*)
*libarch.a:*cpu.*(.text .text.* .literal .literal.*)
*libarch.a:*gpio_hal.*(.text .text.* .literal .literal.*)
@ -212,6 +214,8 @@ SECTIONS
*libsched.a:irq_dispatch.*(.rodata .rodata.*)
*libarch.a:*(.rodata.esprv_intc_int_get_type)
*libarch.a:*riscv_doirq.*(.rodata .rodata.*)
*libarch.a:*brownout.*(.rodata .rodata.*)
*libarch.a:*cpu.*(.rodata .rodata.*)
*libarch.a:*gpio_hal.*(.rodata .rodata.*)
@ -488,4 +492,3 @@ SECTIONS
"RTC reserved segment data does not fit.")
}

View file

@ -73,6 +73,8 @@ SECTIONS
*libsched.a:irq_dispatch.*(.text .text.* .literal .literal.*)
*libarch.a:*(.text.esprv_intc_int_get_type .literal.esprv_intc_int_get_type)
*libarch.a:*riscv_doirq.*(.text .text.* .literal .literal.*)
*libarch.a:*brownout.*(.text .text.* .literal .literal.*)
*libarch.a:*cpu.*(.text .text.* .literal .literal.*)
*libarch.a:*gpio_hal.*(.text .text.* .literal .literal.*)
@ -209,6 +211,8 @@ SECTIONS
*libsched.a:irq_dispatch.*(.rodata .rodata.*)
*libarch.a:*(.rodata.esprv_intc_int_get_type)
*libarch.a:*riscv_doirq.*(.rodata .rodata.*)
*libarch.a:*brownout.*(.rodata .rodata.*)
*libarch.a:*cpu.*(.rodata .rodata.*)
*libarch.a:*gpio_hal.*(.rodata .rodata.*)