Skip to content
Snippets Groups Projects
Commit 79a0d3d5 authored by rahix's avatar rahix
Browse files

feat(interrupts): Dispatch interrupts asynchroneously


Instead of blocking the triggering task when core 1 is still busy
handling the previous interrupt, offload interrupt dispatching into
a separate task.  This is the first step towards making API-calls
interrupt safe.

Next to the async triggering, the synchroneous mechanism is retained for
special cases where async does not work (e.g. because of spin-locks).
Currently, there is only one such case when resetting core 1 (triggering
EPIC_INT_RESET).

Signed-off-by: default avatarRahix <rahix@rahix.de>
parent 7b56f29a
Branches
No related tags found
No related merge requests found
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "tmr.h" #include "tmr.h"
static void __core1_init(void); static void __core1_init(void);
extern void interrupt_trigger(api_int_id_t id); extern void interrupt_trigger_sync(api_int_id_t id);
struct core1_info { struct core1_info {
/* Location of core1's interrupt vector table */ /* Location of core1's interrupt vector table */
...@@ -206,8 +206,13 @@ void core1_boot(void) ...@@ -206,8 +206,13 @@ void core1_boot(void)
void core1_trigger_reset(void) void core1_trigger_reset(void)
{ {
/* Signal core 1 that we intend to load a new payload. */ /*
interrupt_trigger(EPIC_INT_RESET); * Signal core 1 that we intend to load a new payload.
*
* This needs to be synchroneous because otherwise we will deadlock
* (Lifecycle task busy-spins and interrupt can never get dispatched).
*/
interrupt_trigger_sync(EPIC_INT_RESET);
} }
void core1_wait_ready(void) void core1_wait_ready(void)
......
...@@ -133,6 +133,16 @@ int main(void) ...@@ -133,6 +133,16 @@ int main(void)
&dispatcher_task_id) != pdPASS) { &dispatcher_task_id) != pdPASS) {
panic("Failed to create %s task!", "API Dispatcher"); panic("Failed to create %s task!", "API Dispatcher");
} }
/* Interrupts */
if (xTaskCreate(
vInterruptsTask,
(const char *)"Interrupt Dispatcher",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY + 2,
NULL) != pdPASS) {
panic("Failed to create %s task!", "Interrupt Dispatcher");
}
/* BLE */ /* BLE */
if (ble_shall_start()) { if (ble_shall_start()) {
......
#include "modules/mutex.h" #include "modules/mutex.h"
#include "modules/log.h"
#include "epicardium.h" #include "epicardium.h"
#include "api/interrupt-sender.h" #include "api/interrupt-sender.h"
#include <assert.h> #include <assert.h>
...@@ -14,11 +15,28 @@ struct interrupt_priv { ...@@ -14,11 +15,28 @@ struct interrupt_priv {
static struct interrupt_priv interrupt_data; static struct interrupt_priv interrupt_data;
static struct mutex interrupt_mutex; static struct mutex interrupt_mutex;
static TaskHandle_t interrupts_task;
void interrupt_trigger(api_int_id_t id) void interrupt_trigger(api_int_id_t id)
{ {
assert(id < EPIC_INT_NUM); assert(id < EPIC_INT_NUM);
mutex_lock(&interrupt_mutex);
if (interrupt_data.int_enabled[id]) {
interrupt_data.int_pending[id] = true;
interrupt_data.has_pending = true;
mutex_unlock(&interrupt_mutex);
xTaskNotifyGive(interrupts_task);
} else {
mutex_unlock(&interrupt_mutex);
}
}
void interrupt_trigger_sync(api_int_id_t id)
{
assert(id < EPIC_INT_NUM);
mutex_lock(&interrupt_mutex); mutex_lock(&interrupt_mutex);
if (!interrupt_data.int_enabled[id]) if (!interrupt_data.int_enabled[id])
goto out; goto out;
...@@ -97,3 +115,42 @@ int epic_interrupt_disable(api_int_id_t int_id) ...@@ -97,3 +115,42 @@ int epic_interrupt_disable(api_int_id_t int_id)
return 0; return 0;
} }
/* }}} */ /* }}} */
void vInterruptsTask(void *pvParameters)
{
interrupts_task = xTaskGetCurrentTaskHandle();
while (true) {
mutex_lock(&interrupt_mutex);
if (!interrupt_data.has_pending) {
/* Wait for a wakeup event from interrupt_trigger() */
mutex_unlock(&interrupt_mutex);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
mutex_lock(&interrupt_mutex);
}
while (!api_interrupt_is_ready()) {
mutex_unlock(&interrupt_mutex);
vTaskDelay(pdMS_TO_TICKS(5));
mutex_lock(&interrupt_mutex);
}
api_int_id_t current_irq = EPIC_INT_NUM;
for (size_t i = 0; i < EPIC_INT_NUM; i++) {
if (interrupt_data.int_pending[i]) {
current_irq = i;
interrupt_data.int_pending[i] = false;
break;
}
}
if (current_irq == EPIC_INT_NUM) {
interrupt_data.has_pending = false;
} else if (interrupt_data.int_enabled[current_irq]) {
api_interrupt_trigger(current_irq);
}
mutex_unlock(&interrupt_mutex);
}
}
...@@ -31,9 +31,11 @@ void return_to_menu(void); ...@@ -31,9 +31,11 @@ void return_to_menu(void);
/* ---------- Interrupts --------------------------------------------------- */ /* ---------- Interrupts --------------------------------------------------- */
void interrupt_init(void); void interrupt_init(void);
void interrupt_trigger(api_int_id_t id); void interrupt_trigger(api_int_id_t id);
void interrupt_trigger_sync(api_int_id_t id);
void interrupt_trigger_unsafe(api_int_id_t id) __attribute__((deprecated( void interrupt_trigger_unsafe(api_int_id_t id) __attribute__((deprecated(
"interrupt_trigger_unsafe() is racy and only exists for legacy code." "interrupt_trigger_unsafe() is racy and only exists for legacy code."
))); )));
void vInterruptsTask(void *pvParameters);
/* ---------- Serial ------------------------------------------------------- */ /* ---------- Serial ------------------------------------------------------- */
#define SERIAL_READ_BUFFER_SIZE 128 #define SERIAL_READ_BUFFER_SIZE 128
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment