From ac04bb85ebea019afe4253253945f978661b8fa2 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 12 Mar 2018 16:42:16 +0100 Subject: bsps/powerpc: Move legacy IRQ support This patch is a part of the BSP source reorganization. Update #3285. --- bsps/powerpc/shared/irq/ppc-irq-legacy.c | 393 +++++++++++++++++++++ c/src/lib/libbsp/powerpc/beatnik/Makefile.am | 2 +- c/src/lib/libbsp/powerpc/haleakala/Makefile.am | 2 +- .../libbsp/powerpc/motorola_powerpc/Makefile.am | 2 +- c/src/lib/libbsp/powerpc/mvme3100/Makefile.am | 4 +- c/src/lib/libbsp/powerpc/mvme5500/Makefile.am | 2 +- c/src/lib/libbsp/powerpc/psim/Makefile.am | 2 +- c/src/lib/libcpu/powerpc/Makefile.am | 6 - .../libcpu/powerpc/new-exceptions/bspsupport/irq.c | 393 --------------------- 9 files changed, 400 insertions(+), 406 deletions(-) create mode 100644 bsps/powerpc/shared/irq/ppc-irq-legacy.c delete mode 100644 c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c diff --git a/bsps/powerpc/shared/irq/ppc-irq-legacy.c b/bsps/powerpc/shared/irq/ppc-irq-legacy.c new file mode 100644 index 0000000000..931a9c6074 --- /dev/null +++ b/bsps/powerpc/shared/irq/ppc-irq-legacy.c @@ -0,0 +1,393 @@ +/* + * + * This file contains the PIC-independent implementation of the functions described in irq.h + * + * Copyright (C) 1998, 1999 valette@crf.canon.fr + * + * 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 /* for printk */ +#include +#include +#include + +/* + * default handler connected on each irq after bsp initialization + */ +static rtems_irq_connect_data default_rtems_entry; + +/* + * location used to store initial tables used for interrupt + * management. + */ +static rtems_irq_global_settings* internal_config; +static rtems_irq_connect_data* rtems_hdl_tbl; + + +SPR_RW(BOOKE_TSR) +SPR_RW(PPC405_TSR) + +/* legacy mode for bookE DEC exception; + * to avoid the double layer of function calls + * (dec_handler_bookE -> C_dispatch_irq_handler -> user handler) + * it is preferrable for the user to hook the DEC + * exception directly. + * However, the legacy mode works with less modifications + * of user code. + */ +static int C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum) +{ + /* clear interrupt; we must do this + * before C_dispatch_irq_handler() + * re-enables MSR_EE. + * Note that PPC405 uses a different SPR# for TSR + */ + if ( ppc_cpu_is_bookE()==PPC_BOOKE_405) + _write_PPC405_TSR( BOOKE_TSR_DIS ); + else + _write_BOOKE_TSR( BOOKE_TSR_DIS ); + return C_dispatch_irq_handler(frame, ASM_DEC_VECTOR); +} + +/* + * ------------------------ RTEMS Irq helper functions ---------------- + */ + +/* + * This function check that the value given for the irq line + * is valid. + */ + +static int isValidInterrupt(int irq) +{ + if ( (irq < internal_config->irqBase) || (irq >= internal_config->irqBase + internal_config->irqNb)) + return 0; + return 1; +} + +/* + * ------------------------ RTEMS Shared Irq Handler Mngt Routines ---------------- + */ +int BSP_install_rtems_shared_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + rtems_irq_connect_data* vchain; + + if (!isValidInterrupt(irq->name)) { + printk("Invalid interrupt vector %d\n",irq->name); + return 0; + } + + /* pre-allocate memory outside of critical section */ + vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data)); + + rtems_interrupt_disable(level); + + if ( (intptr_t)rtems_hdl_tbl[irq->name].next_handler == -1 ) { + rtems_interrupt_enable(level); + printk("IRQ vector %d already connected to an unshared handler\n",irq->name); + free(vchain); + return 0; + } + + /* save off topmost handler */ + vchain[0]= rtems_hdl_tbl[irq->name]; + + /* + * store the data provided by user + */ + rtems_hdl_tbl[irq->name] = *irq; + + /* link chain to new topmost handler */ + rtems_hdl_tbl[irq->name].next_handler = (void *)vchain; + + /* + * enable_irq_at_pic is supposed to ignore + * requests to disable interrupts outside + * of the range handled by the PIC + */ + BSP_enable_irq_at_pic(irq->name); + + /* + * Enable interrupt on device + */ + if (irq->on) + irq->on(irq); + + rtems_interrupt_enable(level); + + return 1; +} + +/* + * ------------------------ RTEMS Single Irq Handler Mngt Routines ---------------- + */ + +int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + if (!isValidInterrupt(irq->name)) { + printk("Invalid interrupt vector %d\n",irq->name); + return 0; + } + /* + * Check if default handler is actually connected. If not issue an error. + * You must first get the current handler via i386_get_current_idt_entry + * and then disconnect it using i386_delete_idt_entry. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + rtems_interrupt_disable(level); + if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { + rtems_interrupt_enable(level); + printk("IRQ vector %d already connected\n",irq->name); + return 0; + } + + /* + * store the data provided by user + */ + rtems_hdl_tbl[irq->name] = *irq; + rtems_hdl_tbl[irq->name].next_handler = (void *)-1; + + /* + * enable_irq_at_pic is supposed to ignore + * requests to disable interrupts outside + * of the range handled by the PIC + */ + BSP_enable_irq_at_pic(irq->name); + + /* + * Enable interrupt on device + */ + if (irq->on) + irq->on(irq); + + rtems_interrupt_enable(level); + + return 1; +} + +int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) +{ + rtems_interrupt_level level; + + if (!isValidInterrupt(irq->name)) { + return 0; + } + rtems_interrupt_disable(level); + *irq = rtems_hdl_tbl[irq->name]; + rtems_interrupt_enable(level); + return 1; +} + +int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) +{ + rtems_irq_connect_data *pchain= NULL, *vchain = NULL; + rtems_interrupt_level level; + + if (!isValidInterrupt(irq->name)) { + return 0; + } + /* + * Check if default handler is actually connected. If not issue an error. + * You must first get the current handler via i386_get_current_idt_entry + * and then disconnect it using i386_delete_idt_entry. + * RATIONALE : to always have the same transition by forcing the user + * to get the previous handler before accepting to disconnect. + */ + rtems_interrupt_disable(level); + if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { + rtems_interrupt_enable(level); + return 0; + } + + if( (intptr_t)rtems_hdl_tbl[irq->name].next_handler != -1 ) + { + int found = 0; + + for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]); + (vchain->hdl != default_rtems_entry.hdl); + (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) ) + { + if( vchain->hdl == irq->hdl ) + { + found= -1; break; + } + } + + if( !found ) + { + rtems_interrupt_enable(level); + return 0; + } + } + else + { + if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) + { + rtems_interrupt_enable(level); + return 0; + } + } + + /* + * Disable interrupt on device + */ + if (irq->off) + irq->off(irq); + + /* + * restore the default irq value + */ + if( !vchain ) + { + /* single handler vector... */ + rtems_hdl_tbl[irq->name] = default_rtems_entry; + } + else + { + if( pchain ) + { + /* non-first handler being removed */ + pchain->next_handler = vchain->next_handler; + } + else + { + /* first handler isn't malloc'ed, so just overwrite it. Since + the contents of vchain are being struct copied, vchain itself + goes away */ + vchain = vchain->next_handler; + rtems_hdl_tbl[irq->name]= *vchain; + } + } + + /* Only disable at PIC if we removed the last handler */ + if ( rtems_hdl_tbl[irq->name].hdl == default_rtems_entry.hdl ) { + /* + * disable_irq_at_pic is supposed to ignore + * requests to disable interrupts outside + * of the range handled by the PIC; + */ + BSP_disable_irq_at_pic(irq->name); + } + + rtems_interrupt_enable(level); + + free(vchain); + + return 1; +} + +/* + * Less cumbersome, alternate entry points; + * RETURNS: more traditional, 0 on success, nonzero on error + */ + +static int doit( + int (*p)(const rtems_irq_connect_data*), + rtems_irq_number n, + rtems_irq_hdl hdl, + rtems_irq_hdl_param prm) +{ +rtems_irq_connect_data xx; + xx.name = n; + xx.hdl = hdl; + xx.handle = prm; + xx.on = 0; + xx.off = 0; + xx.isOn = 0; + return ! p(&xx); +} + +int BSP_rtems_int_connect(rtems_irq_number n, rtems_irq_hdl hdl, rtems_irq_hdl_param p) +{ + return doit(BSP_install_rtems_shared_irq_handler, n, hdl, p); +} + +int BSP_rtems_int_disconnect(rtems_irq_number n, rtems_irq_hdl hdl, rtems_irq_hdl_param p) +{ + return doit(BSP_remove_rtems_irq_handler, n, hdl, p); +} + + +/* + * RTEMS Global Interrupt Handler Management Routines + */ + +int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) +{ + int i; + rtems_interrupt_level level; + rtems_irq_connect_data* vchain; + + /* + * Store various code accelerators + */ + internal_config = config; + default_rtems_entry = config->defaultEntry; + rtems_hdl_tbl = config->irqHdlTbl; + + rtems_interrupt_disable(level); + + if ( !BSP_setup_the_pic(config) ) { + printk("PIC setup failed; leaving IRQs OFF\n"); + return 0; + } + + for ( i = config->irqBase; i < config->irqBase + config->irqNb; i++ ) { + for( vchain = &rtems_hdl_tbl[i]; + ((intptr_t)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); + vchain = (rtems_irq_connect_data*)vchain->next_handler ) + { + if (vchain->on) + vchain->on(vchain); + } + if ( vchain != &rtems_hdl_tbl[i] ) { + /* at least one handler registered */ + BSP_enable_irq_at_pic(i); + } else { +/* Do NOT disable; there might be boards with cascaded + * interrupt controllers where the BSP (incorrectly) does + * not ignore the cascaded interrupts in BSP_disable_irq_at_pic()! + * Instead, we rely on BSP_setup_the_pic() for a good + * initial configuration. + * + BSP_disable_irq_at_pic(i); + */ + } + } + + rtems_interrupt_enable(level); + + { + ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler); + + if ( ppc_cpu_is_bookE() ) { + /* bookE decrementer interrupt needs to be cleared BEFORE + * dispatching the user ISR (because the user ISR is called + * with EE enabled) + * We do this so that existing DEC handlers can be used + * with minor modifications. + */ + ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler_bookE); + } else { + ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler); + } + } + return 1; +} + +int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config) +{ + *config = internal_config; + return 0; +} diff --git a/c/src/lib/libbsp/powerpc/beatnik/Makefile.am b/c/src/lib/libbsp/powerpc/beatnik/Makefile.am index dcb82d9917..ae8971ded8 100644 --- a/c/src/lib/libbsp/powerpc/beatnik/Makefile.am +++ b/c/src/lib/libbsp/powerpc/beatnik/Makefile.am @@ -164,12 +164,12 @@ endif libbsp_a_SOURCES += ../../shared/tod.c tod/todcfg.c libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \ ../../../libcpu/@RTEMS_CPU@/shared/stack.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \ - ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/clock.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/mmu.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/timer.rel \ diff --git a/c/src/lib/libbsp/powerpc/haleakala/Makefile.am b/c/src/lib/libbsp/powerpc/haleakala/Makefile.am index dcb66d0f72..7a85b96caf 100644 --- a/c/src/lib/libbsp/powerpc/haleakala/Makefile.am +++ b/c/src/lib/libbsp/powerpc/haleakala/Makefile.am @@ -43,10 +43,10 @@ libbsp_a_SOURCES += network/network.c endif libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \ - ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel \ ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \ ../../../libcpu/@RTEMS_CPU@/ppc403/clock.rel \ ../../../libcpu/@RTEMS_CPU@/ppc403/timer.rel diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am b/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am index 1cf3671233..ceb0f8844a 100644 --- a/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am +++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.am @@ -115,6 +115,7 @@ endif endif libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c libbsp_a_LIBADD = \ polledIO.rel \ @@ -123,7 +124,6 @@ libbsp_a_LIBADD = \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/clock.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \ - ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/mmu.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/timer.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/altivec.rel diff --git a/c/src/lib/libbsp/powerpc/mvme3100/Makefile.am b/c/src/lib/libbsp/powerpc/mvme3100/Makefile.am index a684c75a47..d7c2870e51 100644 --- a/c/src/lib/libbsp/powerpc/mvme3100/Makefile.am +++ b/c/src/lib/libbsp/powerpc/mvme3100/Makefile.am @@ -106,6 +106,7 @@ network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) endif libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \ ../../../libcpu/@RTEMS_CPU@/shared/stack.rel \ @@ -113,8 +114,7 @@ libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \ ../../../libcpu/@RTEMS_CPU@/e500/timer.rel \ ../../../libcpu/@RTEMS_CPU@/e500/mmu.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \ - ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \ - ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel + ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel if HAS_NETWORKING libbsp_a_LIBADD += network.rel diff --git a/c/src/lib/libbsp/powerpc/mvme5500/Makefile.am b/c/src/lib/libbsp/powerpc/mvme5500/Makefile.am index 72a3f719e5..c82e38486c 100644 --- a/c/src/lib/libbsp/powerpc/mvme5500/Makefile.am +++ b/c/src/lib/libbsp/powerpc/mvme5500/Makefile.am @@ -84,6 +84,7 @@ project_lib_DATA += linkcmds dist_project_lib_DATA += ../shared/startup/linkcmds.share libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c libbsp_a_LIBADD = \ ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \ @@ -91,7 +92,6 @@ libbsp_a_LIBADD = \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/clock.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \ - ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/mmu.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/timer.rel\ ../../../libcpu/@RTEMS_CPU@/mpc6xx/altivec.rel diff --git a/c/src/lib/libbsp/powerpc/psim/Makefile.am b/c/src/lib/libbsp/powerpc/psim/Makefile.am index 5206c63984..6e0c38473a 100644 --- a/c/src/lib/libbsp/powerpc/psim/Makefile.am +++ b/c/src/lib/libbsp/powerpc/psim/Makefile.am @@ -61,13 +61,13 @@ libbsp_a_SOURCES += network/if_sim.c endif libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c +libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \ ../../../libcpu/@RTEMS_CPU@/shared/stack.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/clock.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \ - ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/mmu.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/timer.rel \ ../../../libcpu/@RTEMS_CPU@/mpc6xx/altivec.rel diff --git a/c/src/lib/libcpu/powerpc/Makefile.am b/c/src/lib/libcpu/powerpc/Makefile.am index b0bb0735e5..a16c762edf 100644 --- a/c/src/lib/libcpu/powerpc/Makefile.am +++ b/c/src/lib/libcpu/powerpc/Makefile.am @@ -33,12 +33,6 @@ endif new_exceptions_exc_bspsupport_rel_CPPFLAGS = $(AM_CPPFLAGS) new_exceptions_exc_bspsupport_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) - -noinst_PROGRAMS += new-exceptions/irq_bspsupport.rel - -new_exceptions_irq_bspsupport_rel_SOURCES = new-exceptions/bspsupport/irq.c -new_exceptions_irq_bspsupport_rel_CPPFLAGS = $(AM_CPPFLAGS) -new_exceptions_irq_bspsupport_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) endif EXTRA_DIST += new-exceptions/bspsupport/README diff --git a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c b/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c deleted file mode 100644 index 931a9c6074..0000000000 --- a/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * - * This file contains the PIC-independent implementation of the functions described in irq.h - * - * Copyright (C) 1998, 1999 valette@crf.canon.fr - * - * 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 /* for printk */ -#include -#include -#include - -/* - * default handler connected on each irq after bsp initialization - */ -static rtems_irq_connect_data default_rtems_entry; - -/* - * location used to store initial tables used for interrupt - * management. - */ -static rtems_irq_global_settings* internal_config; -static rtems_irq_connect_data* rtems_hdl_tbl; - - -SPR_RW(BOOKE_TSR) -SPR_RW(PPC405_TSR) - -/* legacy mode for bookE DEC exception; - * to avoid the double layer of function calls - * (dec_handler_bookE -> C_dispatch_irq_handler -> user handler) - * it is preferrable for the user to hook the DEC - * exception directly. - * However, the legacy mode works with less modifications - * of user code. - */ -static int C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum) -{ - /* clear interrupt; we must do this - * before C_dispatch_irq_handler() - * re-enables MSR_EE. - * Note that PPC405 uses a different SPR# for TSR - */ - if ( ppc_cpu_is_bookE()==PPC_BOOKE_405) - _write_PPC405_TSR( BOOKE_TSR_DIS ); - else - _write_BOOKE_TSR( BOOKE_TSR_DIS ); - return C_dispatch_irq_handler(frame, ASM_DEC_VECTOR); -} - -/* - * ------------------------ RTEMS Irq helper functions ---------------- - */ - -/* - * This function check that the value given for the irq line - * is valid. - */ - -static int isValidInterrupt(int irq) -{ - if ( (irq < internal_config->irqBase) || (irq >= internal_config->irqBase + internal_config->irqNb)) - return 0; - return 1; -} - -/* - * ------------------------ RTEMS Shared Irq Handler Mngt Routines ---------------- - */ -int BSP_install_rtems_shared_irq_handler (const rtems_irq_connect_data* irq) -{ - rtems_interrupt_level level; - rtems_irq_connect_data* vchain; - - if (!isValidInterrupt(irq->name)) { - printk("Invalid interrupt vector %d\n",irq->name); - return 0; - } - - /* pre-allocate memory outside of critical section */ - vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data)); - - rtems_interrupt_disable(level); - - if ( (intptr_t)rtems_hdl_tbl[irq->name].next_handler == -1 ) { - rtems_interrupt_enable(level); - printk("IRQ vector %d already connected to an unshared handler\n",irq->name); - free(vchain); - return 0; - } - - /* save off topmost handler */ - vchain[0]= rtems_hdl_tbl[irq->name]; - - /* - * store the data provided by user - */ - rtems_hdl_tbl[irq->name] = *irq; - - /* link chain to new topmost handler */ - rtems_hdl_tbl[irq->name].next_handler = (void *)vchain; - - /* - * enable_irq_at_pic is supposed to ignore - * requests to disable interrupts outside - * of the range handled by the PIC - */ - BSP_enable_irq_at_pic(irq->name); - - /* - * Enable interrupt on device - */ - if (irq->on) - irq->on(irq); - - rtems_interrupt_enable(level); - - return 1; -} - -/* - * ------------------------ RTEMS Single Irq Handler Mngt Routines ---------------- - */ - -int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) -{ - rtems_interrupt_level level; - - if (!isValidInterrupt(irq->name)) { - printk("Invalid interrupt vector %d\n",irq->name); - return 0; - } - /* - * Check if default handler is actually connected. If not issue an error. - * You must first get the current handler via i386_get_current_idt_entry - * and then disconnect it using i386_delete_idt_entry. - * RATIONALE : to always have the same transition by forcing the user - * to get the previous handler before accepting to disconnect. - */ - rtems_interrupt_disable(level); - if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { - rtems_interrupt_enable(level); - printk("IRQ vector %d already connected\n",irq->name); - return 0; - } - - /* - * store the data provided by user - */ - rtems_hdl_tbl[irq->name] = *irq; - rtems_hdl_tbl[irq->name].next_handler = (void *)-1; - - /* - * enable_irq_at_pic is supposed to ignore - * requests to disable interrupts outside - * of the range handled by the PIC - */ - BSP_enable_irq_at_pic(irq->name); - - /* - * Enable interrupt on device - */ - if (irq->on) - irq->on(irq); - - rtems_interrupt_enable(level); - - return 1; -} - -int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) -{ - rtems_interrupt_level level; - - if (!isValidInterrupt(irq->name)) { - return 0; - } - rtems_interrupt_disable(level); - *irq = rtems_hdl_tbl[irq->name]; - rtems_interrupt_enable(level); - return 1; -} - -int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) -{ - rtems_irq_connect_data *pchain= NULL, *vchain = NULL; - rtems_interrupt_level level; - - if (!isValidInterrupt(irq->name)) { - return 0; - } - /* - * Check if default handler is actually connected. If not issue an error. - * You must first get the current handler via i386_get_current_idt_entry - * and then disconnect it using i386_delete_idt_entry. - * RATIONALE : to always have the same transition by forcing the user - * to get the previous handler before accepting to disconnect. - */ - rtems_interrupt_disable(level); - if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { - rtems_interrupt_enable(level); - return 0; - } - - if( (intptr_t)rtems_hdl_tbl[irq->name].next_handler != -1 ) - { - int found = 0; - - for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]); - (vchain->hdl != default_rtems_entry.hdl); - (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) ) - { - if( vchain->hdl == irq->hdl ) - { - found= -1; break; - } - } - - if( !found ) - { - rtems_interrupt_enable(level); - return 0; - } - } - else - { - if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) - { - rtems_interrupt_enable(level); - return 0; - } - } - - /* - * Disable interrupt on device - */ - if (irq->off) - irq->off(irq); - - /* - * restore the default irq value - */ - if( !vchain ) - { - /* single handler vector... */ - rtems_hdl_tbl[irq->name] = default_rtems_entry; - } - else - { - if( pchain ) - { - /* non-first handler being removed */ - pchain->next_handler = vchain->next_handler; - } - else - { - /* first handler isn't malloc'ed, so just overwrite it. Since - the contents of vchain are being struct copied, vchain itself - goes away */ - vchain = vchain->next_handler; - rtems_hdl_tbl[irq->name]= *vchain; - } - } - - /* Only disable at PIC if we removed the last handler */ - if ( rtems_hdl_tbl[irq->name].hdl == default_rtems_entry.hdl ) { - /* - * disable_irq_at_pic is supposed to ignore - * requests to disable interrupts outside - * of the range handled by the PIC; - */ - BSP_disable_irq_at_pic(irq->name); - } - - rtems_interrupt_enable(level); - - free(vchain); - - return 1; -} - -/* - * Less cumbersome, alternate entry points; - * RETURNS: more traditional, 0 on success, nonzero on error - */ - -static int doit( - int (*p)(const rtems_irq_connect_data*), - rtems_irq_number n, - rtems_irq_hdl hdl, - rtems_irq_hdl_param prm) -{ -rtems_irq_connect_data xx; - xx.name = n; - xx.hdl = hdl; - xx.handle = prm; - xx.on = 0; - xx.off = 0; - xx.isOn = 0; - return ! p(&xx); -} - -int BSP_rtems_int_connect(rtems_irq_number n, rtems_irq_hdl hdl, rtems_irq_hdl_param p) -{ - return doit(BSP_install_rtems_shared_irq_handler, n, hdl, p); -} - -int BSP_rtems_int_disconnect(rtems_irq_number n, rtems_irq_hdl hdl, rtems_irq_hdl_param p) -{ - return doit(BSP_remove_rtems_irq_handler, n, hdl, p); -} - - -/* - * RTEMS Global Interrupt Handler Management Routines - */ - -int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) -{ - int i; - rtems_interrupt_level level; - rtems_irq_connect_data* vchain; - - /* - * Store various code accelerators - */ - internal_config = config; - default_rtems_entry = config->defaultEntry; - rtems_hdl_tbl = config->irqHdlTbl; - - rtems_interrupt_disable(level); - - if ( !BSP_setup_the_pic(config) ) { - printk("PIC setup failed; leaving IRQs OFF\n"); - return 0; - } - - for ( i = config->irqBase; i < config->irqBase + config->irqNb; i++ ) { - for( vchain = &rtems_hdl_tbl[i]; - ((intptr_t)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); - vchain = (rtems_irq_connect_data*)vchain->next_handler ) - { - if (vchain->on) - vchain->on(vchain); - } - if ( vchain != &rtems_hdl_tbl[i] ) { - /* at least one handler registered */ - BSP_enable_irq_at_pic(i); - } else { -/* Do NOT disable; there might be boards with cascaded - * interrupt controllers where the BSP (incorrectly) does - * not ignore the cascaded interrupts in BSP_disable_irq_at_pic()! - * Instead, we rely on BSP_setup_the_pic() for a good - * initial configuration. - * - BSP_disable_irq_at_pic(i); - */ - } - } - - rtems_interrupt_enable(level); - - { - ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler); - - if ( ppc_cpu_is_bookE() ) { - /* bookE decrementer interrupt needs to be cleared BEFORE - * dispatching the user ISR (because the user ISR is called - * with EE enabled) - * We do this so that existing DEC handlers can be used - * with minor modifications. - */ - ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler_bookE); - } else { - ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler); - } - } - return 1; -} - -int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config) -{ - *config = internal_config; - return 0; -} -- cgit v1.2.3