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

4.104.114.84.95
Last change on this file since f05b2ac was f05b2ac, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/21/04 at 16:01:48

Remove duplicate white lines.

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