From 0b5d311673cdb9b2b57f5f7eb1ff6444a20d7a6a Mon Sep 17 00:00:00 2001 From: Jeremy Lorelli Date: Sun, 28 Dec 2025 02:18:54 -0800 Subject: [PATCH] bsps/m68k: Implement new IRQ system Implements the required bsp directives for the 'new' style rtems interrupt system. Previously, uC5282 only supported interrupts through the BSP_installVME_isr directive. BSP_installVME_isr still behaves the same, but is instead implemented using the new IRQ directives. To ensure compatibility with existing EPICS related code without causing subtle bugs, BSP_installVME_isr will also poke at the EPORT interrupt settings to enable IRQ1 when installing a "fake VME" interrupt (vector >= 192). This also fixes a regression from e9cb088995 that broke clock interrupt handlers, leading to the BSP crashing shortly after boot. --- bsps/m68k/uC5282/include/bsp/irq.h | 41 +- bsps/m68k/uC5282/irq/irq.c | 456 ++++++++++++++++++++++ bsps/m68k/uC5282/start/bspstart.c | 208 +--------- spec/build/bsps/m68k/uC5282/bspuc5282.yml | 4 +- 4 files changed, 502 insertions(+), 207 deletions(-) create mode 100644 bsps/m68k/uC5282/irq/irq.c diff --git a/bsps/m68k/uC5282/include/bsp/irq.h b/bsps/m68k/uC5282/include/bsp/irq.h index 8a97d7a1b0..30a04fb741 100644 --- a/bsps/m68k/uC5282/include/bsp/irq.h +++ b/bsps/m68k/uC5282/include/bsp/irq.h @@ -1 +1,40 @@ -#include +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsm68kuC5282 + * + * @brief Core IRQ definitions + */ + +/* + * Copyright (c) 2025 Jeremy Lorelli + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef LIBBSP_M68K_UC5282_IRQ_H +#define LIBBSP_M68K_UC5282_IRQ_H + +#include +#include +#include + +#define BSP_INTERRUPT_CUSTOM_VALID_VECTOR + +#define BSP_INTERRUPT_VECTOR_COUNT 192 + +#define BSP_VME_INTERRUPT_VECTOR_COUNT (255 - BSP_INTERRUPT_VECTOR_COUNT) + +#define BSP_FIRST_VME_INTERRUPT_VECTOR BSP_INTERRUPT_VECTOR_COUNT + +extern void uC5282_interrupt_vector_install(rtems_vector_number vector); +extern void uC5282_interrupt_vector_remove(rtems_vector_number vector); + +#define bsp_interrupt_vector_install(v) uC5282_interrupt_vector_install(v) +#define bsp_interrupt_vector_remove(v) uC5282_interrupt_vector_remove(v) + +#endif // LIBBSP_M68K_UC5282_IRQ_H diff --git a/bsps/m68k/uC5282/irq/irq.c b/bsps/m68k/uC5282/irq/irq.c new file mode 100644 index 0000000000..92ead40184 --- /dev/null +++ b/bsps/m68k/uC5282/irq/irq.c @@ -0,0 +1,456 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (c) 2025 Jeremy Lorelli + * Copyright (c) 2005 Eric Norum + * COPYRIGHT (c) 2005. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +#include +#include +#include + +#include + +typedef void(*void_func_t)(void); + +extern void bsp_default_isr_handler(int); + +/* + * Adjust interrupt vector to an offset in INTCn register + * MCF5282 interrupt vector mapping: + * * 0-63 -- internal CF interrupts + * * 64-127 -- INTC0 + * * 128-191 -- INTC1 + * * 192-255 -- Unused by hardware; used for fake interrupts in software + */ +static int vector_to_offset(int vector) +{ + if (vector < 128 && vector >= 64) + return vector - 64; + else if (vector < 192) + return vector - 128; + return 0; +} + +/* + * Get the associated INTCn chip. + * 0 == INTC0, 1 == INTC1, -1 == neither + */ +static int vector_to_source(int vector) +{ + if (vector < 128 && vector >= 64) + return 0; + else if (vector < 192 && vector >= 128) + return 1; + return -1; +} + +bool bsp_interrupt_is_valid_vector(rtems_vector_number vector) +{ + return vector < BSP_INTERRUPT_VECTOR_COUNT; +} + +static uint32_t s_wasInstalled[6]; + +static bool bsp_interrupt_was_installed(int vector) +{ + return !!(s_wasInstalled[vector/32] & (1< 7) || (priority < 0) || (priority > 7)) + return RTEMS_INVALID_NUMBER; + rtems_interrupt_disable(l); + if ((used[level-1] & (1 << priority)) == 0) { + used[level-1] |= (1 << priority); + ret = RTEMS_SUCCESSFUL; + } + rtems_interrupt_enable(l); + return ret; +} + +static void enable_irq(int which, int off) +{ + if (off < 32) { + *(which ? &MCF5282_INTC1_IMRL : &MCF5282_INTC0_IMRL) &= + ~(1< 8) { + reg = (which ? &MCF5282_INTC1_ICR09 - 8 : &MCF5282_INTC0_ICR1); + reg += off - 1; + + /* configure level and prio */ + *reg |= MCF5282_INTC_ICR_IL(level) | + MCF5282_INTC_ICR_IP(prio); + } + + enable_irq(which, off); + return RTEMS_SUCCESSFUL; + } + } + } + + return RTEMS_UNSATISFIED; + } + + enable_irq(which, off); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_interrupt_get_attributes( + rtems_vector_number vector, + rtems_interrupt_attributes *attributes +) +{ + return RTEMS_SUCCESSFUL; +} + +rtems_status_code bsp_interrupt_is_pending( + rtems_vector_number vector, + bool *pending +) +{ + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + bsp_interrupt_assert(pending != NULL); + *pending = false; + return RTEMS_UNSATISFIED; +} + +rtems_status_code bsp_interrupt_raise(rtems_vector_number vector) +{ + int off; + int which; + + bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector)); + + if ((which = vector_to_source(vector)) < 0) { + return RTEMS_UNSATISFIED; + } + + off = vector_to_offset(vector); + + if (off < 32) + *(which ? &MCF5282_INTC1_INTFRCL : &MCF5282_INTC0_INTFRCL) |= (1<= NVECTORS) + return (BSP_VME_ISR_t)NULL; + if (pusrArg) + *pusrArg = handlerTab[vector].arg; + return handlerTab[vector].func; +} + +/* + * Trampoline for FPGA interrupts on the IRQ1* pin + */ +static void fpga_trampoline(void* arg) +{ + rtems_vector_number v = (rtems_vector_number)arg; + + /* ACK the interrupt */ + MCF5282_EPORT_EPFR |= MCF5282_EPORT_EPFR_EPF1; + + /* + * Handle FPGA interrupts until all have been consumed + */ + int loopcount = 0; + while (((v = FPGA_IRQ_INFO) & 0x80) != 0) { + v = 192 + (v & 0x3f); + if (++loopcount >= 50) { + rtems_interrupt_level level; + rtems_interrupt_disable(level); + printk( + "\nTOO MANY FPGA INTERRUPTS (LAST WAS 0x%x) -- " + "DISABLING ALL FPGA INTERRUPTS.\n", + v & 0x3f + ); + MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT1; + rtems_interrupt_enable(level); + return; + } + + if (handlerTab[v].func) { + (*handlerTab[v].func)(handlerTab[v].arg, (unsigned long)v); + } + else { + rtems_interrupt_level level; + rtems_vector_number nv; + rtems_interrupt_disable(level); + printk("\nSPURIOUS FPGA INTERRUPT (0x%x).\n", v & 0x3f); + if ((((nv = FPGA_IRQ_INFO) & 0x80) != 0) + && ((nv & 0x3f) == (v & 0x3f))) { + printk("DISABLING ALL FPGA INTERRUPTS.\n"); + MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT1; + } + rtems_interrupt_enable(level); + return; + } + } +} + +/* + * Trampoline for legacy interrupts installed via BSP_installVME_isr + */ +static void trampoline(void* arg) +{ + rtems_vector_number vec = (rtems_vector_number)arg; + if (handlerTab[vec].func) + (*handlerTab[vec].func)(handlerTab[vec].arg, (unsigned long)vec); +} + +int BSP_installVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *usrArg) +{ + rtems_interrupt_level level; + int i; + + /* + * Register the handler information + */ + if (vector >= NVECTORS) + return -1; + + handlerTab[vector].func = handler; + handlerTab[vector].arg = usrArg; + + rtems_interrupt_disable(level); + + /* + * If this is an external FPGA ('VME') vector set up the real IRQ. + */ + if ((vector >= BSP_FIRST_VME_INTERRUPT_VECTOR) && (vector <= 255)) { + static volatile int setupDone; + if (setupDone) { + rtems_interrupt_enable(level); + return 0; + } + setupDone = 1; + + i = rtems_interrupt_handler_install( + FPGA_VECTOR, + "fpga_trampoline", + RTEMS_INTERRUPT_UNIQUE, + fpga_trampoline, + (void*)FPGA_VECTOR + ); + + if (i == RTEMS_SUCCESSFUL) + i = bsp_interrupt_vector_enable(FPGA_VECTOR); + + /* enable IRQ1 EPORT interrupts as well */ + MCF5282_EPORT_EPIER |= MCF5282_EPORT_EPIER_EPIE1; + + rtems_interrupt_enable(level); + return i; + } + + /* + * Make the connection between the interrupt and the local handler + */ + i = rtems_interrupt_handler_install( + vector, + "trampoline", + RTEMS_INTERRUPT_UNIQUE, + trampoline, + (void*)vector + ); + + if (i != RTEMS_SUCCESSFUL) { + rtems_interrupt_enable(level); + return i; + } + + /* for compatibility with older code: Enable IRQn interrupts on EPORT too. + * This used to be done in init_intc0_bit */ + if (vector <= (64 + 7) && vector > 64) { + MCF5282_EPORT_EPIER |= 1 << (vector - 64); + } + + i = bsp_interrupt_vector_enable(vector); + + rtems_interrupt_enable(level); + return i; +} + +int BSP_removeVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *usrArg) +{ + if (vector >= NVECTORS) + return -1; + if ((handlerTab[vector].func != handler) + || (handlerTab[vector].arg != usrArg)) + return -1; + handlerTab[vector].func = (BSP_VME_ISR_t)NULL; + return 0; +} diff --git a/bsps/m68k/uC5282/start/bspstart.c b/bsps/m68k/uC5282/start/bspstart.c index 83516bd18b..20e8fe1095 100644 --- a/bsps/m68k/uC5282/start/bspstart.c +++ b/bsps/m68k/uC5282/start/bspstart.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -322,6 +323,8 @@ void bsp_start( void ) "System clock speed: %" PRIu32 "Hz\n", bsp_get_CPU_clock_speed() ); } + + bsp_interrupt_initialize(); } uint32_t bsp_get_CPU_clock_speed(void) @@ -329,27 +332,6 @@ uint32_t bsp_get_CPU_clock_speed(void) return( BSP_sys_clk_speed ); } -/* - * Interrupt controller allocation - */ -rtems_status_code -bsp_allocate_interrupt(int level, int priority) -{ - static char used[7]; - rtems_interrupt_level l; - rtems_status_code ret = RTEMS_RESOURCE_IN_USE; - - if ((level < 1) || (level > 7) || (priority < 0) || (priority > 7)) - return RTEMS_INVALID_NUMBER; - rtems_interrupt_disable(l); - if ((used[level-1] & (1 << priority)) == 0) { - used[level-1] |= (1 << priority); - ret = RTEMS_SUCCESSFUL; - } - rtems_interrupt_enable(l); - return ret; -} - /* * Arcturus bootloader system calls */ @@ -482,190 +464,6 @@ int BSP_disableVME_int_lvl(unsigned int level) return 0; } -/* - * 'VME' interrupt support - * Interrupt vectors 192-255 are set aside for use by external logic which - * drives IRQ1*. The actual interrupt source is read from the external - * logic at FPGA_IRQ_INFO. The most-significant bit of the least-significant - * byte read from this location is set as long as the external logic has - * interrupts to be serviced. The least-significant six bits indicate the - * interrupt source within the external logic and are used to select the - * specified interupt handler. - */ -#define NVECTOR 256 -#define FPGA_VECTOR (64+1) /* IRQ1* pin connected to external FPGA */ -#define FPGA_IRQ_INFO *((vuint16 *)(0x31000000 + 0xfffffe)) - -static struct handlerTab { - BSP_VME_ISR_t func; - void *arg; -} handlerTab[NVECTOR]; - -BSP_VME_ISR_t -BSP_getVME_isr(unsigned long vector, void **pusrArg) -{ - if (vector >= NVECTOR) - return (BSP_VME_ISR_t)NULL; - if (pusrArg) - *pusrArg = handlerTab[vector].arg; - return handlerTab[vector].func; -} - -static rtems_isr -fpga_trampoline (rtems_vector_number v) -{ - /* - * Handle FPGA interrupts until all have been consumed - */ - int loopcount = 0; - while (((v = FPGA_IRQ_INFO) & 0x80) != 0) { - v = 192 + (v & 0x3f); - if (++loopcount >= 50) { - rtems_interrupt_level level; - rtems_interrupt_disable(level); - printk( - "\nTOO MANY FPGA INTERRUPTS (LAST WAS 0x%x) -- " - "DISABLING ALL FPGA INTERRUPTS.\n", - v & 0x3f - ); - MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT1; - rtems_interrupt_enable(level); - return; - } - if (handlerTab[v].func) { - (*handlerTab[v].func)(handlerTab[v].arg, (unsigned long)v); - } - else { - rtems_interrupt_level level; - rtems_vector_number nv; - rtems_interrupt_disable(level); - printk("\nSPURIOUS FPGA INTERRUPT (0x%x).\n", v & 0x3f); - if ((((nv = FPGA_IRQ_INFO) & 0x80) != 0) - && ((nv & 0x3f) == (v & 0x3f))) { - printk("DISABLING ALL FPGA INTERRUPTS.\n"); - MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT1; - } - rtems_interrupt_enable(level); - return; - } - } -} - -static rtems_isr -trampoline (rtems_vector_number v) -{ - if (handlerTab[v].func) - (*handlerTab[v].func)(handlerTab[v].arg, (unsigned long)v); -} - -static void -enable_irq(unsigned source) -{ -rtems_interrupt_level level; - rtems_interrupt_disable(level); - if (source >= 32) - MCF5282_INTC0_IMRH &= ~(1 << (source - 32)); - else - MCF5282_INTC0_IMRL &= ~((1 << source) | - MCF5282_INTC_IMRL_MASKALL); - rtems_interrupt_enable(level); -} - -static int -init_intc0_bit(unsigned long vector) -{ -rtems_interrupt_level level; - - /* - * Find an unused level/priority if this is an on-chip (INTC0) - * source and this is the first time the source is being used. - * Interrupt sources 1 through 7 are fixed level/priority - */ - - if ((vector >= 65) && (vector <= 127)) { - int l, p; - int source = vector - 64; - static unsigned char installed[8]; - - rtems_interrupt_disable(level); - if (installed[source/8] & (1 << (source % 8))) { - rtems_interrupt_enable(level); - return 0; - } - installed[source/8] |= (1 << (source % 8)); - rtems_interrupt_enable(level); - for (l = 1 ; l < 7 ; l++) { - for (p = 0 ; p < 8 ; p++) { - if ((source < 8) - || (bsp_allocate_interrupt(l,p) == RTEMS_SUCCESSFUL)) { - if (source < 8) - MCF5282_EPORT_EPIER |= 1 << source; - else - *(&MCF5282_INTC0_ICR1 + (source - 1)) = - MCF5282_INTC_ICR_IL(l) | - MCF5282_INTC_ICR_IP(p); - enable_irq(source); - return 0; - } - } - } - return -1; - } - return 0; -} - -int -BSP_installVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *usrArg) -{ - rtems_isr_entry old_handler; - rtems_interrupt_level level; - - /* - * Register the handler information - */ - if (vector >= NVECTOR) - return -1; - handlerTab[vector].func = handler; - handlerTab[vector].arg = usrArg; - - /* - * If this is an external FPGA ('VME') vector set up the real IRQ. - */ - if ((vector >= 192) && (vector <= 255)) { - int i; - static volatile int setupDone; - rtems_interrupt_disable(level); - if (setupDone) { - rtems_interrupt_enable(level); - return 0; - } - setupDone = 1; - rtems_interrupt_catch(fpga_trampoline, FPGA_VECTOR, &old_handler); - i = init_intc0_bit(FPGA_VECTOR); - rtems_interrupt_enable(level); - return i; - } - - /* - * Make the connection between the interrupt and the local handler - */ - rtems_interrupt_catch(trampoline, vector, &old_handler); - - return init_intc0_bit(vector); -} - -int -BSP_removeVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *usrArg) -{ - if (vector >= NVECTOR) - return -1; - if ((handlerTab[vector].func != handler) - || (handlerTab[vector].arg != usrArg)) - return -1; - handlerTab[vector].func = (BSP_VME_ISR_t)NULL; - return 0; -} - int BSP_vme2local_adrs( unsigned am, unsigned long vmeaddr, unsigned long *plocaladdr) diff --git a/spec/build/bsps/m68k/uC5282/bspuc5282.yml b/spec/build/bsps/m68k/uC5282/bspuc5282.yml index 9ddab00657..13656aef44 100644 --- a/spec/build/bsps/m68k/uC5282/bspuc5282.yml +++ b/spec/build/bsps/m68k/uC5282/bspuc5282.yml @@ -29,7 +29,7 @@ links: - role: build-dependency uid: ../../obj - role: build-dependency - uid: ../../objirqdflt + uid: ../../objirq - role: build-dependency uid: ../../objmem - role: build-dependency @@ -46,6 +46,8 @@ source: - bsps/m68k/uC5282/start/bspreset.c - bsps/m68k/uC5282/start/bspstart.c - bsps/m68k/uC5282/start/init5282.c +- bsps/m68k/uC5282/irq/irq.c +- bsps/shared/irq/irq-default-handler.c - bsps/shared/dev/getentropy/getentropy-cpucounter.c - bsps/shared/start/gettargethash-default.c - bsps/shared/start/sbrk.c