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

4.104.114.84.95
Last change on this file since fc57b7b2 was fc57b7b2, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 12, 2007 at 3:16:41 PM

2007-09-12 Joel Sherrill <joel.sherrill@…>

PR 1257/bsps

  • shared/irq/i8259.c, shared/irq/irq.c: Code outside of cpukit should use the public API for rtems_interrupt_disable/rtems_interrupt_enable. By bypassing the public API and directly accessing _CPU_ISR_Disable and _CPU_ISR_Enable, they were bypassing the compiler memory barrier directive which could lead to problems. This patch also changes the type of the variable passed into these routines and addresses minor style issues.
  • Property mode set to 100644
File size: 9.5 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    rtems_interrupt_level   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    rtems_interrupt_disable(level);
96
97    if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
98      rtems_interrupt_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    rtems_interrupt_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    rtems_interrupt_level  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    rtems_interrupt_disable(level);
153    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
154      rtems_interrupt_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    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    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    rtems_interrupt_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    rtems_interrupt_level         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    rtems_interrupt_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    rtems_interrupt_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 (!ppc_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 (!ppc_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.