Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:52

0001 /* Interrupt driver + dispatcher for the discovery host controller */
0002 
0003 /* Author: T. Straumann, 2005-2007
0004  *
0005  * Acknowledgements:
0006  * Valuable information was obtained from the following drivers
0007  *   netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
0008  *   linux:  (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
0009  *   rtems:  (C) Brookhaven National Laboratory; K. Feng
0010  * but this implementation is original work by the author.
0011  */
0012 
0013 /* 
0014  * Authorship
0015  * ----------
0016  * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
0017  *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
0018  *     Stanford Linear Accelerator Center, Stanford University.
0019  * 
0020  * Acknowledgement of sponsorship
0021  * ------------------------------
0022  * The 'beatnik' BSP was produced by
0023  *     the Stanford Linear Accelerator Center, Stanford University,
0024  *     under Contract DE-AC03-76SFO0515 with the Department of Energy.
0025  * 
0026  * Government disclaimer of liability
0027  * ----------------------------------
0028  * Neither the United States nor the United States Department of Energy,
0029  * nor any of their employees, makes any warranty, express or implied, or
0030  * assumes any legal liability or responsibility for the accuracy,
0031  * completeness, or usefulness of any data, apparatus, product, or process
0032  * disclosed, or represents that its use would not infringe privately owned
0033  * rights.
0034  * 
0035  * Stanford disclaimer of liability
0036  * --------------------------------
0037  * Stanford University makes no representations or warranties, express or
0038  * implied, nor assumes any liability for the use of this software.
0039  * 
0040  * Stanford disclaimer of copyright
0041  * --------------------------------
0042  * Stanford University, owner of the copyright, hereby disclaims its
0043  * copyright and all other rights in this software.  Hence, anyone may
0044  * freely use it for any purpose without restriction.  
0045  * 
0046  * Maintenance of notices
0047  * ----------------------
0048  * In the interest of clarity regarding the origin and status of this
0049  * SLAC software, this and all the preceding Stanford University notices
0050  * are to remain affixed to any copy or derivative of this software made
0051  * or distributed by the recipient and are to be affixed to any copy of
0052  * software made or distributed by the recipient that contains a copy or
0053  * derivative of this software.
0054  * 
0055  * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
0056  */ 
0057 #include <rtems.h>
0058 #include <bsp.h>
0059 #include <bsp/irq.h>
0060 #include <bsp/gtreg.h>
0061 #include <bsp/gtintrreg.h>
0062 #include <rtems/bspIo.h>
0063 #include <bsp/vectors.h>
0064 #include <libcpu/byteorder.h>
0065 #include <libcpu/spr.h>
0066 
0067 /* dont change the order (main_lo, main_hi, gpp) which
0068  * matches the interrupt numbers!
0069  */
0070 #define MAIN_LO_IDX 0
0071 #define MAIN_HI_IDX 1
0072 #define GPP_IDX     2
0073 #define NUM_INTR_REGS 3
0074 
0075 
0076 #define SYNC() __asm__ volatile("sync")
0077 
0078 /* How many times should the ISR dispatcher check for
0079  * pending interrupts until it decides that something's
0080  * fishy (i.e., a user ISR fails to clear the interrupt
0081  * source)
0082  */
0083 #define MAX_SPIN_LOOPS 100
0084 
0085 /* If FASTER is defined, a few obscure I/O statements found in the linux
0086  * driver are removed
0087  */
0088 #define FASTER
0089 
0090 /* Array helper */
0091 #define NumberOf(arr) (sizeof(arr)/sizeof((arr)[0]))
0092 
0093 
0094 /* MVME6100 specific; re-define watchdog NMI pin to be a normal output
0095  * so we have a way to raise an interrupt in software (GPP[26] is wired to
0096  * GPP[6] on the MVME6100).
0097  */
0098 #define MVME6100_IRQ_DEBUG 4
0099 
0100 #define GPP_WIRED_OUT_BIT_6100 26   /* CAVEAT: this is bit 26 on the 6100 */
0101 #define GPP_WIRED_OUT_BIT_5500 24   /* CAVEAT: this is bit 24 on the 5500 */
0102 #define GPP_WIRED_IN_BIT   6
0103 
0104 /* Ored mask of debugging features to enable */
0105 #define IRQ_DEBUG_BASIC         1
0106 /* This is _very_ lowlevel */
0107 #define IRQ_DEBUG_DISPATCHER    2
0108 /* Record maximal dispatching latency */
0109 #define IRQ_DEBUG_MAXLAT        8   /* PPC only */
0110 
0111 #define IRQ_DEBUG (0 /*|(IRQ_DEBUG_BASIC)*/|(MVME6100_IRQ_DEBUG)|(IRQ_DEBUG_MAXLAT))
0112 
0113 /**********
0114  * Typedefs
0115  **********/
0116 
0117 /* Set of the three relevant cause registers */
0118 typedef volatile unsigned IrqMask[NUM_INTR_REGS];
0119 
0120 #define REGP(x) ((volatile uint32_t *)(x))
0121 
0122 /* Information we keep about the PIC         */
0123 typedef struct _Mv64x60PicRec {
0124                             /* base address as seen from CPU  */
0125     uintptr_t               reg_base;
0126 
0127                             /* addresses of 'cause' registers */
0128     volatile uint32_t       *causes[NUM_INTR_REGS];
0129 
0130                             /* addresses of 'mask'  registers */
0131     volatile uint32_t       *masks[NUM_INTR_REGS];
0132 
0133                             /* masks for all priorities. If an
0134                              * interrupt source has priority X,
0135                              * its corresponding bit is set
0136                              * (enabled) in mcache[i] for all
0137                              * i < X and cleared for i >= X
0138                              */
0139     volatile IrqMask        mcache[BSP_IRQ_MAX_PRIO+1];
0140 
0141                             /* Priority we're executing at.
0142                              * Thread-level is priority 0,
0143                              * ISRs range from 1..MAX_PRIO
0144                              */
0145     volatile rtems_irq_prio current_priority;
0146 } Mv64x60PicRec, *Mv64x60Pic;
0147 
0148 /**********
0149  * Globals
0150  **********/
0151 
0152 
0153 /* Copy of the configuration */
0154 static rtems_irq_global_settings    theConfig;
0155 /* PIC description           */
0156 static Mv64x60PicRec                thePic;
0157 
0158 #if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
0159 static unsigned long                gpp_out_bit = 0;
0160 #endif
0161 
0162 #if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
0163 unsigned long                       discovery_pic_max_dispatching_latency = 0;
0164 #ifdef __PPC__
0165 static inline unsigned long mftb(void)
0166 {
0167 unsigned long rval;
0168     asm volatile("mftb %0":"=r"(rval));
0169     return rval;
0170 }
0171 #else
0172 #define mftb()  0
0173 #endif
0174 #endif
0175 
0176 /**********
0177  * Functions
0178  **********/
0179 
0180 /* Debugging helper routines */
0181 static void pregs(volatile uint32_t **p)
0182 {
0183 int i;
0184     for (i=NUM_INTR_REGS-1; i>=0; i--) {
0185         printk(" 0x%08x", ld_le32(p[i]));
0186         printk( i ? " --":"\n");
0187     }
0188 }
0189 
0190 static void pmsks(volatile IrqMask p)
0191 {
0192 int i;
0193     for (i=NUM_INTR_REGS-1; i>=0; i--) {
0194         printk(" 0x%08x", p[i]);
0195         printk( i ? " --":"\n");
0196     }
0197 }
0198 
0199 static void discovery_dump_picregs(void)
0200 {
0201         printk("       ..GPP_IRQ. -- ..MAIN_HI. -- ..MAIN_LO.\n");
0202         printk("Cause:"); pregs(thePic.causes);
0203         printk("Mask: "); pregs(thePic.masks);
0204 }
0205 
0206 /* Small inline helpers      */
0207 
0208 /* return 0 if this PIC is not 'responsible' for a given irq number
0209  * we also 'ignore' the GPP summary bits - these must always remain
0210  * enabled.
0211  */
0212 static inline int
0213 validIrqNo(rtems_irq_number irq)
0214 {
0215     return
0216            irq >= BSP_PCI_IRQ_LOWEST_OFFSET
0217         && irq <= BSP_PCI_IRQ_MAX_OFFSET
0218         && ! (IMH_GPP_SUM & (1<<(irq-32)));
0219 }
0220 
0221 /* return 0 if a given priority is outside the valid range          */
0222 static inline int
0223 validPri(rtems_irq_prio pri)
0224 {
0225     /* silence compiler warning about limited range of type;
0226      * hope it never changes...
0227      */
0228     return /* pri>=0 && */ pri <=BSP_IRQ_MAX_PRIO;
0229 }
0230 
0231 /* Return position of the most significant bit that is set in 'x'  */
0232 static inline int
0233 __ilog2(unsigned x)
0234 {
0235     asm volatile("cntlzw %0, %0":"=&r"(x):"0"(x));
0236     return 31-x;
0237 }
0238 
0239 /* Convert irq number to cause register index
0240  * (array of handles in the PicRec).
0241  * ASSUMES: 'irq' within valid range.
0242  */
0243 static inline unsigned
0244 irqDiv32(unsigned irq)
0245 {
0246     return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)>>5;
0247 }
0248 
0249 /* Convert irq number to cause/mask bit number.
0250  * ASSUMES: 'irq' within valid range.
0251  */
0252 
0253 static inline unsigned
0254 irqMod32(unsigned irq)
0255 {
0256     return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)&31;
0257 }
0258 
0259 /* NON-ATOMICALLY set/clear bits in a MV64x60 register
0260  *
0261  * register contents at offset 'off' are ANDed with
0262  * complement of the 'clr' mask and ORed with 'set' mask:
0263  *
0264  *   *off = (*off & ~clr) | set
0265  * 
0266  * ASSUMES: executed from IRQ-disabled section
0267  */
0268 static inline void
0269 gt_bitmod(unsigned off, unsigned set, unsigned clr)
0270 {
0271     st_le32(REGP(thePic.reg_base + off),
0272             (ld_le32(REGP(thePic.reg_base+off)) & ~clr) | set);
0273 }
0274 
0275 static inline unsigned
0276 gt_read(unsigned off)
0277 {
0278     return ld_le32(REGP(thePic.reg_base + off));
0279 }
0280 
0281 static inline void
0282 gt_write(unsigned off, unsigned val)
0283 {
0284     st_le32(REGP(thePic.reg_base + off), val);
0285 }
0286 
0287 /* Enable interrupt number 'irq' at the PIC.
0288  *
0289  * Checks for valid arguments but has no way of
0290  * communicating violation; prints to console
0291  * if illegal arguments are given.
0292  *
0293  * This routine may be called from ISR level.
0294  *
0295  * Algorithm: set corresponding bit in masks
0296  *            for all priorities lower than the
0297  *            target irq's priority and push
0298  *            mask for the currently executing
0299  *            priority out to the PIC.
0300  */
0301 
0302 void
0303 BSP_enable_irq_at_pic(rtems_irq_number irq)
0304 {
0305 unsigned           i,j;
0306 unsigned long      flags;
0307 volatile uint32_t *p;
0308 uint32_t           v,m;
0309 
0310     if ( !validIrqNo(irq) ) {
0311 /* API change - must silently ignore...
0312         printk("BSP_enable_irq_at_pic: Invalid argument (irq #%i)\n",irq);
0313  */
0314         return;
0315     }
0316 
0317 #if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
0318     printk("IRQ: Enable #%i;",irq);
0319 #endif
0320 
0321     if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
0322         /* This is probably a more serious error; don't ignore silently */
0323         printk("BSP_enable_irq_at_pic: illegal argument\n");
0324         return;
0325     }
0326     /* compute register pointer and bit mask */
0327     p = thePic.masks[i];
0328     m = 1<<irqMod32(irq);
0329         
0330     rtems_interrupt_disable(flags);
0331     {
0332         /* access table from protected section to be thread-safe */
0333         rtems_irq_prio  pri = theConfig.irqPrioTbl[irq];
0334         for ( j=0; j<pri; j++ ) {
0335             thePic.mcache[j][i] |= m;
0336         }
0337         st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
0338         /* linux driver reads back GPP mask; maybe it's wise to do the same */
0339         (void)ld_le32(thePic.masks[GPP_IDX]);
0340     }
0341     SYNC();
0342     rtems_interrupt_enable(flags);
0343 
0344 #if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
0345     printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
0346 
0347 #endif
0348 }
0349 
0350 /* Disable interrupt number 'irq' at the PIC.
0351  *
0352  * Checks for valid arguments but has no way of
0353  * communicating violation; prints to console
0354  * if illegal arguments are given.
0355  *
0356  * This routine may be called from ISR level.
0357  *
0358  * Algorithm: clear corresponding bit in masks
0359  *            for all priorities and push the
0360  *            mask for the currently executing
0361  *            priority out to the PIC.
0362  */
0363 
0364 int
0365 BSP_disable_irq_at_pic(rtems_irq_number irq)
0366 {
0367 unsigned           i,j;
0368 unsigned long      flags;
0369 volatile uint32_t *p;
0370 uint32_t           v,m;
0371 int                rval;
0372 
0373     if ( !validIrqNo(irq) ) {
0374 /* API change - must silently ignore...
0375         printk("BSP_disable_irq_at_pic: Invalid argument (irq #%i)\n",irq);
0376  */
0377         return -1;
0378     }
0379 
0380 #if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
0381     printk("IRQ: Disable #%i;",irq);
0382 #endif
0383 
0384     if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
0385         /* This is probably a more serious error; don't ignore silently */
0386         printk("BSP_enable_irq_at_pic: illegal argument\n");
0387         return -1;
0388     }
0389 
0390     /* compute register pointer and bit mask */
0391     p = thePic.masks[i];
0392     m = (1<<irqMod32(irq));
0393 
0394     rtems_interrupt_disable(flags);
0395     {
0396         rval = thePic.mcache[thePic.current_priority][i] & m;
0397         for (j=0; j<=BSP_IRQ_MAX_PRIO; j++)
0398             thePic.mcache[j][i] &= ~m;
0399         st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
0400         /* linux driver reads back GPP mask; maybe it's wise to do the same */
0401         (void)ld_le32(thePic.masks[GPP_IDX]);
0402     }
0403     SYNC();
0404     rtems_interrupt_enable(flags);
0405 
0406 #if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
0407     printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
0408 #endif
0409 
0410     return rval ? 1 : 0;
0411 }
0412 
0413 int
0414 BSP_irq_is_enabled_at_pic(rtems_irq_number irq)
0415 {
0416 unsigned i;
0417     if ( !validIrqNo(irq) ) {
0418         printk("BSP_irq_is_enabled_at_pic: Invalid argument (irq #%i)\n",irq);
0419         return -1;
0420     }
0421 
0422     if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
0423         printk("BSP_enable_irq_at_pic: illegal argument\n");
0424         return -1;
0425     }
0426     return ld_le32(thePic.masks[i]) & (1<<irqMod32(irq)) ? 1 : 0;
0427 }
0428 
0429 
0430 /* Change priority of interrupt number 'irq' to 'pri'
0431  *
0432  * RETURNS: 0 on success, nonzero on failure (illegal args)
0433  *
0434  * NOTE: This routine must not be called from ISR level.
0435  *
0436  * Algorithm: Set bit corresponding to 'irq' in the masks for
0437  *            all priorities < pri and clear in all masks
0438  *            for priorities >=pri
0439  */
0440 int
0441 BSP_irq_set_priority(rtems_irq_number irq, rtems_irq_prio pri)
0442 {
0443 unsigned long      flags;
0444 volatile uint32_t *p;
0445 uint32_t           v,m;
0446 unsigned           i,j;
0447 
0448     if ( thePic.current_priority > 0 ) {
0449         printk("BSP_irq_set_priority: must not be called from ISR level\n");
0450         return -1;
0451     }
0452 
0453     if ( !validPri(pri) ) {
0454         printk("BSP_irq_set_priority: invalid argument (pri #%i)\n",pri);       
0455         return -1;
0456     }
0457 
0458     if ( BSP_DECREMENTER != irq ) {
0459         if ( !validIrqNo(irq) ) {
0460             printk("BSP_irq_set_priority: invalid argument (irq #%i)\n",irq);       
0461             return -1;
0462         }
0463 
0464         if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
0465             printk("BSP_irq_set_priority: illegal argument (irq #%i not PCI?)\n", irq);
0466             return -1;
0467         }
0468     }
0469 
0470 #if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
0471     printk("IRQ: Set Priority #%i -> %i;",irq,pri);
0472 #endif
0473 
0474     if ( BSP_DECREMENTER == irq ) {
0475         theConfig.irqPrioTbl[irq] = pri;
0476         return 0;
0477     }
0478 
0479     /* compute register pointer and bit mask */
0480     p = thePic.masks[i];
0481     m = 1<<irqMod32(irq);
0482     
0483     rtems_interrupt_disable(flags);
0484     {
0485         for (j=0; j<=BSP_IRQ_MAX_PRIO; j++) {
0486             if ( j<pri )
0487                 thePic.mcache[j][i] |= m;
0488             else
0489                 thePic.mcache[j][i] &= ~m;
0490         }
0491         theConfig.irqPrioTbl[irq] = pri;
0492         st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
0493         /* linux driver reads back GPP mask; maybe it's wise to do the same */
0494         (void)ld_le32(thePic.masks[GPP_IDX]);
0495     }
0496     SYNC();
0497     rtems_interrupt_enable(flags);
0498 
0499 #if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
0500     printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
0501 #endif
0502 
0503     return 0;
0504 }
0505 
0506 /* Initialize the PIC; routine needed by BSP framework
0507  *
0508  * RETURNS: NONZERO on SUCCESS, 0 on error!
0509  */
0510 int
0511 BSP_setup_the_pic(rtems_irq_global_settings* config)
0512 {
0513 int i;
0514    /*
0515     * Store copy of configuration
0516     */
0517     theConfig               = *config;
0518 
0519     /* check config */
0520     if ( theConfig.irqNb <= BSP_PCI_IRQ_MAX_OFFSET ) {
0521         printk("BSP_setup_the_pic: FATAL ERROR: configured IRQ table too small???\n");
0522         return 0;
0523     } 
0524 
0525     for ( i=0; i<theConfig.irqNb; i++ ) {
0526         if ( !validPri(theConfig.irqPrioTbl[i]) ) {
0527             printk("BSP_setup_the_pic: invalid priority (%i) for irg #%i; setting to 1\n", theConfig.irqPrioTbl[i], i);
0528             theConfig.irqPrioTbl[i]=1;
0529         }
0530     }
0531 
0532     /* TODO: Detect; Switch wired-out bit;  */
0533     thePic.reg_base = BSP_MV64x60_BASE;
0534 
0535     thePic.current_priority = 0;
0536 
0537 #if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
0538 #endif
0539 
0540     switch ( BSP_getDiscoveryVersion(/* assert */ 1) ) {
0541         case MV_64360:
0542             thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_360_MIC_LO);
0543             thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_360_MIC_HI);
0544             thePic.masks[MAIN_LO_IDX]  = REGP(thePic.reg_base + ICR_360_C0IM_LO);
0545             thePic.masks[MAIN_HI_IDX]  = REGP(thePic.reg_base + ICR_360_C0IM_HI);
0546         break;
0547 
0548         case GT_64260_A:
0549         case GT_64260_B:
0550             thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_260_MIC_LO);
0551             thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_260_MIC_HI);
0552             thePic.masks[MAIN_LO_IDX]  = REGP(thePic.reg_base + ICR_260_CIM_LO);
0553             thePic.masks[MAIN_HI_IDX]  = REGP(thePic.reg_base + ICR_260_CIM_HI);
0554         break;
0555 
0556         default:
0557             rtems_panic("Unable to initialize interrupt controller; unknown chip");
0558         break;
0559     }
0560 
0561     thePic.causes[GPP_IDX]     = REGP(thePic.reg_base + GT_GPP_Interrupt_Cause);
0562     thePic.masks[GPP_IDX]      = REGP(thePic.reg_base + GT_GPP_Interrupt_Mask);
0563 
0564     /* Initialize mask cache */
0565     for ( i=0; i<=BSP_IRQ_MAX_PRIO; i++ ) {
0566         thePic.mcache[i][MAIN_LO_IDX] = 0;
0567         /* Always enable the summary bits. Otherwise, GPP interrupts dont
0568          * make it 'through' to the GPP cause
0569          */
0570         thePic.mcache[i][MAIN_HI_IDX] = IMH_GPP_SUM;
0571         thePic.mcache[i][GPP_IDX]     = 0;
0572     }
0573 
0574     /* mask and clear everything */
0575     for ( i=0; i<NUM_INTR_REGS; i++ ) {
0576         st_le32(thePic.causes[i], 0);
0577         st_le32(thePic.masks[i], 0);
0578     }
0579 
0580     /* make sure GPP Irqs are level sensitive */
0581     gt_bitmod(
0582         GT_CommUnitArb_Ctrl,                            /* reg */
0583         GT_CommUnitArb_Ctrl_GPP_Ints_Level_Sensitive,   /* set */
0584         0);                                             /* clr */
0585 
0586     /* enable summaries */
0587     st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[thePic.current_priority][MAIN_LO_IDX]);
0588     st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[thePic.current_priority][MAIN_HI_IDX]);
0589     st_le32(thePic.masks[GPP_IDX    ], thePic.mcache[thePic.current_priority][GPP_IDX    ]);
0590 
0591     /* believe the interrupts are all level sensitive (which is good); we leave all the
0592      * inputs configured they way the are by MotLoad...
0593      */
0594     
0595     /* Finally, enable all interrupts for which the configuration table has already
0596      * a handler installed.
0597      */
0598     for ( i=BSP_PCI_IRQ_LOWEST_OFFSET; i<=BSP_PCI_IRQ_MAX_OFFSET; i++ ) {
0599         if ( theConfig.irqHdlTbl[i].hdl != theConfig.defaultEntry.hdl ) {
0600             BSP_enable_irq_at_pic(i);
0601         }
0602     }
0603 
0604     return 1;
0605 }
0606 
0607 int discovery_pic_max_loops = 0;
0608 
0609 
0610 /* Change the priority level we're executing at and mask all interrupts of
0611  * the same and lower priorities
0612  *
0613  * RETURNS old priority;
0614  */
0615 
0616 static inline  rtems_irq_prio
0617 change_executing_prio_level(rtems_irq_prio pri)
0618 {
0619 register rtems_irq_prio rval = thePic.current_priority;
0620     thePic.current_priority = pri;
0621     st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[pri][MAIN_LO_IDX]);
0622     st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[pri][MAIN_HI_IDX]);
0623     st_le32(thePic.masks[GPP_IDX    ], thePic.mcache[pri][GPP_IDX    ]);
0624     /* this DOES seem to be necessary */
0625     (void)ld_le32(thePic.masks[GPP_IDX]);
0626     return rval;
0627 }
0628 
0629 /* Scan the three cause register and find the pending interrupt with
0630  * the highest priority.
0631  *
0632  * Two facts make this quite efficient
0633  *   a) the PPC has an opcode for finding the number of leading zero-bits
0634  *      in a register (__ilog2()).
0635  *   b) as we proceed we mask all sources of equal or lower priorites; they won't be
0636  *      seen while scanning:
0637  *
0638  *   maxpri = 0;
0639  *   bits   = in_le32(cause);
0640  *   while ( bits &= mask[maxpri] ) {
0641  *      irq_no = __ilog2(bits);
0642  *      maxpri = priority[irq_no]; 
0643  *   }
0644  *   
0645  *   a)  __ilog() is 1-2 machine instructions
0646  *   b) while loop is only executed as many times as interrupts of different
0647  *      priorities are pending at the same time (and only if lower-priority
0648  *      ones are found first; otherwise, the iteration terminates quicker).
0649  *
0650  *   ==> highest priority source is found quickly. It takes at most
0651  *
0652  *      BSP_IRQ_MAX_PRIO * ( ~3 reg-only instructions + 2 memory access )
0653  *      + 2 reg-only instructions + 1 I/O + 1 memory access.
0654  *
0655  *       
0656  */
0657 
0658 static unsigned mlc, mhc, gpc;
0659 
0660 static int decrementerPending = 0;
0661 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0662 int        decrementerIrqs    = 0;
0663 #endif
0664 
0665 static inline unsigned 
0666 find_highest_priority_pending_irq(rtems_irq_prio *ppri)
0667 {
0668 register int            rval = -1;
0669 register rtems_irq_prio *pt  = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET;
0670 register rtems_irq_prio pmax = *ppri;
0671 register unsigned       cse,ocse;
0672 
0673 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0674     discovery_dump_picregs();
0675 #endif
0676 
0677     if ( decrementerPending ) {
0678 /* Don't flood 
0679 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0680         printk("Decrementer IRQ pending\n");
0681 #endif
0682 */
0683         if ( theConfig.irqPrioTbl[BSP_DECREMENTER] > pmax ) {
0684             pmax = theConfig.irqPrioTbl[BSP_DECREMENTER];
0685             rval = BSP_DECREMENTER;
0686         }
0687     }
0688 
0689     mlc = cse = ld_le32(thePic.causes[MAIN_LO_IDX]);
0690 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0691     printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]);
0692 #endif
0693     while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) {
0694         rval = __ilog2(cse);
0695         pmax = pt[rval];
0696 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0697         printk("Max pri IRQ now %i\n",rval);
0698 #endif
0699     }
0700     mhc = cse = ocse = ld_le32(thePic.causes[MAIN_HI_IDX]);
0701 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0702     printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]);
0703 #endif
0704     /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */
0705     cse &= ~IMH_GPP_SUM;
0706     while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) {
0707         rval = __ilog2(cse) + 32;
0708         pmax = pt[rval];
0709 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0710         printk("Max pri IRQ now %i\n",rval);
0711 #endif
0712     }
0713     gpc = cse = ld_le32(thePic.causes[GPP_IDX    ]);
0714     /* if there were GPP ints, scan the GPP cause now */
0715     if ( ocse & IMH_GPP_SUM ) {
0716 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0717         printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX    ]);
0718 #endif
0719         cse &= thePic.mcache[pmax][GPP_IDX    ];
0720         ocse = cse;
0721         while ( cse ) {
0722             rval = __ilog2(cse) + 64;
0723             pmax = pt[rval];
0724             cse &= thePic.mcache[pmax][GPP_IDX    ];
0725 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0726             printk("Max pri IRQ now %i\n",rval);
0727 #endif
0728         }
0729 #ifndef FASTER
0730         /* this doesn't seem to be necessary -- however, the linux people do it... */
0731         out_le32(thePic.causes[GPP_IDX], ~ocse);
0732 #endif
0733     }
0734 #ifndef FASTER
0735     /* this doesn't seem to be necessary -- however, the linux people do it... */
0736     (void)in_le32(thePic.causes[GPP_IDX]);
0737 #endif
0738 
0739     *ppri = pmax;
0740 
0741     if ( BSP_DECREMENTER == rval ) {
0742 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0743         decrementerIrqs++;
0744 #endif
0745         decrementerPending = 0;
0746     }
0747 
0748     return rval;
0749 }
0750 
0751 #if 0 /* TODO: should this be cleaned up ? */
0752 #define _IRQ_DEBUG IRQ_DEBUG_DISPATCHER
0753 static inline unsigned 
0754 ffind_highest_priority_pending_irq(rtems_irq_prio *ppri)
0755 {
0756 register int            rval = -1;
0757 register rtems_irq_prio *pt  = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET;
0758 register rtems_irq_prio pmax = *ppri;
0759 register unsigned       cse,ocse;
0760 
0761 #if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0762     discovery_dump_picregs();
0763 #endif
0764 
0765     cse = in_le32(thePic.causes[MAIN_LO_IDX]);
0766 #if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0767     printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]);
0768 #endif
0769     while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) {
0770         rval = __ilog2(cse);
0771         pmax = pt[rval];
0772 #if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0773         printk("Max pri IRQ now %i\n",rval);
0774 #endif
0775     }
0776     cse = ocse = in_le32(thePic.causes[MAIN_HI_IDX]);
0777 #if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0778     printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]);
0779 #endif
0780     /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */
0781     cse &= ~IMH_GPP_SUM;
0782     while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) {
0783         rval = __ilog2(cse) + 32;
0784         pmax = pt[rval];
0785 #if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0786         printk("Max pri IRQ now %i\n",rval);
0787 #endif
0788     }
0789     /* if there were GPP ints, scan the GPP cause now */
0790     if ( ocse & IMH_GPP_SUM ) {
0791         cse = in_le32(thePic.causes[GPP_IDX    ]);
0792 #if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0793         printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX    ]);
0794 #endif
0795         cse &= thePic.mcache[pmax][GPP_IDX    ];
0796         ocse = cse;
0797         while ( cse ) {
0798             rval = __ilog2(cse) + 64;
0799             pmax = pt[rval];
0800             cse &= thePic.mcache[pmax][GPP_IDX    ];
0801 #if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0802             printk("Max pri IRQ now %i\n",rval);
0803 #endif
0804         }
0805         /* this doesn't seem to be necessary -- however, the linux people do it... */
0806         out_le32(thePic.causes[GPP_IDX], ~ocse);
0807     }
0808     /* this doesn't seem to be necessary -- however, the linux people do it... */
0809     (void)in_le32(thePic.causes[GPP_IDX]);
0810 
0811     *ppri = pmax;
0812     return rval;
0813 }
0814 #endif
0815 
0816 
0817 /* Here's our dispatcher; the BSP framework uses the same one for EE and decrementer
0818  * exceptions...
0819  */
0820 int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
0821 {
0822 register int             irq;
0823 int                      loop, last_irq;
0824 rtems_irq_prio           pri;
0825 #if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
0826 unsigned long            diff;
0827 #endif
0828 
0829 #if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
0830     diff = mftb();
0831 #endif
0832 
0833     if (excNum == ASM_DEC_VECTOR) {
0834         decrementerPending = 1;
0835     }
0836 
0837     /* Tradeoff: EITHER we loop as long as interrupts are pending
0838      *           incurring the overhead of one extra run of the 'find_pending_irq' routine.
0839      *           OR we do rely on the handler just being invoked again if multiple
0840      *           interrupts are pending.
0841      *
0842      *           The first solution gives better worst-case behavior
0843      *           the second slightly better average performance.
0844      *           --> we go for the first solution. This also enables us to catch
0845      *           runaway interrupts, i.e., bad drivers that don't clear interrupts
0846      *           at the device. Can be very handy during driver development...
0847      */
0848     for ( loop=0, last_irq=-1, pri = thePic.current_priority;
0849           (irq=find_highest_priority_pending_irq(&pri)) >=0;
0850           loop++, last_irq = irq ) {
0851 
0852         /* raise priority level and remember current one */
0853         pri = change_executing_prio_level(pri);
0854 
0855         SYNC();
0856 
0857 #if (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
0858         if ( 0 == loop ) {
0859             diff = mftb()-diff;
0860             if ( diff > discovery_pic_max_dispatching_latency )
0861                 discovery_pic_max_dispatching_latency = diff;
0862         }
0863 #endif
0864 
0865 #if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
0866         if ( BSP_DECREMENTER == irq ) {
0867             printk("IRQ: dispatching DECREMENTER\n");
0868         } else {
0869         int idx = irqDiv32(irq);
0870             printk("IRQ: dispatching #%i; causes[%i]=0x%08x\n", irq, idx, ld_le32(thePic.causes[idx]));
0871         }
0872 #endif
0873 
0874         bsp_irq_dispatch_list( theConfig.irqHdlTbl, irq, theConfig.defaultEntry.hdl );
0875 
0876         /* restore executing priority level */
0877         (void)change_executing_prio_level(pri);
0878 
0879         if ( (loop > MAX_SPIN_LOOPS) && (last_irq == irq) ) {
0880             /* try to catch run-away interrupts without disabling a 'legal' one;
0881              * this should never happen with the decrementer (and
0882              * BSP_disable_irq_at_pic(BSP_DECREMENTER) would fail)
0883              */
0884             printk("Runaway IRQ #%i; disabling\n", irq);
0885             BSP_disable_irq_at_pic(irq);
0886             loop = 0;
0887         }
0888     }
0889 
0890     if (!loop) {
0891         if ( decrementerPending && pri >= theConfig.irqPrioTbl[BSP_DECREMENTER] ) {
0892             /* we cannot mask the decrementer interrupt so it is possible that it
0893              * gets delivered even though it has a lower priority than what we're
0894              * currently executing at.
0895              * In this case, we ignore the zero loop count and return;
0896              * the interrupted instance of C_dispatch_irq_handler() will eventually
0897              * lower the executing priority and catch the 'decrementerPending' flag
0898              * we just set.
0899              */
0900         } else {
0901             printk("Discovery: Spurious interrupt; causes were gpp: 0x%x, mhc: 0x%x, mlc: 0x%x\n", gpc, mhc, mlc);
0902             printk("Current priority level %i, decrementerPending %i\n", pri, decrementerPending);
0903             {
0904                 rtems_irq_prio p=pri;   
0905                 printk("PIC register dump:\n");
0906                 discovery_dump_picregs();
0907                 printk("Current Priority: %i, found %i\n",pri,find_highest_priority_pending_irq(&p));
0908                 discovery_dump_picregs();
0909                 for (p=0; p<=BSP_IRQ_MAX_PRIO; p++) {
0910                     printk("M[%i] :",p);pmsks(thePic.mcache[p]);
0911                 }
0912             }
0913         }
0914     }
0915     else if (loop>discovery_pic_max_loops)
0916         discovery_pic_max_loops = loop;
0917 
0918     return 0;
0919 }
0920 
0921 
0922 #if (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
0923 void
0924 discovery_pic_install_debug_irq(void)
0925 {
0926     switch ( BSP_getBoardType() ) {
0927         case    MVME6100:   gpp_out_bit = GPP_WIRED_OUT_BIT_6100; break;
0928         case    MVME5500:   gpp_out_bit = GPP_WIRED_OUT_BIT_5500; break;
0929         default:
0930                             gpp_out_bit = 0; break;
0931                             break;
0932     }
0933     if ( gpp_out_bit ) {
0934         unsigned mppoff;
0935         switch (gpp_out_bit / 8) {
0936             default:    /* silence warning; this is never reached */
0937             case 0: mppoff = GT_MPP_Control0; break;
0938             case 1: mppoff = GT_MPP_Control1; break;
0939             case 2: mppoff = GT_MPP_Control2; break;
0940             case 3: mppoff = GT_MPP_Control3; break;
0941         }
0942 
0943         /* switch GPP pin allocated to watchdog (value 4) to
0944          * GPP I/O (value 0 ??; have no doc, found out by experimenting)
0945          */
0946         gt_bitmod(mppoff, 0, (0xf<<(4*(gpp_out_bit % 8))));
0947 
0948         /* make it an output */
0949         gt_bitmod(GT_GPP_IO_Control, (1<<gpp_out_bit), 0);
0950 
0951         /* don't invert levels */
0952         gt_bitmod(GT_GPP_Level_Control, 0, (1<<GPP_WIRED_IN_BIT) | (1<<gpp_out_bit));
0953 
0954         /* clear output */
0955         gt_bitmod(GT_GPP_Value, 0, 1<<gpp_out_bit);
0956 
0957         printk("GPP levelctl now 0x%08x\n", gt_read(GT_GPP_Level_Control));
0958         printk("GPP value    now 0x%08x\n", gt_read(GT_GPP_Value));
0959         printk("MPP ctl 0    now 0x%08x\n", gt_read(GT_MPP_Control0));
0960         printk("MPP ctl 1    now 0x%08x\n", gt_read(GT_MPP_Control1));
0961         printk("MPP ctl 2    now 0x%08x\n", gt_read(GT_MPP_Control2));
0962         printk("MPP ctl 3    now 0x%08x\n", gt_read(GT_MPP_Control3));
0963 
0964     }
0965 }
0966 
0967 /* Control the state of the external 'wire' that connects the
0968  * GPP_WIRED_OUT --> GPP_WIRED_IN pins
0969  */
0970 void
0971 discovery_pic_set_debug_irq(int on)
0972 {
0973 unsigned long flags, clr;
0974     if ( !gpp_out_bit ) {
0975         printk("discovery_pic_set_debug_irq(): unknown wire output\n");
0976         return;
0977     }
0978     if (on) {
0979         on  = 1<<gpp_out_bit;
0980         clr = 0;
0981     } else {
0982         clr = 1<<gpp_out_bit;
0983         on  = 0;
0984     }
0985     rtems_interrupt_disable(flags);
0986         gt_bitmod(GT_GPP_Value, on, clr);
0987     rtems_interrupt_enable(flags);
0988 }
0989 #endif
0990 
0991 #if 0
0992 /* Here's some code for testing */
0993 #endif