diff options
Diffstat (limited to 'c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c')
-rw-r--r-- | c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c | 993 |
1 files changed, 0 insertions, 993 deletions
diff --git a/c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c b/c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c deleted file mode 100644 index f77125c4a7..0000000000 --- a/c/src/lib/libbsp/powerpc/beatnik/irq/discovery_pic.c +++ /dev/null @@ -1,993 +0,0 @@ -/* Interrupt driver + dispatcher for the discovery host controller */ - -/* Author: T. Straumann, 2005-2007 - * - * Acknowledgements: - * Valuable information was obtained from the following drivers - * netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc. - * linux: (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer. - * rtems: (C) Brookhaven National Laboratory; K. Feng - * but this implementation is original work by the author. - */ - -/* - * Authorship - * ---------- - * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was - * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * The 'beatnik' BSP was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ -#include <rtems.h> -#include <bsp.h> -#include <bsp/irq.h> -#include <bsp/gtreg.h> -#include <bsp/gtintrreg.h> -#include <rtems/bspIo.h> -#include <bsp/vectors.h> -#include <libcpu/byteorder.h> -#include <libcpu/spr.h> - -/* dont change the order (main_lo, main_hi, gpp) which - * matches the interrupt numbers! - */ -#define MAIN_LO_IDX 0 -#define MAIN_HI_IDX 1 -#define GPP_IDX 2 -#define NUM_INTR_REGS 3 - - -#define SYNC() __asm__ volatile("sync") - -/* How many times should the ISR dispatcher check for - * pending interrupts until it decides that something's - * fishy (i.e., a user ISR fails to clear the interrupt - * source) - */ -#define MAX_SPIN_LOOPS 100 - -/* If FASTER is defined, a few obscure I/O statements found in the linux - * driver are removed - */ -#define FASTER - -/* Array helper */ -#define NumberOf(arr) (sizeof(arr)/sizeof((arr)[0])) - - -/* MVME6100 specific; re-define watchdog NMI pin to be a normal output - * so we have a way to raise an interrupt in software (GPP[26] is wired to - * GPP[6] on the MVME6100). - */ -#define MVME6100_IRQ_DEBUG 4 - -#define GPP_WIRED_OUT_BIT_6100 26 /* CAVEAT: this is bit 26 on the 6100 */ -#define GPP_WIRED_OUT_BIT_5500 24 /* CAVEAT: this is bit 24 on the 5500 */ -#define GPP_WIRED_IN_BIT 6 - -/* Ored mask of debugging features to enable */ -#define IRQ_DEBUG_BASIC 1 -/* This is _very_ lowlevel */ -#define IRQ_DEBUG_DISPATCHER 2 -/* Record maximal dispatching latency */ -#define IRQ_DEBUG_MAXLAT 8 /* PPC only */ - -#define IRQ_DEBUG (0 /*|(IRQ_DEBUG_BASIC)*/|(MVME6100_IRQ_DEBUG)|(IRQ_DEBUG_MAXLAT)) - -/********** - * Typedefs - **********/ - -/* Set of the three relevant cause registers */ -typedef volatile unsigned IrqMask[NUM_INTR_REGS]; - -#define REGP(x) ((volatile uint32_t *)(x)) - -/* Information we keep about the PIC */ -typedef struct _Mv64x60PicRec { - /* base address as seen from CPU */ - uintptr_t reg_base; - - /* addresses of 'cause' registers */ - volatile uint32_t *causes[NUM_INTR_REGS]; - - /* addresses of 'mask' registers */ - volatile uint32_t *masks[NUM_INTR_REGS]; - - /* masks for all priorities. If an - * interrupt source has priority X, - * its corresponding bit is set - * (enabled) in mcache[i] for all - * i < X and cleared for i >= X - */ - volatile IrqMask mcache[BSP_IRQ_MAX_PRIO+1]; - - /* Priority we're executing at. - * Thread-level is priority 0, - * ISRs range from 1..MAX_PRIO - */ - volatile rtems_irq_prio current_priority; -} Mv64x60PicRec, *Mv64x60Pic; - -/********** - * Globals - **********/ - - -/* Copy of the configuration */ -static rtems_irq_global_settings theConfig; -/* PIC description */ -static Mv64x60PicRec thePic; - -#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG -static unsigned long gpp_out_bit = 0; -#endif - -#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT -unsigned long discovery_pic_max_dispatching_latency = 0; -#ifdef __PPC__ -static inline unsigned long mftb(void) -{ -unsigned long rval; - asm volatile("mftb %0":"=r"(rval)); - return rval; -} -#else -#define mftb() 0 -#endif -#endif - -/********** - * Functions - **********/ - -/* Debugging helper routines */ -static void pregs(volatile uint32_t **p) -{ -int i; - for (i=NUM_INTR_REGS-1; i>=0; i--) { - printk(" 0x%08x", ld_le32(p[i])); - printk( i ? " --":"\n"); - } -} - -static void pmsks(volatile IrqMask p) -{ -int i; - for (i=NUM_INTR_REGS-1; i>=0; i--) { - printk(" 0x%08x", p[i]); - printk( i ? " --":"\n"); - } -} - -static void discovery_dump_picregs(void) -{ - printk(" ..GPP_IRQ. -- ..MAIN_HI. -- ..MAIN_LO.\n"); - printk("Cause:"); pregs(thePic.causes); - printk("Mask: "); pregs(thePic.masks); -} - -/* Small inline helpers */ - -/* return 0 if this PIC is not 'responsible' for a given irq number - * we also 'ignore' the GPP summary bits - these must always remain - * enabled. - */ -static inline int -validIrqNo(rtems_irq_number irq) -{ - return - irq >= BSP_PCI_IRQ_LOWEST_OFFSET - && irq <= BSP_PCI_IRQ_MAX_OFFSET - && ! (IMH_GPP_SUM & (1<<(irq-32))); -} - -/* return 0 if a given priority is outside the valid range */ -static inline int -validPri(rtems_irq_prio pri) -{ - /* silence compiler warning about limited range of type; - * hope it never changes... - */ - return /* pri>=0 && */ pri <=BSP_IRQ_MAX_PRIO; -} - -/* Return position of the most significant bit that is set in 'x' */ -static inline int -__ilog2(unsigned x) -{ - asm volatile("cntlzw %0, %0":"=&r"(x):"0"(x)); - return 31-x; -} - -/* Convert irq number to cause register index - * (array of handles in the PicRec). - * ASSUMES: 'irq' within valid range. - */ -static inline unsigned -irqDiv32(unsigned irq) -{ - return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)>>5; -} - -/* Convert irq number to cause/mask bit number. - * ASSUMES: 'irq' within valid range. - */ - -static inline unsigned -irqMod32(unsigned irq) -{ - return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)&31; -} - -/* NON-ATOMICALLY set/clear bits in a MV64x60 register - * - * register contents at offset 'off' are ANDed with - * complement of the 'clr' mask and ORed with 'set' mask: - * - * *off = (*off & ~clr) | set - * - * ASSUMES: executed from IRQ-disabled section - */ -static inline void -gt_bitmod(unsigned off, unsigned set, unsigned clr) -{ - st_le32(REGP(thePic.reg_base + off), - (ld_le32(REGP(thePic.reg_base+off)) & ~clr) | set); -} - -static inline unsigned -gt_read(unsigned off) -{ - return ld_le32(REGP(thePic.reg_base + off)); -} - -static inline void -gt_write(unsigned off, unsigned val) -{ - st_le32(REGP(thePic.reg_base + off), val); -} - -/* Enable interrupt number 'irq' at the PIC. - * - * Checks for valid arguments but has no way of - * communicating violation; prints to console - * if illegal arguments are given. - * - * This routine may be called from ISR level. - * - * Algorithm: set corresponding bit in masks - * for all priorities lower than the - * target irq's priority and push - * mask for the currently executing - * priority out to the PIC. - */ - -void -BSP_enable_irq_at_pic(rtems_irq_number irq) -{ -unsigned i,j; -unsigned long flags; -volatile uint32_t *p; -uint32_t v,m; - - if ( !validIrqNo(irq) ) { -/* API change - must silently ignore... - printk("BSP_enable_irq_at_pic: Invalid argument (irq #%i)\n",irq); - */ - return; - } - -#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC - printk("IRQ: Enable #%i;",irq); -#endif - - if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) { - /* This is probably a more serious error; don't ignore silently */ - printk("BSP_enable_irq_at_pic: illegal argument\n"); - return; - } - /* compute register pointer and bit mask */ - p = thePic.masks[i]; - m = 1<<irqMod32(irq); - - rtems_interrupt_disable(flags); - { - /* access table from protected section to be thread-safe */ - rtems_irq_prio pri = theConfig.irqPrioTbl[irq]; - for ( j=0; j<pri; j++ ) { - thePic.mcache[j][i] |= m; - } - st_le32(p, (v=thePic.mcache[thePic.current_priority][i])); - /* linux driver reads back GPP mask; maybe it's wise to do the same */ - (void)ld_le32(thePic.masks[GPP_IDX]); - } - SYNC(); - rtems_interrupt_enable(flags); - -#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC - printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p)); - -#endif -} - -/* Disable interrupt number 'irq' at the PIC. - * - * Checks for valid arguments but has no way of - * communicating violation; prints to console - * if illegal arguments are given. - * - * This routine may be called from ISR level. - * - * Algorithm: clear corresponding bit in masks - * for all priorities and push the - * mask for the currently executing - * priority out to the PIC. - */ - -int -BSP_disable_irq_at_pic(rtems_irq_number irq) -{ -unsigned i,j; -unsigned long flags; -volatile uint32_t *p; -uint32_t v,m; -int rval; - - if ( !validIrqNo(irq) ) { -/* API change - must silently ignore... - printk("BSP_disable_irq_at_pic: Invalid argument (irq #%i)\n",irq); - */ - return -1; - } - -#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC - printk("IRQ: Disable #%i;",irq); -#endif - - if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) { - /* This is probably a more serious error; don't ignore silently */ - printk("BSP_enable_irq_at_pic: illegal argument\n"); - return -1; - } - - /* compute register pointer and bit mask */ - p = thePic.masks[i]; - m = (1<<irqMod32(irq)); - - rtems_interrupt_disable(flags); - { - rval = thePic.mcache[thePic.current_priority][i] & m; - for (j=0; j<=BSP_IRQ_MAX_PRIO; j++) - thePic.mcache[j][i] &= ~m; - st_le32(p, (v=thePic.mcache[thePic.current_priority][i])); - /* linux driver reads back GPP mask; maybe it's wise to do the same */ - (void)ld_le32(thePic.masks[GPP_IDX]); - } - SYNC(); - rtems_interrupt_enable(flags); - -#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC - printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p)); -#endif - - return rval ? 1 : 0; -} - -int -BSP_irq_is_enabled_at_pic(rtems_irq_number irq) -{ -unsigned i; - if ( !validIrqNo(irq) ) { - printk("BSP_irq_is_enabled_at_pic: Invalid argument (irq #%i)\n",irq); - return -1; - } - - if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) { - printk("BSP_enable_irq_at_pic: illegal argument\n"); - return -1; - } - return ld_le32(thePic.masks[i]) & (1<<irqMod32(irq)) ? 1 : 0; -} - - -/* Change priority of interrupt number 'irq' to 'pri' - * - * RETURNS: 0 on success, nonzero on failure (illegal args) - * - * NOTE: This routine must not be called from ISR level. - * - * Algorithm: Set bit corresponding to 'irq' in the masks for - * all priorities < pri and clear in all masks - * for priorities >=pri - */ -int -BSP_irq_set_priority(rtems_irq_number irq, rtems_irq_prio pri) -{ -unsigned long flags; -volatile uint32_t *p; -uint32_t v,m; -unsigned i,j; - - if ( thePic.current_priority > 0 ) { - printk("BSP_irq_set_priority: must not be called from ISR level\n"); - return -1; - } - - if ( !validPri(pri) ) { - printk("BSP_irq_set_priority: invalid argument (pri #%i)\n",pri); - return -1; - } - - if ( BSP_DECREMENTER != irq ) { - if ( !validIrqNo(irq) ) { - printk("BSP_irq_set_priority: invalid argument (irq #%i)\n",irq); - return -1; - } - - if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) { - printk("BSP_irq_set_priority: illegal argument (irq #%i not PCI?)\n", irq); - return -1; - } - } - -#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC - printk("IRQ: Set Priority #%i -> %i;",irq,pri); -#endif - - if ( BSP_DECREMENTER == irq ) { - theConfig.irqPrioTbl[irq] = pri; - return 0; - } - - /* compute register pointer and bit mask */ - p = thePic.masks[i]; - m = 1<<irqMod32(irq); - - rtems_interrupt_disable(flags); - { - for (j=0; j<=BSP_IRQ_MAX_PRIO; j++) { - if ( j<pri ) - thePic.mcache[j][i] |= m; - else - thePic.mcache[j][i] &= ~m; - } - theConfig.irqPrioTbl[irq] = pri; - st_le32(p, (v=thePic.mcache[thePic.current_priority][i])); - /* linux driver reads back GPP mask; maybe it's wise to do the same */ - (void)ld_le32(thePic.masks[GPP_IDX]); - } - SYNC(); - rtems_interrupt_enable(flags); - -#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC - printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p)); -#endif - - return 0; -} - -/* Initialize the PIC; routine needed by BSP framework - * - * RETURNS: NONZERO on SUCCESS, 0 on error! - */ -int -BSP_setup_the_pic(rtems_irq_global_settings* config) -{ -int i; - /* - * Store copy of configuration - */ - theConfig = *config; - - /* check config */ - if ( theConfig.irqNb <= BSP_PCI_IRQ_MAX_OFFSET ) { - printk("BSP_setup_the_pic: FATAL ERROR: configured IRQ table too small???\n"); - return 0; - } - - for ( i=0; i<theConfig.irqNb; i++ ) { - if ( !validPri(theConfig.irqPrioTbl[i]) ) { - printk("BSP_setup_the_pic: invalid priority (%i) for irg #%i; setting to 1\n", theConfig.irqPrioTbl[i], i); - theConfig.irqPrioTbl[i]=1; - } - } - - /* TODO: Detect; Switch wired-out bit; */ - thePic.reg_base = BSP_MV64x60_BASE; - - thePic.current_priority = 0; - -#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG -#endif - - switch ( BSP_getDiscoveryVersion(/* assert */ 1) ) { - case MV_64360: - thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_360_MIC_LO); - thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_360_MIC_HI); - thePic.masks[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_360_C0IM_LO); - thePic.masks[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_360_C0IM_HI); - break; - - case GT_64260_A: - case GT_64260_B: - thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_260_MIC_LO); - thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_260_MIC_HI); - thePic.masks[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_260_CIM_LO); - thePic.masks[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_260_CIM_HI); - break; - - default: - rtems_panic("Unable to initialize interrupt controller; unknown chip"); - break; - } - - thePic.causes[GPP_IDX] = REGP(thePic.reg_base + GT_GPP_Interrupt_Cause); - thePic.masks[GPP_IDX] = REGP(thePic.reg_base + GT_GPP_Interrupt_Mask); - - /* Initialize mask cache */ - for ( i=0; i<=BSP_IRQ_MAX_PRIO; i++ ) { - thePic.mcache[i][MAIN_LO_IDX] = 0; - /* Always enable the summary bits. Otherwise, GPP interrupts dont - * make it 'through' to the GPP cause - */ - thePic.mcache[i][MAIN_HI_IDX] = IMH_GPP_SUM; - thePic.mcache[i][GPP_IDX] = 0; - } - - /* mask and clear everything */ - for ( i=0; i<NUM_INTR_REGS; i++ ) { - st_le32(thePic.causes[i], 0); - st_le32(thePic.masks[i], 0); - } - - /* make sure GPP Irqs are level sensitive */ - gt_bitmod( - GT_CommUnitArb_Ctrl, /* reg */ - GT_CommUnitArb_Ctrl_GPP_Ints_Level_Sensitive, /* set */ - 0); /* clr */ - - /* enable summaries */ - st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[thePic.current_priority][MAIN_LO_IDX]); - st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[thePic.current_priority][MAIN_HI_IDX]); - st_le32(thePic.masks[GPP_IDX ], thePic.mcache[thePic.current_priority][GPP_IDX ]); - - /* believe the interrupts are all level sensitive (which is good); we leave all the - * inputs configured they way the are by MotLoad... - */ - - /* Finally, enable all interrupts for which the configuration table has already - * a handler installed. - */ - for ( i=BSP_PCI_IRQ_LOWEST_OFFSET; i<=BSP_PCI_IRQ_MAX_OFFSET; i++ ) { - if ( theConfig.irqHdlTbl[i].hdl != theConfig.defaultEntry.hdl ) { - BSP_enable_irq_at_pic(i); - } - } - - return 1; -} - -int discovery_pic_max_loops = 0; - - -/* Change the priority level we're executing at and mask all interrupts of - * the same and lower priorities - * - * RETURNS old priority; - */ - -static inline rtems_irq_prio -change_executing_prio_level(rtems_irq_prio pri) -{ -register rtems_irq_prio rval = thePic.current_priority; - thePic.current_priority = pri; - st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[pri][MAIN_LO_IDX]); - st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[pri][MAIN_HI_IDX]); - st_le32(thePic.masks[GPP_IDX ], thePic.mcache[pri][GPP_IDX ]); - /* this DOES seem to be necessary */ - (void)ld_le32(thePic.masks[GPP_IDX]); - return rval; -} - -/* Scan the three cause register and find the pending interrupt with - * the highest priority. - * - * Two facts make this quite efficient - * a) the PPC has an opcode for finding the number of leading zero-bits - * in a register (__ilog2()). - * b) as we proceed we mask all sources of equal or lower priorites; they won't be - * seen while scanning: - * - * maxpri = 0; - * bits = in_le32(cause); - * while ( bits &= mask[maxpri] ) { - * irq_no = __ilog2(bits); - * maxpri = priority[irq_no]; - * } - * - * a) __ilog() is 1-2 machine instructions - * b) while loop is only executed as many times as interrupts of different - * priorities are pending at the same time (and only if lower-priority - * ones are found first; otherwise, the iteration terminates quicker). - * - * ==> highest priority source is found quickly. It takes at most - * - * BSP_IRQ_MAX_PRIO * ( ~3 reg-only instructions + 2 memory access ) - * + 2 reg-only instructions + 1 I/O + 1 memory access. - * - * - */ - -static unsigned mlc, mhc, gpc; - -static int decrementerPending = 0; -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER -int decrementerIrqs = 0; -#endif - -static inline unsigned -find_highest_priority_pending_irq(rtems_irq_prio *ppri) -{ -register int rval = -1; -register rtems_irq_prio *pt = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET; -register rtems_irq_prio pmax = *ppri; -register unsigned cse,ocse; - -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - discovery_dump_picregs(); -#endif - - if ( decrementerPending ) { -/* Don't flood -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("Decrementer IRQ pending\n"); -#endif -*/ - if ( theConfig.irqPrioTbl[BSP_DECREMENTER] > pmax ) { - pmax = theConfig.irqPrioTbl[BSP_DECREMENTER]; - rval = BSP_DECREMENTER; - } - } - - mlc = cse = ld_le32(thePic.causes[MAIN_LO_IDX]); -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]); -#endif - while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) { - rval = __ilog2(cse); - pmax = pt[rval]; -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("Max pri IRQ now %i\n",rval); -#endif - } - mhc = cse = ocse = ld_le32(thePic.causes[MAIN_HI_IDX]); -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]); -#endif - /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */ - cse &= ~IMH_GPP_SUM; - while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) { - rval = __ilog2(cse) + 32; - pmax = pt[rval]; -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("Max pri IRQ now %i\n",rval); -#endif - } - gpc = cse = ld_le32(thePic.causes[GPP_IDX ]); - /* if there were GPP ints, scan the GPP cause now */ - if ( ocse & IMH_GPP_SUM ) { -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX ]); -#endif - cse &= thePic.mcache[pmax][GPP_IDX ]; - ocse = cse; - while ( cse ) { - rval = __ilog2(cse) + 64; - pmax = pt[rval]; - cse &= thePic.mcache[pmax][GPP_IDX ]; -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("Max pri IRQ now %i\n",rval); -#endif - } -#ifndef FASTER - /* this doesn't seem to be necessary -- however, the linux people do it... */ - out_le32(thePic.causes[GPP_IDX], ~ocse); -#endif - } -#ifndef FASTER - /* this doesn't seem to be necessary -- however, the linux people do it... */ - (void)in_le32(thePic.causes[GPP_IDX]); -#endif - - *ppri = pmax; - - if ( BSP_DECREMENTER == rval ) { -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - decrementerIrqs++; -#endif - decrementerPending = 0; - } - - return rval; -} - -#if 0 /* TODO: should this be cleaned up ? */ -#define _IRQ_DEBUG IRQ_DEBUG_DISPATCHER -static inline unsigned -ffind_highest_priority_pending_irq(rtems_irq_prio *ppri) -{ -register int rval = -1; -register rtems_irq_prio *pt = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET; -register rtems_irq_prio pmax = *ppri; -register unsigned cse,ocse; - -#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - discovery_dump_picregs(); -#endif - - cse = in_le32(thePic.causes[MAIN_LO_IDX]); -#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]); -#endif - while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) { - rval = __ilog2(cse); - pmax = pt[rval]; -#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("Max pri IRQ now %i\n",rval); -#endif - } - cse = ocse = in_le32(thePic.causes[MAIN_HI_IDX]); -#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]); -#endif - /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */ - cse &= ~IMH_GPP_SUM; - while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) { - rval = __ilog2(cse) + 32; - pmax = pt[rval]; -#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("Max pri IRQ now %i\n",rval); -#endif - } - /* if there were GPP ints, scan the GPP cause now */ - if ( ocse & IMH_GPP_SUM ) { - cse = in_le32(thePic.causes[GPP_IDX ]); -#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX ]); -#endif - cse &= thePic.mcache[pmax][GPP_IDX ]; - ocse = cse; - while ( cse ) { - rval = __ilog2(cse) + 64; - pmax = pt[rval]; - cse &= thePic.mcache[pmax][GPP_IDX ]; -#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - printk("Max pri IRQ now %i\n",rval); -#endif - } - /* this doesn't seem to be necessary -- however, the linux people do it... */ - out_le32(thePic.causes[GPP_IDX], ~ocse); - } - /* this doesn't seem to be necessary -- however, the linux people do it... */ - (void)in_le32(thePic.causes[GPP_IDX]); - - *ppri = pmax; - return rval; -} -#endif - - -/* Here's our dispatcher; the BSP framework uses the same one for EE and decrementer - * exceptions... - */ -int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum) -{ -register int irq; -int loop, last_irq; -rtems_irq_prio pri; -#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT -unsigned long diff; -#endif - -#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT - diff = mftb(); -#endif - - if (excNum == ASM_DEC_VECTOR) { - decrementerPending = 1; - } - - /* Tradeoff: EITHER we loop as long as interrupts are pending - * incurring the overhead of one extra run of the 'find_pending_irq' routine. - * OR we do rely on the handler just being invoked again if multiple - * interrupts are pending. - * - * The first solution gives better worst-case behavior - * the second slightly better average performance. - * --> we go for the first solution. This also enables us to catch - * runaway interrupts, i.e., bad drivers that don't clear interrupts - * at the device. Can be very handy during driver development... - */ - for ( loop=0, last_irq=-1, pri = thePic.current_priority; - (irq=find_highest_priority_pending_irq(&pri)) >=0; - loop++, last_irq = irq ) { - - /* raise priority level and remember current one */ - pri = change_executing_prio_level(pri); - - SYNC(); - -#if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT - if ( 0 == loop ) { - diff = mftb()-diff; - if ( diff > discovery_pic_max_dispatching_latency ) - discovery_pic_max_dispatching_latency = diff; - } -#endif - -#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER - if ( BSP_DECREMENTER == irq ) { - printk("IRQ: dispatching DECREMENTER\n"); - } else { - int idx = irqDiv32(irq); - printk("IRQ: dispatching #%i; causes[%i]=0x%08x\n", irq, idx, ld_le32(thePic.causes[idx])); - } -#endif - - bsp_irq_dispatch_list( theConfig.irqHdlTbl, irq, theConfig.defaultEntry.hdl ); - - /* restore executing priority level */ - (void)change_executing_prio_level(pri); - - if ( (loop > MAX_SPIN_LOOPS) && (last_irq == irq) ) { - /* try to catch run-away interrupts without disabling a 'legal' one; - * this should never happen with the decrementer (and - * BSP_disable_irq_at_pic(BSP_DECREMENTER) would fail) - */ - printk("Runaway IRQ #%i; disabling\n", irq); - BSP_disable_irq_at_pic(irq); - loop = 0; - } - } - - if (!loop) { - if ( decrementerPending && pri >= theConfig.irqPrioTbl[BSP_DECREMENTER] ) { - /* we cannot mask the decrementer interrupt so it is possible that it - * gets delivered even though it has a lower priority than what we're - * currently executing at. - * In this case, we ignore the zero loop count and return; - * the interrupted instance of C_dispatch_irq_handler() will eventually - * lower the executing priority and catch the 'decrementerPending' flag - * we just set. - */ - } else { - printk("Discovery: Spurious interrupt; causes were gpp: 0x%x, mhc: 0x%x, mlc: 0x%x\n", gpc, mhc, mlc); - printk("Current priority level %i, decrementerPending %i\n", pri, decrementerPending); - { - rtems_irq_prio p=pri; - printk("PIC register dump:\n"); - discovery_dump_picregs(); - printk("Current Priority: %i, found %i\n",pri,find_highest_priority_pending_irq(&p)); - discovery_dump_picregs(); - for (p=0; p<=BSP_IRQ_MAX_PRIO; p++) { - printk("M[%i] :",p);pmsks(thePic.mcache[p]); - } - } - } - } - else if (loop>discovery_pic_max_loops) - discovery_pic_max_loops = loop; - - return 0; -} - - -#if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG -void -discovery_pic_install_debug_irq(void) -{ - switch ( BSP_getBoardType() ) { - case MVME6100: gpp_out_bit = GPP_WIRED_OUT_BIT_6100; break; - case MVME5500: gpp_out_bit = GPP_WIRED_OUT_BIT_5500; break; - default: - gpp_out_bit = 0; break; - break; - } - if ( gpp_out_bit ) { - unsigned mppoff; - switch (gpp_out_bit / 8) { - default: /* silence warning; this is never reached */ - case 0: mppoff = GT_MPP_Control0; break; - case 1: mppoff = GT_MPP_Control1; break; - case 2: mppoff = GT_MPP_Control2; break; - case 3: mppoff = GT_MPP_Control3; break; - } - - /* switch GPP pin allocated to watchdog (value 4) to - * GPP I/O (value 0 ??; have no doc, found out by experimenting) - */ - gt_bitmod(mppoff, 0, (0xf<<(4*(gpp_out_bit % 8)))); - - /* make it an output */ - gt_bitmod(GT_GPP_IO_Control, (1<<gpp_out_bit), 0); - - /* don't invert levels */ - gt_bitmod(GT_GPP_Level_Control, 0, (1<<GPP_WIRED_IN_BIT) | (1<<gpp_out_bit)); - - /* clear output */ - gt_bitmod(GT_GPP_Value, 0, 1<<gpp_out_bit); - - printk("GPP levelctl now 0x%08x\n", gt_read(GT_GPP_Level_Control)); - printk("GPP value now 0x%08x\n", gt_read(GT_GPP_Value)); - printk("MPP ctl 0 now 0x%08x\n", gt_read(GT_MPP_Control0)); - printk("MPP ctl 1 now 0x%08x\n", gt_read(GT_MPP_Control1)); - printk("MPP ctl 2 now 0x%08x\n", gt_read(GT_MPP_Control2)); - printk("MPP ctl 3 now 0x%08x\n", gt_read(GT_MPP_Control3)); - - } -} - -/* Control the state of the external 'wire' that connects the - * GPP_WIRED_OUT --> GPP_WIRED_IN pins - */ -void -discovery_pic_set_debug_irq(int on) -{ -unsigned long flags, clr; - if ( !gpp_out_bit ) { - printk("discovery_pic_set_debug_irq(): unknown wire output\n"); - return; - } - if (on) { - on = 1<<gpp_out_bit; - clr = 0; - } else { - clr = 1<<gpp_out_bit; - on = 0; - } - rtems_interrupt_disable(flags); - gt_bitmod(GT_GPP_Value, on, clr); - rtems_interrupt_enable(flags); -} -#endif - -#if 0 -/* Here's some code for testing */ -#endif |