source: rtems/c/src/lib/libbsp/powerpc/shared/irq/irq.c @ 2b370444

4.104.114.84.9
Last change on this file since 2b370444 was 2b370444, checked in by Till Straumann <strauman@…>, on Nov 30, 2005 at 1:22:48 AM

2005-11-29 Till Straumann <strauman@…>

  • shared/irq/irq.c: Fixed incorrect removal of first shared interrupt in chain.
  • Property mode set to 100644
File size: 9.3 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 <bsp.h>
17#include <bsp/irq.h>
18#include <rtems/score/apiext.h>  /* for post ISR signal processing */
19#include <libcpu/raw_exception.h>
20#include <bsp/vectors.h>
21#include <stdlib.h>
22
23#include <rtems/bspIo.h> /* for printk */
24
25extern unsigned int external_exception_vector_prolog_code_size[];
26extern void external_exception_vector_prolog_code();
27extern unsigned int decrementer_exception_vector_prolog_code_size[];
28extern void decrementer_exception_vector_prolog_code();
29
30/*
31 * default handler connected on each irq after bsp initialization
32 */
33static rtems_irq_connect_data   default_rtems_entry;
34
35/*
36 * location used to store initial tables used for interrupt
37 * management.
38 */
39static rtems_irq_global_settings*       internal_config;
40static rtems_irq_connect_data*          rtems_hdl_tbl;
41
42/*
43 * Check if IRQ is a Processor IRQ
44 */
45static inline int is_processor_irq(const rtems_irq_number irqLine)
46{
47  return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
48          ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
49         );
50}
51
52/*
53 * default on/off function
54 */
55static void nop_func(){}
56/*
57 * default isOn function
58static int not_connected() {return 0;}
59 */
60/*
61 * default possible isOn function
62 */
63static int connected() {return 1;}
64
65
66/*
67 * ------------------------ RTEMS Irq helper functions ----------------
68 */
69
70/*
71 * This function check that the value given for the irq line
72 * is valid.
73 */
74
75static int isValidInterrupt(int irq)
76{
77  if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET))
78    return 0;
79  return 1;
80}
81
82/*
83 * ------------------------ RTEMS Shared Irq Handler Mngt Routines ----------------
84 */
85int BSP_install_rtems_shared_irq_handler  (const rtems_irq_connect_data* irq)
86{
87    unsigned int level;
88    rtems_irq_connect_data* vchain;
89
90    if (!isValidInterrupt(irq->name)) {
91      printk("Invalid interrupt vector %d\n",irq->name);
92      return 0;
93    }
94
95    _CPU_ISR_Disable(level);
96
97    if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
98      _CPU_ISR_Enable(level);
99      printk("IRQ vector %d already connected to an unshared handler\n",irq->name);
100      return 0;
101    }
102
103     vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
104
105    /* save off topmost handler */
106    vchain[0]= rtems_hdl_tbl[irq->name];
107
108    /*
109     * store the data provided by user
110     */
111    rtems_hdl_tbl[irq->name] = *irq;
112
113    /* link chain to new topmost handler */
114    rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
115
116    if (is_processor_irq(irq->name)) {
117      /*
118       * Enable exception at processor level
119       */
120    } else {
121                BSP_enable_irq_at_pic(irq->name);
122        }
123    /*
124     * Enable interrupt on device
125     */
126    irq->on(irq);
127
128    _CPU_ISR_Enable(level);
129
130    return 1;
131}
132
133/*
134 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
135 */
136
137int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
138{
139    unsigned int level;
140
141    if (!isValidInterrupt(irq->name)) {
142      printk("Invalid interrupt vector %d\n",irq->name);
143      return 0;
144    }
145    /*
146     * Check if default handler is actually connected. If not issue an error.
147     * You must first get the current handler via i386_get_current_idt_entry
148     * and then disconnect it using i386_delete_idt_entry.
149     * RATIONALE : to always have the same transition by forcing the user
150     * to get the previous handler before accepting to disconnect.
151     */
152    _CPU_ISR_Disable(level);
153    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
154      _CPU_ISR_Enable(level);
155      printk("IRQ vector %d already connected\n",irq->name);
156      return 0;
157    }
158
159    /*
160     * store the data provided by user
161     */
162    rtems_hdl_tbl[irq->name] = *irq;
163    rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
164
165    if (is_processor_irq(irq->name)) {
166      /*
167       * Enable exception at processor level
168       */
169    } else {
170          BSP_enable_irq_at_pic(irq->name);
171        }
172    /*
173     * Enable interrupt on device
174     */
175    irq->on(irq);
176
177    _CPU_ISR_Enable(level);
178
179    return 1;
180}
181
182int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
183{
184     unsigned int level;
185
186     if (!isValidInterrupt(irq->name)) {
187      return 0;
188     }
189     _CPU_ISR_Disable(level);
190     *irq = rtems_hdl_tbl[irq->name];
191     _CPU_ISR_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    unsigned int 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    _CPU_ISR_Disable(level);
211    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
212      _CPU_ISR_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          _CPU_ISR_Enable(level);
233          return 0;
234       }
235    }
236    else
237    {
238       if (rtems_hdl_tbl[irq->name].hdl != irq->hdl)
239       {
240          _CPU_ISR_Enable(level);
241         return 0;
242       }
243    }
244
245    if (is_processor_irq(irq->name)) {
246      /*
247       * disable exception at processor level
248       */
249    } else {
250          BSP_disable_irq_at_pic(irq->name);
251        }
252
253    /*
254     * Disable interrupt on device
255     */
256    irq->off(irq);
257
258    /*
259     * restore the default irq value
260     */
261    if( !vchain )
262    {
263       /* single handler vector... */
264       rtems_hdl_tbl[irq->name] = default_rtems_entry;
265    }
266    else
267    {
268       if( pchain )
269       {
270          /* non-first handler being removed */
271          pchain->next_handler = vchain->next_handler;
272       }
273       else
274       {
275          /* first handler isn't malloc'ed, so just overwrite it.  Since
276          the contents of vchain are being struct copied, vchain itself
277          goes away */
278          vchain = vchain->next_handler;
279          rtems_hdl_tbl[irq->name]= *vchain;
280       }
281       free(vchain);
282    }
283
284    _CPU_ISR_Enable(level);
285
286    return 1;
287}
288
289/*
290 * RTEMS Global Interrupt Handler Management Routines
291 */
292
293int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
294{
295    int i;
296    unsigned int level;
297        rtems_irq_connect_data* vchain;
298        rtems_raw_except_connect_data vectorDesc;
299
300        /*
301         * Store various code accelerators
302         */
303    internal_config             = config;
304    default_rtems_entry         = config->defaultEntry;
305    rtems_hdl_tbl                   = config->irqHdlTbl;
306
307    _CPU_ISR_Disable(level);
308
309        if ( !BSP_setup_the_pic(config) ) {
310                printk("PIC setup failed; leaving IRQs OFF\n");
311                return 0;
312        }
313
314        for ( i = BSP_LOWEST_OFFSET; i <= BSP_MAX_OFFSET; i++ ) {
315                for( vchain = &rtems_hdl_tbl[i];
316                     ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); 
317                     vchain = (rtems_irq_connect_data*)vchain->next_handler )
318                {
319              vchain->on(vchain);
320                }
321        }
322
323    _CPU_ISR_Enable(level);
324
325        /*
326         * We must connect the raw irq handler for the two
327         * expected interrupt sources : decrementer and external interrupts.
328         */
329    vectorDesc.exceptIndex      =       ASM_DEC_VECTOR;
330    vectorDesc.hdl.vector       =       ASM_DEC_VECTOR;
331    vectorDesc.hdl.raw_hdl      =       decrementer_exception_vector_prolog_code;
332    vectorDesc.hdl.raw_hdl_size =       (unsigned) decrementer_exception_vector_prolog_code_size;
333    vectorDesc.on               =       nop_func;
334    vectorDesc.off              =       nop_func;
335    vectorDesc.isOn             =       connected;
336    if (!mpc60x_set_exception (&vectorDesc)) {
337      BSP_panic("Unable to initialize RTEMS decrementer raw exception\n");
338    }
339    vectorDesc.exceptIndex      =       ASM_EXT_VECTOR;
340    vectorDesc.hdl.vector       =       ASM_EXT_VECTOR;
341    vectorDesc.hdl.raw_hdl      =       external_exception_vector_prolog_code;
342    vectorDesc.hdl.raw_hdl_size =       (unsigned) external_exception_vector_prolog_code_size;
343    if (!mpc60x_set_exception (&vectorDesc)) {
344      BSP_panic("Unable to initialize RTEMS external raw exception\n");
345    }
346    return 1;
347}
348
349int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
350{
351    *config = internal_config;
352    return 0;
353}
354
355void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
356{
357  /*
358   * Process pending signals that have not already been
359   * processed by _Thread_Displatch. This happens quite
360   * unfrequently : the ISR must have posted an action
361   * to the current running thread.
362   */
363  if ( _Thread_Do_post_task_switch_extension ||
364       _Thread_Executing->do_post_task_switch_extension ) {
365    _Thread_Executing->do_post_task_switch_extension = FALSE;
366    _API_extensions_Run_postswitch();
367  }
368  /*
369   * I plan to process other thread related events here.
370   * This will include DEBUG session requested from keyboard...
371   */
372}
Note: See TracBrowser for help on using the repository browser.