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

4.104.114.84.9
Last change on this file since 2d0d029 was 2d0d029, checked in by Jennifer Averett <Jennifer.Averett@…>, on Apr 15, 2005 at 5:52:46 PM

2005-04-15 Jennifer Averett <jennifer.averett@…>

PR 779/bsp

  • clock/p_clock.c, console/console.c, console/uart.c, console/uart.h, irq/irq.c, irq/irq.h, irq/irq_init.c: powerpc: add parameter to new exception interrupt handlers
  • Property mode set to 100644
File size: 15.7 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.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 <bsp/VME.h>
19#include <bsp/openpic.h>
20#include <rtems/score/apiext.h>  /* for post ISR signal processing */
21#include <libcpu/raw_exception.h>
22#include <libcpu/io.h>
23#include <bsp/vectors.h>
24#include <stdlib.h>
25
26#include <rtems/bspIo.h> /* for printk */
27#define RAVEN_INTR_ACK_REG 0xfeff0030
28
29/*
30 * pointer to the mask representing the additionnal irq vectors
31 * that must be disabled when a particular entry is activated.
32 * They will be dynamically computed from the priority table given
33 * in BSP_rtems_irq_mngt_set();
34 * CAUTION : this table is accessed directly by interrupt routine
35 *           prologue.
36 */
37rtems_i8259_masks       irq_mask_or_tbl[BSP_IRQ_NUMBER];
38/*
39 * default handler connected on each irq after bsp initialization
40 */
41static rtems_irq_connect_data   default_rtems_entry;
42
43/*
44 * location used to store initial tables used for interrupt
45 * management.
46 */
47static rtems_irq_global_settings*       internal_config;
48static rtems_irq_connect_data*          rtems_hdl_tbl;
49
50/*
51 * Check if IRQ is an ISA IRQ
52 */
53static inline int is_isa_irq(const rtems_irq_symbolic_name irqLine)
54{
55  return (((int) irqLine <= BSP_ISA_IRQ_MAX_OFFSET) &
56          ((int) irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET)
57         );
58}
59
60/*
61 * Check if IRQ is an OPENPIC IRQ
62 */
63static inline int is_pci_irq(const rtems_irq_symbolic_name irqLine)
64{
65  return (((int) irqLine <= BSP_PCI_IRQ_MAX_OFFSET) &
66          ((int) irqLine >= BSP_PCI_IRQ_LOWEST_OFFSET)
67         );
68}
69
70/*
71 * Check if IRQ is a Processor IRQ
72 */
73static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine)
74{
75  return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
76          ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
77         );
78}
79
80/*
81 * ------------------------ RTEMS Irq helper functions ----------------
82 */
83
84/*
85 * Caution : this function assumes the variable "internal_config"
86 * is already set and that the tables it contains are still valid
87 * and accessible.
88 */
89static void compute_i8259_masks_from_prio ()
90{
91  int i;
92  int j;
93  /*
94   * Always mask at least current interrupt to prevent re-entrance
95   */
96  for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) {
97    * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
98    for (j = BSP_ISA_IRQ_LOWEST_OFFSET; j < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; j++) {
99      /*
100       * Mask interrupts at i8259 level that have a lower priority
101       */
102      if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) {
103        * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
104      }
105    }
106  }
107}
108
109/*
110 * This function check that the value given for the irq line
111 * is valid.
112 */
113
114static int isValidInterrupt(int irq)
115{
116  if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET))
117    return 0;
118  return 1;
119}
120
121/*
122 * ------------------------ RTEMS Shared Irq Handler Mngt Routines ----------------
123 */
124int BSP_install_rtems_shared_irq_handler  (const rtems_irq_connect_data* irq)
125{
126    unsigned int level;
127    rtems_irq_connect_data* vchain;
128
129    if (!isValidInterrupt(irq->name)) {
130      printk("Invalid interrupt vector %d\n",irq->name);
131      return 0;
132    }
133
134    _CPU_ISR_Disable(level);
135
136    if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
137      _CPU_ISR_Enable(level);
138      printk("IRQ vector %d already connected to an unshared handler\n",irq->name);
139      return 0;
140    }
141
142     vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
143
144    /* save off topmost handler */
145    vchain[0]= rtems_hdl_tbl[irq->name];
146
147    /*
148     * store the data provided by user
149     */
150    rtems_hdl_tbl[irq->name] = *irq;
151
152    /* link chain to new topmost handler */
153    rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
154
155    if (is_isa_irq(irq->name)) {
156      /*
157       * Enable interrupt at PIC level
158       */
159      BSP_irq_enable_at_i8259s (irq->name);
160    }
161
162    if (is_pci_irq(irq->name)) {
163      /*
164       * Enable interrupt at OPENPIC level
165       */
166      openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
167    }
168
169    if (is_processor_irq(irq->name)) {
170      /*
171       * Enable exception at processor level
172       */
173    }
174    /*
175     * Enable interrupt on device
176     */
177    irq->on(irq);
178
179    _CPU_ISR_Enable(level);
180
181    return 1;
182}
183
184/*
185 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
186 */
187
188int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
189{
190    unsigned int level;
191
192    if (!isValidInterrupt(irq->name)) {
193      printk("Invalid interrupt vector %d\n",irq->name);
194      return 0;
195    }
196    /*
197     * Check if default handler is actually connected. If not issue an error.
198     * You must first get the current handler via i386_get_current_idt_entry
199     * and then disconnect it using i386_delete_idt_entry.
200     * RATIONALE : to always have the same transition by forcing the user
201     * to get the previous handler before accepting to disconnect.
202     */
203    _CPU_ISR_Disable(level);
204    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
205      _CPU_ISR_Enable(level);
206      printk("IRQ vector %d already connected\n",irq->name);
207      return 0;
208    }
209
210    /*
211     * store the data provided by user
212     */
213    rtems_hdl_tbl[irq->name] = *irq;
214    rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
215
216    if (is_isa_irq(irq->name)) {
217      /*
218       * Enable interrupt at PIC level
219       */
220      BSP_irq_enable_at_i8259s (irq->name);
221    }
222
223    if (is_pci_irq(irq->name)) {
224      /*
225       * Enable interrupt at OPENPIC level
226       */
227      openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
228    }
229
230    if (is_processor_irq(irq->name)) {
231      /*
232       * Enable exception at processor level
233       */
234    }
235    /*
236     * Enable interrupt on device
237     */
238    irq->on(irq);
239
240    _CPU_ISR_Enable(level);
241
242    return 1;
243}
244
245int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
246{
247     unsigned int level;
248
249     if (!isValidInterrupt(irq->name)) {
250      return 0;
251     }
252     _CPU_ISR_Disable(level);
253     *irq = rtems_hdl_tbl[irq->name];
254     _CPU_ISR_Enable(level);
255     return 1;
256}
257
258int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
259{
260   rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
261    unsigned int level;
262
263    if (!isValidInterrupt(irq->name)) {
264      return 0;
265    }
266    /*
267     * Check if default handler is actually connected. If not issue an error.
268     * You must first get the current handler via i386_get_current_idt_entry
269     * and then disconnect it using i386_delete_idt_entry.
270     * RATIONALE : to always have the same transition by forcing the user
271     * to get the previous handler before accepting to disconnect.
272     */
273    _CPU_ISR_Disable(level);
274    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
275      _CPU_ISR_Enable(level);
276      return 0;
277    }
278
279    if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 )
280    {
281       int found = 0;
282
283       for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
284            (vchain->hdl != default_rtems_entry.hdl);
285            (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) )
286       {
287          if( vchain->hdl == irq->hdl )
288          {
289             found= -1; break;
290          }
291       }
292
293       if( !found )
294       {
295          _CPU_ISR_Enable(level);
296          return 0;
297       }
298    }
299    else
300    {
301       if (rtems_hdl_tbl[irq->name].hdl != irq->hdl)
302       {
303          _CPU_ISR_Enable(level);
304         return 0;
305       }
306    }
307
308    if (is_isa_irq(irq->name)) {
309      /*
310       * disable interrupt at PIC level
311       */
312      BSP_irq_disable_at_i8259s (irq->name);
313    }
314    if (is_pci_irq(irq->name)) {
315      /*
316       * disable interrupt at OPENPIC level
317       */
318      openpic_disable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
319    }
320    if (is_processor_irq(irq->name)) {
321      /*
322       * disable exception at processor level
323       */
324    }
325
326    /*
327     * Disable interrupt on device
328     */
329    irq->off(irq);
330
331    /*
332     * restore the default irq value
333     */
334    if( !vchain )
335    {
336       /* single handler vector... */
337       rtems_hdl_tbl[irq->name] = default_rtems_entry;
338    }
339    else
340    {
341       if( pchain )
342       {
343          /* non-first handler being removed */
344          pchain->next_handler = vchain->next_handler;
345       }
346       else
347       {
348          /* first handler isn't malloc'ed, so just overwrite it.  Since
349          the contents of vchain are being struct copied, vchain itself
350          goes away */
351          rtems_hdl_tbl[irq->name]= *vchain;
352       }
353       free(vchain);
354    }
355
356    _CPU_ISR_Enable(level);
357
358    return 1;
359}
360
361/*
362 * RTEMS Global Interrupt Handler Management Routines
363 */
364
365int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
366{
367    int i;
368    unsigned int level;
369   /*
370    * Store various code accelerators
371    */
372    internal_config             = config;
373    default_rtems_entry         = config->defaultEntry;
374    rtems_hdl_tbl               = config->irqHdlTbl;
375
376    _CPU_ISR_Disable(level);
377    /*
378     * set up internal tables used by rtems interrupt prologue
379     */
380    /*
381     * start with ISA IRQ
382     */
383    compute_i8259_masks_from_prio ();
384
385    for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) {
386      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
387         BSP_irq_enable_at_i8259s (i);
388
389         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
390         {
391            rtems_irq_connect_data* vchain;
392            for( vchain = &rtems_hdl_tbl[i];
393                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
394                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
395            {
396               vchain->on(vchain);
397            }
398         }
399      }
400      else {
401         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
402         {
403            rtems_irq_connect_data* vchain;
404            for( vchain = &rtems_hdl_tbl[i];
405                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
406                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
407            {
408               vchain->off(vchain);
409            }
410         }
411         BSP_irq_disable_at_i8259s (i);
412      }
413    }
414    /*
415     * must enable slave pic anyway
416     */
417    BSP_irq_enable_at_i8259s (2);
418    /*
419     * continue with PCI IRQ
420     */
421    for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) {
422      /*
423       * Note that openpic_set_priority() sets the TASK priority of the PIC
424       */
425      openpic_set_source_priority(i - BSP_PCI_IRQ_LOWEST_OFFSET,
426                                  internal_config->irqPrioTbl[i]);
427      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
428         openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
429         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
430         {
431            rtems_irq_connect_data* vchain;
432            for( vchain = &rtems_hdl_tbl[i];
433                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
434                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
435            {
436               vchain->on(vchain);
437            }
438         }
439
440      }
441      else {
442         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
443         {
444            rtems_irq_connect_data* vchain;
445            for( vchain = &rtems_hdl_tbl[i];
446                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
447                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
448            {
449               vchain->off(vchain);
450            }
451         }
452
453         openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
454      }
455    }
456    /*
457     * Must enable PCI/ISA bridge IRQ
458     */
459    openpic_enable_irq (0);
460    /*
461     * finish with Processor exceptions handled like IRQ
462     */
463    for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
464      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
465         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
466         {
467            rtems_irq_connect_data* vchain;
468            for( vchain = &rtems_hdl_tbl[i];
469                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
470                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
471            {
472               vchain->on(vchain);
473            }
474         }
475
476      }
477      else {
478         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
479         {
480            rtems_irq_connect_data* vchain;
481            for( vchain = &rtems_hdl_tbl[i];
482                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
483                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
484            {
485               vchain->off(vchain);
486            }
487         }
488
489      }
490    }
491    _CPU_ISR_Enable(level);
492    return 1;
493}
494
495int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
496{
497    *config = internal_config;
498    return 0;
499}
500
501int _BSP_vme_bridge_irq = -1;
502
503unsigned BSP_spuriousIntr = 0;
504/*
505 * High level IRQ handler called from shared_raw_irq_code_entry
506 */
507void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
508{
509  register unsigned int irq;
510  register unsigned isaIntr;                  /* boolean */
511  register unsigned oldMask = 0;              /* old isa pic masks */
512  register unsigned newMask;                  /* new isa pic masks */
513  register unsigned msr;
514  register unsigned new_msr;
515
516  if (excNum == ASM_DEC_VECTOR) {
517    _CPU_MSR_GET(msr);
518    new_msr = msr | MSR_EE;
519    _CPU_MSR_SET(new_msr);
520
521    rtems_hdl_tbl[BSP_DECREMENTER].hdl(rtems_hdl_tbl[BSP_DECREMENTER].handle);
522
523    _CPU_MSR_SET(msr);
524    return;
525
526  }
527  irq = openpic_irq(0);
528  if (irq == OPENPIC_VEC_SPURIOUS) {
529    ++BSP_spuriousIntr;
530    return;
531  }
532  isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
533  if (isaIntr)  {
534    /*
535     * Acknowledge and read 8259 vector
536     */
537    irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG);
538    /*
539     * store current PIC mask
540     */
541    oldMask = i8259s_cache;
542    newMask = oldMask | irq_mask_or_tbl [irq];
543    i8259s_cache = newMask;
544    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
545    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
546    BSP_irq_ack_at_i8259s (irq);
547    openpic_eoi(0);
548  }
549  _CPU_MSR_GET(msr);
550  new_msr = msr | MSR_EE;
551  _CPU_MSR_SET(new_msr);
552
553  /* rtems_hdl_tbl[irq].hdl(rtems_hdl_tbl[irq].handle); */
554  {
555     rtems_irq_connect_data* vchain;
556     for( vchain = &rtems_hdl_tbl[irq];
557          ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
558          vchain = (rtems_irq_connect_data*)vchain->next_handler )
559     {
560        vchain->hdl(vchain->handle);
561     }
562  }
563
564  _CPU_MSR_SET(msr);
565
566  if (isaIntr)  {
567    i8259s_cache = oldMask;
568    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
569    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
570  }
571  else {
572#ifdef BSP_PCI_VME_DRIVER_DOES_EOI
573        /* leave it to the VME bridge driver to do EOI, so
574     * it can re-enable the openpic while handling
575     * VME interrupts (-> VME priorities in software)
576         */
577        if (_BSP_vme_bridge_irq != irq)
578#endif
579                openpic_eoi(0);
580  }
581}
582
583void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
584{
585  /*
586   * Process pending signals that have not already been
587   * processed by _Thread_Displatch. This happens quite
588   * unfrequently : the ISR must have posted an action
589   * to the current running thread.
590   */
591  if ( _Thread_Do_post_task_switch_extension ||
592       _Thread_Executing->do_post_task_switch_extension ) {
593    _Thread_Executing->do_post_task_switch_extension = FALSE;
594    _API_extensions_Run_postswitch();
595  }
596  /*
597   * I plan to process other thread related events here.
598   * This will include DEBUG session requested from keyboard...
599   */
600}
Note: See TracBrowser for help on using the repository browser.