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

4.104.114.84.95
Last change on this file since 3a3e0b0e was 3a3e0b0e, checked in by Joel Sherrill <joel.sherrill@…>, on 06/13/03 at 17:39:46

2003-06-13 Greg Menke <gregory.menke@…>

PR 405/bsps

  • bootloader/pci.c: Added support for configuring devices for pci busses > 0
  • pci/pci.c, pci/pci.h: Added FixupPCI() to store vectors in the INTERRUPT_LINE register of pci devices any # of hops away from the host processor.
  • motorola/motorola.c, motorola/motorola.h: Added interrupt routing tables in support of FixupPCI. This is board-specific, each board will have to supply information for FixupPCI() to do anything for it.
  • startup/bspstart.c: Extended bat2 to cover entire PCI address space.
  • irq/irq.c, irq/irq.h: Added support for shared interrupts. Existing single hander vectors are undisturbed, a new function added to allow adding/removing handlers from a vector.
  • Property mode set to 100644
File size: 15.6 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/VME.h>
18#include <bsp/openpic.h>
19#include <rtems/score/thread.h>
20#include <rtems/score/apiext.h>
21#include <libcpu/raw_exception.h>
22#include <libcpu/io.h>
23#include <bsp/vectors.h>
24
25#include <rtems/bspIo.h> /* for printk */
26#define RAVEN_INTR_ACK_REG 0xfeff0030
27
28/*
29 * pointer to the mask representing the additionnal irq vectors
30 * that must be disabled when a particular entry is activated.
31 * They will be dynamically computed from teh prioruty table given
32 * in BSP_rtems_irq_mngt_set();
33 * CAUTION : this table is accessed directly by interrupt routine
34 *           prologue.
35 */
36rtems_i8259_masks       irq_mask_or_tbl[BSP_IRQ_NUMBER];
37/*
38 * default handler connected on each irq after bsp initialization
39 */
40static rtems_irq_connect_data   default_rtems_entry;
41
42/*
43 * location used to store initial tables used for interrupt
44 * management.
45 */
46static rtems_irq_global_settings*       internal_config;
47static rtems_irq_connect_data*          rtems_hdl_tbl;
48
49/*
50 * Check if IRQ is an ISA IRQ
51 */
52static inline int is_isa_irq(const rtems_irq_symbolic_name irqLine)
53{
54  return (((int) irqLine <= BSP_ISA_IRQ_MAX_OFFSET) &
55          ((int) irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET)
56         );
57}
58
59/*
60 * Check if IRQ is an OPENPIC IRQ
61 */
62static inline int is_pci_irq(const rtems_irq_symbolic_name irqLine)
63{
64  return (((int) irqLine <= BSP_PCI_IRQ_MAX_OFFSET) &
65          ((int) irqLine >= BSP_PCI_IRQ_LOWEST_OFFSET)
66         );
67}
68
69/*
70 * Check if IRQ is a Porcessor IRQ
71 */
72static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine)
73{
74  return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
75          ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
76         );
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/*
123 * ------------------------ RTEMS Shared Irq Handler Mngt Routines ----------------
124 */
125int BSP_install_rtems_shared_irq_handler  (const rtems_irq_connect_data* irq)
126{
127    unsigned int level;
128    rtems_irq_connect_data* vchain;
129 
130    if (!isValidInterrupt(irq->name)) {
131      printk("Invalid interrupt vector %i\n",irq->name);
132      return 0;
133    }
134    if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
135      printk("IRQ vector %i already connected to an unshared handler\n",irq->name);
136      return 0;
137    }
138    _CPU_ISR_Disable(level);
139
140
141     vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
142
143    /* save off topmost handler */
144    vchain[0]= rtems_hdl_tbl[irq->name];
145   
146    /*
147     * store the data provided by user
148     */
149    rtems_hdl_tbl[irq->name] = *irq;
150
151    /* link chain to new topmost handler */
152    rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
153
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/*
186 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
187 */
188
189int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
190{
191    unsigned int level;
192 
193    if (!isValidInterrupt(irq->name)) {
194      printk("Invalid interrupt vector %i\n",irq->name);
195      return 0;
196    }
197    /*
198     * Check if default handler is actually connected. If not issue an error.
199     * You must first get the current handler via i386_get_current_idt_entry
200     * and then disconnect it using i386_delete_idt_entry.
201     * RATIONALE : to always have the same transition by forcing the user
202     * to get the previous handler before accepting to disconnect.
203     */
204    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
205      printk("IRQ vector %i already connected\n",irq->name);
206      return 0;
207    }
208    _CPU_ISR_Disable(level);
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
245
246int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
247{
248     if (!isValidInterrupt(irq->name)) {
249      return 0;
250     }
251     *irq = rtems_hdl_tbl[irq->name];
252     return 1;
253}
254
255int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
256{
257   rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
258    unsigned int level;
259 
260    if (!isValidInterrupt(irq->name)) {
261      return 0;
262    }
263    /*
264     * Check if default handler is actually connected. If not issue an error.
265     * You must first get the current handler via i386_get_current_idt_entry
266     * and then disconnect it using i386_delete_idt_entry.
267     * RATIONALE : to always have the same transition by forcing the user
268     * to get the previous handler before accepting to disconnect.
269     */
270    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
271      return 0;
272    }
273    _CPU_ISR_Disable(level);
274
275    if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 )
276    {
277       int found = 0;
278
279       for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
280            (vchain->hdl != default_rtems_entry.hdl);
281            (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) )
282       {
283          if( vchain->hdl == irq->hdl )
284          {
285             found= -1; break;
286          }
287       }
288
289       if( !found )
290       {
291          _CPU_ISR_Enable(level);
292          return 0;
293       }
294    }
295    else
296    {
297       if (rtems_hdl_tbl[irq->name].hdl != irq->hdl)
298       {
299          _CPU_ISR_Enable(level);
300         return 0;
301       }
302    }
303
304    if (is_isa_irq(irq->name)) {
305      /*
306       * disable interrupt at PIC level
307       */
308      BSP_irq_disable_at_i8259s (irq->name);
309    }
310    if (is_pci_irq(irq->name)) {
311      /*
312       * disable interrupt at OPENPIC level
313       */
314      openpic_disable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
315    }
316    if (is_processor_irq(irq->name)) {
317      /*
318       * disable exception at processor level
319       */
320    }   
321
322    /*
323     * Disable interrupt on device
324     */
325    irq->off(irq);
326
327    /*
328     * restore the default irq value
329     */
330    if( !vchain )
331    {
332       /* single handler vector... */
333       rtems_hdl_tbl[irq->name] = default_rtems_entry;
334    }
335    else
336    {
337       if( pchain )
338       {
339          /* non-first handler being removed */
340          pchain->next_handler = vchain->next_handler;
341       }
342       else
343       {
344          /* first handler isn't malloc'ed, so just overwrite it.  Since
345          the contents of vchain are being struct copied, vchain itself
346          goes away */
347          rtems_hdl_tbl[irq->name]= *vchain;
348       }
349       free(vchain);
350    }
351
352    _CPU_ISR_Enable(level);
353
354    return 1;
355}
356
357/*
358 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
359 */
360
361int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
362{
363    int i;
364    unsigned int level;
365   /*
366    * Store various code accelerators
367    */
368    internal_config             = config;
369    default_rtems_entry         = config->defaultEntry;
370    rtems_hdl_tbl               = config->irqHdlTbl;
371
372    _CPU_ISR_Disable(level);
373    /*
374     * set up internal tables used by rtems interrupt prologue
375     */
376    /*
377     * start with ISA IRQ
378     */
379    compute_i8259_masks_from_prio ();
380
381    for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) {
382      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
383         BSP_irq_enable_at_i8259s (i);
384
385         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
386         {
387            rtems_irq_connect_data* vchain;
388            for( vchain = &rtems_hdl_tbl[i];
389                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
390                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
391            {
392               vchain->on(vchain);
393            }
394         }
395      }
396      else {
397         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
398         {
399            rtems_irq_connect_data* vchain;
400            for( vchain = &rtems_hdl_tbl[i];
401                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
402                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
403            {
404               vchain->off(vchain);
405            }
406         }
407         BSP_irq_disable_at_i8259s (i);
408      }
409    }
410    /*
411     * must enable slave pic anyway
412     */
413    BSP_irq_enable_at_i8259s (2);
414    /*
415     * continue with PCI IRQ
416     */
417    for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) {
418      /*
419       * Note that openpic_set_priority() sets the TASK priority of the PIC
420       */
421      openpic_set_source_priority(i - BSP_PCI_IRQ_LOWEST_OFFSET,
422                                  internal_config->irqPrioTbl[i]);
423      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
424         openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
425         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
426         {
427            rtems_irq_connect_data* vchain;
428            for( vchain = &rtems_hdl_tbl[i];
429                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
430                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
431            {
432               vchain->on(vchain);
433            }
434         }
435
436      }
437      else {
438         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
439         {
440            rtems_irq_connect_data* vchain;
441            for( vchain = &rtems_hdl_tbl[i];
442                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
443                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
444            {
445               vchain->off(vchain);
446            }
447         }
448         
449         openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
450      }
451    }
452    /*
453     * Must enable PCI/ISA bridge IRQ
454     */
455    openpic_enable_irq (0);
456    /*
457     * finish with Processor exceptions handled like IRQ
458     */
459    for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
460      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
461         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
462         {
463            rtems_irq_connect_data* vchain;
464            for( vchain = &rtems_hdl_tbl[i];
465                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
466                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
467            {
468               vchain->on(vchain);
469            }
470         }
471
472      }
473      else {
474         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
475         {
476            rtems_irq_connect_data* vchain;
477            for( vchain = &rtems_hdl_tbl[i];
478                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
479                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
480            {
481               vchain->off(vchain);
482            }
483         }
484
485      }
486    }
487    _CPU_ISR_Enable(level);
488    return 1;
489}
490
491int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
492{
493    *config = internal_config;
494    return 0;
495}   
496
497int _BSP_vme_bridge_irq = -1;
498 
499unsigned BSP_spuriousIntr = 0;
500/*
501 * High level IRQ handler called from shared_raw_irq_code_entry
502 */
503void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
504{
505  register unsigned int irq;
506  register unsigned isaIntr;                  /* boolean */
507  register unsigned oldMask = 0;              /* old isa pic masks */
508  register unsigned newMask;                  /* new isa pic masks */
509  register unsigned msr;
510  register unsigned new_msr;
511
512
513  if (excNum == ASM_DEC_VECTOR) {
514    _CPU_MSR_GET(msr);
515    new_msr = msr | MSR_EE;
516    _CPU_MSR_SET(new_msr);
517   
518    rtems_hdl_tbl[BSP_DECREMENTER].hdl();
519
520    _CPU_MSR_SET(msr);
521    return;
522   
523  }
524  irq = openpic_irq(0);
525  if (irq == OPENPIC_VEC_SPURIOUS) {
526    ++BSP_spuriousIntr;
527    return;
528  }
529  isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
530  if (isaIntr)  {
531    /*
532     * Acknowledge and read 8259 vector
533     */
534    irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG);
535    /*
536     * store current PIC mask
537     */
538    oldMask = i8259s_cache;
539    newMask = oldMask | irq_mask_or_tbl [irq];
540    i8259s_cache = newMask;
541    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
542    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
543    BSP_irq_ack_at_i8259s (irq);
544    openpic_eoi(0);
545  }
546  _CPU_MSR_GET(msr);
547  new_msr = msr | MSR_EE;
548  _CPU_MSR_SET(new_msr);
549   
550  /* rtems_hdl_tbl[irq].hdl(); */
551  {
552     rtems_irq_connect_data* vchain;
553     for( vchain = &rtems_hdl_tbl[irq];
554          ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
555          vchain = (rtems_irq_connect_data*)vchain->next_handler )
556     {
557        vchain->hdl();
558     }
559  }
560
561
562  _CPU_MSR_SET(msr);
563
564  if (isaIntr)  {
565    i8259s_cache = oldMask;
566    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
567    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
568  }
569  else {
570#ifdef BSP_PCI_VME_DRIVER_DOES_EOI
571        /* leave it to the VME bridge driver to do EOI, so
572     * it can re-enable the openpic while handling
573     * VME interrupts (-> VME priorities in software)
574         */
575        if (_BSP_vme_bridge_irq != irq)
576#endif
577                openpic_eoi(0);
578  }
579}
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.