/*===============================================================*\ | Project: RTEMS generic MPC83xx BSP | +-----------------------------------------------------------------+ | Copyright (c) 2007 | | Embedded Brains GmbH | | Obere Lagerstr. 30 | | D-82178 Puchheim | | Germany | | rtems@embedded-brains.de | +-----------------------------------------------------------------+ | The license and distribution terms for this file may be | | found in the file LICENSE in this distribution or at | | | | http://www.rtems.com/license/LICENSE. | | | +-----------------------------------------------------------------+ | this file contains the irq controller init code | +-----------------------------------------------------------------+ | derived from the virtex BSP | \*===============================================================*/ #include #include #include #include #include #include #include static rtems_irq_connect_data rtemsIrqTbl[BSP_IRQ_NUMBER]; rtems_irq_connect_data *BSP_rtems_irq_tbl; rtems_irq_global_settings* BSP_rtems_irq_config; /*********************************************************** * dummy functions for on/off/isOn calls * these functions just do nothing fulfill the semantic * requirements to enable/disable a certain interrupt or exception */ void BSP_irq_nop_func(const rtems_irq_connect_data *unused) { /* * nothing to do */ } void BSP_irq_nop_hdl(void *hdl) { /* * nothing to do */ } int BSP_irq_true_func(const rtems_irq_connect_data *unused) { /* * nothing to do */ return TRUE; } /*********************************************************** * interrupt handler and its enable/disable functions ***********************************************************/ /*********************************************************** * functions to enable/disable/query external/critical interrupts */ void BSP_irqexc_on_fnc(rtems_irq_connect_data *conn_data) { uint32_t msr_value; /* * get current MSR value */ _CPU_MSR_GET(msr_value); msr_value |= PPC_MSR_EE; _CPU_MSR_SET(msr_value); } void BSP_irqexc_off_fnc(rtems_irq_connect_data *unused) { /* * nothing to do */ } /*********************************************************** * High level IRQ handler called from shared_raw_irq_code_entry */ void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum) { uint32_t msr_value,new_msr; /* * Handle interrupt */ switch(excNum) { case ASM_DEC_VECTOR: _CPU_MSR_GET(msr_value); new_msr = msr_value | MSR_EE; _CPU_MSR_SET(new_msr); BSP_rtems_irq_tbl[BSP_DECREMENTER].hdl (BSP_rtems_irq_tbl[BSP_DECREMENTER].handle); _CPU_MSR_SET(msr_value); break; #if 0 /* Critical interrupts not yet supported */ case ASM_CRIT_VECTOR: #endif case ASM_SYSMGMT_VECTOR: case ASM_EXT_VECTOR: BSP_irq_handle_at_ipic(excNum); break; } } void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx) { /* * Process pending signals that have not already been * processed by _Thread_Displatch. This happens quite * unfrequently : the ISR must have posted an action * to the current running thread. */ if ( _Thread_Do_post_task_switch_extension || _Thread_Executing->do_post_task_switch_extension ) { _Thread_Executing->do_post_task_switch_extension = FALSE; _API_extensions_Run_postswitch(); } } /*********************************************************** * functions to set/get/remove interrupt handlers ***********************************************************/ int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) { rtems_interrupt_level level; /* * check for valid irq name * if invalid, print error and return 0 */ if (!BSP_IS_VALID_IRQ(irq->name)) { printk("Invalid interrupt vector %d\n",irq->name); return 0; } /* * disable interrupts */ rtems_interrupt_disable(level); /* * check, that default handler is installed now */ if (rtemsIrqTbl[irq->name].hdl != BSP_rtems_irq_config->defaultEntry.hdl) { rtems_interrupt_enable(level); printk("IRQ vector %d already connected\n",irq->name); return 0; } /* * store new handler data */ rtemsIrqTbl[irq->name] = *irq; /* * enable irq at interrupt controller */ if (BSP_IS_IPIC_IRQ(irq->name)) { BSP_irq_enable_at_ipic(irq->name); } /* * call "on" function to enable interrupt at device */ irq->on(irq); /* * reenable interrupts */ rtems_interrupt_enable(level); return 1; } int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) { rtems_interrupt_level level; /* * check for valid IRQ name */ if (!BSP_IS_VALID_IRQ(irq->name)) { return 0; } rtems_interrupt_disable(level); /* * return current IRQ entry */ *irq = rtemsIrqTbl[irq->name]; rtems_interrupt_enable(level); return 1; } int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) { rtems_interrupt_level level; /* * check for valid IRQ name */ if (!BSP_IS_VALID_IRQ(irq->name)) { return 0; } rtems_interrupt_disable(level); /* * check, that specified handler is really connected now */ if (rtemsIrqTbl[irq->name].hdl != irq->hdl) { rtems_interrupt_enable(level); return 0; } /* * disable interrupt at interrupt controller */ if (BSP_IS_IPIC_IRQ(irq->name)) { BSP_irq_disable_at_ipic(irq->name); } /* * disable interrupt at source */ irq->off(irq); /* * restore default interrupt handler */ rtemsIrqTbl[irq->name] = BSP_rtems_irq_config->defaultEntry; /* * reenable interrupts */ rtems_interrupt_enable(level); return 1; } /*********************************************************** * functions to set/get the basic interrupt management setup ***********************************************************/ /* * (Re) get info on current RTEMS interrupt management. */ int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** ret_ptr) { *ret_ptr = BSP_rtems_irq_config; return 0; } /* * set management stuff */ int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) { int i; rtems_interrupt_level level; rtems_interrupt_disable(level); /* * store given configuration */ BSP_rtems_irq_config = config; BSP_rtems_irq_tbl = BSP_rtems_irq_config->irqHdlTbl; /* * enable any non-empty IRQ entries at OPBINTC */ for (i = BSP_IPIC_IRQ_LOWEST_OFFSET; i <= BSP_IPIC_IRQ_MAX_OFFSET; i++) { if (BSP_rtems_irq_tbl[i].hdl != config->defaultEntry.hdl) { BSP_irq_enable_at_ipic(i); BSP_rtems_irq_tbl[i].on((&BSP_rtems_irq_tbl[i])); } else { BSP_rtems_irq_tbl[i].off(&(BSP_rtems_irq_tbl[i])); BSP_irq_disable_at_ipic(i); } } /* * store any irq-like processor exceptions */ for (i = BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_MAX_OFFSET; i++) { if (BSP_rtems_irq_tbl[i].hdl != config->defaultEntry.hdl) { if (BSP_rtems_irq_tbl[i].on != NULL) { BSP_rtems_irq_tbl[i].on (&(BSP_rtems_irq_tbl[i])); } } else { if (BSP_rtems_irq_tbl[i].off != NULL) { BSP_rtems_irq_tbl[i].off (&(BSP_rtems_irq_tbl[i])); } } } rtems_interrupt_enable(level); return 1; } /********************************************** * list of exception vectors to tap for interrupt handlers */ static rtems_raw_except_connect_data BSP_vec_desc[] = { #if defined(ASM_DEC_VECTOR) {ASM_DEC_VECTOR, {ASM_DEC_VECTOR, decrementer_exception_vector_prolog_code, (size_t)decrementer_exception_vector_prolog_code_size }, exception_nop_enable, exception_nop_enable, exception_always_enabled }, #endif #if defined(ASM_SYSMGMT_VECTOR) {ASM_SYSMGMT_VECTOR, {ASM_SYSMGMT_VECTOR, sysmgmt_exception_vector_prolog_code, (size_t)sysmgmt_exception_vector_prolog_code_size }, exception_nop_enable, exception_nop_enable, exception_always_enabled }, #endif {ASM_EXT_VECTOR, {ASM_EXT_VECTOR, external_exception_vector_prolog_code, (size_t)&external_exception_vector_prolog_code_size }, exception_nop_enable, exception_nop_enable, exception_always_enabled } #if 0 /* Critical interrupts not yet supported */ ,{ASM_CRIT_VECTOR, {ASM_CRIT_VECTOR, critical_exception_vector_prolog_code, critical_exception_vector_prolog_code_size } BSP_irq_nop_func, BSP_irq_nop_func, BSP_irq_true_func } #endif }; /* * dummy for an empty IRQ handler entry */ static rtems_irq_connect_data emptyIrq = { 0, /* Irq Name */ BSP_irq_nop_hdl, /* handler function */ NULL, /* handle passed to handler */ BSP_irq_nop_func, /* on function */ BSP_irq_nop_func, /* off function */ BSP_irq_true_func /* isOn function */ }; static rtems_irq_global_settings initialConfig = { BSP_IRQ_NUMBER, /* irqNb */ { 0, /* Irq Name */ BSP_irq_nop_hdl, /* handler function */ NULL, /* handle passed to handler */ BSP_irq_nop_func, /* on function */ BSP_irq_nop_func, /* off function */ BSP_irq_true_func /* isOn function */ }, /* emptyIrq */ rtemsIrqTbl, /* irqHdlTbl */ 0, /* irqBase */ NULL /* irqPrioTbl */ }; void BSP_rtems_irq_mng_init(unsigned cpuId) { int i; /* * connect all exception vectors needed */ for (i = 0; i < (sizeof(BSP_vec_desc) / sizeof(BSP_vec_desc[0])); i++) { if (!ppc_set_exception (&BSP_vec_desc[i])) { BSP_panic("Unable to initialize RTEMS raw exception\n"); } } /* * setup interrupt handlers table */ for (i = 0; i < BSP_IRQ_NUMBER; i++) { rtemsIrqTbl[i] = emptyIrq; rtemsIrqTbl[i].name = i; } /* * initialize interrupt management */ if (!BSP_rtems_irq_mngt_set(&initialConfig)) { BSP_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); } }