source: rtems/c/src/lib/libbsp/powerpc/eth_comm/irq/irq.c @ 4055e6f8

4.104.114.84.95
Last change on this file since 4055e6f8 was 4055e6f8, checked in by Joel Sherrill <joel.sherrill@…>, on Apr 16, 2001 at 8:18:03 PM

2001-04-11 Eric Valette <valette@…>

  • clock/.cvsignore, clock/Makefile.am, clock/p_clock.c, include/8xx_immap.h, include/commproc.h, irq/.cvsignore, irq/Makefile.am, irq/irq.c, irq/irq.h, irq/irq_asm.S, irq/irq_init.c, vectors/.cvsignore, vectors/Makefile.am, vectors/vectors.S, vectors/vectors.h, vectors/vectors_init.c: New file.
  • Switch the eth_comm BSP to use the "new exception processing model."
  • 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 <bsp.h>
15#include <bsp/irq.h>
16#include <rtems/score/thread.h>
17#include <rtems/score/apiext.h>
18#include <libcpu/raw_exception.h>
19#include <bsp/vectors.h>
20#include <libcpu/cpu.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  unsigned loopCounter;
405
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();
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();
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 & ~(SIU_IvectMask[irq]));
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
486   
487 
488void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
489{
490  /*
491   * Process pending signals that have not already been
492   * processed by _Thread_Displatch. This happens quite
493   * unfrequently : the ISR must have posted an action
494   * to the current running thread.
495   */
496  if ( _Thread_Do_post_task_switch_extension ||
497       _Thread_Executing->do_post_task_switch_extension ) {
498    _Thread_Executing->do_post_task_switch_extension = FALSE;
499    _API_extensions_Run_postswitch();
500  }
501  /*
502   * I plan to process other thread related events here.
503   * This will include DEBUG session requested from keyboard...
504   */
505}
Note: See TracBrowser for help on using the repository browser.