source: rtems/c/src/lib/libbsp/i386/shared/irq/irq.c @ c83c325

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

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

PR 1257/bsps

  • shared/irq/idt.c, shared/irq/irq.c, shared/irq/irq_init.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.4 KB
Line 
1/* irq.c
2 *
3 *  This file contains the implementation of the function described in irq.h
4 *
5 *  CopyRight (C) 1998 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 <bsp.h>
15#include <bsp/irq.h>
16#include <rtems/score/thread.h>
17#include <rtems/score/apiext.h>
18
19/*
20 * pointer to the mask representing the additionnal irq vectors
21 * that must be disabled when a particular entry is activated.
22 * They will be dynamically computed from teh prioruty table given
23 * in BSP_rtems_irq_mngt_set();
24 * CAUTION : this table is accessed directly by interrupt routine
25 *           prologue.
26 */
27rtems_i8259_masks       irq_mask_or_tbl[BSP_IRQ_LINES_NUMBER];
28
29/*
30 * default handler connected on each irq after bsp initialization
31 */
32static rtems_irq_connect_data   default_rtems_entry;
33
34/*
35 * location used to store initial tables used for interrupt
36 * management.
37 */
38static rtems_irq_global_settings*       internal_config;
39rtems_irq_connect_data*                 rtems_hdl_tbl;
40/*-------------------------------------------------------------------------+
41| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
42+--------------------------------------------------------------------------*/
43/*
44 * lower byte is interrupt mask on the master PIC.
45 * while upper bits are interrupt on the slave PIC.
46 * This cache is initialized in ldseg.s
47 */
48rtems_i8259_masks i8259s_cache = 0xFFFB;
49
50/*-------------------------------------------------------------------------+
51|         Function:  BSP_irq_disable_at_i8259s
52|      Description: Mask IRQ line in appropriate PIC chip.
53| Global Variables: i8259s_cache
54|        Arguments: vector_offset - number of IRQ line to mask.
55|          Returns: Nothing.
56+--------------------------------------------------------------------------*/
57int BSP_irq_disable_at_i8259s    (const rtems_irq_number irqLine)
58{
59  unsigned short        mask;
60  rtems_interrupt_level level;
61
62  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
63       ((int)irqLine > BSP_MAX_OFFSET )
64       )
65    return 1;
66
67  rtems_interrupt_disable(level);
68
69  mask = 1 << irqLine;
70  i8259s_cache |= mask;
71
72  if (irqLine < 8)
73  {
74    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
75  }
76  else
77  {
78    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
79  }
80  rtems_interrupt_enable(level);
81
82  return 0;
83}
84
85/*-------------------------------------------------------------------------+
86|         Function:  BSP_irq_enable_at_i8259s
87|      Description: Unmask IRQ line in appropriate PIC chip.
88| Global Variables: i8259s_cache
89|        Arguments: irqLine - number of IRQ line to mask.
90|          Returns: Nothing.
91+--------------------------------------------------------------------------*/
92int BSP_irq_enable_at_i8259s    (const rtems_irq_number irqLine)
93{
94  unsigned short        mask;
95  rtems_interrupt_level level;
96
97  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
98       ((int)irqLine > BSP_MAX_OFFSET )
99       )
100    return 1;
101
102  rtems_interrupt_disable(level);
103
104  mask = ~(1 << irqLine);
105  i8259s_cache &= mask;
106
107  if (irqLine < 8)
108  {
109    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
110  }
111  else
112  {
113    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
114  }
115  rtems_interrupt_enable(level);
116
117  return 0;
118} /* mask_irq */
119
120int BSP_irq_enabled_at_i8259s           (const rtems_irq_number irqLine)
121{
122  unsigned short mask;
123
124  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
125       ((int)irqLine > BSP_MAX_OFFSET )
126     )
127    return 1;
128
129  mask = (1 << irqLine);
130  return  (~(i8259s_cache & mask));
131}
132
133/*-------------------------------------------------------------------------+
134|         Function: BSP_irq_ack_at_i8259s
135|      Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
136| Global Variables: None.
137|        Arguments: irqLine - number of IRQ line to acknowledge.
138|          Returns: Nothing.
139+--------------------------------------------------------------------------*/
140int BSP_irq_ack_at_i8259s       (const rtems_irq_number irqLine)
141{
142  if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
143       ((int)irqLine > BSP_MAX_OFFSET )
144       )
145    return 1;
146
147  if (irqLine >= 8) {
148   outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
149  }
150  outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
151
152  return 0;
153
154} /* ackIRQ */
155
156/*
157 * ------------------------ RTEMS Irq helper functions ----------------
158 */
159
160/*
161 * Caution : this function assumes the variable "internal_config"
162 * is already set and that the tables it contains are still valid
163 * and accessible.
164 */
165static void compute_i8259_masks_from_prio ()
166{
167  unsigned int i;
168  unsigned int j;
169  /*
170   * Always mask at least current interrupt to prevent re-entrance
171   */
172  for (i=0; i < internal_config->irqNb; i++) {
173    * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
174    for (j = 0; j < internal_config->irqNb; j++) {
175      /*
176       * Mask interrupts at i8259 level that have a lower priority
177       */
178      if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) {
179        * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
180      }
181    }
182  }
183}
184
185/*
186 * This function check that the value given for the irq line
187 * is valid.
188 */
189
190static int isValidInterrupt(int irq)
191{
192  if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET))
193    return 0;
194  return 1;
195}
196
197/*
198 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
199 */
200
201int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
202{
203    rtems_interrupt_level       level;
204
205    if (!isValidInterrupt(irq->name)) {
206      return 0;
207    }
208    /*
209     * Check if default handler is actually connected. If not issue an error.
210     * You must first get the current handler via i386_get_current_idt_entry
211     * and then disconnect it using i386_delete_idt_entry.
212     * RATIONALE : to always have the same transition by forcing the user
213     * to get the previous handler before accepting to disconnect.
214     */
215    rtems_interrupt_disable(level);
216    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
217          rtems_interrupt_enable(level);
218      return 0;
219    }
220
221    /*
222     * store the data provided by user
223     */
224    rtems_hdl_tbl[irq->name] = *irq;
225    /*
226     * Enable interrupt at PIC level
227     */
228    BSP_irq_enable_at_i8259s (irq->name);
229    /*
230     * Enable interrupt on device
231     */
232    irq->on(irq);
233
234    rtems_interrupt_enable(level);
235
236    return 1;
237}
238
239int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
240{
241    rtems_interrupt_level       level;
242
243    if (!isValidInterrupt(irq->name)) {
244      return 0;
245    }
246    rtems_interrupt_disable(level);
247      *irq = rtems_hdl_tbl[irq->name];
248    rtems_interrupt_enable(level);
249    return 1;
250}
251
252int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
253{
254    rtems_interrupt_level       level;
255
256    if (!isValidInterrupt(irq->name)) {
257      return 0;
258    }
259    /*
260     * Check if default handler is actually connected. If not issue an error.
261     * You must first get the current handler via i386_get_current_idt_entry
262     * and then disconnect it using i386_delete_idt_entry.
263     * RATIONALE : to always have the same transition by forcing the user
264     * to get the previous handler before accepting to disconnect.
265     */
266    rtems_interrupt_disable(level);
267    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
268      rtems_interrupt_enable(level);
269      return 0;
270    }
271
272    /*
273     * disable interrupt at PIC level
274     */
275    BSP_irq_disable_at_i8259s (irq->name);
276
277    /*
278     * Disable interrupt on device
279     */
280    irq->off(irq);
281
282    /*
283     * restore the default irq value
284     */
285    rtems_hdl_tbl[irq->name] = default_rtems_entry;
286
287    rtems_interrupt_enable(level);
288
289    return 1;
290}
291
292/*
293 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
294 */
295
296int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
297{
298    int                    i;
299    rtems_interrupt_level  level;
300
301    /*
302     * Store various code accelerators
303     */
304    internal_config             = config;
305    default_rtems_entry         = config->defaultEntry;
306    rtems_hdl_tbl               = config->irqHdlTbl;
307
308    rtems_interrupt_disable(level);
309    /*
310     * set up internal tables used by rtems interrupt prologue
311     */
312    compute_i8259_masks_from_prio ();
313
314    for (i=0; i < internal_config->irqNb; i++) {
315      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
316        BSP_irq_enable_at_i8259s (i);
317        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
318      }
319      else {
320        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
321        BSP_irq_disable_at_i8259s (i);
322      }
323    }
324    /*
325     * must enable slave pic anyway
326     */
327    BSP_irq_enable_at_i8259s (2);
328    rtems_interrupt_enable(level);
329    return 1;
330}
331
332int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
333{
334    *config = internal_config;
335    return 0;
336}
337
338void _ThreadProcessSignalsFromIrq (CPU_Exception_frame* ctx)
339{
340  /*
341   * Process pending signals that have not already been
342   * processed by _Thread_Displatch. This happens quite
343   * unfrequently : the ISR must have posted an action
344   * to the current running thread.
345   */
346  if ( _Thread_Do_post_task_switch_extension ||
347       _Thread_Executing->do_post_task_switch_extension ) {
348    _Thread_Executing->do_post_task_switch_extension = FALSE;
349    _API_extensions_Run_postswitch();
350  }
351  /*
352   * I plan to process other thread related events here.
353   * This will include DEBUG session requested from keyboard...
354   */
355}
356
357void processIrq(unsigned index)
358{
359  rtems_hdl_tbl[index].hdl(rtems_hdl_tbl[index].handle);
360}
361
Note: See TracBrowser for help on using the repository browser.