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

4.104.114.84.9
Last change on this file since ec1d0b9d was ec1d0b9d, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 12, 2007 at 3:16:36 PM

2007-09-12 Joel Sherrill <joel.sherrill@…>

PR 1257/bsps

  • irq/irq.c: Code outside of cpukit should use the public API for rtems_interrupt_disable/rtems_interrupt_enable. By bypassing the public API and directly accessing _CPU_ISR_Disable and _CPU_ISR_Enable, they were bypassing the compiler memory barrier directive which could lead to problems. This patch also changes the type of the variable passed into these routines and addresses minor style issues.
  • Property mode set to 100644
File size: 14.0 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    irq->on(irq);
158   
159    rtems_interrupt_enable(level);
160
161    return 1;
162}
163
164
165/*
166 * ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
167 */
168
169int BSP_install_rtems_irq_handler  (const rtems_irq_connect_data* irq)
170{
171    rtems_interrupt_level       level;
172
173    if (!isValidInterrupt(irq->name)) {
174      printk("Invalid interrupt vector %d\n",irq->name);
175      return 0;
176    }
177    /*
178     * Check if default handler is actually connected. If not issue an error.
179     * You must first get the current handler via i386_get_current_idt_entry
180     * and then disconnect it using i386_delete_idt_entry.
181     * RATIONALE : to always have the same transition by forcing the user
182     * to get the previous handler before accepting to disconnect.
183     */
184    rtems_interrupt_disable(level);
185    if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
186      rtems_interrupt_enable(level);
187      printk("IRQ vector %d already connected\n",irq->name);
188      return 0;
189    }
190
191    /*
192     * store the data provided by user
193     */
194    rtems_hdl_tbl[irq->name] = *irq;
195    rtems_hdl_tbl[irq->name].next_handler = (void *)-1;
196   
197    if (is_isa_irq(irq->name)) {
198      /*
199       * Enable interrupt at PIC level
200       */
201      BSP_irq_enable_at_i8259s (irq->name);
202    }
203   
204    if (is_pci_irq(irq->name)) {
205      /*
206       * Enable interrupt at OPENPIC level
207       */
208      openpic_enable_irq ((int) irq->name ); /* - BSP_PCI_IRQ_LOWEST_OFFSET); */
209    }
210
211    if (is_processor_irq(irq->name)) {
212      /*
213       * Enable exception at processor level
214       */
215    }
216    /*
217     * Enable interrupt on device
218     */
219    irq->on(irq);
220   
221    rtems_interrupt_enable(level);
222
223    return 1;
224}
225
226
227int BSP_get_current_rtems_irq_handler   (rtems_irq_connect_data* irq)
228{
229    rtems_interrupt_level       level;
230
231    if (!isValidInterrupt(irq->name)) {
232      return 0;
233    }
234    rtems_interrupt_disable(level);
235      *irq = rtems_hdl_tbl[irq->name];
236    rtems_interrupt_enable(level);
237    return 1;
238}
239
240int BSP_remove_rtems_irq_handler  (const rtems_irq_connect_data* irq)
241{
242    rtems_irq_connect_data *pchain= NULL, *vchain = NULL;
243    rtems_interrupt_level   level;
244 
245    if (!isValidInterrupt(irq->name)) {
246      return 0;
247    }
248    /*
249     * Check if default handler is actually connected. If not issue an error.
250     * You must first get the current handler via i386_get_current_idt_entry
251     * and then disconnect it using i386_delete_idt_entry.
252     * RATIONALE : to always have the same transition by forcing the user
253     * to get the previous handler before accepting to disconnect.
254     */
255    rtems_interrupt_disable(level);
256    if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
257      rtems_interrupt_enable(level);
258      return 0;
259    }
260
261    if( (int)rtems_hdl_tbl[irq->name].next_handler != -1 )
262    {
263       int found = 0;
264
265       for( (pchain= NULL, vchain = &rtems_hdl_tbl[irq->name]);
266            (vchain->hdl != default_rtems_entry.hdl);
267            (pchain= vchain, vchain = (rtems_irq_connect_data*)vchain->next_handler) )
268       {
269          if( vchain->hdl == irq->hdl )
270          {
271             found= -1; break;
272          }
273       }
274
275       if( !found )
276       {
277          rtems_interrupt_enable(level);
278          return 0;
279       }
280    }
281    else
282    {
283       if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) 
284       {
285          rtems_interrupt_enable(level);
286         return 0;
287       }
288    }
289
290    if (is_isa_irq(irq->name)) {
291      /*
292       * disable interrupt at PIC level
293       */
294      BSP_irq_disable_at_i8259s (irq->name);
295    }
296    if (is_pci_irq(irq->name)) {
297      /*
298       * disable interrupt at OPENPIC level
299       */
300      openpic_disable_irq ((int) irq->name ); 
301    }
302    if (is_processor_irq(irq->name)) {
303      /*
304       * disable exception at processor level
305       */
306    }   
307
308    /*
309     * Disable interrupt on device
310     */
311    irq->off(irq);
312
313    /*
314     * restore the default irq value
315     */
316    if( !vchain )
317    {
318       /* single handler vector... */
319       rtems_hdl_tbl[irq->name] = default_rtems_entry;
320    }
321    else
322    {
323       if( pchain )
324       {
325          /* non-first handler being removed */
326          pchain->next_handler = vchain->next_handler;
327       }
328       else
329       {
330          /* first handler isn't malloc'ed, so just overwrite it.  Since
331          the contents of vchain are being struct copied, vchain itself
332          goes away */
333          rtems_hdl_tbl[irq->name]= *vchain;
334       }
335       free(vchain);
336    }
337
338    rtems_interrupt_enable(level);
339
340    return 1;
341}
342
343/*
344 * ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
345 */
346
347int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
348{
349    int                    i;
350    rtems_interrupt_level  level;
351
352    /*
353     * Store various code accelerators
354     */
355    internal_config             = config;
356    default_rtems_entry         = config->defaultEntry;
357    rtems_hdl_tbl               = config->irqHdlTbl;
358    return 1; 
359
360    rtems_interrupt_disable(level);
361    /*
362     * set up internal tables used by rtems interrupt prologue
363     */
364    for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) {
365      /*
366       * Note that openpic_set_priority() sets the TASK priority of the PIC
367       */
368      openpic_set_source_priority(i, internal_config->irqPrioTbl[i]);
369      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
370         openpic_enable_irq ((int) i); 
371         {
372            rtems_irq_connect_data* vchain;
373            for( vchain = &rtems_hdl_tbl[i];
374                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); 
375                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
376            {
377               vchain->on(vchain);
378            }
379         }
380
381      }
382      else {
383         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
384         {
385            rtems_irq_connect_data* vchain;
386            for( vchain = &rtems_hdl_tbl[i];
387                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); 
388                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
389            {
390               vchain->off(vchain);
391            }
392         }
393         
394         openpic_disable_irq ((int) i ); 
395      }
396    }
397    /*
398     * Must enable PCI/ISA bridge IRQ
399     */
400    openpic_enable_irq (0);
401    /*
402     * finish with Processor exceptions handled like IRQ
403     */
404    for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
405      if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
406         /* rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); */
407         {
408            rtems_irq_connect_data* vchain;
409            for( vchain = &rtems_hdl_tbl[i];
410                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); 
411                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
412            {
413               vchain->on(vchain);
414            }
415         }
416
417      }
418      else {
419         /* rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); */
420         {
421            rtems_irq_connect_data* vchain;
422            for( vchain = &rtems_hdl_tbl[i];
423                 ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl); 
424                 vchain = (rtems_irq_connect_data*)vchain->next_handler )
425            {
426               vchain->off(vchain);
427            }
428         }
429
430      }
431    }
432    rtems_interrupt_enable(level);
433    return 1;
434}
435
436int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
437{
438    *config = internal_config;
439    return 0;
440}   
441
442int _BSP_vme_bridge_irq = -1;
443 
444unsigned BSP_spuriousIntr = 0;
445/*
446 * High level IRQ handler called from shared_raw_irq_code_entry
447 */
448void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
449{
450  register unsigned int irq;
451  register unsigned isaIntr;                  /* boolean */
452  register unsigned oldMask = 0;              /* old isa pic masks */
453  register unsigned newMask;                  /* new isa pic masks */
454  register unsigned msr;
455  register unsigned new_msr;
456
457  if (excNum == ASM_DEC_VECTOR) {
458    _CPU_MSR_GET(msr);
459    new_msr = msr | MSR_EE;
460    _CPU_MSR_SET(new_msr);
461   
462    rtems_hdl_tbl[BSP_DECREMENTER].hdl( rtems_hdl_tbl[BSP_DECREMENTER].handle );
463
464    _CPU_MSR_SET(msr);
465    return;
466   
467  }
468
469  irq = openpic_irq(0);
470
471  if (irq == OPENPIC_VEC_SPURIOUS) {
472    ++BSP_spuriousIntr;
473   return;
474  }
475
476  isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
477  if (isaIntr)  {
478    /*
479     * Acknowledge and read 8259 vector
480     */
481    irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG);
482    /*
483     * store current PIC mask
484     */
485    oldMask = i8259s_cache;
486    newMask = oldMask | irq_mask_or_tbl [irq];
487    i8259s_cache = newMask;
488    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
489    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
490    BSP_irq_ack_at_i8259s (irq);
491    openpic_eoi(0);
492  }
493
494  _CPU_MSR_GET(msr);
495  new_msr = msr | MSR_EE;
496  _CPU_MSR_SET(new_msr);
497
498  {
499     rtems_irq_connect_data* vchain;
500     irq -= 16;    /* Correct the vector for the 8240 */ 
501     for( vchain = &rtems_hdl_tbl[irq];
502          ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
503          vchain = (rtems_irq_connect_data*)vchain->next_handler )
504     {
505        vchain->hdl( vchain->handle );
506     }
507  }
508  _CPU_MSR_SET(msr);
509
510  if (isaIntr)  {
511    i8259s_cache = oldMask;
512    outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
513    outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
514  }
515  else {
516#ifdef BSP_PCI_VME_DRIVER_DOES_EOI
517        /* leave it to the VME bridge driver to do EOI, so
518     * it can re-enable the openpic while handling
519     * VME interrupts (-> VME priorities in software)
520         */
521        if (_BSP_vme_bridge_irq != irq)
522#endif
523                openpic_eoi(0);
524  }
525}
526   
527   
528 
529void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
530{
531  /*
532   * Process pending signals that have not already been
533   * processed by _Thread_Displatch. This happens quite
534   * unfrequently : the ISR must have posted an action
535   * to the current running thread.
536   */
537  if ( _Thread_Do_post_task_switch_extension ||
538       _Thread_Executing->do_post_task_switch_extension ) {
539    _Thread_Executing->do_post_task_switch_extension = FALSE;
540    _API_extensions_Run_postswitch();
541  }
542  /*
543   * I plan to process other thread related events here.
544   * This will include DEBUG session requested from keyboard...
545   */
546}
Note: See TracBrowser for help on using the repository browser.