|
0
|
1 //========================================================================== |
|
|
2 // |
|
|
3 // intr/intr.cxx |
|
|
4 // |
|
|
5 // Interrupt class implementations |
|
|
6 // |
|
|
7 //========================================================================== |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
|
25 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. |
|
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //####COPYRIGHTEND#### |
|
|
29 //========================================================================== |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
|
32 // Author(s): nickg |
|
|
33 // Contributors: nickg |
|
|
34 // Date: 1997-10-15 |
|
|
35 // Purpose: Interrupt class implementation |
|
|
36 // Description: This file contains the definitions of the interrupt |
|
|
37 // class. |
|
|
38 // |
|
|
39 //####DESCRIPTIONEND#### |
|
|
40 // |
|
|
41 //========================================================================== |
|
|
42 |
|
|
43 #include <pkgconf/kernel.h> |
|
|
44 |
|
|
45 #include <cyg/kernel/ktypes.h> // base kernel types |
|
|
46 #include <cyg/infra/cyg_trac.h> // tracing macros |
|
|
47 #include <cyg/infra/cyg_ass.h> // assertion macros |
|
|
48 #include <cyg/kernel/instrmnt.h> // instrumentation |
|
|
49 |
|
|
50 #include <cyg/kernel/intr.hxx> // our header |
|
|
51 |
|
|
52 #include <cyg/kernel/sched.hxx> // scheduler |
|
|
53 |
|
|
54 #include <cyg/kernel/sched.inl> |
|
|
55 |
|
|
56 // ------------------------------------------------------------------------- |
|
|
57 |
|
|
58 Cyg_Interrupt::Cyg_Interrupt( |
|
|
59 cyg_vector vec, // Vector to attach to |
|
|
60 cyg_priority pri, // Queue priority |
|
|
61 CYG_ADDRWORD d, // Data pointer |
|
|
62 cyg_ISR *ir, // Interrupt Service Routine |
|
|
63 cyg_DSR *dr // Deferred Service Routine |
|
|
64 ) |
|
|
65 { |
|
|
66 vector = vec; |
|
|
67 priority = pri; |
|
|
68 isr = ir; |
|
|
69 dsr = dr; |
|
|
70 data = d; |
|
|
71 |
|
|
72 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST |
|
|
73 |
|
|
74 dsr_count = 0; |
|
|
75 next_dsr = NULL; |
|
|
76 |
|
|
77 #endif |
|
|
78 |
|
|
79 #ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN |
|
|
80 |
|
|
81 next = NULL; |
|
|
82 |
|
|
83 #endif |
|
|
84 |
|
|
85 }; |
|
|
86 |
|
|
87 // ------------------------------------------------------------------------- |
|
|
88 |
|
|
89 Cyg_Interrupt::~Cyg_Interrupt() |
|
|
90 { |
|
|
91 detach(); |
|
|
92 }; |
|
|
93 |
|
|
94 // ------------------------------------------------------------------------- |
|
|
95 // DSR handling statics: |
|
|
96 |
|
|
97 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE |
|
|
98 |
|
|
99 Cyg_Interrupt *Cyg_Interrupt::dsr_table[CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE]; |
|
|
100 |
|
|
101 cyg_ucount32 Cyg_Interrupt::dsr_table_head = 0; |
|
|
102 |
|
|
103 cyg_ucount32 Cyg_Interrupt::dsr_table_tail = 0; |
|
|
104 |
|
|
105 #endif |
|
|
106 |
|
|
107 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST |
|
|
108 |
|
|
109 Cyg_Interrupt *Cyg_Interrupt::dsr_list = NULL; |
|
|
110 |
|
|
111 #endif |
|
|
112 |
|
|
113 // ------------------------------------------------------------------------- |
|
|
114 // Call any pending DSRs |
|
|
115 |
|
|
116 void Cyg_Interrupt::call_pending_DSRs() |
|
|
117 { |
|
|
118 // CYG_REPORT_FUNCTION(); |
|
|
119 |
|
|
120 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE |
|
|
121 |
|
|
122 while( dsr_table_head != dsr_table_tail ) |
|
|
123 { |
|
|
124 Cyg_Interrupt *intr = dsr_table[dsr_table_head]; |
|
|
125 |
|
|
126 dsr_table_head++; |
|
|
127 if( dsr_table_head >= CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE ) |
|
|
128 dsr_table_head = 0; |
|
|
129 |
|
|
130 CYG_INSTRUMENT_INTR(CALL_DSR, intr->vector, 0); |
|
|
131 |
|
|
132 intr->dsr( intr->vector, 1, (CYG_ADDRWORD)intr->data ); |
|
|
133 } |
|
|
134 |
|
|
135 #endif |
|
|
136 |
|
|
137 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST |
|
|
138 |
|
|
139 while( dsr_list != NULL ) |
|
|
140 { |
|
|
141 Cyg_Interrupt *intr; |
|
|
142 cyg_uint32 old_intr; |
|
|
143 cyg_count32 count; |
|
|
144 |
|
|
145 HAL_DISABLE_INTERRUPTS(old_intr); |
|
|
146 |
|
|
147 intr = dsr_list; |
|
|
148 dsr_list = intr->next_dsr; |
|
|
149 count = intr->dsr_count; |
|
|
150 intr->dsr_count = 0; |
|
|
151 |
|
|
152 HAL_RESTORE_INTERRUPTS(old_intr); |
|
|
153 |
|
|
154 intr->dsr( intr->vector, count, (CYG_ADDRWORD)intr->data ); |
|
|
155 |
|
|
156 } |
|
|
157 |
|
|
158 #endif |
|
|
159 |
|
|
160 }; |
|
|
161 |
|
|
162 // ------------------------------------------------------------------------- |
|
|
163 |
|
|
164 void Cyg_Interrupt::post_dsr() |
|
|
165 { |
|
|
166 // CYG_REPORT_FUNCTION(); |
|
|
167 |
|
|
168 CYG_INSTRUMENT_INTR(POST_DSR, vector, 0); |
|
|
169 |
|
|
170 cyg_uint32 old_intr; |
|
|
171 |
|
|
172 // We need to disable interrupts during this part to |
|
|
173 // guard against nested interrupts. |
|
|
174 |
|
|
175 HAL_DISABLE_INTERRUPTS(old_intr); |
|
|
176 |
|
|
177 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE |
|
|
178 |
|
|
179 dsr_table[dsr_table_tail++] = this; |
|
|
180 if( dsr_table_tail >= CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE ) |
|
|
181 dsr_table_tail = 0; |
|
|
182 |
|
|
183 #endif |
|
|
184 |
|
|
185 #ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST |
|
|
186 |
|
|
187 // Only add the interrupt to the dsr list if this is |
|
|
188 // the first DSR call. |
|
|
189 // At present DSRs are pushed onto the list and will be |
|
|
190 // called in reverse order. We do not define the order |
|
|
191 // in which DSRs are called, so this is acceptable. |
|
|
192 |
|
|
193 if( dsr_count++ == 0 ) |
|
|
194 { |
|
|
195 next_dsr = dsr_list; |
|
|
196 dsr_list = this; |
|
|
197 } |
|
|
198 |
|
|
199 #endif |
|
|
200 |
|
|
201 HAL_RESTORE_INTERRUPTS(old_intr); |
|
|
202 }; |
|
|
203 |
|
|
204 // ------------------------------------------------------------------------- |
|
|
205 |
|
|
206 externC void interrupt_end( |
|
|
207 cyg_uint32 isr_ret, |
|
|
208 Cyg_Interrupt *intr, |
|
|
209 HAL_SavedRegisters *regs |
|
|
210 ) |
|
|
211 { |
|
|
212 // CYG_REPORT_FUNCTION(); |
|
|
213 |
|
|
214 CYG_INSTRUMENT_INTR(END, intr->vector, isr_ret); |
|
|
215 |
|
|
216 #ifndef CYGIMP_KERNEL_INTERRUPTS_CHAIN |
|
|
217 |
|
|
218 // Only do this if we are in a non-chained configuration. |
|
|
219 // If we are chained, then chain_isr below will do the DSR |
|
|
220 // posting. |
|
|
221 |
|
|
222 if( isr_ret & 2 ) intr->post_dsr(); |
|
|
223 |
|
|
224 #endif |
|
|
225 |
|
|
226 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT |
|
|
227 |
|
|
228 // If we have GDB support enabled, and there is the possibility |
|
|
229 // that this thread will be context switched as a result of this |
|
|
230 // interrupt, then save the pointer to the saved thread context in |
|
|
231 // the thread object so that GDB can get a meaningful context to |
|
|
232 // look at. |
|
|
233 |
|
|
234 Cyg_Scheduler::get_current_thread()->set_saved_context(regs); |
|
|
235 |
|
|
236 #endif |
|
|
237 |
|
|
238 // Now unlock the scheduler, which may also call DSRs |
|
|
239 // and cause a thread switch to happen. |
|
|
240 |
|
|
241 Cyg_Scheduler::unlock(); |
|
|
242 |
|
|
243 #ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT |
|
|
244 |
|
|
245 Cyg_Scheduler::get_current_thread()->set_saved_context(0); |
|
|
246 |
|
|
247 #endif |
|
|
248 |
|
|
249 |
|
|
250 CYG_INSTRUMENT_INTR(RESTORE, intr->vector, 0); |
|
|
251 } |
|
|
252 |
|
|
253 // ------------------------------------------------------------------------- |
|
|
254 // Interrupt chaining statics. |
|
|
255 |
|
|
256 #ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN |
|
|
257 |
|
|
258 Cyg_Interrupt *Cyg_Interrupt::chain_list[CYG_ISR_COUNT]; |
|
|
259 |
|
|
260 #endif |
|
|
261 |
|
|
262 // ------------------------------------------------------------------------- |
|
|
263 // Chaining ISR inserted in HAL vector |
|
|
264 |
|
|
265 #ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN |
|
|
266 |
|
|
267 cyg_uint32 Cyg_Interrupt::chain_isr(cyg_vector vector, CYG_ADDRWORD data) |
|
|
268 { |
|
|
269 Cyg_Interrupt *p = *(Cyg_Interrupt **)data; |
|
|
270 |
|
|
271 CYG_INSTRUMENT_INTR(CHAIN_ISR, vector, 0); |
|
|
272 |
|
|
273 while( p != NULL ) |
|
|
274 { |
|
|
275 if( p->vector == vector ) |
|
|
276 { |
|
|
277 register cyg_uint32 isr_ret = p->isr(vector, p->data); |
|
|
278 |
|
|
279 if( isr_ret & 2 ) p->post_dsr(); |
|
|
280 |
|
|
281 if( isr_ret & 1 ) break; |
|
|
282 } |
|
|
283 |
|
|
284 p = p->next; |
|
|
285 } |
|
|
286 |
|
|
287 return 0; |
|
|
288 } |
|
|
289 |
|
|
290 #endif |
|
|
291 |
|
|
292 // ------------------------------------------------------------------------- |
|
|
293 // Attach an ISR to an interrupt vector. |
|
|
294 |
|
|
295 void Cyg_Interrupt::attach() |
|
|
296 { |
|
|
297 CYG_REPORT_FUNCTION(); |
|
|
298 |
|
|
299 CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector"); |
|
|
300 CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector"); |
|
|
301 |
|
|
302 CYG_INSTRUMENT_INTR(ATTACH, vector, 0); |
|
|
303 |
|
|
304 HAL_INTERRUPT_SET_LEVEL( vector, priority ); |
|
|
305 |
|
|
306 #ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN |
|
|
307 |
|
|
308 CYG_ASSERT( next == NULL , "Cyg_Interrupt already on a list"); |
|
|
309 |
|
|
310 cyg_uint32 index; |
|
|
311 |
|
|
312 HAL_TRANSLATE_VECTOR( vector, index ); |
|
|
313 |
|
|
314 if( chain_list[index] == NULL ) |
|
|
315 { |
|
|
316 // First Interrupt on this chain, just assign it and register |
|
|
317 // the chain_isr with the HAL. |
|
|
318 |
|
|
319 chain_list[index] = this; |
|
|
320 |
|
|
321 HAL_INTERRUPT_ATTACH( vector, chain_isr, &chain_list[index], NULL ); |
|
|
322 } |
|
|
323 else |
|
|
324 { |
|
|
325 // There are already interrupts chained, add this one into the |
|
|
326 // chain in priority order. |
|
|
327 |
|
|
328 Cyg_Interrupt **p = &chain_list[index]; |
|
|
329 |
|
|
330 while( *p != NULL ) |
|
|
331 { |
|
|
332 Cyg_Interrupt *n = *p; |
|
|
333 |
|
|
334 if( n->priority < priority ) break; |
|
|
335 |
|
|
336 p = &n->next; |
|
|
337 } |
|
|
338 next = *p; |
|
|
339 *p = this; |
|
|
340 } |
|
|
341 |
|
|
342 #else |
|
|
343 |
|
|
344 HAL_INTERRUPT_ATTACH( vector, isr, data, this ); |
|
|
345 |
|
|
346 #endif |
|
|
347 } |
|
|
348 |
|
|
349 // ------------------------------------------------------------------------- |
|
|
350 // Detach the ISR from the vector |
|
|
351 |
|
|
352 void Cyg_Interrupt::detach() |
|
|
353 { |
|
|
354 CYG_REPORT_FUNCTION(); |
|
|
355 |
|
|
356 CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector"); |
|
|
357 CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector"); |
|
|
358 |
|
|
359 CYG_INSTRUMENT_INTR(DETACH, vector, 0); |
|
|
360 |
|
|
361 #ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN |
|
|
362 |
|
|
363 // Remove the interrupt object from the vector chain. |
|
|
364 |
|
|
365 Cyg_Interrupt **p = &chain_list[vector]; |
|
|
366 |
|
|
367 while( *p != NULL ) |
|
|
368 { |
|
|
369 Cyg_Interrupt *n = *p; |
|
|
370 |
|
|
371 if( n == this ) |
|
|
372 { |
|
|
373 *p = next; |
|
|
374 break; |
|
|
375 } |
|
|
376 |
|
|
377 p = &n->next; |
|
|
378 } |
|
|
379 |
|
|
380 // If this was the last one, detach the vector. |
|
|
381 |
|
|
382 if( chain_list[vector] == NULL ) |
|
|
383 HAL_INTERRUPT_DETACH( vector, chain_isr ); |
|
|
384 |
|
|
385 #else |
|
|
386 |
|
|
387 HAL_INTERRUPT_DETACH( vector, isr ); |
|
|
388 |
|
|
389 #endif |
|
|
390 |
|
|
391 } |
|
|
392 |
|
|
393 // ------------------------------------------------------------------------- |
|
|
394 // Get the current service routine |
|
|
395 |
|
|
396 void Cyg_Interrupt::get_vsr(cyg_vector vector, cyg_VSR **vsr) |
|
|
397 { |
|
|
398 CYG_REPORT_FUNCTION(); |
|
|
399 |
|
|
400 CYG_ASSERT( vector >= CYG_VSR_MIN, "Invalid vector"); |
|
|
401 CYG_ASSERT( vector <= CYG_VSR_MAX, "Invalid vector"); |
|
|
402 |
|
|
403 HAL_VSR_GET( vector, vsr ); |
|
|
404 } |
|
|
405 |
|
|
406 // ------------------------------------------------------------------------- |
|
|
407 // Install a vector service routine |
|
|
408 |
|
|
409 void Cyg_Interrupt::set_vsr(cyg_vector vector, cyg_VSR *vsr, cyg_VSR **old) |
|
|
410 { |
|
|
411 CYG_REPORT_FUNCTION(); |
|
|
412 |
|
|
413 CYG_INSTRUMENT_INTR(SET_VSR, vector, vsr); |
|
|
414 |
|
|
415 CYG_ASSERT( vector >= CYG_VSR_MIN, "Invalid vector"); |
|
|
416 CYG_ASSERT( vector <= CYG_VSR_MAX, "Invalid vector"); |
|
|
417 |
|
|
418 CYG_INTERRUPT_STATE old_ints; |
|
|
419 |
|
|
420 HAL_DISABLE_INTERRUPTS(old_ints); |
|
|
421 |
|
|
422 HAL_VSR_SET( vector, vsr, old ); |
|
|
423 |
|
|
424 HAL_RESTORE_INTERRUPTS(old_ints); |
|
|
425 } |
|
|
426 |
|
|
427 // ------------------------------------------------------------------------- |
|
|
428 // Disable interrupts at the CPU |
|
|
429 |
|
|
430 |
|
|
431 void Cyg_Interrupt::disable_interrupts() |
|
|
432 { |
|
|
433 CYG_REPORT_FUNCTION(); |
|
|
434 |
|
|
435 CYG_INSTRUMENT_INTR(DISABLE, 0, 0); |
|
|
436 |
|
|
437 CYG_INTERRUPT_STATE dummy; |
|
|
438 |
|
|
439 HAL_DISABLE_INTERRUPTS(dummy); |
|
|
440 |
|
|
441 // Keep a disable level counter?? |
|
|
442 } |
|
|
443 |
|
|
444 |
|
|
445 // ------------------------------------------------------------------------- |
|
|
446 // Re-enable CPU interrupts |
|
|
447 |
|
|
448 void Cyg_Interrupt::enable_interrupts() |
|
|
449 { |
|
|
450 CYG_REPORT_FUNCTION(); |
|
|
451 |
|
|
452 CYG_INSTRUMENT_INTR(ENABLE, 0, 0); |
|
|
453 |
|
|
454 HAL_ENABLE_INTERRUPTS(); |
|
|
455 } |
|
|
456 |
|
|
457 // ------------------------------------------------------------------------- |
|
|
458 // Mask a specific interrupt in a PIC |
|
|
459 |
|
|
460 void Cyg_Interrupt::mask_interrupt(cyg_vector vector) |
|
|
461 { |
|
|
462 CYG_REPORT_FUNCTION(); |
|
|
463 |
|
|
464 CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector"); |
|
|
465 CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector"); |
|
|
466 |
|
|
467 CYG_INSTRUMENT_INTR(MASK, vector, 0); |
|
|
468 |
|
|
469 HAL_INTERRUPT_MASK( vector ) |
|
|
470 } |
|
|
471 |
|
|
472 // ------------------------------------------------------------------------- |
|
|
473 // Clear PIC mask |
|
|
474 |
|
|
475 void Cyg_Interrupt::unmask_interrupt(cyg_vector vector) |
|
|
476 { |
|
|
477 CYG_REPORT_FUNCTION(); |
|
|
478 |
|
|
479 CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector"); |
|
|
480 CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector"); |
|
|
481 |
|
|
482 CYG_INSTRUMENT_INTR(UNMASK, vector, 0); |
|
|
483 |
|
|
484 HAL_INTERRUPT_UNMASK( vector ); |
|
|
485 } |
|
|
486 |
|
|
487 |
|
|
488 // ------------------------------------------------------------------------- |
|
|
489 // Acknowledge interrupt at PIC |
|
|
490 |
|
|
491 void Cyg_Interrupt::acknowledge_interrupt(cyg_vector vector) |
|
|
492 { |
|
|
493 // CYG_REPORT_FUNCTION(); |
|
|
494 |
|
|
495 CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector"); |
|
|
496 CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector"); |
|
|
497 |
|
|
498 CYG_INSTRUMENT_INTR(ACK, vector, 0); |
|
|
499 |
|
|
500 HAL_INTERRUPT_ACKNOWLEDGE( vector ); |
|
|
501 } |
|
|
502 |
|
|
503 // ------------------------------------------------------------------------- |
|
|
504 // Change interrupt detection at PIC |
|
|
505 |
|
|
506 void Cyg_Interrupt::configure_interrupt( |
|
|
507 cyg_vector vector, // vector to control |
|
|
508 cyg_bool level, // level or edge triggered |
|
|
509 cyg_bool up // hi/lo level, rising/falling edge |
|
|
510 ) |
|
|
511 { |
|
|
512 CYG_REPORT_FUNCTION(); |
|
|
513 |
|
|
514 CYG_ASSERT( vector >= CYG_ISR_MIN, "Invalid vector"); |
|
|
515 CYG_ASSERT( vector <= CYG_ISR_MAX, "Invalid vector"); |
|
|
516 |
|
|
517 CYG_INSTRUMENT_INTR(CONFIGURE, vector, (level<<1)|up); |
|
|
518 |
|
|
519 HAL_INTERRUPT_CONFIGURE( vector, level, up ); |
|
|
520 } |
|
|
521 |
|
|
522 // ------------------------------------------------------------------------- |
|
|
523 // EOF intr/intr.cxx |