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

4.104.114.84.95
Last change on this file since adc53ec9 was adc53ec9, checked in by Jennifer Averett <Jennifer.Averett@…>, on 05/17/05 at 14:59:39

2005-05-17 Jennifer Averett <jennifer.averett@…>

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