source: rtems/c/src/lib/libcpu/powerpc/ppc403/ictrl/ictrl.c @ 73b5bd5d

4.104.114.84.95
Last change on this file since 73b5bd5d was 73b5bd5d, checked in by Ralf Corsepius <ralf.corsepius@…>, on Apr 15, 2004 at 1:33:58 PM

Remove stray white spaces.

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/*  ictrl.c
2 *
3 *  This routine installs and handles external interrupt vectors for
4 *  PowerPC 403 CPU built-in external interrupt controller
5 *
6 *  Author: Thomas Doerfler <td@imd.m.isar.de>
7 *
8 *  COPYRIGHT (c) 1998 by IMD, Puchheim, Germany
9 *
10 *  To anyone who acknowledges that this file is provided "AS IS"
11 *  without any express or implied warranty:
12 *      permission to use, copy, modify, and distribute this file
13 *      for any purpose is hereby granted without fee, provided that
14 *      the above copyright notice and this notice appears in all
15 *      copies, and that the name of IMD not be used in
16 *      advertising or publicity pertaining to distribution of the
17 *      software without specific, written prior permission.
18 *      IMD makes no representations about the suitability
19 *      of this software for any purpose.
20 *
21 *  Modifications for PPC405GP by Dennis Ehlin
22 *
23 */
24
25#include "ictrl.h"
26#include <rtems.h>
27#include <rtems/libio.h>
28
29#include <stdlib.h>                     /* for atexit() */
30
31/*
32 *  ISR vector table to dispatch external interrupts
33 */
34 
35rtems_isr_entry ictrl_vector_table[PPC_IRQ_EXT_MAX];
36
37/*
38 *
39 *  some utilities to access the EXI* registers
40 *
41 */
42
43/*
44 *  clear bits in EXISR that have a bit set in mask
45 */
46#if defined(ppc405)
47RTEMS_INLINE_ROUTINE void 
48clr_exisr(uint32_t   mask) 
49{
50    asm volatile ("mtdcr 0xC0,%0"::"r" (mask));/*EXISR*/
51} 
52
53/*
54 *  get value of EXISR
55 */
56RTEMS_INLINE_ROUTINE uint32_t   
57get_exisr(void) 
58{
59    uint32_t   val;
60
61    asm volatile ("mfdcr %0,0xC0":"=r" (val));/*EXISR*/
62    return val; 
63} 
64
65/*
66 *  get value of EXIER
67 */
68RTEMS_INLINE_ROUTINE uint32_t   
69get_exier(void) 
70{
71    uint32_t   val;
72    asm volatile ("mfdcr %0,0xC2":"=r" (val));/*EXIER*/
73    return val; 
74} 
75
76/*
77 *  set value of EXIER
78 */
79RTEMS_INLINE_ROUTINE void 
80set_exier(uint32_t   val) 
81{
82    asm volatile ("mtdcr 0xC2,%0"::"r" (val));/*EXIER*/
83} 
84
85#else /* not ppc405 */
86
87RTEMS_INLINE_ROUTINE void 
88clr_exisr(uint32_t   mask) 
89{
90    asm volatile ("mtdcr 0x40,%0"::"r" (mask));/*EXISR*/
91} 
92
93/*
94 *  get value of EXISR
95 */
96RTEMS_INLINE_ROUTINE uint32_t   
97get_exisr(void) 
98{
99    uint32_t   val;
100
101    asm volatile ("mfdcr %0,0x40":"=r" (val));/*EXISR*/
102    return val; 
103} 
104
105/*
106 *  get value of EXIER
107 */
108RTEMS_INLINE_ROUTINE uint32_t   
109get_exier(void) 
110{
111    uint32_t   val;
112    asm volatile ("mfdcr %0,0x42":"=r" (val));/*EXIER*/
113    return val; 
114} 
115
116/*
117 *  set value of EXIER
118 */
119RTEMS_INLINE_ROUTINE void 
120set_exier(uint32_t   val) 
121{
122    asm volatile ("mtdcr 0x42,%0"::"r" (val));/*EXIER*/
123} 
124#endif /* ppc405 */
125/*
126 *  enable an external interrupt, make this interrupt consistent
127 */
128RTEMS_INLINE_ROUTINE void 
129enable_ext_irq( uint32_t   mask)
130{
131    uint32_t   isrlvl;
132    _CPU_ISR_Disable(isrlvl);
133    set_exier(get_exier() | ((mask)&PPC_EXI_MASK));
134    _CPU_ISR_Enable(isrlvl);
135}
136
137/*
138 *  disable an external interrupt, make this interrupt consistent
139 */
140RTEMS_INLINE_ROUTINE void 
141disable_ext_irq( uint32_t   mask)
142{
143    uint32_t   isrlvl;
144    _CPU_ISR_Disable(isrlvl);
145    set_exier(get_exier() & ~(mask) & PPC_EXI_MASK);
146    _CPU_ISR_Enable(isrlvl);
147}
148
149/*
150 *
151 *  this function is called, when a external interrupt is present and
152 *  enabled but there is no handler installed. It will clear
153 *  the corresponding enable bits and call the spurious handler
154 *  present in the CPU Configuration Table, if any.
155 *
156 */
157void 
158ictrl_spurious_handler(uint32_t   spurious_mask, 
159                       CPU_Interrupt_frame *cpu_frame)
160{
161  int v;
162 
163  for (v=0; v < PPC_IRQ_EXT_MAX; v++) {
164    if (VEC_TO_EXMSK(v) & spurious_mask) {
165      clr_exisr(VEC_TO_EXMSK(v));
166      disable_ext_irq(VEC_TO_EXMSK(v));
167#if 0
168      printf("spurious external interrupt: %d at pc 0x%x; disabling\n",
169             vector, cpu_frame->Interrupt.pcoqfront);
170#endif
171      if (rtems_cpu_configuration_get_spurious_handler()) {
172        rtems_cpu_configuration_get_spurious_handler()(v + PPC_IRQ_EXT_BASE,cpu_frame);
173      }
174    }
175  }
176}
177
178
179/*
180 *  ISR Handler: this is called from the primary exception dispatcher
181 */
182 
183void
184ictrl_isr(rtems_vector_number vector,CPU_Interrupt_frame *cpu_frame)
185{
186  uint32_t          istat,
187                    mask,
188                    global_vec;
189  int               exvec;
190  rtems_isr_entry handler;
191
192  istat = get_exisr() & get_exier() & PPC_EXI_MASK;
193
194  /* FIXME: this may be speeded up using cntlzw instruction */
195  for (exvec = 0;exvec < PPC_IRQ_EXT_MAX;exvec++) {
196    mask = VEC_TO_EXMSK(exvec);
197    if (0 != (istat & mask)) {
198      /*clr_exisr(mask); too early to ack*/
199      handler = ictrl_vector_table[exvec];
200      if (handler) {
201        istat &= ~mask;
202        global_vec = exvec + PPC_IRQ_EXT_BASE;
203        (handler)(global_vec);
204      }
205      clr_exisr(mask);/* now we can ack*/
206    }
207  }
208  if (istat != 0) { /* anything left? then we have a spurious interrupt */
209    ictrl_spurious_handler(istat,cpu_frame);
210  }
211}
212
213/*
214 *
215 * the following functions form the user interface
216 *
217 */
218
219/*
220 *
221 * install a user vector for one of the external interrupt sources
222 *
223 */ 
224rtems_status_code
225ictrl_set_vector(rtems_isr_entry   new_handler,
226                 uint32_t          vector,
227                 rtems_isr_entry   *old_handler
228)
229{
230  /*
231   *  We put the actual user ISR address in 'ictrl_vector_table'.  This will
232   *  be used by the _ictrl_isr so the user gets control.
233   */
234
235  /* check for valid vector range */
236  if ((vector >= PPC_IRQ_EXT_BASE) &&
237      (vector <  PPC_IRQ_EXT_BASE + PPC_IRQ_EXT_MAX)) {
238    /* return old handler entry */
239    *old_handler = ictrl_vector_table[vector - PPC_IRQ_EXT_BASE];
240
241    if (new_handler != NULL) {
242      /* store handler function... */
243      ictrl_vector_table[vector - PPC_IRQ_EXT_BASE] = new_handler;
244      /* then enable it in EXIER register */
245      enable_ext_irq(VEC_TO_EXMSK(vector - PPC_IRQ_EXT_BASE));
246    }
247    else { /* new_handler == NULL */
248      /* then disable it in EXIER register */
249      disable_ext_irq(VEC_TO_EXMSK(vector - PPC_IRQ_EXT_BASE));
250      ictrl_vector_table[vector - PPC_IRQ_EXT_BASE] = NULL;
251    }
252    return RTEMS_SUCCESSFUL;
253  }
254  else {
255    return RTEMS_INVALID_NUMBER;
256  }
257}
258
259/*
260 * Called via atexit()
261 * deactivate the interrupt controller
262 */
263
264void
265ictrl_exit(void)
266{
267  /* mark them all unused */
268  disable_ext_irq(~0);
269  clr_exisr(~0);
270 
271}
272
273/*
274 * activate the interrupt controller
275 */
276
277rtems_status_code
278ictrl_init(void)
279{
280  proc_ptr dummy;
281
282  /* mark them all unused */
283  disable_ext_irq(~0);
284  clr_exisr(~0);
285 
286  /* install the external interrupt handler */
287  _CPU_ISR_install_vector(PPC_IRQ_EXTERNAL,
288                          ictrl_isr,
289                          &dummy);
290  atexit(ictrl_exit);
291  return RTEMS_SUCCESSFUL;
292}
Note: See TracBrowser for help on using the repository browser.