diff options
Diffstat (limited to 'c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c')
-rw-r--r-- | c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c | 463 |
1 files changed, 0 insertions, 463 deletions
diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c b/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c deleted file mode 100644 index 8bb3cd240e..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc5xx/irq/irq.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * This file contains the implementation of the function described in irq.h - */ - -/* - * MPC5xx port sponsored by Defence Research and Development Canada - Suffield - * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) - * - * Derived from libbsp/powerpc/mbx8xx/irq/irq.c: - * - * 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 <rtems.h> -#include <mpc5xx.h> -#include <libcpu/vectors.h> -#include <libcpu/raw_exception.h> -#include <libcpu/irq.h> -#include <bsp/irq.h> - -/* - * Convert an rtems_irq_number constant to an interrupt level - * suitable for programming into an I/O device's interrupt level field. - */ -int CPU_irq_level_from_symbolic_name(const rtems_irq_number name) -{ - if (CPU_USIU_EXT_IRQ_0 <= name && name <= CPU_USIU_INT_IRQ_7) - return (name - CPU_USIU_EXT_IRQ_0) / 2; - - if (CPU_UIMB_IRQ_8 <= name && name <= CPU_UIMB_IRQ_31) - return 8 + (name - CPU_UIMB_IRQ_8); - - return 31; /* reasonable default */ -} - -/* - * 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; - -/* - * Check if symbolic IRQ name is an USIU IRQ - */ -static inline int is_usiu_irq(const rtems_irq_number irqLine) -{ - return (((int) irqLine <= CPU_USIU_IRQ_MAX_OFFSET) && - ((int) irqLine >= CPU_USIU_IRQ_MIN_OFFSET) - ); -} - -/* - * Check if symbolic IRQ name is an UIMB IRQ - */ -static inline int is_uimb_irq(const rtems_irq_number irqLine) -{ - return (((int) irqLine <= CPU_UIMB_IRQ_MAX_OFFSET) && - ((int) irqLine >= CPU_UIMB_IRQ_MIN_OFFSET) - ); -} - -/* - * Check if symbolic IRQ name is a Processor IRQ - */ -static inline int is_proc_irq(const rtems_irq_number irqLine) -{ - return (((int) irqLine <= CPU_PROC_IRQ_MAX_OFFSET) && - ((int) irqLine >= CPU_PROC_IRQ_MIN_OFFSET) - ); -} - - -/* - * Masks used to mask off the interrupts. For exmaple, for ILVL2, the - * mask is used to mask off interrupts ILVL2, IRQ3, ILVL3, ... IRQ7 - * and ILVL7. - * - */ -const static unsigned int USIU_IvectMask[CPU_USIU_IRQ_COUNT] = -{ - 0, /* external IRQ 0 */ - 0xFFFFFFFF << 31, /* internal level 0 */ - 0xFFFFFFFF << 30, /* external IRQ 1 */ - 0xFFFFFFFF << 29, /* internal level 1 */ - 0xFFFFFFFF << 28, /* external IRQ 2 */ - 0xFFFFFFFF << 27, /* internal level 2 */ - 0xFFFFFFFF << 26, /* external IRQ 3 */ - 0xFFFFFFFF << 25, /* internal level 3 */ - 0xFFFFFFFF << 24, /* external IRQ 4 */ - 0xFFFFFFFF << 23, /* internal level 4 */ - 0xFFFFFFFF << 22, /* external IRQ 5 */ - 0xFFFFFFFF << 21, /* internal level 5 */ - 0xFFFFFFFF << 20, /* external IRQ 6 */ - 0xFFFFFFFF << 19, /* internal level 6 */ - 0xFFFFFFFF << 18, /* external IRQ 7 */ - 0xFFFFFFFF << 17 /* internal level 7 */ -}; - - -/* - * ------------------------ RTEMS Irq helper functions ---------------- - */ - -/* - * Caution : this function assumes the variable "internal_config" - * is already set and that the tables it contains are still valid - * and accessible. - */ -static void compute_USIU_IvectMask_from_prio (void) -{ - /* - * In theory this is feasible. No time to code it yet. See i386/shared/irq.c - * for an example based on 8259 controller mask. The actual masks defined - * correspond to the priorities defined for the USIU in irq_init.c. - */ -} - -/* - * This function check that the value given for the irq line - * is valid. - */ -static int isValidInterrupt(int irq) -{ - if ( (irq < CPU_MIN_OFFSET) || (irq > CPU_MAX_OFFSET) - || (irq == CPU_UIMB_INTERRUPT) ) - return 0; - return 1; -} - -static int CPU_irq_enable_at_uimb(const rtems_irq_number irqLine) -{ - if (!is_uimb_irq(irqLine)) - return 1; - return 0; -} - -static int CPU_irq_disable_at_uimb(const rtems_irq_number irqLine) -{ - if (!is_uimb_irq(irqLine)) - return 1; - return 0; -} - -static int CPU_irq_enable_at_usiu(const rtems_irq_number irqLine) -{ - int usiu_irq_index; - - if (!is_usiu_irq(irqLine)) - return 1; - - usiu_irq_index = ((int) (irqLine) - CPU_USIU_IRQ_MIN_OFFSET); - ppc_cached_irq_mask |= (1 << (31-usiu_irq_index)); - usiu.simask = ppc_cached_irq_mask; - - return 0; -} - -static int CPU_irq_disable_at_usiu(const rtems_irq_number irqLine) -{ - int usiu_irq_index; - - if (!is_usiu_irq(irqLine)) - return 1; - - usiu_irq_index = ((int) (irqLine) - CPU_USIU_IRQ_MIN_OFFSET); - ppc_cached_irq_mask &= ~(1 << (31-usiu_irq_index)); - usiu.simask = ppc_cached_irq_mask; - - return 0; -} - -/* - * --------------- RTEMS Single Irq Handler Mngt Routines ---------------- - */ - -int CPU_install_rtems_irq_handler (const rtems_irq_connect_data* irq) -{ - 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 CPU_get_current_idt_entry - * and then disconnect it using CPU_delete_idt_entry. - * RATIONALE : to always have the same transition by forcing the user - * to get the previous handler before accepting to disconnect. - */ - if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { - return 0; - } - - rtems_interrupt_disable(level); - - /* - * store the data provided by user - */ - rtems_hdl_tbl[irq->name] = *irq; - - if (is_uimb_irq(irq->name)) { - /* - * Enable interrupt at UIMB level - */ - CPU_irq_enable_at_uimb (irq->name); - } - - if (is_usiu_irq(irq->name)) { - /* - * Enable interrupt at USIU level - */ - CPU_irq_enable_at_usiu (irq->name); - } - - if (is_proc_irq(irq->name)) { - /* - * Should Enable exception at processor level but not needed. Will restore - * EE flags at the end of the routine anyway. - */ - } - /* - * Enable interrupt on device - */ - if (irq->on) - irq->on(irq); - - rtems_interrupt_enable(level); - - return 1; -} - - -int CPU_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) -{ - if (!isValidInterrupt(irq->name)) { - return 0; - } - *irq = rtems_hdl_tbl[irq->name]; - return 1; -} - -int CPU_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) -{ - 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 CPU_get_current_idt_entry - * and then disconnect it using CPU_delete_idt_entry. - * RATIONALE : to always have the same transition by forcing the user - * to get the previous handler before accepting to disconnect. - */ - if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { - return 0; - } - rtems_interrupt_disable(level); - - /* - * Disable interrupt on device - */ - if (irq->off) - irq->off(irq); - - if (is_uimb_irq(irq->name)) { - /* - * disable interrupt at UIMB level - */ - CPU_irq_disable_at_uimb (irq->name); - } - if (is_usiu_irq(irq->name)) { - /* - * disable interrupt at USIU level - */ - CPU_irq_disable_at_usiu (irq->name); - } - if (is_proc_irq(irq->name)) { - /* - * disable exception at processor level - */ - } - - /* - * restore the default irq value - */ - rtems_hdl_tbl[irq->name] = default_rtems_entry; - - rtems_interrupt_enable(level); - - return 1; -} - -/* - * ---------------- RTEMS Global Irq Handler Mngt Routines ---------------- - */ - -int CPU_rtems_irq_mngt_set (rtems_irq_global_settings* config) -{ - int i; - rtems_interrupt_level level; - - /* - * Store various code accelerators - */ - internal_config = config; - default_rtems_entry = config->defaultEntry; - rtems_hdl_tbl = config->irqHdlTbl; - - rtems_interrupt_disable(level); - - /* - * Start with UIMB IRQ - */ - for (i = CPU_UIMB_IRQ_MIN_OFFSET; i <= CPU_UIMB_IRQ_MAX_OFFSET ; i++) { - if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { - CPU_irq_enable_at_uimb (i); - if (rtems_hdl_tbl[i].on) - rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); - } - else { - if (rtems_hdl_tbl[i].off) - rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); - CPU_irq_disable_at_uimb (i); - } - } - - /* - * Continue with USIU IRQ - * Set up internal tables used by rtems interrupt prologue - */ - compute_USIU_IvectMask_from_prio (); - - for (i = CPU_USIU_IRQ_MIN_OFFSET; i <= CPU_USIU_IRQ_MAX_OFFSET ; i++) { - if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { - CPU_irq_enable_at_usiu (i); - if (rtems_hdl_tbl[i].on) - rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); - } - else { - if (rtems_hdl_tbl[i].off) - rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); - CPU_irq_disable_at_usiu (i); - } - } - - /* - * Enable all UIMB interrupt lines, then enable at USIU. - */ - imb.uimb.umcr |= UIMB_UMCR_IRQMUX(3); - CPU_irq_enable_at_usiu (CPU_UIMB_INTERRUPT); - - /* - * finish with Processor exceptions handled like IRQ - */ - for (i = CPU_PROC_IRQ_MIN_OFFSET; i <= CPU_PROC_IRQ_MAX_OFFSET; i++) { - if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { - if (rtems_hdl_tbl[i].on) - rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); - } - else { - if (rtems_hdl_tbl[i].off) - rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); - } - } - rtems_interrupt_enable(level); - return 1; -} - -int CPU_rtems_irq_mngt_get(rtems_irq_global_settings** config) -{ - *config = internal_config; - return 0; -} - - -/* - * High level IRQ handler called from shared_raw_irq_code_entry - */ -void C_dispatch_irq_handler (MPC5XX_Interrupt_frame *frame, unsigned int excNum) -{ - register unsigned int irq; - register unsigned uimbIntr; /* boolean */ - register unsigned oldMask; /* old siu pic masks */ - register unsigned msr; - register unsigned new_msr; - - /* - * Handle decrementer interrupt - */ - if (excNum == ASM_DEC_VECTOR) { - _CPU_MSR_GET(msr); - new_msr = msr | MSR_EE; - _CPU_MSR_SET(new_msr); - - rtems_hdl_tbl[CPU_DECREMENTER].hdl(rtems_hdl_tbl[CPU_DECREMENTER].handle); - - _CPU_MSR_SET(msr); - return; - } - - /* - * Handle external interrupt generated by USIU on PPC core - */ - while ((ppc_cached_irq_mask & usiu.sipend) != 0) { - irq = (usiu.sivec >> 26); - uimbIntr = (irq == CPU_UIMB_INTERRUPT); - /* - * Disable the interrupt of the same and lower priority. - */ - oldMask = ppc_cached_irq_mask; - ppc_cached_irq_mask = oldMask & USIU_IvectMask[irq]; - usiu.simask = ppc_cached_irq_mask; - /* - * Acknowledge current interrupt. This has no effect on internal level - * interrupts. - */ - usiu.sipend = (1 << (31 - irq)); - - if (uimbIntr) { - /* - * Look at the bits set in the UIMB interrupt-pending register. The - * highest-order set bit indicates the handler we will run. - * - * Unfortunately, we can't easily mask individual UIMB interrupts - * unless they use USIU levels 0 to 6, so we must mask all low-level - * (level > 7) UIMB interrupts while we service any interrupt. - */ - int uipend = imb.uimb.uipend << 8; - - if (uipend == 0) { /* spurious interrupt? use last vector */ - irq = CPU_UIMB_IRQ_MAX_OFFSET; - } - else { - irq = CPU_UIMB_IRQ_MIN_OFFSET; - for ( ; (uipend & 0x8000000) == 0; uipend <<= 1) { - irq++; - } - } - } - _CPU_MSR_GET(msr); - new_msr = msr | MSR_EE; - _CPU_MSR_SET(new_msr); - - rtems_hdl_tbl[irq].hdl(rtems_hdl_tbl[irq].handle); - - _CPU_MSR_SET(msr); - - ppc_cached_irq_mask = oldMask; - usiu.simask = ppc_cached_irq_mask; - } -} |