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

4.104.114.95
Last change on this file since d3b840b8 was d3b840b8, checked in by Joel Sherrill <joel.sherrill@…>, on 12/03/07 at 22:39:46

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

  • shared/irq/irq.c: Spacing.
  • Property mode set to 100644
File size: 9.0 KB
Line 
1/*
2 *
3 *  This file contains the PIC-independent implementation of the
4 *  functions described in irq.h
5 *
6 *  Copyright (C) 1998, 1999 valette@crf.canon.fr
7 *
8 *  The license and distribution terms for this file may be
9 *  found in found in the file LICENSE in this distribution or at
10 *  http://www.rtems.com/license/LICENSE.
11 *
12 *  $Id$
13 */
14
15#include <stdlib.h>
16
17#include <bsp.h>
18#include <bsp/irq_supp.h>
19#include <rtems/irq.h>
20#include <rtems/score/apiext.h>  /* for post ISR signal processing */
21#include <libcpu/raw_exception.h>
22#include <bsp/vectors.h>
23#include <stdlib.h>
24
25#include <rtems/bspIo.h> /* for printk */
26
27extern unsigned int external_exception_vector_prolog_code_size[];
28extern void external_exception_vector_prolog_code();
29extern unsigned int decrementer_exception_vector_prolog_code_size[];
30extern void decrementer_exception_vector_prolog_code();
31
32/*
33 * default handler connected on each irq after bsp initialization
34 */
35static rtems_irq_connect_data  default_rtems_entry;
36
37/*
38 * location used to store initial tables used for interrupt
39 * management.
40 */
41static rtems_irq_global_settings*   internal_config;
42static rtems_irq_connect_data*    rtems_hdl_tbl;
43
44/*
45 * ------------------------ RTEMS Irq helper functions ----------------
46 */
47
48/*
49 * This function check that the value given for the irq line
50 * is valid.
51 */
52
53static int isValidInterrupt(int irq)
54{
55  if ( (irq < internal_config->irqBase) ||
56       (irq >= internal_config->irqBase + internal_config->irqNb))
57    return 0;
58  return 1;
59}
60
61/*
62 * ------------------- RTEMS Shared Irq Handler Mngt Routines ------------
63 */
64int BSP_install_rtems_shared_irq_handler  (const rtems_irq_connect_data* irq)
65{
66  rtems_interrupt_level   level;
67  rtems_irq_connect_data* vchain;
68
69  if (!isValidInterrupt(irq->name)) {
70    printk("Invalid interrupt vector %d\n",irq->name);
71    return 0;
72  }
73
74  rtems_interrupt_disable(level);
75
76  if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
77    rtems_interrupt_enable(level);
78    printk(
79      "IRQ vector %d already connected to an unshared handler\n",
80      irq->name
81    );
82    return 0;
83  }
84
85   vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
86
87  /* save off topmost handler */
88  vchain[0]= rtems_hdl_tbl[irq->name];
89
90  /*
91   * store the data provided by user
92   */
93  rtems_hdl_tbl[irq->name] = *irq;
94
95  /* link chain to new topmost handler */
96  rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
97
98  /*
99   * enable_irq_at_pic is supposed to ignore
100   * requests to disable interrupts outside
101   * of the range handled by the PIC
102   */
103  BSP_enable_irq_at_pic(irq->name);
104
105  /*
106   * Enable interrupt on device
107   */
108  if (irq->on)
109    irq->on(irq);
110
111  rtems_interrupt_enable(level);
112
113  return 1;
114}
115
116/*
117 * ------------------- RTEMS Single Irq Handler Mngt Routines ------------
118 */
119
120int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
121{
122  rtems_interrupt_level  level;
123
124  if (!isValidInterrupt(irq->name)) {
125    printk("Invalid interrupt vector %d\n",irq->name);
126    return 0;
127  }
128  /*
129   * Check if default handler is actually connected. If not issue an error.
130   * You must first get the current handler via i386_get_current_idt_entry
131   * and then disconnect it using i386_delete_idt_entry.
132   * RATIONALE : to always have the same transition by forcing the user
133   * to get the previous handler before accepting to disconnect.
134   */
135  rtems_interrupt_disable(level);
136  if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
137    rtems_interrupt_enable(level);
138    printk("IRQ vector %d already connected\n",irq->name);
139    return 0;
140  }
141
142  /*
143   * store the data provided by user
144   */
145  rtems_hdl_tbl[irq->name] = *irq;
146  rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
147
148  /*
149   * enable_irq_at_pic is supposed to ignore
150   * requests to disable interrupts outside
151   * of the range handled by the PIC
152   */
153  BSP_enable_irq_at_pic(irq->name);
154
155  /*
156   * Enable interrupt on device
157   */
158  if (irq->on)
159    irq->on(irq);
160
161  rtems_interrupt_enable(level);
162
163  return 1;
164}
165
166int BSP_get_current_rtems_irq_handler  (rtems_irq_connect_data* irq)
167{
168  rtems_interrupt_level       level;
169
170  if (!isValidInterrupt(irq->name)) {
171    return 0;
172  }
173  rtems_interrupt_disable(level);
174  *irq = rtems_hdl_tbl[irq->name];
175  rtems_interrupt_enable(level);
176  return 1;
177}
178
179int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
180{
181  rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
182  rtems_interrupt_level   level;
183
184  if (!isValidInterrupt(irq->name)) {
185    return 0;
186  }
187  /*
188   * Check if default handler is actually connected. If not issue an error.
189   * You must first get the current handler via i386_get_current_idt_entry
190   * and then disconnect it using i386_delete_idt_entry.
191   * RATIONALE : to always have the same transition by forcing the user
192   * to get the previous handler before accepting to disconnect.
193   */
194  rtems_interrupt_disable(level);
195  if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
196    rtems_interrupt_enable(level);
197    return 0;
198  }
199
200  if ( (int)rtems_hdl_tbl[irq->name].next_handler != -1 ) {
201    int found = 0;
202
203    for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
204         (vchain->hdl != default_rtems_entry.hdl);
205         (pchain= vchain,
206          vchain = (rtems_irq_connect_data*)vchain->next_handler) ) {
207      if ( vchain->hdl == irq->hdl ) {
208        found =  -1;
209        break;
210      }
211    }
212
213    if ( !found ) {
214      rtems_interrupt_enable(level);
215      return 0;
216    }
217  } else {
218    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
219      rtems_interrupt_enable(level);
220      return 0;
221    }
222  }
223
224  /*
225   * disable_irq_at_pic is supposed to ignore
226   * requests to disable interrupts outside
227   * of the range handled by the PIC
228   */
229  BSP_disable_irq_at_pic(irq->name);
230
231  /*
232   * Disable interrupt on device
233   */
234  if (irq->off)
235    irq->off(irq);
236
237  /*
238   * restore the default irq value
239   */
240  if( !vchain ) {
241     /* single handler vector... */
242     rtems_hdl_tbl[irq->name] = default_rtems_entry;
243  } else {
244    if ( pchain ) {
245       /* non-first handler being removed */
246       pchain->next_handler = vchain->next_handler;
247    } else {
248       /* first handler isn't malloc'ed, so just overwrite it.  Since
249        * the contents of vchain are being struct copied, vchain itself
250        * goes away
251        */
252       vchain = vchain->next_handler;
253       rtems_hdl_tbl[irq->name]= *vchain;
254    }
255    free(vchain);
256  }
257
258  rtems_interrupt_enable(level);
259
260  return 1;
261}
262
263/*
264 * RTEMS Global Interrupt Handler Management Routines
265 */
266
267int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
268{
269  int                           i;
270  rtems_interrupt_level         level;
271  rtems_irq_connect_data*       vchain;
272  rtems_raw_except_connect_data vectorDesc;
273
274  /*
275   * Store various code accelerators
276   */
277  internal_config     = config;
278  default_rtems_entry   = config->defaultEntry;
279  rtems_hdl_tbl     = config->irqHdlTbl;
280
281  rtems_interrupt_disable(level);
282
283  if ( !BSP_setup_the_pic(config) ) {
284    printk("PIC setup failed; leaving IRQs OFF\n");
285    return 0;
286  }
287
288  for ( i = config->irqBase; i < config->irqBase + config->irqNb; i++ ) {
289    for( vchain = &rtems_hdl_tbl[i];
290         ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
291         vchain = (rtems_irq_connect_data*)vchain->next_handler ) {
292      if (vchain->on)
293        vchain->on(vchain);
294    }
295  }
296
297    rtems_interrupt_enable(level);
298
299  /*
300   * We must connect the raw irq handler for the two
301   * expected interrupt sources : decrementer and external interrupts.
302   */
303  vectorDesc.exceptIndex       =  ASM_DEC_VECTOR;
304  vectorDesc.hdl.vector        =  ASM_DEC_VECTOR;
305  vectorDesc.hdl.raw_hdl       =  decrementer_exception_vector_prolog_code;
306  vectorDesc.hdl.raw_hdl_size  =
307       (unsigned) decrementer_exception_vector_prolog_code_size;
308  vectorDesc.on     =  0;
309  vectorDesc.off    =  0;
310  vectorDesc.isOn   =  0;
311  if (!ppc_set_exception (&vectorDesc)) {
312    BSP_panic("Unable to initialize RTEMS decrementer raw exception\n");
313  }
314
315  vectorDesc.exceptIndex       =  ASM_EXT_VECTOR;
316  vectorDesc.hdl.vector        =  ASM_EXT_VECTOR;
317  vectorDesc.hdl.raw_hdl       =  external_exception_vector_prolog_code;
318  vectorDesc.hdl.raw_hdl_size  =
319       (unsigned) external_exception_vector_prolog_code_size;
320  if (!ppc_set_exception (&vectorDesc)) {
321    BSP_panic("Unable to initialize RTEMS external raw exception\n");
322  }
323  return 1;
324}
325
326int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
327{
328  *config = internal_config;
329  return 0;
330}
331
332void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
333{
334  /*
335   * Process pending signals that have not already been
336   * processed by _Thread_Displatch. This happens quite
337   * unfrequently : the ISR must have posted an action
338   * to the current running thread.
339   */
340  if ( _Thread_Do_post_task_switch_extension ||
341       _Thread_Executing->do_post_task_switch_extension ) {
342    _Thread_Executing->do_post_task_switch_extension = FALSE;
343    _API_extensions_Run_postswitch();
344  }
345  /*
346   * I plan to process other thread related events here.
347   * This will include DEBUG session requested from keyboard...
348   */
349}
Note: See TracBrowser for help on using the repository browser.