source: rtems/c/src/lib/libbsp/powerpc/mbx8xx/irq/irq.c @ 867ab080

4.104.114.84.95
Last change on this file since 867ab080 was 8038731, checked in by Joel Sherrill <joel.sherrill@…>, on 04/18/02 at 20:54:54

2002-04-18 Ralf Corsepius <corsepiu@…>

  • irq/irq.c: Reflect changes to <rtems/score/cpu.h>. Fix loopCounter.
  • irq/irq_asm.S: Reflect changes to <rtems/score/cpu.h>.
  • vectors/vectors.S: Ditto.
  • vectors/vectors_init.c: Include <rtems/bspIo.h>.
  • Property mode set to 100644
File size: 13.0 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 *  The license and distribution terms for this file may be
8 *  found in found in the file LICENSE in this distribution or at
9 *  http://www.OARcorp.com/rtems/license.html.
10 *
11 *  $Id$
12 */
13 
14#include <rtems/system.h>
15#include <bsp.h>
16#include <bsp/irq.h>
17#include <rtems/score/thread.h>
18#include <rtems/score/apiext.h>
19#include <libcpu/raw_exception.h>
20#include <bsp/vectors.h>
21#include <bsp/8xx_immap.h>
22#include <bsp/mbx.h>
23#include <bsp/commproc.h>
24
25/*
26 * default handler connected on each irq after bsp initialization
27 */
28static rtems_irq_connect_data   default_rtems_entry;
29
30/*
31 * location used to store initial tables used for interrupt
32 * management.
33 */
34static rtems_irq_global_settings*       internal_config;
35static rtems_irq_connect_data*          rtems_hdl_tbl;
36
37/*
38 * Check if symbolic IRQ name is an SIU IRQ
39 */
40static inline int is_siu_irq(const rtems_irq_symbolic_name irqLine)
41{
42  return (((int) irqLine <= BSP_SIU_IRQ_MAX_OFFSET) &
43          ((int) irqLine >= BSP_SIU_IRQ_LOWEST_OFFSET)
44         );
45}
46
47/*
48 * Check if symbolic IRQ name is an CPM IRQ
49 */
50static inline int is_cpm_irq(const rtems_irq_symbolic_name irqLine)
51{
52  return (((int) irqLine <= BSP_CPM_IRQ_MAX_OFFSET) &
53          ((int) irqLine >= BSP_CPM_IRQ_LOWEST_OFFSET)
54         );
55}
56
57/*
58 * Check if symbolic IRQ name is a Processor IRQ
59 */
60static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine)
61{
62  return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
63          ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
64         );
65}
66
67
68/*
69 * masks used to mask off the interrupts. For exmaple, for ILVL2, the 
70 * mask is used to mask off interrupts ILVL2, IRQ3, ILVL3, ... IRQ7   
71 * and ILVL7.                                                         
72 *
73 */
74const static unsigned int SIU_IvectMask[BSP_SIU_IRQ_NUMBER] =
75{
76     /* IRQ0      ILVL0       IRQ1        ILVL1  */
77     0x00000000, 0x80000000, 0xC0000000, 0xE0000000,
78
79     /* IRQ2      ILVL2       IRQ3        ILVL3  */
80     0xF0000000, 0xF8000000, 0xFC000000, 0xFE000000,
81
82     /* IRQ4      ILVL4       IRQ5        ILVL5  */
83     0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000,
84
85     /* IRQ6      ILVL6       IRQ7        ILVL7  */
86     0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000
87};
88
89/*
90 * ------------------------ RTEMS Irq helper functions ----------------
91 */
92
93/*
94 * Caution : this function assumes the variable "internal_config"
95 * is already set and that the tables it contains are still valid
96 * and accessible.
97 */
98static void compute_SIU_IvectMask_from_prio ()
99{
100  /*
101   * In theory this is feasible. No time to code it yet. See i386/shared/irq.c
102   * for an example based on 8259 controller mask. The actual masks defined
103   * correspond to the priorities defined for the SIU in irq_init.c.
104   */
105}
106
107/*
108 * This function check that the value given for the irq line
109 * is valid.
110 */
111
112static int isValidInterrupt(int irq)
113{
114  if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET) || (irq == BSP_CPM_INTERRUPT) )
115    return 0;
116  return 1;
117}
118
119int BSP_irq_enable_at_cpm(const rtems_irq_symbolic_name irqLine)
120{
121  int cpm_irq_index;
122
123  if (!is_cpm_irq(irqLine))
124    return 1;
125
126  cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET);
127  ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << cpm_irq_index);
128
129  return 0;
130}
131
132int BSP_irq_disable_at_cpm(const rtems_irq_symbolic_name irqLine)
133{
134  int cpm_irq_index;
135 
136  if (!is_cpm_irq(irqLine))
137    return 1;
138 
139  cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET);
140  ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << cpm_irq_index);
141
142  return 0;
143}
144
145int BSP_irq_enabled_at_cpm(const rtems_irq_symbolic_name irqLine)
146{
147  int cpm_irq_index;
148 
149  if (!is_cpm_irq(irqLine))
150    return 0;
151 
152  cpm_irq_index = ((int) (irqLine) - BSP_CPM_IRQ_LOWEST_OFFSET);
153  return (((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr & (1 << cpm_irq_index));
154}
155
156int BSP_irq_enable_at_siu(const rtems_irq_symbolic_name irqLine)
157{
158  int siu_irq_index;
159 
160  if (!is_siu_irq(irqLine))
161    return 1;
162
163  siu_irq_index = ((int) (irqLine) - BSP_SIU_IRQ_LOWEST_OFFSET);
164  ppc_cached_irq_mask |= (1 << (31-siu_irq_index));
165  ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask;
166
167  return 0;
168}
169
170int BSP_irq_disable_at_siu(const rtems_irq_symbolic_name irqLine)
171{
172  int siu_irq_index;
173
174  if (!is_siu_irq(irqLine))
175    return 1;
176 
177  siu_irq_index = ((int) (irqLine) - BSP_SIU_IRQ_LOWEST_OFFSET);
178  ppc_cached_irq_mask &= ~(1 << (31-siu_irq_index));
179  ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask;
180
181  return 0;
182}
183
184int BSP_irq_enabled_at_siu      (const rtems_irq_symbolic_name irqLine)
185{
186  int siu_irq_index;
187
188  if (!is_siu_irq(irqLine))
189    return 0;
190
191  siu_irq_index = ((int) (irqLine) - BSP_SIU_IRQ_LOWEST_OFFSET);
192  return ppc_cached_irq_mask & (1 << (31-siu_irq_index));
193}
194
195/*
196 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
197 */
198
199int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
200{
201    unsigned int level;
202 
203    if (!isValidInterrupt(irq->name)) {
204      return 0;
205    }
206    /*
207     * Check if default handler is actually connected. If not issue an error.
208     * You must first get the current handler via i386_get_current_idt_entry
209     * and then disconnect it using i386_delete_idt_entry.
210     * RATIONALE : to always have the same transition by forcing the user
211     * to get the previous handler before accepting to disconnect.
212     */
213    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
214      return 0;
215    }
216
217    _CPU_ISR_Disable(level);
218
219    /*
220     * store the data provided by user
221     */
222    rtems_hdl_tbl[irq->name] = *irq;
223   
224    if (is_cpm_irq(irq->name)) {
225      /*
226       * Enable interrupt at PIC level
227       */
228      BSP_irq_enable_at_cpm (irq->name);
229    }
230   
231    if (is_siu_irq(irq->name)) {
232      /*
233       * Enable interrupt at SIU level
234       */
235      BSP_irq_enable_at_siu (irq->name);
236    }
237
238    if (is_processor_irq(irq->name)) {
239      /*
240       * Should Enable exception at processor level but not needed.  Will restore
241       * EE flags at the end of the routine anyway.
242       */
243    }
244    /*
245     * Enable interrupt on device
246     */
247    irq->on(irq);
248   
249    _CPU_ISR_Enable(level);
250
251    return 1;
252}
253
254
255int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
256{
257     if (!isValidInterrupt(irq->name)) {
258      return 0;
259     }
260     *irq = rtems_hdl_tbl[irq->name];
261     return 1;
262}
263
264int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
265{
266    unsigned int level;
267 
268    if (!isValidInterrupt(irq->name)) {
269      return 0;
270    }
271    /*
272     * Check if default handler is actually connected. If not issue an error.
273     * You must first get the current handler via i386_get_current_idt_entry
274     * and then disconnect it using i386_delete_idt_entry.
275     * RATIONALE : to always have the same transition by forcing the user
276     * to get the previous handler before accepting to disconnect.
277     */
278    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
279      return 0;
280    }
281    _CPU_ISR_Disable(level);
282
283    if (is_cpm_irq(irq->name)) {
284      /*
285       * disable interrupt at PIC level
286       */
287      BSP_irq_disable_at_cpm (irq->name);
288    }
289    if (is_siu_irq(irq->name)) {
290      /*
291       * disable interrupt at OPENPIC level
292       */
293      BSP_irq_disable_at_siu (irq->name);
294    }
295    if (is_processor_irq(irq->name)) {
296      /*
297       * disable exception at processor level
298       */
299    }   
300
301    /*
302     * Disable interrupt on device
303     */
304    irq->off(irq);
305
306    /*
307     * restore the default irq value
308     */
309    rtems_hdl_tbl[irq->name] = default_rtems_entry;
310
311    _CPU_ISR_Enable(level);
312
313    return 1;
314}
315
316/*
317 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
318 */
319
320int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
321{
322    int i;
323    unsigned int level;
324   /*
325    * Store various code accelerators
326    */
327    internal_config             = config;
328    default_rtems_entry         = config->defaultEntry;
329    rtems_hdl_tbl               = config->irqHdlTbl;
330
331    _CPU_ISR_Disable(level);
332    /*
333     * start with CPM IRQ
334     */
335    for (i=BSP_CPM_IRQ_LOWEST_OFFSET; i < BSP_CPM_IRQ_LOWEST_OFFSET + BSP_CPM_IRQ_NUMBER ; i++) {
336      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
337        BSP_irq_enable_at_cpm (i);
338        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
339      }
340      else {
341        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
342        BSP_irq_disable_at_cpm (i);
343      }
344    }
345
346    /*
347     * continue with PCI IRQ
348     */
349    /*
350     * set up internal tables used by rtems interrupt prologue
351     */
352    compute_SIU_IvectMask_from_prio ();
353
354    for (i=BSP_SIU_IRQ_LOWEST_OFFSET; i < BSP_SIU_IRQ_LOWEST_OFFSET + BSP_SIU_IRQ_NUMBER ; i++) {
355      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
356        BSP_irq_enable_at_siu (i);
357        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
358      }
359      else {
360        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
361        BSP_irq_disable_at_siu (i);
362       }
363    }
364    /*
365     * Must enable CPM interrupt on SIU. CPM on SIU Interrupt level has already been
366     * set up in BSP_CPM_irq_init.
367     */
368    ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
369    BSP_irq_enable_at_siu (BSP_CPM_INTERRUPT);
370    /*
371     * finish with Processor exceptions handled like IRQ
372     */
373    for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
374      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
375        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
376      }
377      else {
378        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
379      }
380    }
381    _CPU_ISR_Enable(level);
382    return 1;
383}
384
385int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
386{
387    *config = internal_config;
388    return 0;
389}
390
391#ifdef DISPATCH_HANDLER_STAT
392volatile unsigned int maxLoop = 0;
393#endif
394
395/*
396 * High level IRQ handler called from shared_raw_irq_code_entry
397 */
398void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
399{
400  register unsigned int irq;
401  register unsigned cpmIntr;                  /* boolean */
402  register unsigned oldMask;                  /* old siu pic masks */
403  register unsigned msr;
404  register unsigned new_msr;
405#ifdef DISPATCH_HANDLER_STAT
406  unsigned loopCounter;
407#endif
408  /*
409   * Handle decrementer interrupt
410   */
411  if (excNum == ASM_DEC_VECTOR) {
412    _CPU_MSR_GET(msr);
413    new_msr = msr | MSR_EE;
414    _CPU_MSR_SET(new_msr);
415   
416    rtems_hdl_tbl[BSP_DECREMENTER].hdl();
417
418    _CPU_MSR_SET(msr);
419    return;
420  }
421  /*
422   * Handle external interrupt generated by SIU on PPC core
423   */
424#ifdef DISPATCH_HANDLER_STAT
425  loopCounter = 0;
426#endif 
427  while (1) {
428    if ((ppc_cached_irq_mask & ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend) == 0) {
429#ifdef DISPATCH_HANDLER_STAT
430      if (loopCounter >  maxLoop) maxLoop = loopCounter;
431#endif     
432      break;
433    }
434    irq = (((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26);
435    cpmIntr = (irq == BSP_CPM_INTERRUPT);
436    /*
437     * Disable the interrupt of the same and lower priority.
438     */
439    oldMask = ppc_cached_irq_mask;
440    ppc_cached_irq_mask = oldMask & SIU_IvectMask[irq];
441    ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask;
442    /*
443     * Acknowledge current interrupt. This has no effect on internal level interrupt.
444     */
445    ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = (1 << (31 - irq));
446   
447    if (cpmIntr)  {
448      /*
449       * We will reenable the SIU CPM interrupt to allow nesting of CPM interrupt.
450       * We must before acknowledege the current irq at CPM level to avoid trigerring
451       * the interrupt again.
452       */
453      /*
454       * Acknowledge and get the vector.
455       */
456      ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
457      irq = (((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr >> 11);
458      /*
459       * transform IRQ to normalized irq table index.
460       */
461      irq += BSP_CPM_IRQ_LOWEST_OFFSET;
462      /*
463       * Unmask CPM interrupt at SIU level
464       */
465      ppc_cached_irq_mask |= (1 << (31 - BSP_CPM_INTERRUPT));
466      ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask;
467    }
468    _CPU_MSR_GET(msr);
469    new_msr = msr | MSR_EE;
470    _CPU_MSR_SET(new_msr);
471   
472    rtems_hdl_tbl[irq].hdl();
473
474    _CPU_MSR_SET(msr);
475
476    if (cpmIntr)  {
477      irq -= BSP_CPM_IRQ_LOWEST_OFFSET;
478      ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << irq);
479    }
480    ppc_cached_irq_mask = oldMask;
481    ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask;
482#ifdef DISPATCH_HANDLER_STAT
483    ++ loopCounter;
484#endif   
485  }
486}
487
488   
489 
490void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
491{
492  /*
493   * Process pending signals that have not already been
494   * processed by _Thread_Displatch. This happens quite
495   * unfrequently : the ISR must have posted an action
496   * to the current running thread.
497   */
498  if ( _Thread_Do_post_task_switch_extension ||
499       _Thread_Executing->do_post_task_switch_extension ) {
500    _Thread_Executing->do_post_task_switch_extension = FALSE;
501    _API_extensions_Run_postswitch();
502  }
503  /*
504   * I plan to process other thread related events here.
505   * This will include DEBUG session requested from keyboard...
506   */
507}
Note: See TracBrowser for help on using the repository browser.