arch/esp32: Properly handle GPIO interrupt in SMP.

The PRO CPU and APP CPU have different peripherals for GPIO interrupts.
Each CPU needs to allocate an interrupt and attach it to its GPIO
peripheral.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
This commit is contained in:
Abdelatif Guettouche 2021-08-19 22:20:22 +02:00 committed by Masayuki Ishikawa
parent 5df1a544cf
commit 1385ea7673
5 changed files with 88 additions and 22 deletions

View File

@ -279,12 +279,27 @@
#define ESP32_NIRQ_PERIPH ESP32_NPERIPHERALS
#ifdef CONFIG_ESP32_GPIO_IRQ
/* The PRO and APP CPU have different interrupts sources for the GPIO
* peripheral. Each CPU needs to allocate a separate interrupt and attach
* it to its peripheral.
* Here we add a separate IRQ to differentiate between each interrupt.
* When enabling/disabling the IRQ we handle the APP's GPIO separately
* to correctly retrieve the peripheral.
*/
# ifdef CONFIG_SMP
# define ESP32_IRQ_APPCPU_GPIO ESP32_NPERIPHERALS
# undef ESP32_NIRQ_PERIPH
# define ESP32_NIRQ_PERIPH ESP32_NPERIPHERALS + 1
# endif
/* Second level GPIO interrupts. GPIO interrupts are decoded and dispatched
* as a second level of decoding: The first level dispatches to the GPIO
* interrupt handler. The second to the decoded GPIO interrupt handler.
*/
#ifdef CONFIG_ESP32_GPIO_IRQ
# define ESP32_NIRQ_GPIO 40
# define ESP32_FIRST_GPIOIRQ (XTENSA_NIRQ_INTERNAL+ESP32_NIRQ_PERIPH)
# define ESP32_LAST_GPIOIRQ (ESP32_FIRST_GPIOIRQ+ESP32_NIRQ_GPIO-1)
@ -409,6 +424,24 @@
* Inline functions
****************************************************************************/
#ifdef CONFIG_ESP32_GPIO_IRQ
#ifdef CONFIG_SMP
static inline int esp32_irq_gpio(int cpu)
{
if (cpu == 0)
{
return ESP32_IRQ_CPU_GPIO;
}
else
{
return ESP32_IRQ_APPCPU_GPIO;
}
}
#else
# define esp32_irq_gpio(c) (UNUSED(c), ESP32_IRQ_CPU_GPIO)
#endif
#endif
/****************************************************************************
* Public Data
****************************************************************************/

View File

@ -44,6 +44,7 @@
#include "esp32_region.h"
#include "esp32_irq.h"
#include "esp32_smp.h"
#include "esp32_gpio.h"
#ifdef CONFIG_SMP
@ -208,6 +209,12 @@ void xtensa_appcpu_start(void)
xtensa_registerdump(tcb);
#ifdef CONFIG_ESP32_GPIO_IRQ
/* Initialize GPIO interrupt support */
esp32_gpioirqinitialize(1);
#endif
#ifndef CONFIG_SUPPRESS_INTERRUPTS
/* And Enable interrupts */

View File

@ -56,7 +56,11 @@
****************************************************************************/
#ifdef CONFIG_ESP32_GPIO_IRQ
static int g_gpio_cpuint;
#ifdef CONFIG_SMP
static int g_gpio_cpuint[CONFIG_SMP_NCPUS];
#else
static int g_gpio_cpuint[1];
#endif
#endif
static const uint8_t g_pin2func[40] =
@ -409,22 +413,24 @@ bool esp32_gpioread(int pin)
****************************************************************************/
#ifdef CONFIG_ESP32_GPIO_IRQ
void esp32_gpioirqinitialize(void)
void esp32_gpioirqinitialize(int cpu)
{
int cpu;
#ifdef CONFIG_SMP
DEBUGASSERT(cpu >= 0 && cpu <= CONFIG_SMP_NCPUS);
#else
DEBUGASSERT(cpu == 0);
#endif
/* Setup the GPIO interrupt. */
cpu = up_cpu_index();
g_gpio_cpuint = esp32_setup_irq(cpu, ESP32_PERIPH_CPU_GPIO,
1, ESP32_CPUINT_LEVEL);
DEBUGASSERT(g_gpio_cpuint >= 0);
g_gpio_cpuint[cpu] = esp32_setup_irq(cpu, ESP32_PERIPH_CPU_GPIO,
1, ESP32_CPUINT_LEVEL);
DEBUGASSERT(g_gpio_cpuint[cpu] >= 0);
/* Attach and enable the interrupt handler */
DEBUGVERIFY(irq_attach(ESP32_IRQ_CPU_GPIO, gpio_interrupt, NULL));
up_enable_irq(ESP32_IRQ_CPU_GPIO);
DEBUGVERIFY(irq_attach(esp32_irq_gpio(cpu), gpio_interrupt, NULL));
up_enable_irq(esp32_irq_gpio(cpu));
}
#endif
@ -441,10 +447,8 @@ void esp32_gpioirqenable(int irq, gpio_intrtype_t intrtype)
{
uintptr_t regaddr;
uint32_t regval;
#ifdef CONFIG_SMP
int cpu;
#endif
int pin;
int cpu = up_cpu_index();
DEBUGASSERT(irq >= ESP32_FIRST_GPIOIRQ && irq <= ESP32_LAST_GPIOIRQ);
@ -454,7 +458,7 @@ void esp32_gpioirqenable(int irq, gpio_intrtype_t intrtype)
/* Get the address of the GPIO PIN register for this pin */
up_disable_irq(ESP32_IRQ_CPU_GPIO);
up_disable_irq(esp32_irq_gpio(cpu));
regaddr = GPIO_REG(pin);
regval = getreg32(regaddr);
@ -470,7 +474,6 @@ void esp32_gpioirqenable(int irq, gpio_intrtype_t intrtype)
*/
#ifdef CONFIG_SMP
cpu = up_cpu_index();
if (cpu != 0)
{
/* APP_CPU */
@ -488,7 +491,7 @@ void esp32_gpioirqenable(int irq, gpio_intrtype_t intrtype)
regval |= (intrtype << GPIO_PIN_INT_TYPE_S);
putreg32(regval, regaddr);
up_enable_irq(ESP32_IRQ_CPU_GPIO);
up_enable_irq(esp32_irq_gpio(cpu));
}
#endif
@ -506,6 +509,7 @@ void esp32_gpioirqdisable(int irq)
uintptr_t regaddr;
uint32_t regval;
int pin;
int cpu = up_cpu_index();
DEBUGASSERT(irq >= ESP32_FIRST_GPIOIRQ && irq <= ESP32_LAST_GPIOIRQ);
@ -515,14 +519,14 @@ void esp32_gpioirqdisable(int irq)
/* Get the address of the GPIO PIN register for this pin */
up_disable_irq(ESP32_IRQ_CPU_GPIO);
up_disable_irq(esp32_irq_gpio(cpu));
regaddr = GPIO_REG(pin);
regval = getreg32(regaddr);
regval &= ~(GPIO_PIN_INT_ENA_M | GPIO_PIN_INT_TYPE_M);
putreg32(regval, regaddr);
up_enable_irq(ESP32_IRQ_CPU_GPIO);
up_enable_irq(esp32_irq_gpio(cpu));
}
#endif

View File

@ -144,9 +144,9 @@ extern "C"
****************************************************************************/
#ifdef CONFIG_ESP32_GPIO_IRQ
void esp32_gpioirqinitialize(void);
void esp32_gpioirqinitialize(int c);
#else
# define esp32_gpioirqinitialize()
# define esp32_gpioirqinitialize(c)
#endif
/****************************************************************************

View File

@ -481,7 +481,7 @@ void up_irqinitialize(void)
#ifdef CONFIG_ESP32_GPIO_IRQ
/* Initialize GPIO interrupt support */
esp32_gpioirqinitialize();
esp32_gpioirqinitialize(0);
#endif
#ifndef CONFIG_SUPPRESS_INTERRUPTS
@ -544,6 +544,17 @@ void up_disable_irq(int irq)
uintptr_t regaddr;
uint8_t *intmap;
#ifdef CONFIG_ESP32_GPIO_IRQ
#ifdef CONFIG_SMP
/* The APP's CPU GPIO is a special case. See esp32/irq.h */
if (periph == ESP32_IRQ_APPCPU_GPIO)
{
periph = ESP32_IRQ_CPU_GPIO;
}
#endif
#endif
DEBUGASSERT(periph >= 0 && periph < ESP32_NPERIPHERALS);
esp32_intinfo(cpu, periph, &regaddr, &intmap);
@ -588,6 +599,17 @@ void up_enable_irq(int irq)
uintptr_t regaddr;
uint8_t *intmap;
#ifdef CONFIG_ESP32_GPIO_IRQ
#ifdef CONFIG_SMP
/* The APP's CPU GPIO is a special case. See esp32/irq.h */
if (periph == ESP32_IRQ_APPCPU_GPIO)
{
periph = ESP32_IRQ_CPU_GPIO;
}
#endif
#endif
DEBUGASSERT(periph >= 0 && periph < ESP32_NPERIPHERALS);
esp32_intinfo(cpu, periph, &regaddr, &intmap);