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

4.104.114.84.95
Last change on this file since a77cd066 was e831de8, checked in by Joel Sherrill <joel.sherrill@…>, on 09/04/03 at 18:52:38

2003-09-04 Joel Sherrill <joel@…>

  • bootloader/bootldr.h, bootloader/em86.c, bootloader/em86real.S, bootloader/exception.S, bootloader/head.S, bootloader/lib.c, bootloader/misc.c, bootloader/mm.c, bootloader/pci.c, clock/p_clock.c, console/console.c, console/consoleIo.h, console/inch.c, console/keyboard.h, console/polled_io.c, include/bsp.h, irq/i8259.c, irq/irq.c, irq/irq.h, irq/irq_asm.S, irq/irq_init.c, motorola/motorola.c, motorola/motorola.h, openpic/openpic.c, openpic/openpic.h, pci/pci.c, residual/residual.c, start/start.S, startup/bspstart.c, vectors/vectors.h, vectors/vectors_init.c: URL for license changed.
  • Property mode set to 100644
File size: 15.8 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 <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 %d\n",irq->name);
132      return 0;
133    }
134
135    _CPU_ISR_Disable(level);
136
137    if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
138      _CPU_ISR_Enable(level);
139      printk("IRQ vector %d already connected to an unshared handler\n",irq->name);
140      return 0;
141    }
142
143     vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
144
145    /* save off topmost handler */
146    vchain[0]= rtems_hdl_tbl[irq->name];
147   
148    /*
149     * store the data provided by user
150     */
151    rtems_hdl_tbl[irq->name] = *irq;
152
153    /* link chain to new topmost handler */
154    rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
155
156   
157    if (is_isa_irq(irq->name)) {
158      /*
159       * Enable interrupt at PIC level
160       */
161      BSP_irq_enable_at_i8259s (irq->name);
162    }
163   
164    if (is_pci_irq(irq->name)) {
165      /*
166       * Enable interrupt at OPENPIC level
167       */
168      openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
169    }
170
171    if (is_processor_irq(irq->name)) {
172      /*
173       * Enable exception at processor level
174       */
175    }
176    /*
177     * Enable interrupt on device
178     */
179    irq->on(irq);
180   
181    _CPU_ISR_Enable(level);
182
183    return 1;
184}
185
186
187/*
188 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
189 */
190
191int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
192{
193    unsigned int level;
194 
195    if (!isValidInterrupt(irq->name)) {
196      printk("Invalid interrupt vector %d\n",irq->name);
197      return 0;
198    }
199    /*
200     * Check if default handler is actually connected. If not issue an error.
201     * You must first get the current handler via i386_get_current_idt_entry
202     * and then disconnect it using i386_delete_idt_entry.
203     * RATIONALE : to always have the same transition by forcing the user
204     * to get the previous handler before accepting to disconnect.
205     */
206    _CPU_ISR_Disable(level);
207    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
208      _CPU_ISR_Enable(level);
209      printk("IRQ vector %d already connected\n",irq->name);
210      return 0;
211    }
212
213    /*
214     * store the data provided by user
215     */
216    rtems_hdl_tbl[irq->name] = *irq;
217    rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
218   
219    if (is_isa_irq(irq->name)) {
220      /*
221       * Enable interrupt at PIC level
222       */
223      BSP_irq_enable_at_i8259s (irq->name);
224    }
225   
226    if (is_pci_irq(irq->name)) {
227      /*
228       * Enable interrupt at OPENPIC level
229       */
230      openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
231    }
232
233    if (is_processor_irq(irq->name)) {
234      /*
235       * Enable exception at processor level
236       */
237    }
238    /*
239     * Enable interrupt on device
240     */
241    irq->on(irq);
242   
243    _CPU_ISR_Enable(level);
244
245    return 1;
246}
247
248
249int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
250{
251     unsigned int level;
252
253     if (!isValidInterrupt(irq->name)) {
254      return 0;
255     }
256     _CPU_ISR_Disable(level);
257     *irq = rtems_hdl_tbl[irq->name];
258     _CPU_ISR_Enable(level);
259     return 1;
260}
261
262int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
263{
264   rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
265    unsigned int level;
266 
267    if (!isValidInterrupt(irq->name)) {
268      return 0;
269    }
270    /*
271     * Check if default handler is actually connected. If not issue an error.
272     * You must first get the current handler via i386_get_current_idt_entry
273     * and then disconnect it using i386_delete_idt_entry.
274     * RATIONALE : to always have the same transition by forcing the user
275     * to get the previous handler before accepting to disconnect.
276     */
277    _CPU_ISR_Disable(level);
278    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
279      _CPU_ISR_Enable(level);
280      return 0;
281    }
282
283    if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 )
284    {
285       int found = 0;
286
287       for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
288            (vchain->hdl != default_rtems_entry.hdl);
289            (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) )
290       {
291          if( vchain->hdl == irq->hdl )
292          {
293             found= -1; break;
294          }
295       }
296
297       if( !found )
298       {
299          _CPU_ISR_Enable(level);
300          return 0;
301       }
302    }
303    else
304    {
305       if (rtems_hdl_tbl[irq->name].hdl != irq->hdl)
306       {
307          _CPU_ISR_Enable(level);
308         return 0;
309       }
310    }
311
312    if (is_isa_irq(irq->name)) {
313      /*
314       * disable interrupt at PIC level
315       */
316      BSP_irq_disable_at_i8259s (irq->name);
317    }
318    if (is_pci_irq(irq->name)) {
319      /*
320       * disable interrupt at OPENPIC level
321       */
322      openpic_disable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
323    }
324    if (is_processor_irq(irq->name)) {
325      /*
326       * disable exception at processor level
327       */
328    }   
329
330    /*
331     * Disable interrupt on device
332     */
333    irq->off(irq);
334
335    /*
336     * restore the default irq value
337     */
338    if( !vchain )
339    {
340       /* single handler vector... */
341       rtems_hdl_tbl[irq->name] = default_rtems_entry;
342    }
343    else
344    {
345       if( pchain )
346       {
347          /* non-first handler being removed */
348          pchain->next_handler = vchain->next_handler;
349       }
350       else
351       {
352          /* first handler isn't malloc'ed, so just overwrite it.  Since
353          the contents of vchain are being struct copied, vchain itself
354          goes away */
355          rtems_hdl_tbl[irq->name]= *vchain;
356       }
357       free(vchain);
358    }
359
360    _CPU_ISR_Enable(level);
361
362    return 1;
363}
364
365/*
366 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
367 */
368
369int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
370{
371    int i;
372    unsigned int level;
373   /*
374    * Store various code accelerators
375    */
376    internal_config             = config;
377    default_rtems_entry         = config->defaultEntry;
378    rtems_hdl_tbl               = config->irqHdlTbl;
379
380    _CPU_ISR_Disable(level);
381    /*
382     * set up internal tables used by rtems interrupt prologue
383     */
384    /*
385     * start with ISA IRQ
386     */
387    compute_i8259_masks_from_prio ();
388
389    for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) {
390      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
391         BSP_irq_enable_at_i8259s (i);
392
393         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
394         {
395            rtems_irq_connect_data* vchain;
396            for( vchain = &rtems_hdl_tbl[i];
397                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
398                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
399            {
400               vchain->on(vchain);
401            }
402         }
403      }
404      else {
405         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
406         {
407            rtems_irq_connect_data* vchain;
408            for( vchain = &rtems_hdl_tbl[i];
409                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
410                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
411            {
412               vchain->off(vchain);
413            }
414         }
415         BSP_irq_disable_at_i8259s (i);
416      }
417    }
418    /*
419     * must enable slave pic anyway
420     */
421    BSP_irq_enable_at_i8259s (2);
422    /*
423     * continue with PCI IRQ
424     */
425    for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) {
426      /*
427       * Note that openpic_set_priority() sets the TASK priority of the PIC
428       */
429      openpic_set_source_priority(i - BSP_PCI_IRQ_LOWEST_OFFSET,
430                                  internal_config->irqPrioTbl[i]);
431      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
432         openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
433         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
434         {
435            rtems_irq_connect_data* vchain;
436            for( vchain = &rtems_hdl_tbl[i];
437                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
438                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
439            {
440               vchain->on(vchain);
441            }
442         }
443
444      }
445      else {
446         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
447         {
448            rtems_irq_connect_data* vchain;
449            for( vchain = &rtems_hdl_tbl[i];
450                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
451                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
452            {
453               vchain->off(vchain);
454            }
455         }
456         
457         openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
458      }
459    }
460    /*
461     * Must enable PCI/ISA bridge IRQ
462     */
463    openpic_enable_irq (0);
464    /*
465     * finish with Processor exceptions handled like IRQ
466     */
467    for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
468      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
469         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
470         {
471            rtems_irq_connect_data* vchain;
472            for( vchain = &rtems_hdl_tbl[i];
473                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
474                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
475            {
476               vchain->on(vchain);
477            }
478         }
479
480      }
481      else {
482         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
483         {
484            rtems_irq_connect_data* vchain;
485            for( vchain = &rtems_hdl_tbl[i];
486                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
487                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
488            {
489               vchain->off(vchain);
490            }
491         }
492
493      }
494    }
495    _CPU_ISR_Enable(level);
496    return 1;
497}
498
499int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
500{
501    *config = internal_config;
502    return 0;
503}   
504
505int _BSP_vme_bridge_irq = -1;
506 
507unsigned BSP_spuriousIntr = 0;
508/*
509 * High level IRQ handler called from shared_raw_irq_code_entry
510 */
511void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
512{
513  register unsigned int irq;
514  register unsigned isaIntr;                  /* boolean */
515  register unsigned oldMask = 0;              /* old isa pic masks */
516  register unsigned newMask;                  /* new isa pic masks */
517  register unsigned msr;
518  register unsigned new_msr;
519
520
521  if (excNum == ASM_DEC_VECTOR) {
522    _CPU_MSR_GET(msr);
523    new_msr = msr | MSR_EE;
524    _CPU_MSR_SET(new_msr);
525   
526    rtems_hdl_tbl[BSP_DECREMENTER].hdl();
527
528    _CPU_MSR_SET(msr);
529    return;
530   
531  }
532  irq = openpic_irq(0);
533  if (irq == OPENPIC_VEC_SPURIOUS) {
534    ++BSP_spuriousIntr;
535    return;
536  }
537  isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
538  if (isaIntr)  {
539    /*
540     * Acknowledge and read 8259 vector
541     */
542    irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG);
543    /*
544     * store current PIC mask
545     */
546    oldMask = i8259s_cache;
547    newMask = oldMask | irq_mask_or_tbl [irq];
548    i8259s_cache = newMask;
549    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
550    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
551    BSP_irq_ack_at_i8259s (irq);
552    openpic_eoi(0);
553  }
554  _CPU_MSR_GET(msr);
555  new_msr = msr | MSR_EE;
556  _CPU_MSR_SET(new_msr);
557   
558  /* rtems_hdl_tbl[irq].hdl(); */
559  {
560     rtems_irq_connect_data* vchain;
561     for( vchain = &rtems_hdl_tbl[irq];
562          ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
563          vchain = (rtems_irq_connect_data*)vchain->next_handler )
564     {
565        vchain->hdl();
566     }
567  }
568
569
570  _CPU_MSR_SET(msr);
571
572  if (isaIntr)  {
573    i8259s_cache = oldMask;
574    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
575    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
576  }
577  else {
578#ifdef BSP_PCI_VME_DRIVER_DOES_EOI
579        /* leave it to the VME bridge driver to do EOI, so
580     * it can re-enable the openpic while handling
581     * VME interrupts (-> VME priorities in software)
582         */
583        if (_BSP_vme_bridge_irq != irq)
584#endif
585                openpic_eoi(0);
586  }
587}
588   
589   
590 
591void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
592{
593  /*
594   * Process pending signals that have not already been
595   * processed by _Thread_Displatch. This happens quite
596   * unfrequently : the ISR must have posted an action
597   * to the current running thread.
598   */
599  if ( _Thread_Do_post_task_switch_extension ||
600       _Thread_Executing->do_post_task_switch_extension ) {
601    _Thread_Executing->do_post_task_switch_extension = FALSE;
602    _API_extensions_Run_postswitch();
603  }
604  /*
605   * I plan to process other thread related events here.
606   * This will include DEBUG session requested from keyboard...
607   */
608}
Note: See TracBrowser for help on using the repository browser.