source: rtems/c/src/lib/libbsp/powerpc/ep1a/irq/irq.c @ a4722f82

4.104.114.9
Last change on this file since a4722f82 was a4722f82, checked in by Till Straumann <strauman@…>, on Nov 6, 2007 at 10:19:41 PM

2007-11-06 Till Straumann <strauman@…>

  • ep1a/irq/irq.c, gen5200/irq/irq.c, mbx8xx/irq/irq.c, mpc8260ads/irq/irq.c, mvme5500/irq/irq.c, psim/irq/irq.c, score603e/irq/irq.c, shared/irq/irq.c: test for non-NULL-ness before calling 'on'/'off' methods so that users don't have to provide no-ops if they don't want this feature.
  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 *
3 *  This file contains the implementation of the function described in irq.h
4 *
5 *  COPYRIGHT (c) 1989-1999.
6 *  On-Line Applications Research Corporation (OAR).
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.rtems.com/license/LICENSE.
11 *
12 *  $Id$
13 */
14 
15#include <rtems/system.h>
16#include <bsp.h>
17#include <bsp/irq.h>
18#include <bsp/VME.h>
19#include <bsp/openpic.h>
20#include <rtems/score/thread.h>
21#include <rtems/score/apiext.h>
22#include <libcpu/raw_exception.h>
23#include <libcpu/io.h>
24#include <bsp/vectors.h>
25#include <stdlib.h>
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 teh prioruty 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_number 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_number 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 Porcessor IRQ
72 */
73static inline int is_processor_irq(const rtems_irq_number irqLine)
74{
75  return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
76          ((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
77         );
78}
79
80
81/*
82 * ------------------------ RTEMS Irq helper functions ----------------
83 */
84 
85/*
86 * This function check that the value given for the irq line
87 * is valid.
88 */
89
90static int isValidInterrupt(int irq)
91{
92  if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET))
93    return 0;
94  return 1;
95}
96
97
98/*
99 * ------------------------ RTEMS Shared Irq Handler Mngt Routines ----------------
100 */
101int BSP_install_rtems_shared_irq_handler  (const rtems_irq_connect_data* irq)
102{
103    rtems_interrupt_level   level;
104    rtems_irq_connect_data* vchain;
105
106    if (!isValidInterrupt(irq->name)) {
107      printk("Invalid interrupt vector %d\n",irq->name);
108      return 0;
109    }
110    printk("Install Shared interrupt %d\n", irq->name);
111
112    rtems_interrupt_disable(level);
113
114    if ( (int)rtems_hdl_tbl[irq->name].next_handler  == -1 ) {
115      rtems_interrupt_enable(level);
116      printk("IRQ vector %d already connected to an unshared handler\n",irq->name);
117      return 0;
118    }
119
120     vchain = (rtems_irq_connect_data*)malloc(sizeof(rtems_irq_connect_data));
121
122    /* save off topmost handler */
123    vchain[0]= rtems_hdl_tbl[irq->name];
124   
125    /*
126     * store the data provided by user
127     */
128    rtems_hdl_tbl[irq->name] = *irq;
129
130    /* link chain to new topmost handler */
131    rtems_hdl_tbl[irq->name].next_handler = (void *)vchain;
132
133   
134    if (is_isa_irq(irq->name)) {
135      /*
136       * Enable interrupt at PIC level
137       */
138      BSP_irq_enable_at_i8259s (irq->name);
139    }
140   
141    if (is_pci_irq(irq->name)) {
142      /*
143       * Enable interrupt at OPENPIC level
144       */
145      printk(" openpic_enable_irq %d\n", (int)irq->name );
146      openpic_enable_irq ((int) irq->name );  /* - BSP_PCI_IRQ_LOWEST_OFFSET); */
147    }
148
149    if (is_processor_irq(irq->name)) {
150      /*
151       * Enable exception at processor level
152       */
153    }
154    /*
155     * Enable interrupt on device
156     */
157        if (irq->on)
158        irq->on(irq);
159   
160    rtems_interrupt_enable(level);
161
162    return 1;
163}
164
165
166/*
167 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
168 */
169
170int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
171{
172    rtems_interrupt_level       level;
173
174    if (!isValidInterrupt(irq->name)) {
175      printk("Invalid interrupt vector %d\n",irq->name);
176      return 0;
177    }
178    /*
179     * Check if default handler is actually connected. If not issue an error.
180     * You must first get the current handler via i386_get_current_idt_entry
181     * and then disconnect it using i386_delete_idt_entry.
182     * RATIONALE : to always have the same transition by forcing the user
183     * to get the previous handler before accepting to disconnect.
184     */
185    rtems_interrupt_disable(level);
186    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
187      rtems_interrupt_enable(level);
188      printk("IRQ vector %d already connected\n",irq->name);
189      return 0;
190    }
191
192    /*
193     * store the data provided by user
194     */
195    rtems_hdl_tbl[irq->name] = *irq;
196    rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
197   
198    if (is_isa_irq(irq->name)) {
199      /*
200       * Enable interrupt at PIC level
201       */
202      BSP_irq_enable_at_i8259s (irq->name);
203    }
204   
205    if (is_pci_irq(irq->name)) {
206      /*
207       * Enable interrupt at OPENPIC level
208       */
209      openpic_enable_irq ((int) irq->name ); /* - BSP_PCI_IRQ_LOWEST_OFFSET); */
210    }
211
212    if (is_processor_irq(irq->name)) {
213      /*
214       * Enable exception at processor level
215       */
216    }
217    /*
218     * Enable interrupt on device
219     */
220        if (irq->on)
221        irq->on(irq);
222   
223    rtems_interrupt_enable(level);
224
225    return 1;
226}
227
228
229int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
230{
231    rtems_interrupt_level       level;
232
233    if (!isValidInterrupt(irq->name)) {
234      return 0;
235    }
236    rtems_interrupt_disable(level);
237      *irq = rtems_hdl_tbl[irq->name];
238    rtems_interrupt_enable(level);
239    return 1;
240}
241
242int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
243{
244    rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
245    rtems_interrupt_level   level;
246 
247    if (!isValidInterrupt(irq->name)) {
248      return 0;
249    }
250    /*
251     * Check if default handler is actually connected. If not issue an error.
252     * You must first get the current handler via i386_get_current_idt_entry
253     * and then disconnect it using i386_delete_idt_entry.
254     * RATIONALE : to always have the same transition by forcing the user
255     * to get the previous handler before accepting to disconnect.
256     */
257    rtems_interrupt_disable(level);
258    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
259      rtems_interrupt_enable(level);
260      return 0;
261    }
262
263    if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 )
264    {
265       int found = 0;
266
267       for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
268            (vchain->hdl != default_rtems_entry.hdl);
269            (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) )
270       {
271          if( vchain->hdl == irq->hdl )
272          {
273             found= -1; break;
274          }
275       }
276
277       if( !found )
278       {
279          rtems_interrupt_enable(level);
280          return 0;
281       }
282    }
283    else
284    {
285       if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) 
286       {
287          rtems_interrupt_enable(level);
288         return 0;
289       }
290    }
291
292    if (is_isa_irq(irq->name)) {
293      /*
294       * disable interrupt at PIC level
295       */
296      BSP_irq_disable_at_i8259s (irq->name);
297    }
298    if (is_pci_irq(irq->name)) {
299      /*
300       * disable interrupt at OPENPIC level
301       */
302      openpic_disable_irq ((int) irq->name ); 
303    }
304    if (is_processor_irq(irq->name)) {
305      /*
306       * disable exception at processor level
307       */
308    }   
309
310    /*
311     * Disable interrupt on device
312     */
313        if (irq->off)
314        irq->off(irq);
315
316    /*
317     * restore the default irq value
318     */
319    if( !vchain )
320    {
321       /* single handler vector... */
322       rtems_hdl_tbl[irq->name] = default_rtems_entry;
323    }
324    else
325    {
326       if( pchain )
327       {
328          /* non-first handler being removed */
329          pchain->next_handler = vchain->next_handler;
330       }
331       else
332       {
333          /* first handler isn't malloc'ed, so just overwrite it.  Since
334          the contents of vchain are being struct copied, vchain itself
335          goes away */
336          rtems_hdl_tbl[irq->name]= *vchain;
337       }
338       free(vchain);
339    }
340
341    rtems_interrupt_enable(level);
342
343    return 1;
344}
345
346/*
347 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
348 */
349
350int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
351{
352    int                    i;
353    rtems_interrupt_level  level;
354
355    /*
356     * Store various code accelerators
357     */
358    internal_config             = config;
359    default_rtems_entry         = config->defaultEntry;
360    rtems_hdl_tbl               = config->irqHdlTbl;
361    return 1; 
362
363    rtems_interrupt_disable(level);
364    /*
365     * set up internal tables used by rtems interrupt prologue
366     */
367    for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) {
368      /*
369       * Note that openpic_set_priority() sets the TASK priority of the PIC
370       */
371      openpic_set_source_priority(i, internal_config->irqPrioTbl[i]);
372      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
373         openpic_enable_irq ((int) i); 
374         {
375            rtems_irq_connect_data* vchain;
376            for( vchain = &rtems_hdl_tbl[i];
377                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); 
378                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
379            {
380                          if(vchain->on)
381               vchain->on(vchain);
382            }
383         }
384
385      }
386      else {
387         /* if (rtems_hdl_tbl[i].off) rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
388         {
389            rtems_irq_connect_data* vchain;
390            for( vchain = &rtems_hdl_tbl[i];
391                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); 
392                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
393            {
394                          if (vchain->off)
395               vchain->off(vchain);
396            }
397         }
398         
399         openpic_disable_irq ((int) i ); 
400      }
401    }
402    /*
403     * Must enable PCI/ISA bridge IRQ
404     */
405    openpic_enable_irq (0);
406    /*
407     * finish with Processor exceptions handled like IRQ
408     */
409    for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
410      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
411         /* if (rtems_hdl_tbl[i].on) rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
412         {
413            rtems_irq_connect_data* vchain;
414            for( vchain = &rtems_hdl_tbl[i];
415                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); 
416                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
417            {
418                          if (vchain->on)
419               vchain->on(vchain);
420            }
421         }
422
423      }
424      else {
425         /* if (rtems_hdl_tbl[i].off) rtems_hdl_tbl[i].off(&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                          if (vchain->off)
433               vchain->off(vchain);
434            }
435         }
436
437      }
438    }
439    rtems_interrupt_enable(level);
440    return 1;
441}
442
443int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
444{
445    *config = internal_config;
446    return 0;
447}   
448
449int _BSP_vme_bridge_irq = -1;
450 
451unsigned BSP_spuriousIntr = 0;
452/*
453 * High level IRQ handler called from shared_raw_irq_code_entry
454 */
455void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
456{
457  register unsigned int irq;
458  register unsigned isaIntr;                  /* boolean */
459  register unsigned oldMask = 0;              /* old isa pic masks */
460  register unsigned newMask;                  /* new isa pic masks */
461  register unsigned msr;
462  register unsigned new_msr;
463
464  if (excNum == ASM_DEC_VECTOR) {
465    _CPU_MSR_GET(msr);
466    new_msr = msr | MSR_EE;
467    _CPU_MSR_SET(new_msr);
468   
469    rtems_hdl_tbl[BSP_DECREMENTER].hdl( rtems_hdl_tbl[BSP_DECREMENTER].handle );
470
471    _CPU_MSR_SET(msr);
472    return;
473   
474  }
475
476  irq = openpic_irq(0);
477
478  if (irq == OPENPIC_VEC_SPURIOUS) {
479    ++BSP_spuriousIntr;
480   return;
481  }
482
483  isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
484  if (isaIntr)  {
485    /*
486     * Acknowledge and read 8259 vector
487     */
488    irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG);
489    /*
490     * store current PIC mask
491     */
492    oldMask = i8259s_cache;
493    newMask = oldMask | irq_mask_or_tbl [irq];
494    i8259s_cache = newMask;
495    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
496    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
497    BSP_irq_ack_at_i8259s (irq);
498    openpic_eoi(0);
499  }
500
501  _CPU_MSR_GET(msr);
502  new_msr = msr | MSR_EE;
503  _CPU_MSR_SET(new_msr);
504
505  {
506     rtems_irq_connect_data* vchain;
507     irq -= 16;    /* Correct the vector for the 8240 */ 
508     for( vchain = &rtems_hdl_tbl[irq];
509          ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
510          vchain = (rtems_irq_connect_data*)vchain->next_handler )
511     {
512        vchain->hdl( vchain->handle );
513     }
514  }
515  _CPU_MSR_SET(msr);
516
517  if (isaIntr)  {
518    i8259s_cache = oldMask;
519    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
520    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
521  }
522  else {
523#ifdef BSP_PCI_VME_DRIVER_DOES_EOI
524        /* leave it to the VME bridge driver to do EOI, so
525     * it can re-enable the openpic while handling
526     * VME interrupts (-> VME priorities in software)
527         */
528        if (_BSP_vme_bridge_irq != irq)
529#endif
530                openpic_eoi(0);
531  }
532}
533   
534   
535 
536void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
537{
538  /*
539   * Process pending signals that have not already been
540   * processed by _Thread_Displatch. This happens quite
541   * unfrequently : the ISR must have posted an action
542   * to the current running thread.
543   */
544  if ( _Thread_Do_post_task_switch_extension ||
545       _Thread_Executing->do_post_task_switch_extension ) {
546    _Thread_Executing->do_post_task_switch_extension = FALSE;
547    _API_extensions_Run_postswitch();
548  }
549  /*
550   * I plan to process other thread related events here.
551   * This will include DEBUG session requested from keyboard...
552   */
553}
Note: See TracBrowser for help on using the repository browser.