]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/kernel/v2_0/include/intr.hxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / kernel / v2_0 / include / intr.hxx
1 #ifndef CYGONCE_KERNEL_INTR_HXX
2 #define CYGONCE_KERNEL_INTR_HXX
3
4 //==========================================================================
5 //
6 //      intr.hxx
7 //
8 //      Interrupt class declaration(s)
9 //
10 //==========================================================================
11 //####ECOSGPLCOPYRIGHTBEGIN####
12 // -------------------------------------------
13 // This file is part of eCos, the Embedded Configurable Operating System.
14 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
15 //
16 // eCos is free software; you can redistribute it and/or modify it under
17 // the terms of the GNU General Public License as published by the Free
18 // Software Foundation; either version 2 or (at your option) any later version.
19 //
20 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
21 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 // for more details.
24 //
25 // You should have received a copy of the GNU General Public License along
26 // with eCos; if not, write to the Free Software Foundation, Inc.,
27 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 //
29 // As a special exception, if other files instantiate templates or use macros
30 // or inline functions from this file, or you compile this file and link it
31 // with other works to produce a work based on this file, this file does not
32 // by itself cause the resulting work to be covered by the GNU General Public
33 // License. However the source code for this file must still be made available
34 // in accordance with section (3) of the GNU General Public License.
35 //
36 // This exception does not invalidate any other reasons why a work based on
37 // this file might be covered by the GNU General Public License.
38 //
39 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
40 // at http://sources.redhat.com/ecos/ecos-license/
41 // -------------------------------------------
42 //####ECOSGPLCOPYRIGHTEND####
43 //==========================================================================
44 //#####DESCRIPTIONBEGIN####
45 //
46 // Author(s):   nickg
47 // Contributors:        nickg
48 // Date:        1997-09-09
49 // Purpose:     Define Interrupt class interfaces
50 // Description: The classes defined here provide the APIs for handling
51 //              interrupts.
52 // Usage:       #include "intr.hxx"
53 //              
54 //
55 //####DESCRIPTIONEND####
56 //
57 //==========================================================================
58
59 #include <cyg/kernel/ktypes.h>
60
61 #include <cyg/kernel/smp.hxx>
62
63 // -------------------------------------------------------------------------
64 // Default definitions
65
66 // Some HALs define the ISR table to be a different size to the number
67 // of ISR vectors. These HALs will define CYGNUM_HAL_ISR_TABLE_SIZE. All
68 // other HALs will have the table size equal to the number of vectors.
69
70 #ifndef CYGNUM_HAL_ISR_TABLE_SIZE
71 # define CYGNUM_HAL_ISR_TABLE_SIZE      CYGNUM_HAL_ISR_COUNT
72 #endif
73
74 // -------------------------------------------------------------------------
75 // Function prototype typedefs
76
77
78 // VSR = Vector Service Routine. This is the code attached directly to an
79 // interrupt vector. It is very architecture/platform specific and usually
80 // must be written in assembler.
81
82 typedef void  cyg_VSR();
83
84 // ISR = Interrupt Service Routine. This is called from the default
85 // VSR in response to an interrupt. It may access shared data but may
86 // not call kernel routines. The return value may be
87 // Cyg_Interrupt::HANDLED and/or Cyg_Interrupt::CALL_DSR.
88
89 typedef cyg_uint32 cyg_ISR(cyg_vector vector, CYG_ADDRWORD data);
90
91 // DSR = Deferred Service Routine. This is called if the ISR returns
92 // the Cyg_Interrupt::CALL_DSR bit. It is called at a "safe" point in
93 // the kernel where it may make calls on kernel routines. The count
94 // argument indicates how many times the ISR has asked for the DSR to
95 // be posted since the last time the DSR ran.
96
97 typedef void cyg_DSR(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data);
98
99 // -------------------------------------------------------------------------
100 // Include HAL definitions
101
102 class Cyg_Interrupt;
103
104 #include <cyg/hal/hal_arch.h>
105
106 #include <cyg/hal/hal_intr.h>
107
108 #ifndef HAL_INTERRUPT_STACK_CALL_PENDING_DSRS
109 #define HAL_INTERRUPT_STACK_CALL_PENDING_DSRS()    \
110       Cyg_Interrupt::call_pending_DSRs_inner()
111 #endif
112
113 externC void interrupt_end(
114     cyg_uint32          isr_ret,
115     Cyg_Interrupt       *intr,
116     HAL_SavedRegisters  *ctx
117     );
118
119 externC void cyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj );
120 externC void cyg_interrupt_call_pending_DSRs( void );
121
122 // -------------------------------------------------------------------------
123 // Interrupt class. This both represents each interrupt and provides a static
124 // interface for controlling the interrupt hardware.
125
126 class Cyg_Interrupt
127 {
128
129     friend class Cyg_Scheduler;
130     friend void interrupt_end( cyg_uint32,
131                                Cyg_Interrupt *,
132                                HAL_SavedRegisters *);
133     friend void cyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj );
134     friend void cyg_interrupt_call_pending_DSRs( void );
135     
136     cyg_vector          vector;         // Interrupt vector
137
138     cyg_priority        priority;       // Queuing priority
139     
140     cyg_ISR             *isr;           // Pointer to ISR
141
142     cyg_DSR             *dsr;           // Pointer to DSR
143
144     CYG_ADDRWORD        data;           // Data pointer
145
146
147     
148     // DSR handling interface called by the scheduler
149
150                                         // Check for pending DSRs
151     static cyg_bool     DSRs_pending();
152
153                                         // Call any pending DSRs
154     static void         call_pending_DSRs();
155     static void         call_pending_DSRs_inner();
156
157     // DSR handling interface called by the scheduler and HAL 
158     // interrupt arbiters.
159
160     void                post_dsr();     // Post the DSR for this interrupt
161
162
163     
164     // Data structures for handling DSR calls.  We implement two DSR
165     // handling mechanisms, a list based one and a table based
166     // one. The list based mechanism is safe with respect to temporary
167     // overloads and will not run out of resource. However it requires
168     // extra data per interrupt object, and interrupts must be turned
169     // off briefly when delivering the DSR. The table based mechanism
170     // does not need unnecessary interrupt switching, but may be prone
171     // to overflow on overload. However, since a correctly programmed
172     // real time application should not experience such a condition,
173     // the table based mechanism is more efficient for real use. The
174     // list based mechainsm is enabled by default since it is safer to
175     // use during development.
176
177 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
178     
179     static Cyg_Interrupt *dsr_table[CYGNUM_KERNEL_CPU_MAX]
180                                    [CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE]
181                                    CYGBLD_ANNOTATE_VARIABLE_INTR;
182
183     static cyg_ucount32 dsr_table_head[CYGNUM_KERNEL_CPU_MAX]
184                                       CYGBLD_ANNOTATE_VARIABLE_INTR;
185
186     static volatile cyg_ucount32 dsr_table_tail[CYGNUM_KERNEL_CPU_MAX]
187                                                CYGBLD_ANNOTATE_VARIABLE_INTR;
188
189 #endif
190 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
191
192     // Number of DSR posts made
193     volatile cyg_ucount32 dsr_count CYGBLD_ANNOTATE_VARIABLE_INTR; 
194
195     // next DSR in list
196     Cyg_Interrupt* volatile next_dsr CYGBLD_ANNOTATE_VARIABLE_INTR; 
197
198     // head of static list of pending DSRs
199     static Cyg_Interrupt* volatile dsr_list[CYGNUM_KERNEL_CPU_MAX]
200                                            CYGBLD_ANNOTATE_VARIABLE_INTR;
201
202 #  ifdef CYGSEM_KERNEL_INTERRUPTS_DSRS_LIST_FIFO
203     // tail of static list of pending DSRs
204     static Cyg_Interrupt* volatile dsr_list_tail[CYGNUM_KERNEL_CPU_MAX]
205                                            CYGBLD_ANNOTATE_VARIABLE_INTR;
206 #  endif
207
208 #endif  // defined  CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
209
210 #ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
211
212     // The default mechanism for handling interrupts is to attach just
213     // one Interrupt object to each vector. In some cases, and on some
214     // hardware, this is not possible, and each vector must carry a chain
215     // of interrupts.
216
217     Cyg_Interrupt       *next;          // Next Interrupt in list
218
219     // Chaining ISR inserted in HAL vector
220     static cyg_uint32 chain_isr(cyg_vector vector, CYG_ADDRWORD data);    
221
222     // Table of interrupt chains
223     static Cyg_Interrupt *chain_list[CYGNUM_HAL_ISR_TABLE_SIZE];
224     
225 #endif
226
227     // Interrupt disable data. Interrupt disable can be nested. On
228     // each CPU this is controlled by disable_counter[cpu]. When the
229     // counter is first incremented from zero to one, the
230     // interrupt_disable_spinlock is claimed using spin_intsave(), the
231     // original interrupt enable state being saved in
232     // interrupt_disable_state[cpu].  When the counter is decremented
233     // back to zero the spinlock is cleared using clear_intsave().
234
235     // The spinlock is necessary in SMP systems since a thread
236     // accessing data shared with an ISR may be scheduled on a
237     // different CPU to the one that handles the interrupt. So, merely
238     // blocking local interrupts would be ineffective. SMP aware
239     // device drivers should either use their own spinlocks to protect
240     // data, or use the API supported by this class, via
241     // cyg_drv_isr_lock()/_unlock(). Note that it now becomes
242     // essential that ISRs do this if they are to be SMP-compatible.
243
244     // In a single CPU system, this mechanism reduces to just
245     // disabling/enabling interrupts.
246
247     // Disable level counter. This counts the number of times
248     // interrupts have been disabled.
249     static volatile cyg_int32 disable_counter[CYGNUM_KERNEL_CPU_MAX]
250                                               CYGBLD_ANNOTATE_VARIABLE_INTR;
251
252     // Interrupt disable spinlock. This is claimed by any CPU that has
253     // disabled interrupts via the Cyg_Interrupt API.
254     static Cyg_SpinLock interrupt_disable_spinlock CYGBLD_ANNOTATE_VARIABLE_INTR;
255
256     // Saved interrupt state. When each CPU first disables interrupts
257     // the original state of the interrupts are saved here to be
258     // restored later.
259     static CYG_INTERRUPT_STATE interrupt_disable_state[CYGNUM_KERNEL_CPU_MAX]
260                                                        CYGBLD_ANNOTATE_VARIABLE_INTR;
261
262     
263 public:
264
265     Cyg_Interrupt                       // Initialize interrupt
266     (
267         cyg_vector      vector,         // Vector to attach to
268         cyg_priority    priority,       // Queue priority
269         CYG_ADDRWORD    data,           // Data pointer
270         cyg_ISR         *isr,           // Interrupt Service Routine
271         cyg_DSR         *dsr            // Deferred Service Routine
272         );
273
274     ~Cyg_Interrupt();
275         
276     // ISR return values
277     enum {
278         HANDLED  = 1,                   // Interrupt was handled
279         CALL_DSR = 2                    // Schedule DSR
280     };
281
282     // Interrupt management
283         
284     void        attach();               // Attach to vector
285
286
287     void        detach();               // Detach from vector
288         
289     
290     // Static Interrupt management functions
291
292     // Get the current service routine
293     static void get_vsr(cyg_vector vector, cyg_VSR **vsr);
294
295     // Install a vector service routine
296     static void set_vsr(
297         cyg_vector vector,              // hardware vector to replace
298         cyg_VSR *vsr,                   // my new service routine
299         cyg_VSR **old = NULL            // pointer to old vsr, if required
300         );
301
302
303     // Static interrupt masking functions
304
305     // Disable interrupts at the CPU
306     static void disable_interrupts();
307
308     // Re-enable CPU interrupts
309     static void enable_interrupts();
310
311     // Are interrupts enabled at the CPU?
312     static inline cyg_bool interrupts_enabled()
313     {
314         return (0 == disable_counter[CYG_KERNEL_CPU_THIS()]);
315     }
316     
317     // Get the vector for the following calls
318     inline cyg_vector get_vector() 
319     {
320         return vector;
321     }
322     
323     // Static PIC control functions
324     
325     // Mask a specific interrupt in a PIC
326     static void mask_interrupt(cyg_vector vector);
327     // The same but not interrupt safe
328     static void mask_interrupt_intunsafe(cyg_vector vector);
329
330     // Clear PIC mask
331     static void unmask_interrupt(cyg_vector vector);
332     // The same but not interrupt safe
333     static void unmask_interrupt_intunsafe(cyg_vector vector);
334
335     // Acknowledge interrupt at PIC
336     static void acknowledge_interrupt(cyg_vector vector);
337
338     // Change interrupt detection at PIC
339     static void configure_interrupt(
340         cyg_vector vector,              // vector to control
341         cyg_bool level,                 // level or edge triggered
342         cyg_bool up                     // hi/lo level, rising/falling edge
343         );
344
345 #ifdef CYGPKG_KERNEL_SMP_SUPPORT
346
347     // SMP support for associating an interrupt with a specific CPU.
348     
349     static void set_cpu( cyg_vector, HAL_SMP_CPU_TYPE cpu );
350     static HAL_SMP_CPU_TYPE get_cpu( cyg_vector );
351     
352 #endif    
353 };
354
355 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS
356 // -------------------------------------------------------------------------
357 // Check for pending DSRs
358
359 inline cyg_bool Cyg_Interrupt::DSRs_pending()
360 {
361     HAL_SMP_CPU_TYPE cpu = CYG_KERNEL_CPU_THIS();
362 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
363     
364     return dsr_table_head[cpu] != dsr_table_tail[cpu];
365
366 #endif
367 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
368     
369     return dsr_list[cpu] != NULL;
370
371 #endif
372 };
373 #endif // CYGIMP_KERNEL_INTERRUPTS_DSRS
374
375 // -------------------------------------------------------------------------
376 #endif // ifndef CYGONCE_KERNEL_INTR_HXX
377 // EOF intr.hxx