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

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

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