source: rtems/c/src/lib/libbsp/powerpc/mcp750/irq/irq.c @ 981b99f

4.104.114.84.95
Last change on this file since 981b99f was 981b99f, checked in by Joel Sherrill <joel.sherrill@…>, on 08/10/99 at 16:41:44

Patch from Eric Valette <valette@…> and Emmanuel Raguet
<raguet@…>:

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