event model seems to work

refactors all the ugly "pendingX" atomic operations into a single "Event" subsystem/interface thing with two operations

moves all existing code to use this instead

also changes the "bkpt" macro to also indicate unreachable code
This commit is contained in:
Wolfvak 2020-11-18 16:47:00 -03:00 committed by d0k3
parent eadc1ab6b9
commit 31389687ab
7 changed files with 109 additions and 69 deletions

View File

@ -19,8 +19,12 @@
#include <common.h> #include <common.h>
#include <arm.h> #include <arm.h>
#include <stdatomic.h>
#include "arm/gic.h" #include "arm/gic.h"
#include "system/event.h"
/* Generic Interrupt Controller Registers */ /* Generic Interrupt Controller Registers */
#define REG_GIC(cpu, o, t) REG_ARM_PMR(0x200 + ((cpu) * 0x100) + (o), t) #define REG_GIC(cpu, o, t) REG_ARM_PMR(0x200 + ((cpu) * 0x100) + (o), t)
@ -72,6 +76,7 @@
#define IRQN_IS_VALID(n) ((n) < DIC_MAX_IRQ) #define IRQN_IS_VALID(n) ((n) < DIC_MAX_IRQ)
static gicIrqHandler gicIrqHandlers[DIC_MAX_IRQ]; static gicIrqHandler gicIrqHandlers[DIC_MAX_IRQ];
static _Atomic(u32) gicIrqPending[DIC_MAX_IRQ / 32];
static struct { static struct {
u8 tgt; u8 tgt;
@ -106,14 +111,13 @@ static u8 gicGetDefaultIrqCfg(u32 irqn) {
return gicDefaultIrqCfg[i].mode; return gicDefaultIrqCfg[i].mode;
} }
// TODO: would it be considerably faster to use bsearch? // TODO: would it be considerably faster to use bsearch?
return GIC_RISINGEDGE_1N; return GIC_RISINGEDGE_1N;
} }
void gicTopHandler(void) void gicTopHandler(void)
{ {
while(1) { while(1) {
u32 irqn; u32 irqn, irqsource, index, mask;
/** /**
If more than one of these CPUs reads the Interrupt Acknowledge Register at the If more than one of these CPUs reads the Interrupt Acknowledge Register at the
@ -121,16 +125,22 @@ void gicTopHandler(void)
routine must ensure that only one of them tries to process the interrupt, with the routine must ensure that only one of them tries to process the interrupt, with the
others returning after writing the ID to the End of Interrupt Register. others returning after writing the ID to the End of Interrupt Register.
*/ */
irqn = REG_GIC_IRQACK(GIC_THIS_CPU_ALIAS); irqsource = REG_GIC_IRQACK(GIC_THIS_CPU_ALIAS);
if (irqn == GIC_IRQ_SPURIOUS) // no further processing is needed if (irqsource == GIC_IRQ_SPURIOUS) // no further processing is needed
break; break;
(gicIrqHandlers[irqn & ~IRQN_SRC_MASK])(irqn); irqn = irqsource & ~IRQN_SRC_MASK;
index = irqn / 32;
mask = BIT(irqn % 32);
atomic_fetch_or(&gicIrqPending[index], mask);
(gicIrqHandlers[irqn])(irqsource);
// if the id is < 16, the source CPU can be obtained from irqn // if the id is < 16, the source CPU can be obtained from irqn
// if the handler isn't set, it'll try to branch to 0 and trigger a prefetch abort // if the handler isn't set, it'll try to branch to 0 and trigger a prefetch abort
REG_GIC_IRQEND(GIC_THIS_CPU_ALIAS) = irqn; REG_GIC_IRQEND(GIC_THIS_CPU_ALIAS) = irqsource;
} }
} }
@ -152,6 +162,7 @@ void gicGlobalReset(void)
gicn = MAX_CPU; gicn = MAX_CPU;
// clear the interrupt handler and config table // clear the interrupt handler and config table
getEventIRQ()->reset();
memset(gicIrqHandlers, 0, sizeof(gicIrqHandlers)); memset(gicIrqHandlers, 0, sizeof(gicIrqHandlers));
memset(gicIrqConfig, 0, sizeof(gicIrqConfig)); memset(gicIrqConfig, 0, sizeof(gicIrqConfig));
@ -263,3 +274,27 @@ void gicTriggerSoftInterrupt(u32 softirq)
{ {
REG_DIC_SOFTINT = softirq; REG_DIC_SOFTINT = softirq;
} }
static void irqEvReset(void) {
memset(&gicIrqPending, 0, sizeof(gicIrqPending));
}
static u32 irqEvTest(u32 param, u32 clear) {
u32 index, tstmask, clrmask;
if (param >= DIC_MAX_IRQ)
bkpt;
index = param / 32;
tstmask = BIT(param % 32);
clrmask = clear ? tstmask : 0;
return !!(atomic_fetch_and(&gicIrqPending[index], ~clrmask) & tstmask);
}
static const EventInterface evIRQ = {
.reset = irqEvReset,
.test = irqEvTest
};
const EventInterface *getEventIRQ(void) {
return &evIRQ;
}

View File

@ -27,6 +27,8 @@
#include "hw/mcu.h" #include "hw/mcu.h"
#include "hw/gpulcd.h" #include "hw/gpulcd.h"
#include "system/event.h"
static struct static struct
{ {
u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen. u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen.
@ -112,13 +114,13 @@ unsigned GFX_init(GfxFbFmt mode)
TIMER_WaitMS(10); TIMER_WaitMS(10);
resetLcdsMaybe(); resetLcdsMaybe();
MCU_controlLCDPower(2u); // Power on LCDs. MCU_controlLCDPower(2u); // Power on LCDs.
if(mcuEventWait(0x3Fu<<24) != 2u<<24) __builtin_trap(); if(eventWait(getEventMCU(), 0x3Fu<<24, 0x3Fu<<24) != 2u<<24) __builtin_trap();
waitLcdsReady(); waitLcdsReady();
REG_LCD_ABL0_LIGHT_PWM = 0x1023E; REG_LCD_ABL0_LIGHT_PWM = 0x1023E;
REG_LCD_ABL1_LIGHT_PWM = 0x1023E; REG_LCD_ABL1_LIGHT_PWM = 0x1023E;
MCU_controlLCDPower(0x28u); // Power on backlights. MCU_controlLCDPower(0x28u); // Power on backlights.
if(mcuEventWait(0x3Fu<<24) != 0x28u<<24) __builtin_trap(); if(eventWait(getEventMCU(), 0x3Fu<<24, 0x3Fu<<24) != 0x28u<<24) __builtin_trap();
g_gfxState.lcdPower = 0x15; // All on. g_gfxState.lcdPower = 0x15; // All on.
// Make sure the fills finished. // Make sure the fills finished.
@ -212,7 +214,7 @@ void GFX_powerOnBacklights(GfxBlight mask)
mask <<= 1; mask <<= 1;
MCU_controlLCDPower(mask); // Power on backlights. MCU_controlLCDPower(mask); // Power on backlights.
mcuEventWait(0x3F<<24); eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24);
/*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24) /*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();*/ __builtin_trap();*/
} }
@ -222,7 +224,7 @@ void GFX_powerOffBacklights(GfxBlight mask)
g_gfxState.lcdPower &= ~mask; g_gfxState.lcdPower &= ~mask;
MCU_controlLCDPower(mask); // Power off backlights. MCU_controlLCDPower(mask); // Power off backlights.
mcuEventWait(0x3F<<24); eventWait(getEventMCU(), 0x3F<<24, 0x3F<<24);
/*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24) /*if(mcuEventWait(0x3Fu<<24) != (u32)mask<<24)
__builtin_trap();*/ __builtin_trap();*/
} }

View File

@ -28,6 +28,8 @@
#include "hw/gpulcd.h" #include "hw/gpulcd.h"
#include "hw/mcu.h" #include "hw/mcu.h"
#include "system/event.h"
#define MCUEV_HID_MASK ( \ #define MCUEV_HID_MASK ( \
MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD | \ MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD | \
MCUEV_HID_HOME_DOWN | MCUEV_HID_HOME_UP | MCUEV_HID_WIFI_SWITCH) MCUEV_HID_HOME_DOWN | MCUEV_HID_HOME_UP | MCUEV_HID_WIFI_SWITCH)
@ -63,13 +65,14 @@ typedef struct {
static u8 volumeSliderValue; static u8 volumeSliderValue;
static u32 shellState; static u32 shellState;
static _Atomic(u32) pendingEvents, pendingUpdate; static _Atomic(u32) pendingEvents;
static void mcuEventUpdate(void) static void mcuEventUpdate(void)
{ {
u32 mask; u32 mask;
if (!atomic_exchange(&pendingUpdate, 0)) // lazily update the mask on each test attempt
if (!getEventIRQ()->test(MCU_INTERRUPT, true))
return; return;
// reading the pending mask automagically acknowledges // reading the pending mask automagically acknowledges
@ -91,27 +94,6 @@ static void mcuEventUpdate(void)
atomic_fetch_or(&pendingEvents, mask); atomic_fetch_or(&pendingEvents, mask);
} }
u32 mcuEventTest(u32 mask)
{
mcuEventUpdate();
return atomic_load(&pendingEvents) & mask;
}
u32 mcuEventClear(u32 mask)
{
mcuEventUpdate();
return atomic_fetch_and(&pendingEvents, ~mask) & mask;
}
u32 mcuEventWait(u32 mask)
{
do {
mcuEventUpdate();
u32 x = mcuEventClear(mask);
if (x) return x;
} while(1);
}
u8 mcuGetVolumeSlider(void) u8 mcuGetVolumeSlider(void)
{ {
mcuEventUpdate(); mcuEventUpdate();
@ -120,7 +102,7 @@ u8 mcuGetVolumeSlider(void)
u32 mcuGetSpecialHID(void) u32 mcuGetSpecialHID(void)
{ {
u32 ret, pend = mcuEventClear(MCUEV_HID_MASK); u32 ret = 0, pend = getEventMCU()->test(MCUEV_HID_MASK, MCUEV_HID_MASK);
// hopefully gets unrolled // hopefully gets unrolled
if (pend & (MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD)) if (pend & (MCUEV_HID_PWR_DOWN | MCUEV_HID_PWR_HOLD))
@ -176,17 +158,11 @@ void mcuResetLEDs(void)
mcuSetStatusLED(0, 0); mcuSetStatusLED(0, 0);
} }
void mcuInterruptHandler(u32 __attribute__((unused)) irqn)
{
atomic_store(&pendingUpdate, 1);
}
void mcuReset(void) void mcuReset(void)
{ {
u32 intmask = 0; u32 intmask = 0;
atomic_init(&pendingEvents, 0); atomic_init(&pendingEvents, 0);
atomic_init(&pendingUpdate, 0);
// set register mask and clear any pending registers // set register mask and clear any pending registers
mcuWriteRegBuf(MCUREG_INT_EN, (const u8*)&intmask, sizeof(intmask)); mcuWriteRegBuf(MCUREG_INT_EN, (const u8*)&intmask, sizeof(intmask));
@ -202,3 +178,22 @@ void mcuReset(void)
GPIO_setBit(19, 9); GPIO_setBit(19, 9);
} }
static void evReset(void) {
atomic_store(&pendingEvents, 0);
}
static u32 evTest(u32 mask, u32 clear) {
mcuEventUpdate();
return atomic_fetch_and(&pendingEvents, ~clear) & mask;
}
static const EventInterface evMCU = {
.reset = evReset,
.test = evTest
};
const EventInterface *getEventMCU(void) {
return &evMCU;
}

View File

@ -37,18 +37,12 @@ enum {
MCUEV_HID_VOLUME_SLIDER = BIT(22), MCUEV_HID_VOLUME_SLIDER = BIT(22),
}; };
u32 mcuEventTest(u32 mask);
u32 mcuEventClear(u32 mask);
u32 mcuEventWait(u32 mask);
u8 mcuGetVolumeSlider(void); u8 mcuGetVolumeSlider(void);
u32 mcuGetSpecialHID(void); u32 mcuGetSpecialHID(void);
void mcuSetStatusLED(u32 period_ms, u32 color); void mcuSetStatusLED(u32 period_ms, u32 color);
void mcuResetLEDs(void); void mcuResetLEDs(void);
void mcuInterruptHandler(u32 irqn);
void mcuReset(void); void mcuReset(void);
static inline u8 mcuReadReg(u8 addr) static inline u8 mcuReadReg(u8 addr)

View File

@ -22,8 +22,6 @@
#include <arm.h> #include <arm.h>
#include <pxi.h> #include <pxi.h>
#include <stdatomic.h>
#include "arm/gic.h" #include "arm/gic.h"
#include "hw/hid.h" #include "hw/hid.h"
@ -33,6 +31,7 @@
#include "hw/nvram.h" #include "hw/nvram.h"
#include "system/sys.h" #include "system/sys.h"
#include "system/event.h"
static const u8 brightness_lvls[] = { static const u8 brightness_lvls[] = {
0x10, 0x17, 0x1E, 0x25, 0x10, 0x17, 0x1E, 0x25,
@ -48,16 +47,9 @@ static bool auto_brightness;
static SystemSHMEM __attribute__((section(".shared"))) sharedMem; static SystemSHMEM __attribute__((section(".shared"))) sharedMem;
static _Atomic(u32) pendingVblank, pendingPxiRx;
static void vblankHandler(u32 __attribute__((unused)) irqn)
{
atomic_store(&pendingVblank, 1);
}
static void vblankUpdate(void) static void vblankUpdate(void)
{ {
if (!atomic_exchange(&pendingVblank, 0)) if (!getEventIRQ()->test(VBLANK_INTERRUPT, true))
return; return;
#ifndef FIXED_BRIGHTNESS #ifndef FIXED_BRIGHTNESS
@ -70,7 +62,8 @@ static void vblankUpdate(void)
#endif #endif
// handle shell events // handle shell events
u32 shell = mcuEventClear(MCUEV_HID_SHELL_OPEN | MCUEV_HID_SHELL_CLOSE); static const u32 mcuEvShell = MCUEV_HID_SHELL_OPEN | MCUEV_HID_SHELL_CLOSE;
u32 shell = getEventMCU()->test(mcuEvShell, mcuEvShell);
if (shell & MCUEV_HID_SHELL_CLOSE) { if (shell & MCUEV_HID_SHELL_CLOSE) {
GFX_powerOffBacklights(GFX_BLIGHT_BOTH); GFX_powerOffBacklights(GFX_BLIGHT_BOTH);
} else if (shell & MCUEV_HID_SHELL_OPEN) { } else if (shell & MCUEV_HID_SHELL_OPEN) {
@ -80,16 +73,11 @@ static void vblankUpdate(void)
sharedMem.hidState.full = HID_GetState(); sharedMem.hidState.full = HID_GetState();
} }
static void pxiRxHandler(u32 __attribute__((unused)) irqn)
{
atomic_store(&pendingPxiRx, 1);
}
static u32 pxiRxUpdate(u32 *args) static u32 pxiRxUpdate(u32 *args)
{ {
u32 msg, lo, hi; u32 msg, lo, hi;
if (!atomic_exchange(&pendingPxiRx, 0)) if (!getEventIRQ()->test(PXI_RX_INTERRUPT, true))
return PXICMD_NONE; return PXICMD_NONE;
msg = PXI_Recv(); msg = PXI_Recv();
@ -113,14 +101,14 @@ void __attribute__((noreturn)) MainLoop(void)
#endif #endif
// initialize state stuff // initialize state stuff
atomic_init(&pendingVblank, 0); getEventIRQ()->reset();
atomic_init(&pendingPxiRx, 0); getEventMCU()->reset();
memset(&sharedMem, 0, sizeof(sharedMem)); memset(&sharedMem, 0, sizeof(sharedMem));
// configure interrupts // configure interrupts
gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO0, pxiRxHandler); gicSetInterruptConfig(PXI_RX_INTERRUPT, BIT(0), GIC_PRIO0, NULL);
gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO0, mcuInterruptHandler); gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, NULL);
gicSetInterruptConfig(VBLANK_INTERRUPT, BIT(0), GIC_PRIO0, vblankHandler); gicSetInterruptConfig(MCU_INTERRUPT, BIT(0), GIC_PRIO0, NULL);
// enable interrupts // enable interrupts
gicEnableInterrupt(MCU_INTERRUPT); gicEnableInterrupt(MCU_INTERRUPT);

View File

@ -0,0 +1,26 @@
#pragma once
#include <types.h>
typedef struct {
void (*reset)(void);
u32 (*test)(u32 param, u32 clear);
} EventInterface;
const EventInterface *getEventIRQ(void);
const EventInterface *getEventMCU(void);
static inline void eventReset(const EventInterface *ei) {
ei->reset();
}
static inline u32 eventTest(const EventInterface *ei, u32 param, u32 clear) {
return ei->test(param, clear);
}
static inline u32 eventWait(const EventInterface *ei, u32 param, u32 clear) {
while(1) {
u32 ret = ei->test(param, clear);
if (ret) return ret;
}
}

View File

@ -53,7 +53,7 @@
(sizeof(x) / sizeof(*(x))) (sizeof(x) / sizeof(*(x)))
#define bkpt \ #define bkpt \
__builtin_trap() do{__builtin_trap(); __builtin_unreachable();}while(0)
#define assert(x) \ #define assert(x) \
(!!(x) ? (void)0 : __builtin_trap()) (!!(x) ? (void)0 : __builtin_trap())