source: rtems/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/irq.c @ 3c6fe2e

4.104.114.95
Last change on this file since 3c6fe2e was 3c6fe2e, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 07/14/08 at 08:46:06

added haleakala BSP contributed by Michael Hamel

  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 *
3 *  This file contains the PIC-independent implementation of the functions 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 <stdlib.h>
15
16#include <rtems.h>
17#include "irq_supp.h"
18#include <rtems/score/apiext.h>  /* for post ISR signal processing */
19#include <libcpu/raw_exception.h>
20#include <libcpu/cpuIdent.h>
21#include "vectors.h"
22#include "ppc_exc_bspsupp.h"
23#include <stdlib.h>
24#include <rtems/bspIo.h> /* for printk */
25#include <libcpu/spr.h>
26
27/*
28 * default handler connected on each irq after bsp initialization
29 */
30static rtems_irq_connect_data   default_rtems_entry;
31
32/*
33 * location used to store initial tables used for interrupt
34 * management.
35 */
36static rtems_irq_global_settings*       internal_config;
37static rtems_irq_connect_data*          rtems_hdl_tbl;
38
39
40SPR_RW(BOOKE_TSR)
41SPR_RW(PPC405_TSR)
42
43/* legacy mode for bookE DEC exception;
44 * to avoid the double layer of function calls
45 * (dec_handler_bookE -> C_dispatch_irq_handler -> user handler)
46 * it is preferrable for the user to hook the DEC
47 * exception directly.
48 * However, the legacy mode works with less modifications
49 * of user code.
50 */
51int C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum)
52{
53        /* clear interrupt; we must do this
54         * before C_dispatch_irq_handler()
55         * re-enables MSR_EE.
56         * Note that PPC405 uses a different SPR# for TSR
57         */
58        if ( ppc_cpu_is_bookE()==PPC_BOOKE_405)
59                _write_PPC405_TSR( BOOKE_TSR_DIS );
60        else
61                _write_BOOKE_TSR( BOOKE_TSR_DIS );
62        return C_dispatch_irq_handler(frame, ASM_DEC_VECTOR);   
63}
64
65/*
66 * ------------------------ RTEMS Irq helper functions ----------------
67 */
68
69/*
70 * This function check that the value given for the irq line
71 * is valid.
72 */
73
74static int isValidInterrupt(int irq)
75{
76  if ( (irq < internal_config->irqBase) || (irq >= internal_config->irqBase + internal_config->irqNb))
77    return 0;
78  return 1;
79}
80
81/*
82 * ------------------------ RTEMS Shared Irq Handler Mngt Routines ----------------
83 */
84int BSP_install_rtems_shared_irq_handler  (const rtems_irq_connect_data* irq)
85{
86    rtems_interrupt_level   level;
87    rtems_irq_connect_data* vchain;
88
89    if (!isValidInterrupt(irq->name)) {
90      printk("Invalid interrupt vector %d\n",irq->name);
91      return 0;
92    }
93
94        /* pre-allocate memory outside of critical section */
95    vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
96
97    rtems_interrupt_disable(level);
98
99    if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
100      rtems_interrupt_enable(level);
101      printk("IRQ vector %d already connected to an unshared handler\n",irq->name);
102          free(vchain);
103      return 0;
104    }
105
106    /* save off topmost handler */
107    vchain[0]= rtems_hdl_tbl[irq->name];
108
109    /*
110     * store the data provided by user
111     */
112    rtems_hdl_tbl[irq->name] = *irq;
113
114    /* link chain to new topmost handler */
115    rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
116
117        /*
118         * enable_irq_at_pic is supposed to ignore
119         * requests to disable interrupts outside
120         * of the range handled by the PIC
121         */
122        BSP_enable_irq_at_pic(irq->name);
123
124    /*
125     * Enable interrupt on device
126     */
127        if (irq->on)
128        irq->on(irq);
129
130    rtems_interrupt_enable(level);
131
132    return 1;
133}
134
135/*
136 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
137 */
138
139int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
140{
141    rtems_interrupt_level  level;
142
143    if (!isValidInterrupt(irq->name)) {
144      printk("Invalid interrupt vector %d\n",irq->name);
145      return 0;
146    }
147    /*
148     * Check if default handler is actually connected. If not issue an error.
149     * You must first get the current handler via i386_get_current_idt_entry
150     * and then disconnect it using i386_delete_idt_entry.
151     * RATIONALE : to always have the same transition by forcing the user
152     * to get the previous handler before accepting to disconnect.
153     */
154    rtems_interrupt_disable(level);
155    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
156      rtems_interrupt_enable(level);
157      printk("IRQ vector %d already connected\n",irq->name);
158      return 0;
159    }
160
161    /*
162     * store the data provided by user
163     */
164    rtems_hdl_tbl[irq->name] = *irq;
165    rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
166
167        /*
168         * enable_irq_at_pic is supposed to ignore
169         * requests to disable interrupts outside
170         * of the range handled by the PIC
171         */
172        BSP_enable_irq_at_pic(irq->name);
173
174    /*
175     * Enable interrupt on device
176     */
177        if (irq->on)
178        irq->on(irq);
179
180    rtems_interrupt_enable(level);
181
182    return 1;
183}
184
185int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
186{
187    rtems_interrupt_level       level;
188
189    if (!isValidInterrupt(irq->name)) {
190      return 0;
191    }
192    rtems_interrupt_disable(level);
193      *irq = rtems_hdl_tbl[irq->name];
194    rtems_interrupt_enable(level);
195    return 1;
196}
197
198int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
199{
200    rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
201    rtems_interrupt_level   level;
202
203    if (!isValidInterrupt(irq->name)) {
204      return 0;
205    }
206    /*
207     * Check if default handler is actually connected. If not issue an error.
208     * You must first get the current handler via i386_get_current_idt_entry
209     * and then disconnect it using i386_delete_idt_entry.
210     * RATIONALE : to always have the same transition by forcing the user
211     * to get the previous handler before accepting to disconnect.
212     */
213    rtems_interrupt_disable(level);
214    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
215      rtems_interrupt_enable(level);
216      return 0;
217    }
218
219    if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 )
220    {
221       int found = 0;
222
223       for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
224            (vchain->hdl != default_rtems_entry.hdl);
225            (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) )
226       {
227          if( vchain->hdl == irq->hdl )
228          {
229             found= -1; break;
230          }
231       }
232
233       if( !found )
234       {
235          rtems_interrupt_enable(level);
236          return 0;
237       }
238    }
239    else
240        {
241                if (rtems_hdl_tbl[irq->name].hdl != irq->hdl)
242                {
243                        rtems_interrupt_enable(level);
244                        return 0;
245                }
246        }
247
248    /*
249     * Disable interrupt on device
250     */
251        if (irq->off)
252        irq->off(irq);
253
254    /*
255     * restore the default irq value
256     */
257    if( !vchain )
258    {
259       /* single handler vector... */
260       rtems_hdl_tbl[irq->name] = default_rtems_entry;
261    }
262    else
263    {
264       if( pchain )
265       {
266          /* non-first handler being removed */
267          pchain->next_handler = vchain->next_handler;
268       }
269       else
270       {
271          /* first handler isn't malloc'ed, so just overwrite it.  Since
272          the contents of vchain are being struct copied, vchain itself
273          goes away */
274          vchain = vchain->next_handler;
275          rtems_hdl_tbl[irq->name]= *vchain;
276       }
277    }
278
279        /* Only disable at PIC if we removed the last handler */
280        if ( rtems_hdl_tbl[irq->name].hdl == default_rtems_entry.hdl ) {
281                /*
282                 * disable_irq_at_pic is supposed to ignore
283                 * requests to disable interrupts outside
284                 * of the range handled by the PIC;
285                 */
286                BSP_disable_irq_at_pic(irq->name);
287        }
288
289    rtems_interrupt_enable(level);
290
291    free(vchain);
292
293    return 1;
294}
295
296/*
297 * Less cumbersome, alternate entry points;
298 * RETURNS: more traditional, 0 on success, nonzero on error
299 */
300
301static int doit(
302        int (*p)(const rtems_irq_connect_data*),
303        rtems_irq_number n,
304        rtems_irq_hdl hdl,
305        rtems_irq_hdl_param prm)
306{
307rtems_irq_connect_data  xx;
308        xx.name   = n;
309        xx.hdl    = hdl;
310        xx.handle = prm;
311        xx.on     = 0;
312        xx.off    = 0;
313        xx.isOn   = 0;
314        return ! p(&xx);
315}
316
317int BSP_rtems_int_connect(rtems_irq_number n, rtems_irq_hdl hdl, rtems_irq_hdl_param p)
318{
319        return doit(BSP_install_rtems_shared_irq_handler, n, hdl, p);
320}
321
322int BSP_rtems_int_disconnect(rtems_irq_number n, rtems_irq_hdl hdl, rtems_irq_hdl_param p)
323{
324        return doit(BSP_remove_rtems_irq_handler, n, hdl, p);
325}
326
327
328/*
329 * RTEMS Global Interrupt Handler Management Routines
330 */
331
332int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
333{
334    int                           i;
335    rtems_interrupt_level         level;
336    rtems_irq_connect_data*       vchain;
337
338    /*
339     * Store various code accelerators
340     */
341    internal_config             = config;
342    default_rtems_entry         = config->defaultEntry;
343    rtems_hdl_tbl               = config->irqHdlTbl;
344
345    rtems_interrupt_disable(level);
346
347        if ( !BSP_setup_the_pic(config) ) {
348                printk("PIC setup failed; leaving IRQs OFF\n");
349                return 0;
350        }
351
352        for ( i = config->irqBase; i < config->irqBase + config->irqNb; i++ ) {
353                for( vchain = &rtems_hdl_tbl[i];
354                     ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
355                     vchain = (rtems_irq_connect_data*)vchain->next_handler )
356                {
357                        if (vchain->on)
358              vchain->on(vchain);
359                }
360                if ( vchain != &rtems_hdl_tbl[i] ) {
361                        /* at least one handler registered */
362                        BSP_enable_irq_at_pic(i);
363                } else {
364/* Do NOT disable; there might be boards with cascaded
365 * interrupt controllers where the BSP (incorrectly) does
366 * not ignore the cascaded interrupts in BSP_disable_irq_at_pic()!
367 * Instead, we rely on BSP_setup_the_pic() for a good
368 * initial configuration.
369 *
370                        BSP_disable_irq_at_pic(i);
371 */
372                }
373        }
374
375    rtems_interrupt_enable(level);
376
377        {
378                        ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler);
379
380                        if ( ppc_cpu_is_bookE() ) {
381                                /* bookE decrementer interrupt needs to be cleared BEFORE
382                                 * dispatching the user ISR (because the user ISR is called
383                                 * with EE enabled)
384                                 * We do this so that existing DEC handlers can be used
385                                 * with minor modifications.
386                                 */
387                                ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler_bookE);
388                        } else {
389                                ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler);
390                        }
391        }
392    return 1;
393}
394
395int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
396{
397    *config = internal_config;
398    return 0;
399}
Note: See TracBrowser for help on using the repository browser.