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

4.104.114.95
Last change on this file since 9f91d0f was 9f91d0f, checked in by Ralf Corsepius <ralf.corsepius@…>, on 09/06/08 at 17:16:21

Convert to bool.

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