source: rtems/bsps/powerpc/beatnik/irq/discovery_pic.c @ 8f8ccee

Last change on this file since 8f8ccee was 8f8ccee, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 23, 2018 at 7:50:39 AM

bsps: Move interrupt controller support to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 27.4 KB
Line 
1/* Interrupt driver + dispatcher for the discovery host controller */
2
3/* Author: T. Straumann, 2005-2007
4 *
5 * Acknowledgements:
6 * Valuable information was obtained from the following drivers
7 *   netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
8 *   linux:  (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
9 *   rtems:  (C) Brookhaven National Laboratory; K. Feng
10 * but this implementation is original work by the author.
11 */
12
13/*
14 * Authorship
15 * ----------
16 * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was
17 *     created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
18 *         Stanford Linear Accelerator Center, Stanford University.
19 *
20 * Acknowledgement of sponsorship
21 * ------------------------------
22 * The 'beatnik' BSP was produced by
23 *     the Stanford Linear Accelerator Center, Stanford University,
24 *         under Contract DE-AC03-76SFO0515 with the Department of Energy.
25 *
26 * Government disclaimer of liability
27 * ----------------------------------
28 * Neither the United States nor the United States Department of Energy,
29 * nor any of their employees, makes any warranty, express or implied, or
30 * assumes any legal liability or responsibility for the accuracy,
31 * completeness, or usefulness of any data, apparatus, product, or process
32 * disclosed, or represents that its use would not infringe privately owned
33 * rights.
34 *
35 * Stanford disclaimer of liability
36 * --------------------------------
37 * Stanford University makes no representations or warranties, express or
38 * implied, nor assumes any liability for the use of this software.
39 *
40 * Stanford disclaimer of copyright
41 * --------------------------------
42 * Stanford University, owner of the copyright, hereby disclaims its
43 * copyright and all other rights in this software.  Hence, anyone may
44 * freely use it for any purpose without restriction. 
45 *
46 * Maintenance of notices
47 * ----------------------
48 * In the interest of clarity regarding the origin and status of this
49 * SLAC software, this and all the preceding Stanford University notices
50 * are to remain affixed to any copy or derivative of this software made
51 * or distributed by the recipient and are to be affixed to any copy of
52 * software made or distributed by the recipient that contains a copy or
53 * derivative of this software.
54 *
55 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
56 */ 
57#include <rtems.h>
58#include <bsp.h>
59#include <bsp/irq.h>
60#include <bsp/gtreg.h>
61#include <bsp/gtintrreg.h>
62#include <rtems/bspIo.h>
63#include <bsp/vectors.h>
64#include <libcpu/byteorder.h>
65#include <libcpu/spr.h>
66
67/* dont change the order (main_lo, main_hi, gpp) which
68 * matches the interrupt numbers!
69 */
70#define MAIN_LO_IDX     0
71#define MAIN_HI_IDX     1
72#define GPP_IDX         2
73#define NUM_INTR_REGS 3
74
75
76#define SYNC() __asm__ volatile("sync")
77
78/* How many times should the ISR dispatcher check for
79 * pending interrupts until it decides that something's
80 * fishy (i.e., a user ISR fails to clear the interrupt
81 * source)
82 */
83#define MAX_SPIN_LOOPS 100
84
85/* If FASTER is defined, a few obscure I/O statements found in the linux
86 * driver are removed
87 */
88#define FASTER
89
90/* Array helper */
91#define NumberOf(arr) (sizeof(arr)/sizeof((arr)[0]))
92
93
94/* MVME6100 specific; re-define watchdog NMI pin to be a normal output
95 * so we have a way to raise an interrupt in software (GPP[26] is wired to
96 * GPP[6] on the MVME6100).
97 */
98#define MVME6100_IRQ_DEBUG 4
99
100#define GPP_WIRED_OUT_BIT_6100 26       /* CAVEAT: this is bit 26 on the 6100 */
101#define GPP_WIRED_OUT_BIT_5500 24       /* CAVEAT: this is bit 24 on the 5500 */
102#define GPP_WIRED_IN_BIT   6
103
104/* Ored mask of debugging features to enable */
105#define IRQ_DEBUG_BASIC                 1
106/* This is _very_ lowlevel */
107#define IRQ_DEBUG_DISPATCHER    2
108/* Record maximal dispatching latency */
109#define IRQ_DEBUG_MAXLAT                8       /* PPC only */
110
111#define IRQ_DEBUG (0 /*|(IRQ_DEBUG_BASIC)*/|(MVME6100_IRQ_DEBUG)|(IRQ_DEBUG_MAXLAT))
112
113/**********
114 * Typedefs
115 **********/
116
117/* Set of the three relevant cause registers */
118typedef volatile unsigned IrqMask[NUM_INTR_REGS];
119
120#define REGP(x) ((volatile uint32_t *)(x))
121
122/* Information we keep about the PIC         */
123typedef struct _Mv64x60PicRec {
124                                                        /* base address as seen from CPU  */
125        uintptr_t                               reg_base;
126
127                                                        /* addresses of 'cause' registers */
128        volatile uint32_t               *causes[NUM_INTR_REGS];
129
130                                                        /* addresses of 'mask'  registers */
131        volatile uint32_t               *masks[NUM_INTR_REGS];
132
133                                                        /* masks for all priorities. If an
134                                                         * interrupt source has priority X,
135                                                         * its corresponding bit is set
136                                                         * (enabled) in mcache[i] for all
137                                                         * i < X and cleared for i >= X
138                                                         */
139        volatile IrqMask                mcache[BSP_IRQ_MAX_PRIO+1];
140
141                                                        /* Priority we're executing at.
142                                                         * Thread-level is priority 0,
143                                                         * ISRs range from 1..MAX_PRIO
144                                                         */
145        volatile rtems_irq_prio current_priority;
146} Mv64x60PicRec, *Mv64x60Pic;
147
148/**********
149 * Globals
150 **********/
151
152
153/* Copy of the configuration */
154static rtems_irq_global_settings        theConfig;
155/* PIC description           */
156static Mv64x60PicRec                            thePic;
157
158#if     (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
159static unsigned long                            gpp_out_bit = 0;
160#endif
161
162#if     (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
163unsigned long                                           discovery_pic_max_dispatching_latency = 0;
164#ifdef __PPC__
165static inline unsigned long mftb(void)
166{
167unsigned long rval;
168        asm volatile("mftb %0":"=r"(rval));
169        return rval;
170}
171#else
172#define mftb()  0
173#endif
174#endif
175
176/**********
177 * Functions
178 **********/
179
180/* Debugging helper routines */
181static void pregs(volatile uint32_t **p)
182{
183int i;
184        for (i=NUM_INTR_REGS-1; i>=0; i--) {
185                printk(" 0x%08x", ld_le32(p[i]));
186                printk( i ? " --":"\n");
187        }
188}
189
190static void pmsks(volatile IrqMask p)
191{
192int i;
193        for (i=NUM_INTR_REGS-1; i>=0; i--) {
194                printk(" 0x%08x", p[i]);
195                printk( i ? " --":"\n");
196        }
197}
198
199static void discovery_dump_picregs(void)
200{
201                printk("       ..GPP_IRQ. -- ..MAIN_HI. -- ..MAIN_LO.\n");
202                printk("Cause:"); pregs(thePic.causes);
203                printk("Mask: "); pregs(thePic.masks);
204}
205
206/* Small inline helpers      */
207
208/* return 0 if this PIC is not 'responsible' for a given irq number
209 * we also 'ignore' the GPP summary bits - these must always remain
210 * enabled.
211 */
212static inline int
213validIrqNo(rtems_irq_number irq)
214{
215        return
216                   irq >= BSP_PCI_IRQ_LOWEST_OFFSET
217                && irq <= BSP_PCI_IRQ_MAX_OFFSET
218                && ! (IMH_GPP_SUM & (1<<(irq-32)));
219}
220
221/* return 0 if a given priority is outside the valid range          */
222static inline int
223validPri(rtems_irq_prio pri)
224{
225        /* silence compiler warning about limited range of type;
226         * hope it never changes...
227         */
228        return /* pri>=0 && */ pri <=BSP_IRQ_MAX_PRIO;
229}
230
231/* Return position of the most significant bit that is set in 'x'  */
232static inline int
233__ilog2(unsigned x)
234{
235        asm volatile("cntlzw %0, %0":"=&r"(x):"0"(x));
236        return 31-x;
237}
238
239/* Convert irq number to cause register index
240 * (array of handles in the PicRec).
241 * ASSUMES: 'irq' within valid range.
242 */
243static inline unsigned
244irqDiv32(unsigned irq)
245{
246        return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)>>5;
247}
248
249/* Convert irq number to cause/mask bit number.
250 * ASSUMES: 'irq' within valid range.
251 */
252
253static inline unsigned
254irqMod32(unsigned irq)
255{
256        return (irq-BSP_PCI_IRQ_LOWEST_OFFSET)&31;
257}
258
259/* NON-ATOMICALLY set/clear bits in a MV64x60 register
260 *
261 * register contents at offset 'off' are ANDed with
262 * complement of the 'clr' mask and ORed with 'set' mask:
263 *
264 *   *off = (*off & ~clr) | set
265 *
266 * ASSUMES: executed from IRQ-disabled section
267 */
268static inline void
269gt_bitmod(unsigned off, unsigned set, unsigned clr)
270{
271        st_le32(REGP(thePic.reg_base + off),
272                        (ld_le32(REGP(thePic.reg_base+off)) & ~clr) | set);
273}
274
275static inline unsigned
276gt_read(unsigned off)
277{
278        return ld_le32(REGP(thePic.reg_base + off));
279}
280
281static inline void
282gt_write(unsigned off, unsigned val)
283{
284        st_le32(REGP(thePic.reg_base + off), val);
285}
286
287/* Enable interrupt number 'irq' at the PIC.
288 *
289 * Checks for valid arguments but has no way of
290 * communicating violation; prints to console
291 * if illegal arguments are given.
292 *
293 * This routine may be called from ISR level.
294 *
295 * Algorithm: set corresponding bit in masks
296 *            for all priorities lower than the
297 *            target irq's priority and push
298 *            mask for the currently executing
299 *            priority out to the PIC.
300 */
301
302void
303BSP_enable_irq_at_pic(rtems_irq_number irq)
304{
305unsigned                   i,j;
306unsigned long      flags;
307volatile uint32_t *p;
308uint32_t                   v,m;
309
310        if ( !validIrqNo(irq) ) {
311/* API change - must silently ignore...
312                printk("BSP_enable_irq_at_pic: Invalid argument (irq #%i)\n",irq);
313 */
314                return;
315        }
316
317#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
318        printk("IRQ: Enable #%i;",irq);
319#endif
320
321        if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
322                /* This is probably a more serious error; don't ignore silently */
323                printk("BSP_enable_irq_at_pic: illegal argument\n");
324                return;
325        }
326        /* compute register pointer and bit mask */
327        p = thePic.masks[i];
328        m = 1<<irqMod32(irq);
329               
330        rtems_interrupt_disable(flags);
331        {
332                /* access table from protected section to be thread-safe */
333                rtems_irq_prio  pri = theConfig.irqPrioTbl[irq];
334                for ( j=0; j<pri; j++ ) {
335                        thePic.mcache[j][i] |= m;
336                }
337                st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
338                /* linux driver reads back GPP mask; maybe it's wise to do the same */
339                (void)ld_le32(thePic.masks[GPP_IDX]);
340        }
341        SYNC();
342        rtems_interrupt_enable(flags);
343
344#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
345        printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
346
347#endif
348}
349
350/* Disable interrupt number 'irq' at the PIC.
351 *
352 * Checks for valid arguments but has no way of
353 * communicating violation; prints to console
354 * if illegal arguments are given.
355 *
356 * This routine may be called from ISR level.
357 *
358 * Algorithm: clear corresponding bit in masks
359 *            for all priorities and push the
360 *            mask for the currently executing
361 *            priority out to the PIC.
362 */
363
364int
365BSP_disable_irq_at_pic(rtems_irq_number irq)
366{
367unsigned                   i,j;
368unsigned long      flags;
369volatile uint32_t *p;
370uint32_t           v,m;
371int                rval;
372
373        if ( !validIrqNo(irq) ) {
374/* API change - must silently ignore...
375                printk("BSP_disable_irq_at_pic: Invalid argument (irq #%i)\n",irq);
376 */
377                return -1;
378        }
379
380#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
381        printk("IRQ: Disable #%i;",irq);
382#endif
383
384        if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
385                /* This is probably a more serious error; don't ignore silently */
386                printk("BSP_enable_irq_at_pic: illegal argument\n");
387                return -1;
388        }
389
390        /* compute register pointer and bit mask */
391        p = thePic.masks[i];
392        m = (1<<irqMod32(irq));
393
394        rtems_interrupt_disable(flags);
395        {
396                rval = thePic.mcache[thePic.current_priority][i] & m;
397                for (j=0; j<=BSP_IRQ_MAX_PRIO; j++)
398                        thePic.mcache[j][i] &= ~m;
399                st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
400                /* linux driver reads back GPP mask; maybe it's wise to do the same */
401                (void)ld_le32(thePic.masks[GPP_IDX]);
402        }
403        SYNC();
404        rtems_interrupt_enable(flags);
405
406#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
407        printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
408#endif
409
410        return rval ? 1 : 0;
411}
412
413int
414BSP_irq_is_enabled_at_pic(rtems_irq_number irq)
415{
416unsigned i;
417        if ( !validIrqNo(irq) ) {
418                printk("BSP_irq_is_enabled_at_pic: Invalid argument (irq #%i)\n",irq);
419                return -1;
420        }
421
422        if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
423                printk("BSP_enable_irq_at_pic: illegal argument\n");
424                return -1;
425        }
426        return ld_le32(thePic.masks[i]) & (1<<irqMod32(irq)) ? 1 : 0;
427}
428
429
430/* Change priority of interrupt number 'irq' to 'pri'
431 *
432 * RETURNS: 0 on success, nonzero on failure (illegal args)
433 *
434 * NOTE: This routine must not be called from ISR level.
435 *
436 * Algorithm: Set bit corresponding to 'irq' in the masks for
437 *            all priorities < pri and clear in all masks
438 *            for priorities >=pri
439 */
440int
441BSP_irq_set_priority(rtems_irq_number irq, rtems_irq_prio pri)
442{
443unsigned long      flags;
444volatile uint32_t *p;
445uint32_t                   v,m;
446unsigned           i,j;
447
448        if ( thePic.current_priority > 0 ) {
449                printk("BSP_irq_set_priority: must not be called from ISR level\n");
450                return -1;
451        }
452
453        if ( !validPri(pri) ) {
454                printk("BSP_irq_set_priority: invalid argument (pri #%i)\n",pri);               
455                return -1;
456        }
457
458        if ( BSP_DECREMENTER != irq ) {
459                if ( !validIrqNo(irq) ) {
460                        printk("BSP_irq_set_priority: invalid argument (irq #%i)\n",irq);               
461                        return -1;
462                }
463
464                if ( (i=irqDiv32(irq)) > NUM_INTR_REGS ) {
465                        printk("BSP_irq_set_priority: illegal argument (irq #%i not PCI?)\n", irq);
466                        return -1;
467                }
468        }
469
470#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
471        printk("IRQ: Set Priority #%i -> %i;",irq,pri);
472#endif
473
474        if ( BSP_DECREMENTER == irq ) {
475                theConfig.irqPrioTbl[irq] = pri;
476                return 0;
477        }
478
479        /* compute register pointer and bit mask */
480        p = thePic.masks[i];
481        m = 1<<irqMod32(irq);
482       
483        rtems_interrupt_disable(flags);
484        {
485                for (j=0; j<=BSP_IRQ_MAX_PRIO; j++) {
486                        if ( j<pri )
487                                thePic.mcache[j][i] |= m;
488                        else
489                                thePic.mcache[j][i] &= ~m;
490                }
491                theConfig.irqPrioTbl[irq] = pri;
492                st_le32(p, (v=thePic.mcache[thePic.current_priority][i]));
493                /* linux driver reads back GPP mask; maybe it's wise to do the same */
494                (void)ld_le32(thePic.masks[GPP_IDX]);
495        }
496        SYNC();
497        rtems_interrupt_enable(flags);
498
499#if (IRQ_DEBUG) & IRQ_DEBUG_BASIC
500        printk(" Mask[%i]: 0x%08x -> 0x%08x\n",i,v,ld_le32(p));
501#endif
502
503        return 0;
504}
505
506/* Initialize the PIC; routine needed by BSP framework
507 *
508 * RETURNS: NONZERO on SUCCESS, 0 on error!
509 */
510int
511BSP_setup_the_pic(rtems_irq_global_settings* config)
512{
513int i;
514   /*
515    * Store copy of configuration
516    */
517        theConfig                               = *config;
518
519        /* check config */
520        if ( theConfig.irqNb <= BSP_PCI_IRQ_MAX_OFFSET ) {
521                printk("BSP_setup_the_pic: FATAL ERROR: configured IRQ table too small???\n");
522                return 0;
523        } 
524
525        for ( i=0; i<theConfig.irqNb; i++ ) {
526                if ( !validPri(theConfig.irqPrioTbl[i]) ) {
527                        printk("BSP_setup_the_pic: invalid priority (%i) for irg #%i; setting to 1\n", theConfig.irqPrioTbl[i], i);
528                        theConfig.irqPrioTbl[i]=1;
529                }
530        }
531
532        /* TODO: Detect; Switch wired-out bit;  */
533        thePic.reg_base = BSP_MV64x60_BASE;
534
535        thePic.current_priority = 0;
536
537#if     (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
538#endif
539
540        switch ( BSP_getDiscoveryVersion(/* assert */ 1) ) {
541                case MV_64360:
542                        thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_360_MIC_LO);
543                        thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_360_MIC_HI);
544                        thePic.masks[MAIN_LO_IDX]  = REGP(thePic.reg_base + ICR_360_C0IM_LO);
545                        thePic.masks[MAIN_HI_IDX]  = REGP(thePic.reg_base + ICR_360_C0IM_HI);
546                break;
547
548                case GT_64260_A:
549                case GT_64260_B:
550                        thePic.causes[MAIN_LO_IDX] = REGP(thePic.reg_base + ICR_260_MIC_LO);
551                        thePic.causes[MAIN_HI_IDX] = REGP(thePic.reg_base + ICR_260_MIC_HI);
552                        thePic.masks[MAIN_LO_IDX]  = REGP(thePic.reg_base + ICR_260_CIM_LO);
553                        thePic.masks[MAIN_HI_IDX]  = REGP(thePic.reg_base + ICR_260_CIM_HI);
554                break;
555
556                default:
557                        rtems_panic("Unable to initialize interrupt controller; unknown chip");
558                break;
559        }
560
561        thePic.causes[GPP_IDX]     = REGP(thePic.reg_base + GT_GPP_Interrupt_Cause);
562        thePic.masks[GPP_IDX]      = REGP(thePic.reg_base + GT_GPP_Interrupt_Mask);
563
564        /* Initialize mask cache */
565        for ( i=0; i<=BSP_IRQ_MAX_PRIO; i++ ) {
566                thePic.mcache[i][MAIN_LO_IDX] = 0;
567                /* Always enable the summary bits. Otherwise, GPP interrupts dont
568                 * make it 'through' to the GPP cause
569                 */
570                thePic.mcache[i][MAIN_HI_IDX] = IMH_GPP_SUM;
571                thePic.mcache[i][GPP_IDX]     = 0;
572        }
573
574        /* mask and clear everything */
575        for ( i=0; i<NUM_INTR_REGS; i++ ) {
576                st_le32(thePic.causes[i], 0);
577                st_le32(thePic.masks[i], 0);
578        }
579
580        /* make sure GPP Irqs are level sensitive */
581        gt_bitmod(
582                GT_CommUnitArb_Ctrl,                                                    /* reg */
583                GT_CommUnitArb_Ctrl_GPP_Ints_Level_Sensitive,   /* set */
584                0);                                                                                             /* clr */
585
586        /* enable summaries */
587        st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[thePic.current_priority][MAIN_LO_IDX]);
588        st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[thePic.current_priority][MAIN_HI_IDX]);
589        st_le32(thePic.masks[GPP_IDX    ], thePic.mcache[thePic.current_priority][GPP_IDX    ]);
590
591        /* believe the interrupts are all level sensitive (which is good); we leave all the
592         * inputs configured they way the are by MotLoad...
593         */
594       
595        /* Finally, enable all interrupts for which the configuration table has already
596         * a handler installed.
597         */
598        for ( i=BSP_PCI_IRQ_LOWEST_OFFSET; i<=BSP_PCI_IRQ_MAX_OFFSET; i++ ) {
599                if ( theConfig.irqHdlTbl[i].hdl != theConfig.defaultEntry.hdl ) {
600                        BSP_enable_irq_at_pic(i);
601                }
602        }
603
604        return 1;
605}
606
607int discovery_pic_max_loops = 0;
608
609
610/* Change the priority level we're executing at and mask all interrupts of
611 * the same and lower priorities
612 *
613 * RETURNS old priority;
614 */
615
616static inline  rtems_irq_prio
617change_executing_prio_level(rtems_irq_prio pri)
618{
619register rtems_irq_prio rval = thePic.current_priority;
620        thePic.current_priority = pri;
621        st_le32(thePic.masks[MAIN_LO_IDX], thePic.mcache[pri][MAIN_LO_IDX]);
622        st_le32(thePic.masks[MAIN_HI_IDX], thePic.mcache[pri][MAIN_HI_IDX]);
623        st_le32(thePic.masks[GPP_IDX    ], thePic.mcache[pri][GPP_IDX    ]);
624        /* this DOES seem to be necessary */
625        (void)ld_le32(thePic.masks[GPP_IDX]);
626        return rval;
627}
628
629/* Scan the three cause register and find the pending interrupt with
630 * the highest priority.
631 *
632 * Two facts make this quite efficient
633 *   a) the PPC has an opcode for finding the number of leading zero-bits
634 *      in a register (__ilog2()).
635 *   b) as we proceed we mask all sources of equal or lower priorites; they won't be
636 *      seen while scanning:
637 *
638 *   maxpri = 0;
639 *   bits   = in_le32(cause);
640 *   while ( bits &= mask[maxpri] ) {
641 *      irq_no = __ilog2(bits);
642 *      maxpri = priority[irq_no];
643 *   }
644 *   
645 *   a)  __ilog() is 1-2 machine instructions
646 *   b) while loop is only executed as many times as interrupts of different
647 *      priorities are pending at the same time (and only if lower-priority
648 *      ones are found first; otherwise, the iteration terminates quicker).
649 *
650 *   ==> highest priority source is found quickly. It takes at most
651 *
652 *              BSP_IRQ_MAX_PRIO * ( ~3 reg-only instructions + 2 memory access )
653 *      + 2 reg-only instructions + 1 I/O + 1 memory access.
654 *
655 *       
656 */
657
658static unsigned mlc, mhc, gpc;
659
660static int decrementerPending = 0;
661#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
662int        decrementerIrqs    = 0;
663#endif
664
665static inline unsigned 
666find_highest_priority_pending_irq(rtems_irq_prio *ppri)
667{
668register int                    rval = -1;
669register rtems_irq_prio *pt  = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET;
670register rtems_irq_prio pmax = *ppri;
671register unsigned               cse,ocse;
672
673#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
674        discovery_dump_picregs();
675#endif
676
677        if ( decrementerPending ) {
678/* Don't flood
679#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
680                printk("Decrementer IRQ pending\n");
681#endif
682*/
683                if ( theConfig.irqPrioTbl[BSP_DECREMENTER] > pmax ) {
684                        pmax = theConfig.irqPrioTbl[BSP_DECREMENTER];
685                        rval = BSP_DECREMENTER;
686                }
687        }
688
689        mlc = cse = ld_le32(thePic.causes[MAIN_LO_IDX]);
690#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
691        printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]);
692#endif
693        while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) {
694                rval = __ilog2(cse);
695                pmax = pt[rval];
696#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
697                printk("Max pri IRQ now %i\n",rval);
698#endif
699        }
700        mhc = cse = ocse = ld_le32(thePic.causes[MAIN_HI_IDX]);
701#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
702        printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]);
703#endif
704        /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */
705        cse &= ~IMH_GPP_SUM;
706        while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) {
707                rval = __ilog2(cse) + 32;
708                pmax = pt[rval];
709#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
710                printk("Max pri IRQ now %i\n",rval);
711#endif
712        }
713        gpc = cse = ld_le32(thePic.causes[GPP_IDX    ]);
714        /* if there were GPP ints, scan the GPP cause now */
715        if ( ocse & IMH_GPP_SUM ) {
716#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
717                printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX    ]);
718#endif
719                cse &= thePic.mcache[pmax][GPP_IDX    ];
720                ocse = cse;
721                while ( cse ) {
722                        rval = __ilog2(cse) + 64;
723                        pmax = pt[rval];
724                        cse &= thePic.mcache[pmax][GPP_IDX    ];
725#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
726                        printk("Max pri IRQ now %i\n",rval);
727#endif
728                }
729#ifndef FASTER
730                /* this doesn't seem to be necessary -- however, the linux people do it... */
731                out_le32(thePic.causes[GPP_IDX], ~ocse);
732#endif
733        }
734#ifndef FASTER
735        /* this doesn't seem to be necessary -- however, the linux people do it... */
736        (void)in_le32(thePic.causes[GPP_IDX]);
737#endif
738
739        *ppri = pmax;
740
741        if ( BSP_DECREMENTER == rval ) {
742#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
743                decrementerIrqs++;
744#endif
745                decrementerPending = 0;
746        }
747
748        return rval;
749}
750
751#if 0 /* TODO: should this be cleaned up ? */
752#define _IRQ_DEBUG IRQ_DEBUG_DISPATCHER
753static inline unsigned
754ffind_highest_priority_pending_irq(rtems_irq_prio *ppri)
755{
756register int                    rval = -1;
757register rtems_irq_prio *pt  = theConfig.irqPrioTbl + BSP_PCI_IRQ_LOWEST_OFFSET;
758register rtems_irq_prio pmax = *ppri;
759register unsigned               cse,ocse;
760
761#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
762        discovery_dump_picregs();
763#endif
764
765        cse = in_le32(thePic.causes[MAIN_LO_IDX]);
766#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
767        printk("MAIN_LO; cse: 0x%08x, msk 0x%08x\n", cse ,thePic.mcache[pmax][MAIN_LO_IDX]);
768#endif
769        while ( cse &= thePic.mcache[pmax][MAIN_LO_IDX] ) {
770                rval = __ilog2(cse);
771                pmax = pt[rval];
772#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
773                printk("Max pri IRQ now %i\n",rval);
774#endif
775        }
776        cse = ocse = in_le32(thePic.causes[MAIN_HI_IDX]);
777#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
778        printk("MAIN_HI; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][MAIN_HI_IDX]);
779#endif
780        /* don't look at the GPP summary; only check for 'real' MAIN_HI sources */
781        cse &= ~IMH_GPP_SUM;
782        while ( cse &= thePic.mcache[pmax][MAIN_HI_IDX] ) {
783                rval = __ilog2(cse) + 32;
784                pmax = pt[rval];
785#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
786                printk("Max pri IRQ now %i\n",rval);
787#endif
788        }
789        /* if there were GPP ints, scan the GPP cause now */
790        if ( ocse & IMH_GPP_SUM ) {
791                cse = in_le32(thePic.causes[GPP_IDX    ]);
792#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
793                printk("GPP; cse: 0x%08x, msk 0x%08x\n", cse, thePic.mcache[pmax][GPP_IDX    ]);
794#endif
795                cse &= thePic.mcache[pmax][GPP_IDX    ];
796                ocse = cse;
797                while ( cse ) {
798                        rval = __ilog2(cse) + 64;
799                        pmax = pt[rval];
800                        cse &= thePic.mcache[pmax][GPP_IDX    ];
801#if (_IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
802                        printk("Max pri IRQ now %i\n",rval);
803#endif
804                }
805                /* this doesn't seem to be necessary -- however, the linux people do it... */
806                out_le32(thePic.causes[GPP_IDX], ~ocse);
807        }
808        /* this doesn't seem to be necessary -- however, the linux people do it... */
809        (void)in_le32(thePic.causes[GPP_IDX]);
810
811        *ppri = pmax;
812        return rval;
813}
814#endif
815
816
817/* Here's our dispatcher; the BSP framework uses the same one for EE and decrementer
818 * exceptions...
819 */
820int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
821{
822register int             irq;
823int                                      loop, last_irq;
824rtems_irq_prio           pri;
825#if     (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
826unsigned long            diff;
827#endif
828
829#if     (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
830        diff = mftb();
831#endif
832
833        if (excNum == ASM_DEC_VECTOR) {
834                decrementerPending = 1;
835        }
836
837        /* Tradeoff: EITHER we loop as long as interrupts are pending
838         *           incurring the overhead of one extra run of the 'find_pending_irq' routine.
839         *           OR we do rely on the handler just being invoked again if multiple
840         *                       interrupts are pending.
841         *
842         *           The first solution gives better worst-case behavior
843         *                       the second slightly better average performance.
844         *                       --> we go for the first solution. This also enables us to catch
845         *                       runaway interrupts, i.e., bad drivers that don't clear interrupts
846         *                       at the device. Can be very handy during driver development...
847         */
848        for ( loop=0, last_irq=-1, pri = thePic.current_priority;
849                  (irq=find_highest_priority_pending_irq(&pri)) >=0;
850                  loop++, last_irq = irq ) {
851
852                /* raise priority level and remember current one */
853                pri = change_executing_prio_level(pri);
854
855                SYNC();
856
857#if     (IRQ_DEBUG) & IRQ_DEBUG_MAXLAT
858                if ( 0 == loop ) {
859                        diff = mftb()-diff;
860                        if ( diff > discovery_pic_max_dispatching_latency )
861                                discovery_pic_max_dispatching_latency = diff;
862                }
863#endif
864
865#if (IRQ_DEBUG) & IRQ_DEBUG_DISPATCHER
866                if ( BSP_DECREMENTER == irq ) {
867                        printk("IRQ: dispatching DECREMENTER\n");
868                } else {
869                int idx = irqDiv32(irq);
870                        printk("IRQ: dispatching #%i; causes[%i]=0x%08x\n", irq, idx, ld_le32(thePic.causes[idx]));
871                }
872#endif
873
874                bsp_irq_dispatch_list( theConfig.irqHdlTbl, irq, theConfig.defaultEntry.hdl );
875
876                /* restore executing priority level */
877                (void)change_executing_prio_level(pri);
878
879                if ( (loop > MAX_SPIN_LOOPS) && (last_irq == irq) ) {
880                        /* try to catch run-away interrupts without disabling a 'legal' one;
881                         * this should never happen with the decrementer (and
882                         * BSP_disable_irq_at_pic(BSP_DECREMENTER) would fail)
883                         */
884                        printk("Runaway IRQ #%i; disabling\n", irq);
885                        BSP_disable_irq_at_pic(irq);
886                        loop = 0;
887                }
888        }
889
890        if (!loop) {
891                if ( decrementerPending && pri >= theConfig.irqPrioTbl[BSP_DECREMENTER] ) {
892                        /* we cannot mask the decrementer interrupt so it is possible that it
893                         * gets delivered even though it has a lower priority than what we're
894                         * currently executing at.
895                         * In this case, we ignore the zero loop count and return;
896                         * the interrupted instance of C_dispatch_irq_handler() will eventually
897                         * lower the executing priority and catch the 'decrementerPending' flag
898                         * we just set.
899                         */
900                } else {
901                        printk("Discovery: Spurious interrupt; causes were gpp: 0x%x, mhc: 0x%x, mlc: 0x%x\n", gpc, mhc, mlc);
902                        printk("Current priority level %i, decrementerPending %i\n", pri, decrementerPending);
903                        {
904                                rtems_irq_prio p=pri;   
905                                printk("PIC register dump:\n");
906                                discovery_dump_picregs();
907                                printk("Current Priority: %i, found %i\n",pri,find_highest_priority_pending_irq(&p));
908                                discovery_dump_picregs();
909                                for (p=0; p<=BSP_IRQ_MAX_PRIO; p++) {
910                                        printk("M[%i] :",p);pmsks(thePic.mcache[p]);
911                                }
912                        }
913                }
914        }
915        else if (loop>discovery_pic_max_loops)
916                discovery_pic_max_loops = loop;
917
918        return 0;
919}
920
921
922#if     (IRQ_DEBUG) & MVME6100_IRQ_DEBUG
923void
924discovery_pic_install_debug_irq(void)
925{
926        switch ( BSP_getBoardType() ) {
927                case    MVME6100:       gpp_out_bit = GPP_WIRED_OUT_BIT_6100; break;
928                case    MVME5500:       gpp_out_bit = GPP_WIRED_OUT_BIT_5500; break;
929                default:
930                                                        gpp_out_bit = 0; break;
931                                                        break;
932        }
933        if ( gpp_out_bit ) {
934                unsigned mppoff;
935                switch (gpp_out_bit / 8) {
936                        default:        /* silence warning; this is never reached */
937                        case 0: mppoff = GT_MPP_Control0; break;
938                        case 1: mppoff = GT_MPP_Control1; break;
939                        case 2: mppoff = GT_MPP_Control2; break;
940                        case 3: mppoff = GT_MPP_Control3; break;
941                }
942
943                /* switch GPP pin allocated to watchdog (value 4) to
944                 * GPP I/O (value 0 ??; have no doc, found out by experimenting)
945                 */
946                gt_bitmod(mppoff, 0, (0xf<<(4*(gpp_out_bit % 8))));
947
948                /* make it an output */
949                gt_bitmod(GT_GPP_IO_Control, (1<<gpp_out_bit), 0);
950
951                /* don't invert levels */
952                gt_bitmod(GT_GPP_Level_Control, 0, (1<<GPP_WIRED_IN_BIT) | (1<<gpp_out_bit));
953
954                /* clear output */
955                gt_bitmod(GT_GPP_Value, 0, 1<<gpp_out_bit);
956
957                printk("GPP levelctl now 0x%08x\n", gt_read(GT_GPP_Level_Control));
958                printk("GPP value    now 0x%08x\n", gt_read(GT_GPP_Value));
959                printk("MPP ctl 0    now 0x%08x\n", gt_read(GT_MPP_Control0));
960                printk("MPP ctl 1    now 0x%08x\n", gt_read(GT_MPP_Control1));
961                printk("MPP ctl 2    now 0x%08x\n", gt_read(GT_MPP_Control2));
962                printk("MPP ctl 3    now 0x%08x\n", gt_read(GT_MPP_Control3));
963
964        }
965}
966
967/* Control the state of the external 'wire' that connects the
968 * GPP_WIRED_OUT --> GPP_WIRED_IN pins
969 */
970void
971discovery_pic_set_debug_irq(int on)
972{
973unsigned long flags, clr;
974        if ( !gpp_out_bit ) {
975                printk("discovery_pic_set_debug_irq(): unknown wire output\n");
976                return;
977        }
978        if (on) {
979                on  = 1<<gpp_out_bit;
980                clr = 0;
981        } else {
982                clr = 1<<gpp_out_bit;
983                on  = 0;
984        }
985        rtems_interrupt_disable(flags);
986                gt_bitmod(GT_GPP_Value, on, clr);
987        rtems_interrupt_enable(flags);
988}
989#endif
990
991#if 0
992/* Here's some code for testing */
993#endif
Note: See TracBrowser for help on using the repository browser.