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

4.104.114.84.9
Last change on this file since 00d8424e was 00d8424e, checked in by Jennifer Averett <Jennifer.Averett@…>, on Apr 15, 2005 at 6:05:34 PM

2005-04-15 Jennifer Averett <jennifer.averett@…>

PR 779/bsp

  • clock/p_clock.c, irq/irq.c, irq/irq.h, irq/irq_init.c, network/network.c: add parameter to new exception interrupt handlers in powerpc bsps
  • 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.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_symbolic_name 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_symbolic_name 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 ()
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_symbolic_name 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_symbolic_name 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_symbolic_name 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        unsigned int 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        _CPU_ISR_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        irq->on(irq);
293
294        _CPU_ISR_Enable(level);
295
296        /*
297            printk( "Enabled\n" );
298        */
299        return 1;
300}
301
302int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
303{
304        if (!isValidInterrupt(irq->name)) {
305                return 0;
306        }
307        *irq = rtems_hdl_tbl[irq->name];
308        return 1;
309}
310
311int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
312{
313        unsigned int level;
314
315        if (!isValidInterrupt(irq->name)) {
316                return 0;
317        }
318        /*
319         * Check if default handler is actually connected. If not issue an error.
320         * You must first get the current handler via i386_get_current_idt_entry
321         * and then disconnect it using i386_delete_idt_entry.
322         * RATIONALE : to always have the same transition by forcing the user
323         * to get the previous handler before accepting to disconnect.
324         */
325        if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
326          return 0;
327        }
328        _CPU_ISR_Disable(level);
329
330        if (is_cpm_irq(irq->name)) {
331          /*
332           * disable interrupt at PIC level
333           */
334          BSP_irq_disable_at_cpm (irq->name);
335        }
336
337        if (is_processor_irq(irq->name)) {
338          /*
339           * disable exception at processor level
340           */
341        }
342
343        /*
344         * Disable interrupt on device
345         */
346        irq->off(irq);
347
348        /*
349         * restore the default irq value
350         */
351        rtems_hdl_tbl[irq->name] = default_rtems_entry;
352
353        _CPU_ISR_Enable(level);
354
355        return 1;
356}
357
358/*
359 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
360 */
361
362int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
363{
364        int i;
365        unsigned int level;
366        /*
367         * Store various code accelerators
368         */
369        internal_config                 = config;
370        default_rtems_entry             = config->defaultEntry;
371        rtems_hdl_tbl           = config->irqHdlTbl;
372
373        /* Fill in priority masks */
374        compute_SIU_IvectMask_from_prio();
375
376        _CPU_ISR_Disable(level);
377        /*
378         * start with CPM IRQ
379         */
380        for (i=BSP_CPM_IRQ_LOWEST_OFFSET; i < BSP_CPM_IRQ_LOWEST_OFFSET + BSP_CPM_IRQ_NUMBER ; i++) {
381                if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
382                        BSP_irq_enable_at_cpm (i);
383                        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
384                } else {
385                        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
386                        BSP_irq_disable_at_cpm (i);
387                }
388        }
389
390        /*
391         * finish with Processor exceptions handled like IRQ
392         */
393        for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
394                if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
395                        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
396                } else {
397                        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
398                }
399        }
400
401        _CPU_ISR_Enable(level);
402        return 1;
403}
404
405int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
406{
407        *config = internal_config;
408        return 0;
409}
410
411#ifdef DISPATCH_HANDLER_STAT
412volatile unsigned int maxLoop = 0;
413#endif
414
415/*
416 * High level IRQ handler called from shared_raw_irq_code_entry
417 */
418void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
419{
420        register unsigned int irq;
421#if 0
422        register unsigned oldMask;                    /* old siu pic masks */
423#endif
424        register unsigned msr;
425        register unsigned new_msr;
426        register unsigned old_simr_h;
427        register unsigned old_simr_l;
428#ifdef DISPATCH_HANDLER_STAT
429        unsigned loopCounter;
430#endif
431
432        /*
433         * Handle decrementer interrupt
434         */
435        if (excNum == ASM_DEC_VECTOR) {
436                _CPU_MSR_GET(msr);
437                new_msr = msr | MSR_EE;
438                _CPU_MSR_SET(new_msr);
439
440                rtems_hdl_tbl[BSP_DECREMENTER].hdl(rtems_hdl_tbl[BSP_DECREMENTER].handle);
441
442                _CPU_MSR_SET(msr);
443
444                return;
445        }
446
447        /*
448         * Handle external interrupt generated by SIU on PPC core
449         */
450#ifdef DISPATCH_HANDLER_STAT
451        loopCounter = 0;
452#endif
453
454        while (1) {
455
456                if( ((m8260.sipnr_h & m8260.simr_h) | (m8260.sipnr_l & m8260.simr_l)) == 0 ) {
457#ifdef DISPATCH_HANDLER_STAT
458                        if (loopCounter >  maxLoop) maxLoop = loopCounter;
459#endif
460                        break;
461                }
462
463                irq = (m8260.sivec >> 26) + BSP_CPM_IRQ_LOWEST_OFFSET;
464
465                /* Clear mask and pending register */
466                if( irq <= BSP_CPM_IRQ_MAX_OFFSET ) {
467                        /* save interrupt masks */
468                        old_simr_h = m8260.simr_h;
469                        old_simr_l = m8260.simr_l;
470
471                        /* mask off current interrupt and lower priority ones */
472                        m8260.simr_h &= SIU_MaskBit[irq].priority_h;
473                        m8260.simr_l &= SIU_MaskBit[irq].priority_l;
474
475                        /* clear pending bit */
476                        m8260.sipnr_h |= SIU_MaskBit[irq].mask_h;
477                        m8260.sipnr_l |= SIU_MaskBit[irq].mask_l;
478
479                        /* re-enable external exceptions */
480                        _CPU_MSR_GET(msr);
481                        new_msr = msr | MSR_EE;
482                        _CPU_MSR_SET(new_msr);
483
484                        /* call handler */
485                        rtems_hdl_tbl[irq].hdl(rtems_hdl_tbl[irq].handle);
486
487                        /* disable exceptions again */
488                        _CPU_MSR_SET(msr);
489
490                        /* restore interrupt masks */
491                        m8260.simr_h = old_simr_h;
492                        m8260.simr_l = old_simr_l;
493
494                }
495#ifdef DISPATCH_HANDLER_STAT
496                ++ loopCounter;
497#endif
498        }
499}
500
501void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
502{
503        /*
504         * Process pending signals that have not already been
505         * processed by _Thread_Displatch. This happens quite
506         * unfrequently : the ISR must have posted an action
507         * to the current running thread.
508         */
509        if ( _Thread_Do_post_task_switch_extension ||
510                _Thread_Executing->do_post_task_switch_extension ) {
511                _Thread_Executing->do_post_task_switch_extension = FALSE;
512                _API_extensions_Run_postswitch();
513        }
514
515        /*
516         * I plan to process other thread related events here.
517         * This will include DEBUG session requested from keyboard...
518         */
519}
Note: See TracBrowser for help on using the repository browser.