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

Last change on this file since 3605c4e was 3605c4e, checked in by Jennifer Averett <Jennifer.Averett@…>, on 08/05/03 at 19:54:27

2003-08-05 Till Strauman <strauman@…>

PR 437/bsps

  • irq/irc.c: calls to bspIo/printk must not use '%i' format which is apparently not supported
  • pci/pci.c: calls to bspIo/printk must not use '%i' format which is apparently not supported
  • Property mode set to 100644
File size: 15.6 KB
RevLine 
[acc25ee]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 
[cd35cf9]14#include <rtems/system.h>
[acc25ee]15#include <bsp.h>
16#include <bsp/irq.h>
[e7625fc6]17#include <bsp/VME.h>
[acc25ee]18#include <bsp/openpic.h>
19#include <rtems/score/thread.h>
20#include <rtems/score/apiext.h>
21#include <libcpu/raw_exception.h>
[2742cc3]22#include <libcpu/io.h>
[acc25ee]23#include <bsp/vectors.h>
24
[69ed59f]25#include <rtems/bspIo.h> /* for printk */
[acc25ee]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{
[e7625fc6]91  int i;
92  int j;
[acc25ee]93  /*
94   * Always mask at least current interrupt to prevent re-entrance
95   */
[e7625fc6]96  for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) {
[acc25ee]97    * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
[e7625fc6]98    for (j = BSP_ISA_IRQ_LOWEST_OFFSET; j < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; j++) {
[acc25ee]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
[12838559]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)) {
[3605c4e]131      printk("Invalid interrupt vector %d\n",irq->name);
[12838559]132      return 0;
133    }
134    if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
[3605c4e]135      printk("IRQ vector %d already connected to an unshared handler\n",irq->name);
[12838559]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
[acc25ee]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)) {
[3605c4e]194      printk("Invalid interrupt vector %d\n",irq->name);
[acc25ee]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) {
[3605c4e]205      printk("IRQ vector %d already connected\n",irq->name);
[acc25ee]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;
[12838559]214    rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
[acc25ee]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{
[12838559]257   rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
[acc25ee]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
[12838559]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
[acc25ee]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     */
[12838559]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    }
[acc25ee]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
[e7625fc6]381    for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER; i++) {
[acc25ee]382      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
[12838559]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         }
[acc25ee]395      }
396      else {
[12838559]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);
[acc25ee]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++) {
[2742cc3]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]);
[acc25ee]423      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
[12838559]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
[acc25ee]436      }
437      else {
[12838559]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);
[acc25ee]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) {
[12838559]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
[acc25ee]472      }
473      else {
[12838559]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
[acc25ee]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
[a3ef256]497int _BSP_vme_bridge_irq = -1;
498 
[2d8eddea]499unsigned BSP_spuriousIntr = 0;
[acc25ee]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 */
[7657233d]507  register unsigned oldMask = 0;              /* old isa pic masks */
[acc25ee]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) {
[2742cc3]526    ++BSP_spuriousIntr;
[acc25ee]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   
[12838559]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
[acc25ee]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 {
[e7625fc6]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)
[69ed59f]574         */
[a3ef256]575        if (_BSP_vme_bridge_irq != irq)
[69ed59f]576#endif
577                openpic_eoi(0);
[acc25ee]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.