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

4.104.115
Last change on this file since 2d2de4eb was 2d2de4eb, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 10/23/09 at 07:32:46

Update for exception support changes.

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