source: rtems/c/src/lib/libbsp/powerpc/eth_comm/irq/irq.c @ 247914a

Last change on this file since 247914a was 247914a, checked in by Joel Sherrill <joel.sherrill@…>, on 09/04/03 at 18:45:02

2003-09-04 Joel Sherrill <joel@…>

  • canbus/canbus.c, clock/p_clock.c, include/bsp.h, include/canbus.h, include/coverhd.h, irq/irq.c, irq/irq.h, irq/irq_asm.S, irq/irq_init.c, startup/bspstart.c, startup/mmutlbtab.c, startup/setvec.c, vectors/vectors.h, vectors/vectors_init.c: URL for license changed.
  • 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.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/commproc.h>
23
24/*
25 * default handler connected on each irq after bsp initialization
26 */
27static rtems_irq_connect_data   default_rtems_entry;
28
29/*
30 * location used to store initial tables used for interrupt
31 * management.
32 */
33static rtems_irq_global_settings*       internal_config;
34static rtems_irq_connect_data*          rtems_hdl_tbl;
35
36/*
37 * Check if symbolic IRQ name is an SIU IRQ
38 */
39static inline int is_siu_irq(const rtems_irq_symbolic_name irqLine)
40{
41  return (((int) irqLine <= BSP_SIU_IRQ_MAX_OFFSET) &
42          ((int) irqLine >= BSP_SIU_IRQ_LOWEST_OFFSET)
43         );
44}
45
46/*
47 * Check if symbolic IRQ name is an CPM IRQ
48 */
49static inline int is_cpm_irq(const rtems_irq_symbolic_name irqLine)
50{
51  return (((int) irqLine <= BSP_CPM_IRQ_MAX_OFFSET) &
52          ((int) irqLine >= BSP_CPM_IRQ_LOWEST_OFFSET)
53         );
54}
55
56/*
57 * Check if symbolic IRQ name is a Processor IRQ
58 */
59static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine)
60{
61  return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
62          ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
63         );
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_symbolic_name 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_symbolic_name 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_symbolic_name 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_symbolic_name 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_symbolic_name 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_symbolic_name 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
253
254int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
255{
256     if (!isValidInterrupt(irq->name)) {
257      return 0;
258     }
259     *irq = rtems_hdl_tbl[irq->name];
260     return 1;
261}
262
263int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
264{
265    unsigned int level;
266 
267    if (!isValidInterrupt(irq->name)) {
268      return 0;
269    }
270    /*
271     * Check if default handler is actually connected. If not issue an error.
272     * You must first get the current handler via i386_get_current_idt_entry
273     * and then disconnect it using i386_delete_idt_entry.
274     * RATIONALE : to always have the same transition by forcing the user
275     * to get the previous handler before accepting to disconnect.
276     */
277    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
278      return 0;
279    }
280    _CPU_ISR_Disable(level);
281
282    if (is_cpm_irq(irq->name)) {
283      /*
284       * disable interrupt at PIC level
285       */
286      BSP_irq_disable_at_cpm (irq->name);
287    }
288    if (is_siu_irq(irq->name)) {
289      /*
290       * disable interrupt at OPENPIC level
291       */
292      BSP_irq_disable_at_siu (irq->name);
293    }
294    if (is_processor_irq(irq->name)) {
295      /*
296       * disable exception at processor level
297       */
298    }   
299
300    /*
301     * Disable interrupt on device
302     */
303    irq->off(irq);
304
305    /*
306     * restore the default irq value
307     */
308    rtems_hdl_tbl[irq->name] = default_rtems_entry;
309
310    _CPU_ISR_Enable(level);
311
312    return 1;
313}
314
315/*
316 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
317 */
318
319int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
320{
321    int i;
322    unsigned int level;
323   /*
324    * Store various code accelerators
325    */
326    internal_config             = config;
327    default_rtems_entry         = config->defaultEntry;
328    rtems_hdl_tbl               = config->irqHdlTbl;
329
330    _CPU_ISR_Disable(level);
331    /*
332     * start with CPM IRQ
333     */
334    for (i=BSP_CPM_IRQ_LOWEST_OFFSET; i < BSP_CPM_IRQ_LOWEST_OFFSET + BSP_CPM_IRQ_NUMBER ; i++) {
335      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
336        BSP_irq_enable_at_cpm (i);
337        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
338      }
339      else {
340        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
341        BSP_irq_disable_at_cpm (i);
342      }
343    }
344
345    /*
346     * continue with PCI IRQ
347     */
348    /*
349     * set up internal tables used by rtems interrupt prologue
350     */
351    compute_SIU_IvectMask_from_prio ();
352
353    for (i=BSP_SIU_IRQ_LOWEST_OFFSET; i < BSP_SIU_IRQ_LOWEST_OFFSET + BSP_SIU_IRQ_NUMBER ; i++) {
354      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
355        BSP_irq_enable_at_siu (i);
356        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
357      }
358      else {
359        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
360        BSP_irq_disable_at_siu (i);
361       }
362    }
363    /*
364     * Must enable CPM interrupt on SIU. CPM on SIU Interrupt level has already been
365     * set up in BSP_CPM_irq_init.
366     */
367    ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
368    BSP_irq_enable_at_siu (BSP_CPM_INTERRUPT);
369    /*
370     * finish with Processor exceptions handled like IRQ
371     */
372    for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
373      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
374        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
375      }
376      else {
377        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
378      }
379    }
380    _CPU_ISR_Enable(level);
381    return 1;
382}
383
384int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
385{
386    *config = internal_config;
387    return 0;
388}
389
390#ifdef DISPATCH_HANDLER_STAT
391volatile unsigned int maxLoop = 0;
392#endif
393
394/*
395 * High level IRQ handler called from shared_raw_irq_code_entry
396 */
397void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
398{
399  register unsigned int irq;
400  register unsigned cpmIntr;                  /* boolean */
401  register unsigned oldMask;                  /* old siu pic masks */
402  register unsigned msr;
403  register unsigned new_msr;
404#ifdef DISPATCH_HANDLER_STAT
405  unsigned loopCounter;
406#endif
407  /*
408   * Handle decrementer interrupt
409   */
410  if (excNum == ASM_DEC_VECTOR) {
411    _CPU_MSR_GET(msr);
412    new_msr = msr | MSR_EE;
413    _CPU_MSR_SET(new_msr);
414   
415    rtems_hdl_tbl[BSP_DECREMENTER].hdl();
416
417    _CPU_MSR_SET(msr);
418    return;
419  }
420  /*
421   * Handle external interrupt generated by SIU on PPC core
422   */
423#ifdef DISPATCH_HANDLER_STAT
424  loopCounter = 0;
425#endif 
426  while (1) {
427    if ((ppc_cached_irq_mask & ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend) == 0) {
428#ifdef DISPATCH_HANDLER_STAT
429      if (loopCounter >  maxLoop) maxLoop = loopCounter;
430#endif     
431      break;
432    }
433    irq = (((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26);
434    cpmIntr = (irq == BSP_CPM_INTERRUPT);
435    /*
436     * Disable the interrupt of the same and lower priority.
437     */
438    oldMask = ppc_cached_irq_mask;
439    ppc_cached_irq_mask = oldMask & SIU_IvectMask[irq];
440    ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask;
441    /*
442     * Acknowledge current interrupt. This has no effect on internal level interrupt.
443     */
444    ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = (1 << (31 - irq));
445   
446    if (cpmIntr)  {
447      /*
448       * We will reenable the SIU CPM interrupt to allow nesting of CPM interrupt.
449       * We must before acknowledege the current irq at CPM level to avoid trigerring
450       * the interrupt again.
451       */
452      /*
453       * Acknowledge and get the vector.
454       */
455      ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
456      irq = (((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr >> 11);
457      /*
458       * transform IRQ to normalized irq table index.
459       */
460      irq += BSP_CPM_IRQ_LOWEST_OFFSET;
461      /*
462       * Unmask CPM interrupt at SIU level
463       */
464      ppc_cached_irq_mask |= (1 << (31 - BSP_CPM_INTERRUPT));
465      ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask;
466    }
467    _CPU_MSR_GET(msr);
468    new_msr = msr | MSR_EE;
469    _CPU_MSR_SET(new_msr);
470   
471    rtems_hdl_tbl[irq].hdl();
472
473    _CPU_MSR_SET(msr);
474
475    if (cpmIntr)  {
476      irq -= BSP_CPM_IRQ_LOWEST_OFFSET;
477      ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << irq);
478    }
479    ppc_cached_irq_mask |= (oldMask & ~(SIU_IvectMask[irq]));
480    ((volatile immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask;
481#ifdef DISPATCH_HANDLER_STAT
482    ++ loopCounter;
483#endif   
484  }
485}
486
487   
488 
489void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
490{
491  /*
492   * Process pending signals that have not already been
493   * processed by _Thread_Displatch. This happens quite
494   * unfrequently : the ISR must have posted an action
495   * to the current running thread.
496   */
497  if ( _Thread_Do_post_task_switch_extension ||
498       _Thread_Executing->do_post_task_switch_extension ) {
499    _Thread_Executing->do_post_task_switch_extension = FALSE;
500    _API_extensions_Run_postswitch();
501  }
502  /*
503   * I plan to process other thread related events here.
504   * This will include DEBUG session requested from keyboard...
505   */
506}
Note: See TracBrowser for help on using the repository browser.