source: rtems/c/src/lib/libbsp/powerpc/mpc8260ads/irq/irq.c @ d36d3a3

4.104.114.84.95
Last change on this file since d36d3a3 was d36d3a3, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 1, 2002 at 2:21:47 PM

2002-11-01 Andy Dachs <a.dachs@…>

  • irq/irq.c, irq/irq_asm.S, irq/irq_init.c: Per PR288, add support for _ISR_Nest_level.
  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 *
3 *  This file contains the implementation of the function described in irq.h
4 *
5 *  Copyright (C) 1998, 1999 valette@crf.canon.fr
6 *
7 *  Modified for mpc8260 Andy Dachs <a.dachs@sstl.co.uk>
8 *  Surrey Satellite Technology Limited, 2000
9+  *    21/4/2002 Added support for nested interrupts and improved
10+  *    masking operations.  Now we compute priority mask based
11+  *            on table in irq_init.c
12 *
13 *  The license and distribution terms for this file may be
14 *  found in found in the file LICENSE in this distribution or at
15 *  http://www.OARcorp.com/rtems/license.html.
16 *
17 *  $Id$
18 */
19 
20#include <bsp.h>
21#include <bsp/irq.h>
22#include <rtems/score/thread.h>
23#include <rtems/score/apiext.h>
24#include <libcpu/raw_exception.h>
25#include <bsp/vectors.h>
26#include <libcpu/cpu.h>
27#include <mpc8260.h>
28
29/*
30 * default handler connected on each irq after bsp initialization
31 */
32static rtems_irq_connect_data   default_rtems_entry;
33
34/*
35 * location used to store initial tables used for interrupt
36 * management.
37 */
38static rtems_irq_global_settings*       internal_config;
39static rtems_irq_connect_data*          rtems_hdl_tbl;
40
41
42/*
43 * Check if symbolic IRQ name is an CPM IRQ
44 */
45static inline int is_cpm_irq(const rtems_irq_symbolic_name irqLine)
46{
47        return (((int) irqLine <= BSP_CPM_IRQ_MAX_OFFSET) &
48                        ((int) irqLine >= BSP_CPM_IRQ_LOWEST_OFFSET)
49        );
50}
51
52/*
53 * Check if symbolic IRQ name is a Processor IRQ
54 */
55static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine)
56{
57        return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
58                        ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
59        );
60}
61
62typedef struct {
63        rtems_unsigned32 mask_h;        /* mask for sipnr_h and simr_h */
64        rtems_unsigned32 mask_l;        /* mask for sipnr_l and simr_l */
65        rtems_unsigned32 priority_h;  /* mask this and lower priority ints */
66        rtems_unsigned32 priority_l;
67} m82xxIrqMasks_t;
68
69/*
70 *  Mask fields should have a '1' in the bit position for that
71 *  interrupt.
72 *      Priority masks calculated later based on priority table
73 */
74
75static m82xxIrqMasks_t SIU_MaskBit[BSP_CPM_IRQ_NUMBER] =
76{
77        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* err */
78        { 0x00000000, 0x00008000, 0x00000000, 0x00000000 }, /* i2c */
79        { 0x00000000, 0x00004000, 0x00000000, 0x00000000 }, /* spi */
80        { 0x00000000, 0x00002000, 0x00000000, 0x00000000 }, /* rtt */
81        { 0x00000000, 0x00001000, 0x00000000, 0x00000000 }, /* smc1 */
82        { 0x00000000, 0x00000800, 0x00000000, 0x00000000 }, /* smc2 */
83        { 0x00000000, 0x00000400, 0x00000000, 0x00000000 }, /* idma1 */
84        { 0x00000000, 0x00000200, 0x00000000, 0x00000000 }, /* idma2 */
85        { 0x00000000, 0x00000100, 0x00000000, 0x00000000 }, /* idma3 */
86        { 0x00000000, 0x00000080, 0x00000000, 0x00000000 }, /* idma4 */
87        { 0x00000000, 0x00000040, 0x00000000, 0x00000000 }, /* sdma */
88        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
89        { 0x00000000, 0x00000010, 0x00000000, 0x00000000 }, /* tmr1 */
90        { 0x00000000, 0x00000008, 0x00000000, 0x00000000 }, /* tmr2 */
91        { 0x00000000, 0x00000004, 0x00000000, 0x00000000 }, /* tmr3 */
92        { 0x00000000, 0x00000002, 0x00000000, 0x00000000 }, /* tmr4 */
93        { 0x00000004, 0x00000000, 0x00000000, 0x00000000 }, /* tmcnt */
94        { 0x00000002, 0x00000000, 0x00000000, 0x00000000 }, /* pit */
95        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
96        { 0x00004000, 0x00000000, 0x00000000, 0x00000000 }, /* irq1 */
97        { 0x00002000, 0x00000000, 0x00000000, 0x00000000 }, /* irq2 */
98        { 0x00001000, 0x00000000, 0x00000000, 0x00000000 }, /* irq3 */
99        { 0x00000800, 0x00000000, 0x00000000, 0x00000000 }, /* irq4 */
100        { 0x00000400, 0x00000000, 0x00000000, 0x00000000 }, /* irq5 */
101        { 0x00000200, 0x00000000, 0x00000000, 0x00000000 }, /* irq6 */
102        { 0x00000100, 0x00000000, 0x00000000, 0x00000000 }, /* irq7 */
103        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
104        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
105        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
106        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
107        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
108        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
109        { 0x00000000, 0x80000000, 0x00000000, 0x00000000 }, /* fcc1 */
110        { 0x00000000, 0x40000000, 0x00000000, 0x00000000 }, /* fcc2 */
111        { 0x00000000, 0x20000000, 0x00000000, 0x00000000 }, /* fcc3 */
112        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
113        { 0x00000000, 0x08000000, 0x00000000, 0x00000000 }, /* mcc1 */
114        { 0x00000000, 0x04000000, 0x00000000, 0x00000000 }, /* mcc2 */
115        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
116        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
117        { 0x00000000, 0x00800000, 0x00000000, 0x00000000 }, /* scc1 */
118        { 0x00000000, 0x00400000, 0x00000000, 0x00000000 }, /* scc2 */
119        { 0x00000000, 0x00200000, 0x00000000, 0x00000000 }, /* scc3 */
120        { 0x00000000, 0x00100000, 0x00000000, 0x00000000 }, /* scc4 */
121        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
122        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
123        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
124        { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* reserved */
125        { 0x00010000, 0x00000000, 0x00000000, 0x00000000 }, /* pc15 */
126        { 0x00020000, 0x00000000, 0x00000000, 0x00000000 }, /* pc14 */
127        { 0x00040000, 0x00000000, 0x00000000, 0x00000000 }, /* pc13 */
128        { 0x00080000, 0x00000000, 0x00000000, 0x00000000 }, /* pc12 */
129        { 0x00100000, 0x00000000, 0x00000000, 0x00000000 }, /* pc11 */
130        { 0x00200000, 0x00000000, 0x00000000, 0x00000000 }, /* pc10 */
131        { 0x00400000, 0x00000000, 0x00000000, 0x00000000 }, /* pc9 */
132        { 0x00800000, 0x00000000, 0x00000000, 0x00000000 }, /* pc8 */
133        { 0x01000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc7 */
134        { 0x02000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc6 */
135        { 0x04000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc5 */
136        { 0x08000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc4 */
137        { 0x10000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc3 */
138        { 0x20000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc2 */
139        { 0x40000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc1 */
140        { 0x80000000, 0x00000000, 0x00000000, 0x00000000 }, /* pc0 */
141
142};
143
144
145
146void dump_irq_masks(void )
147{
148        int i;
149        for( i=0; i<BSP_CPM_IRQ_NUMBER;i++ )   
150        {
151                printk( "%04d: %08X %08X\n",
152                        i,
153                        SIU_MaskBit[i].priority_h,
154                        SIU_MaskBit[i].priority_l
155                );
156        }
157}
158
159/*
160 * ------------------------ RTEMS Irq helper functions ----------------
161 */
162
163/*
164 * Caution : this function assumes the variable "internal_config"
165 * is already set and that the tables it contains are still valid
166 * and accessible.
167 */
168static void compute_SIU_IvectMask_from_prio ()
169{
170        /*
171         * The actual masks defined
172         * correspond to the priorities defined
173         * for the SIU in irq_init.c.
174         */
175       
176         int i,j;
177       
178         for( i=0; i<BSP_CPM_IRQ_NUMBER; i++ )
179         {
180                for( j=0;j<BSP_CPM_IRQ_NUMBER; j++ )
181                        if( internal_config->irqPrioTbl[j] < internal_config->irqPrioTbl[i] )
182                        {
183                                SIU_MaskBit[i].priority_h |= SIU_MaskBit[j].mask_h;
184                                SIU_MaskBit[i].priority_l |= SIU_MaskBit[j].mask_l;
185                        }                               
186         }
187       
188}
189
190/*
191 * This function check that the value given for the irq line
192 * is valid.
193 */
194
195static int isValidInterrupt(int irq)
196{
197        if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET) )
198                return 0;
199        return 1;
200}
201
202int BSP_irq_enable_at_cpm(const rtems_irq_symbolic_name irqLine)
203{
204        int cpm_irq_index;
205
206        if (!is_cpm_irq(irqLine))
207                return 1;
208
209        cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET);
210
211        m8260.simr_h |= SIU_MaskBit[cpm_irq_index].mask_h;
212        m8260.simr_l |= SIU_MaskBit[cpm_irq_index].mask_l;
213
214        return 0;
215}
216
217int BSP_irq_disable_at_cpm(const rtems_irq_symbolic_name irqLine)
218{
219        int cpm_irq_index;
220 
221        if (!is_cpm_irq(irqLine))
222                return 1;
223 
224        cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET);
225
226        m8260.simr_h &= ~(SIU_MaskBit[cpm_irq_index].mask_h);
227        m8260.simr_l &= ~(SIU_MaskBit[cpm_irq_index].mask_l);
228
229
230        return 0;
231}
232
233int BSP_irq_enabled_at_cpm(const rtems_irq_symbolic_name irqLine)
234{
235        int cpm_irq_index;
236 
237        if (!is_cpm_irq(irqLine))
238                return 0;
239 
240        cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET);
241
242        return ((m8260.simr_h & SIU_MaskBit[cpm_irq_index].mask_h) ||
243                    (m8260.simr_l & SIU_MaskBit[cpm_irq_index].mask_l));
244}
245
246
247/*
248 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
249 */
250
251int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
252{
253        unsigned int level;
254
255        if (!isValidInterrupt(irq->name)) {
256                printk( "not a valid intr\n" ) ;
257                return 0;
258        }
259        /*
260         * Check if default handler is actually connected. If not issue an error.
261         * You must first get the current handler via i386_get_current_idt_entry
262         * and then disconnect it using i386_delete_idt_entry.
263         * RATIONALE : to always have the same transition by forcing the user
264         * to get the previous handler before accepting to disconnect.
265         */
266        if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
267                printk( "Default handler not there\n" );
268                return 0;
269        }
270
271        _CPU_ISR_Disable(level);
272
273        /*
274         * store the data provided by user
275         */
276        rtems_hdl_tbl[irq->name] = *irq;
277       
278        if (is_cpm_irq(irq->name)) {
279            /*
280             * Enable interrupt at PIC level
281             */
282            BSP_irq_enable_at_cpm (irq->name);
283        }
284
285#if 0
286        if (is_processor_irq(irq->name)) {
287                /*
288                 * Should Enable exception at processor level but not needed.  Will restore
289                 * EE flags at the end of the routine anyway.
290                 */
291        }
292#endif
293
294        /*
295         * Enable interrupt on device
296         */
297        irq->on(irq);
298
299        _CPU_ISR_Enable(level);
300
301        /*
302            printk( "Enabled\n" );
303        */
304        return 1;
305}
306
307
308int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
309{
310        if (!isValidInterrupt(irq->name)) {
311                return 0;
312        }
313        *irq = rtems_hdl_tbl[irq->name];
314        return 1;
315}
316
317int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
318{
319        unsigned int level;
320 
321        if (!isValidInterrupt(irq->name)) {
322                return 0;
323        }
324        /*
325         * Check if default handler is actually connected. If not issue an error.
326         * You must first get the current handler via i386_get_current_idt_entry
327         * and then disconnect it using i386_delete_idt_entry.
328         * RATIONALE : to always have the same transition by forcing the user
329         * to get the previous handler before accepting to disconnect.
330         */
331        if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
332          return 0;
333        }
334        _CPU_ISR_Disable(level);
335       
336        if (is_cpm_irq(irq->name)) {
337          /*
338           * disable interrupt at PIC level
339           */
340          BSP_irq_disable_at_cpm (irq->name);
341        }
342       
343        if (is_processor_irq(irq->name)) {
344          /*
345           * disable exception at processor level
346           */
347        }   
348       
349        /*
350         * Disable interrupt on device
351         */
352        irq->off(irq);
353       
354        /*
355         * restore the default irq value
356         */
357        rtems_hdl_tbl[irq->name] = default_rtems_entry;
358       
359        _CPU_ISR_Enable(level);
360       
361        return 1;
362}
363
364/*
365 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
366 */
367
368int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
369{
370        int i;
371        unsigned int level;
372        /*
373         * Store various code accelerators
374         */
375        internal_config                 = config;
376        default_rtems_entry             = config->defaultEntry;
377        rtems_hdl_tbl           = config->irqHdlTbl;
378
379        /* Fill in priority masks */
380        compute_SIU_IvectMask_from_prio();
381       
382        _CPU_ISR_Disable(level);
383        /*
384         * start with CPM IRQ
385         */
386        for (i=BSP_CPM_IRQ_LOWEST_OFFSET; i < BSP_CPM_IRQ_LOWEST_OFFSET + BSP_CPM_IRQ_NUMBER ; i++) {
387                if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
388                        BSP_irq_enable_at_cpm (i);
389                        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
390                } else {
391                        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
392                        BSP_irq_disable_at_cpm (i);
393                }
394        }
395
396        /*
397         * finish with Processor exceptions handled like IRQ
398         */
399        for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
400                if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
401                        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
402                } else {
403                        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
404                }
405        }
406
407        _CPU_ISR_Enable(level);
408        return 1;
409}
410
411int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
412{
413        *config = internal_config;
414        return 0;
415}
416
417#ifdef DISPATCH_HANDLER_STAT
418volatile unsigned int maxLoop = 0;
419#endif
420
421
422/*
423 * High level IRQ handler called from shared_raw_irq_code_entry
424 */
425void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
426{
427        register unsigned int irq;
428#if 0
429        register unsigned oldMask;                    /* old siu pic masks */
430#endif
431        register unsigned msr;
432        register unsigned new_msr;
433        register unsigned old_simr_h;
434        register unsigned old_simr_l;
435#ifdef DISPATCH_HANDLER_STAT
436        unsigned loopCounter;
437#endif
438
439
440
441        /*
442         * Handle decrementer interrupt
443         */
444        if (excNum == ASM_DEC_VECTOR) {
445                _CPU_MSR_GET(msr);
446                new_msr = msr | MSR_EE;
447                _CPU_MSR_SET(new_msr);
448
449                rtems_hdl_tbl[BSP_DECREMENTER].hdl();
450
451                _CPU_MSR_SET(msr);
452
453                return;
454        }
455
456        /*
457         * Handle external interrupt generated by SIU on PPC core
458         */
459#ifdef DISPATCH_HANDLER_STAT
460        loopCounter = 0;
461#endif 
462
463        while (1) {
464
465                if( ((m8260.sipnr_h & m8260.simr_h) | (m8260.sipnr_l & m8260.simr_l)) == 0 ) {
466#ifdef DISPATCH_HANDLER_STAT
467                        if (loopCounter >  maxLoop) maxLoop = loopCounter;
468#endif     
469                        break;
470                }
471
472                irq = (m8260.sivec >> 26) + BSP_CPM_IRQ_LOWEST_OFFSET;
473
474                /* Clear mask and pending register */
475                if( irq <= BSP_CPM_IRQ_MAX_OFFSET ) {
476                        /* save interrupt masks */
477                        old_simr_h = m8260.simr_h;
478                        old_simr_l = m8260.simr_l;
479
480                        /* mask off current interrupt and lower priority ones */
481                        m8260.simr_h &= SIU_MaskBit[irq].priority_h;
482                        m8260.simr_l &= SIU_MaskBit[irq].priority_l;
483
484                        /* clear pending bit */
485                        m8260.sipnr_h |= SIU_MaskBit[irq].mask_h;
486                        m8260.sipnr_l |= SIU_MaskBit[irq].mask_l;
487
488                        /* re-enable external exceptions */
489                        _CPU_MSR_GET(msr);
490                        new_msr = msr | MSR_EE;
491                        _CPU_MSR_SET(new_msr);
492
493                        /* call handler */
494                        rtems_hdl_tbl[irq].hdl();
495
496                        /* disable exceptions again */
497                        _CPU_MSR_SET(msr);
498                       
499                        /* restore interrupt masks */
500                        m8260.simr_h = old_simr_h;
501                        m8260.simr_l = old_simr_l;
502                       
503                }
504#ifdef DISPATCH_HANDLER_STAT
505                ++ loopCounter;
506#endif
507        }
508}
509
510   
511 
512void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
513{
514        /*
515         * Process pending signals that have not already been
516         * processed by _Thread_Displatch. This happens quite
517         * unfrequently : the ISR must have posted an action
518         * to the current running thread.
519         */
520        if ( _Thread_Do_post_task_switch_extension ||
521                _Thread_Executing->do_post_task_switch_extension ) {
522                _Thread_Executing->do_post_task_switch_extension = FALSE;
523                _API_extensions_Run_postswitch();
524        }
525
526        /*
527         * I plan to process other thread related events here.
528         * This will include DEBUG session requested from keyboard...
529         */
530}
Note: See TracBrowser for help on using the repository browser.