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

4.104.114.84.95
Last change on this file since 5efc9787 was 69ed59f, checked in by Joel Sherrill <joel.sherrill@…>, on 05/14/02 at 17:10:17

2001-05-14 Till Straumann <strauman@…>

  • bootloader/misc.c, console/Makefile.am, console/console.c, console/consoleIo.h, console/inch.c, console/polled_io.c, console/uart.c, console/uart.h, include/bsp.h, irq/Makefile.am, irq/irq.c, irq/irq.h, irq/irq_init.c, openpic/openpic.c, openpic/openpic.h, pci/Makefile.am, pci/pci.c, pci/pci.h, residual/Makefile.am, start/start.S, startup/bspstart.c, vectors/vectors.S, vectors/vectors.h, vectors/vectors_init.c: Per PR216, "libbsp/powerpc/shared" BSP has been modified considerably with the goal to make it more flexible and reusable by other BSPs. The main strategies were:
    • eliminate hardcoded base addresses; devices use offsets and a BSP defined base address.
    • separate functionality into different files (e.g. reboot from inch.c to reboot.c) which can be overridden by a 'derived' BSP.
    • separate initialization code into separate files (e.g. PCI bridge detection/initialization was separated from the more generic PCI access routines), also to make it easier for 'derived' BSPs to substitute their own initialization code.

There are also a couple of enhancements and fixes:

  • IRQ handling code now has a hook for attaching a VME bridge.
  • OpenPIC is now explicitely initialized (polarities, senses). Eliminated the implicit assumption on the presence of an ISA PIC.
  • UART and console driver now supports more than 1 port. The current maximum of 2 can easily be extended by enlarging a table (it would even be easier if the ISR API was not broken by design).
  • fixed polled_io.c so it correctly supports console on COM2
  • fixed TLB invalidation code (start.S).
  • exception handler prints a stack backtrace.
  • added BSP_pciFindDevice() to scan the pci bus for a particular vendor/device/instance.
  • Property mode set to 100644
File size: 10.3 KB
Line 
1/*
2 *
3 *  This file contains the implementation of the function 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.OARcorp.com/rtems/license.html.
10 *
11 *  $Id$
12 */
13 
14#include <rtems/system.h>
15#include <bsp.h>
16#include <bsp/irq.h>
17#include <bsp/openpic.h>
18#include <rtems/score/thread.h>
19#include <rtems/score/apiext.h>
20#include <libcpu/raw_exception.h>
21#include <bsp/vectors.h>
22
23#include <rtems/bspIo.h> /* for printk */
24#define RAVEN_INTR_ACK_REG 0xfeff0030
25
26/*
27 * pointer to the mask representing the additionnal irq vectors
28 * that must be disabled when a particular entry is activated.
29 * They will be dynamically computed from teh prioruty table given
30 * in BSP_rtems_irq_mngt_set();
31 * CAUTION : this table is accessed directly by interrupt routine
32 *           prologue.
33 */
34rtems_i8259_masks       irq_mask_or_tbl[BSP_IRQ_NUMBER];
35/*
36 * default handler connected on each irq after bsp initialization
37 */
38static rtems_irq_connect_data   default_rtems_entry;
39
40/*
41 * location used to store initial tables used for interrupt
42 * management.
43 */
44static rtems_irq_global_settings*       internal_config;
45static rtems_irq_connect_data*          rtems_hdl_tbl;
46
47/*
48 * Check if IRQ is an ISA IRQ
49 */
50static inline int is_isa_irq(const rtems_irq_symbolic_name irqLine)
51{
52  return (((int) irqLine <= BSP_ISA_IRQ_MAX_OFFSET) &
53          ((int) irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET)
54         );
55}
56
57/*
58 * Check if IRQ is an OPENPIC IRQ
59 */
60static inline int is_pci_irq(const rtems_irq_symbolic_name irqLine)
61{
62  return (((int) irqLine <= BSP_PCI_IRQ_MAX_OFFSET) &
63          ((int) irqLine >= BSP_PCI_IRQ_LOWEST_OFFSET)
64         );
65}
66
67/*
68 * Check if IRQ is a Porcessor IRQ
69 */
70static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine)
71{
72  return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
73          ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
74         );
75}
76
77
78/*
79 * ------------------------ RTEMS Irq helper functions ----------------
80 */
81 
82/*
83 * Caution : this function assumes the variable "internal_config"
84 * is already set and that the tables it contains are still valid
85 * and accessible.
86 */
87static void compute_i8259_masks_from_prio ()
88{
89  unsigned int i;
90  unsigned int j;
91  /*
92   * Always mask at least current interrupt to prevent re-entrance
93   */
94  for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_NUMBER; i++) {
95    * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
96    for (j = BSP_ISA_IRQ_LOWEST_OFFSET; j < BSP_ISA_IRQ_NUMBER; j++) {
97      /*
98       * Mask interrupts at i8259 level that have a lower priority
99       */
100      if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) {
101        * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
102      }
103    }
104  }
105}
106
107/*
108 * This function check that the value given for the irq line
109 * is valid.
110 */
111
112static int isValidInterrupt(int irq)
113{
114  if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET))
115    return 0;
116  return 1;
117}
118
119/*
120 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
121 */
122
123int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
124{
125    unsigned int level;
126 
127    if (!isValidInterrupt(irq->name)) {
128      printk("Invalid interrupt vector %i\n",irq->name);
129      return 0;
130    }
131    /*
132     * Check if default handler is actually connected. If not issue an error.
133     * You must first get the current handler via i386_get_current_idt_entry
134     * and then disconnect it using i386_delete_idt_entry.
135     * RATIONALE : to always have the same transition by forcing the user
136     * to get the previous handler before accepting to disconnect.
137     */
138    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
139      printk("IRQ vector %i already connected\n",irq->name);
140      return 0;
141    }
142    _CPU_ISR_Disable(level);
143
144    /*
145     * store the data provided by user
146     */
147    rtems_hdl_tbl[irq->name] = *irq;
148   
149    if (is_isa_irq(irq->name)) {
150      /*
151       * Enable interrupt at PIC level
152       */
153      BSP_irq_enable_at_i8259s (irq->name);
154    }
155   
156    if (is_pci_irq(irq->name)) {
157      /*
158       * Enable interrupt at OPENPIC level
159       */
160      openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
161    }
162
163    if (is_processor_irq(irq->name)) {
164      /*
165       * Enable exception at processor level
166       */
167    }
168    /*
169     * Enable interrupt on device
170     */
171    irq->on(irq);
172   
173    _CPU_ISR_Enable(level);
174
175    return 1;
176}
177
178
179int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
180{
181     if (!isValidInterrupt(irq->name)) {
182      return 0;
183     }
184     *irq = rtems_hdl_tbl[irq->name];
185     return 1;
186}
187
188int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
189{
190    unsigned int level;
191 
192    if (!isValidInterrupt(irq->name)) {
193      return 0;
194    }
195    /*
196     * Check if default handler is actually connected. If not issue an error.
197     * You must first get the current handler via i386_get_current_idt_entry
198     * and then disconnect it using i386_delete_idt_entry.
199     * RATIONALE : to always have the same transition by forcing the user
200     * to get the previous handler before accepting to disconnect.
201     */
202    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
203      return 0;
204    }
205    _CPU_ISR_Disable(level);
206
207    if (is_isa_irq(irq->name)) {
208      /*
209       * disable interrupt at PIC level
210       */
211      BSP_irq_disable_at_i8259s (irq->name);
212    }
213    if (is_pci_irq(irq->name)) {
214      /*
215       * disable interrupt at OPENPIC level
216       */
217      openpic_disable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
218    }
219    if (is_processor_irq(irq->name)) {
220      /*
221       * disable exception at processor level
222       */
223    }   
224
225    /*
226     * Disable interrupt on device
227     */
228    irq->off(irq);
229
230    /*
231     * restore the default irq value
232     */
233    rtems_hdl_tbl[irq->name] = default_rtems_entry;
234
235    _CPU_ISR_Enable(level);
236
237    return 1;
238}
239
240/*
241 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
242 */
243
244int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
245{
246    int i;
247    unsigned int level;
248   /*
249    * Store various code accelerators
250    */
251    internal_config             = config;
252    default_rtems_entry         = config->defaultEntry;
253    rtems_hdl_tbl               = config->irqHdlTbl;
254
255    _CPU_ISR_Disable(level);
256    /*
257     * set up internal tables used by rtems interrupt prologue
258     */
259    /*
260     * start with ISA IRQ
261     */
262    compute_i8259_masks_from_prio ();
263
264    for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_NUMBER; i++) {
265      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
266        BSP_irq_enable_at_i8259s (i);
267        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
268      }
269      else {
270        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
271        BSP_irq_disable_at_i8259s (i);
272      }
273    }
274    /*
275     * must enable slave pic anyway
276     */
277    BSP_irq_enable_at_i8259s (2);
278    /*
279     * continue with PCI IRQ
280     */
281    for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) {
282      openpic_set_priority(0, internal_config->irqPrioTbl [i]);
283      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
284        openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
285        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
286      }
287      else {
288        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
289        openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
290      }
291    }
292    /*
293     * Must enable PCI/ISA bridge IRQ
294     */
295    openpic_enable_irq (0);
296    /*
297     * finish with Processor exceptions handled like IRQ
298     */
299    for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
300      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
301        rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
302      }
303      else {
304        rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
305      }
306    }
307    _CPU_ISR_Enable(level);
308    return 1;
309}
310
311int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
312{
313    *config = internal_config;
314    return 0;
315}   
316
317static unsigned spuriousIntr = 0;
318/*
319 * High level IRQ handler called from shared_raw_irq_code_entry
320 */
321void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
322{
323  register unsigned int irq;
324  register unsigned isaIntr;                  /* boolean */
325  register unsigned oldMask;                  /* old isa pic masks */
326  register unsigned newMask;                  /* new isa pic masks */
327  register unsigned msr;
328  register unsigned new_msr;
329
330
331  if (excNum == ASM_DEC_VECTOR) {
332    _CPU_MSR_GET(msr);
333    new_msr = msr | MSR_EE;
334    _CPU_MSR_SET(new_msr);
335   
336    rtems_hdl_tbl[BSP_DECREMENTER].hdl();
337
338    _CPU_MSR_SET(msr);
339    return;
340   
341  }
342  irq = openpic_irq(0);
343  if (irq == OPENPIC_VEC_SPURIOUS) {
344    ++spuriousIntr;
345    return;
346  }
347  isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
348  if (isaIntr)  {
349    /*
350     * Acknowledge and read 8259 vector
351     */
352    irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG);
353    /*
354     * store current PIC mask
355     */
356    oldMask = i8259s_cache;
357    newMask = oldMask | irq_mask_or_tbl [irq];
358    i8259s_cache = newMask;
359    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
360    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
361    BSP_irq_ack_at_i8259s (irq);
362    openpic_eoi(0);
363  }
364  _CPU_MSR_GET(msr);
365  new_msr = msr | MSR_EE;
366  _CPU_MSR_SET(new_msr);
367   
368  rtems_hdl_tbl[irq].hdl();
369
370  _CPU_MSR_SET(msr);
371
372  if (isaIntr)  {
373    i8259s_cache = oldMask;
374    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
375    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
376  }
377  else {
378#ifdef BSP_PCI_VME_BRIDGE_DOES_EOI
379        /* leave it to the VME bridge to do EOI, so
380         * it can re-enable the openpic while handling
381         * VME interrupts (-> VME priorities in software)
382         */
383        if (BSP_PCI_VME_BRIDGE_IRQ!=irq)
384#endif
385                openpic_eoi(0);
386  }
387}
388   
389   
390 
391void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
392{
393  /*
394   * Process pending signals that have not already been
395   * processed by _Thread_Displatch. This happens quite
396   * unfrequently : the ISR must have posted an action
397   * to the current running thread.
398   */
399  if ( _Thread_Do_post_task_switch_extension ||
400       _Thread_Executing->do_post_task_switch_extension ) {
401    _Thread_Executing->do_post_task_switch_extension = FALSE;
402    _API_extensions_Run_postswitch();
403  }
404  /*
405   * I plan to process other thread related events here.
406   * This will include DEBUG session requested from keyboard...
407   */
408}
Note: See TracBrowser for help on using the repository browser.