1 //
2 // interrupts.c - interrupts related constants and functions
3 //
4 // $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/interrupts.c#1 $
5
6 // Copyright (c) 2002-2004 Tensilica Inc.
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included
17 // in all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27 #include <xtensa/config/core.h>
28
29 #if XCHAL_HAVE_INTERRUPTS
30
31 /* For internal use by the HAL: */
32 // static void xthal_vpri_lock(void);
33 // static void xthal_vpri_unlock(void);
34 extern void xthal_vpri_lock(void);
35 extern void xthal_vpri_unlock(void);
36
37
38 /*
39 * Definitions:
40 *
41 * Virtual interrupt level = 0 .. 0xFF
42 *
43 * ...
44 */
45
46 #define XTHAL_DEFAULT_SOFTPRI 4 /* default software priority (range 0..15) */
47 /* IMPORTANT: if you change this, you also
48 need to update the initial resolvemap[]
49 value below... */
50
51 /*
52 * Macros to convert between:
53 * intlevel (0..15) and software priority within an intlevel (0..15)
54 * and
55 * virtual interrupt priority (0..0xFF), which is a combination of the above two.
56 */
57 #define XTHAL_VPRI_INTLEVEL(vpri) (((vpri) >> 4) & 0xF)
58 #define XTHAL_VPRI_SOFTPRI(vpri) ((vpri) & 0xF)
59 #define XTHAL_VPRI(intlevel,softpri) ((((intlevel)&0xF)<<4)|((softpri)&0xF))
60
61
62 /*
63 * Virtual priority management data structures.
64 * This structure is instantiated as Xthal_vpri_state (below).
65 *
66 * IMPORTANT: if you change anything in this structure,
67 * you must accordingly change structure offsets
68 * defined in int_asm.S .
69 *
70 * IMPORTANT: the worst-case offset of the resolvemap[] field is 976 bytes
71 * (0x10 + 0x40*15), which is accessed in int_asm.S at a further
72 * offset of 8*4==32 for a total offset of 1008, very close
73 * to l32i's offset limit of 1020. So you can't push it much
74 * further.
75 *
76 * [INTERNAL NOTE: There might be a trick that will save 64 bytes,
77 * if really needed, by trimming 15 word entries from the start
78 * of enablemap[] ... -MG]
79 */
80 typedef struct XtHalVPriState {
81 /*
82 * Current virtual interrupt priority (0x0F .. 0xFF)
83 * (or actually, 0x0F .. XCHAL_NUM_INTLEVELS*0x10+0x0F).
84 * Virtual priorities 0x00 to 0x0E are mapped to 0x0F (they're all
85 * equivalent, because there's no such thing as a level 0 interrupt),
86 * which may help optimize the size of enablemap[] in the future.
87 * Virtual priorities above XCHAL_NUM_INTLEVELS*0x10+0x0F are
88 * mapped to XCHAL_NUM_INTLEVELS*0x10+0x0F, which is equivalent.
89 *
90 * NOTE: this variable is actually part of the processor context,
91 * which means (for most OSes) that it must be saved
92 * in the task control block along with other register state.
93 */
94 unsigned char vpri; // current virtual interrupt priority (0x0F..0xFF)
95 unsigned char locklevel; // real interrupt level used to get exclusive
96 // access to this structure; MUST be at least one (1)
97 unsigned char lockvpri; // virtual interrupt level used to get exclusive
98 // access to this structure; MUST be XTHAL_VPRI(locklevel,15)
99 // (so it's at least 0x1F); placed here for efficiency
100 unsigned char pad0; // (alignment padding, unused)
101
102 unsigned enabled; // mask of which interrupts are enabled, regardless of level
103 // (level masking is applied on top of this)
104
105 unsigned lockmask; // (unused?) INTENABLE value used to lock out
106 // interrupts for exclusive access to this structure
107
108 unsigned pad1; // (alignment padding, unused)
109
110 /*
111 * For each virtual interrupt priority, this array provides the
112 * bitmask of interrupts of greater virtual priority
113 * (ie. the set of interrupts to enable at that virtual priority,
114 * if all interrupts were enabled in field 'enabled').
115 */
116 unsigned enablemap[XCHAL_NUM_INTLEVELS+1][16];
117
118 /*
119 * Table entries for intlevel 'i' are bitmasks defined as follows,
120 * with map == Xthal_vpri_resolvemap[i-1]:
121 * map[8+(x=0)] = ints at pri x + 8..15 (8-15)
122 * map[4+(x=0,8)] = ints at pri x + 4..7 (4-7,12-15)
123 * map[2+(x=0,4,8,12)] = ints at pri x + 2..3 (2-3,6-7,10-11,14-15)
124 * map[1+(x=0,2..12,14)] = ints at pri x + 1 (1,3,5,7,9,11,13,15)
125 * map[0] = 0 (unused; for alignment)
126 */
127 unsigned resolvemap[XCHAL_NUM_INTLEVELS][16];
128
129 } XtHalVPriState;
130
131
132 extern XtHalVPriState Xthal_vpri_state;
133 extern unsigned char Xthal_int_vpri[32];
134 extern XtHalVoidFunc * Xthal_tram_trigger_fn;
135
136 extern void xthal_null_func(void);
137
138 /* Shorthand for structure members: */
139 #define Xthal_vpri_level Xthal_vpri_state.vpri
140 #define Xthal_vpri_locklevel Xthal_vpri_state.locklevel
141 #define Xthal_vpri_lockvpri Xthal_vpri_state.lockvpri
142 #define Xthal_vpri_enabled Xthal_vpri_state.enabled
143 #define Xthal_vpri_lockmask Xthal_vpri_state.lockmask // unused?
144 #define Xthal_vpri_enablemap Xthal_vpri_state.enablemap
145 #define Xthal_vpri_resolvemap Xthal_vpri_state.resolvemap
146 #if 0
147 Combined refs:
148 - enablemap, vpri, enabled (xthal_set_vpri[_nw])
149 - enablemap, vpri, enabled, resolvemap (xthal_get_intpending_nw)
150 - enablemap, vpri, enabled, locklevel (xthal_vpri_lock)
151 - enablemap, vpri, enabled (xthal_vpri_unlock)
152 #endif
153
154 #endif /* XCHAL_HAVE_INTERRUPTS */
155
156
157
158
159 // the number of interrupt levels
160 const unsigned char Xthal_num_intlevels = XCHAL_NUM_INTLEVELS;
161
162
163
164 // the number of interrupts
165 const unsigned char Xthal_num_interrupts = XCHAL_NUM_INTERRUPTS;
166
167
168
169 // the highest level of interrupts masked by PS.EXCM (if XEA2)
170 const unsigned char Xthal_excm_level = XCHAL_EXCM_LEVEL;
171
172
173
174 // mask of interrupts at each intlevel
175 const unsigned Xthal_intlevel_mask[16] = {
176 XCHAL_INTLEVEL_MASKS
177 };
178
179
180
181 // mask for level 1 to N interrupts
182 const unsigned Xthal_intlevel_andbelow_mask[16] = {
183 XCHAL_INTLEVEL_ANDBELOW_MASKS
184 };
185
186
187
188 // level per interrupt
189 const unsigned char Xthal_intlevel[32] = {
190 XCHAL_INT_LEVELS
191 };
192
193
194
195 // type of each interrupt
196 const unsigned char Xthal_inttype[32] = {
197 XCHAL_INT_TYPES
198 };
199
200
201
202 const unsigned Xthal_inttype_mask[XTHAL_MAX_INTTYPES] = {
203 XCHAL_INTTYPE_MASKS
204 };
205
206
207
208 // interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3), -1 if unassigned
209 const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS] = {
210 XCHAL_TIMER_INTERRUPTS
211 };
212
213
214
215 #if XCHAL_HAVE_INTERRUPTS
216
217 /*
218 * Note: this structure changes dynamically at run-time,
219 * but is initialized here for efficiency and simplicity,
220 * according to configuration.
221 */
222 XtHalVPriState Xthal_vpri_state = {
223 0x00, /* vpri */
224 1, /* locklevel */
225 0x1F, /* lockvpri */
226 0, /* pad0 */
227 0x00000000, /* enabled */
228 0x00000000, /* lockmask (unused?) */
229 0, /* pad1 */
230
231 #define DEFAULT_ENABLEMAP(levela,levelb) \
232 { (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 0 ? levela : levelb)), \
233 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 1 ? levela : levelb)), \
234 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 2 ? levela : levelb)), \
235 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 3 ? levela : levelb)), \
236 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 4 ? levela : levelb)), \
237 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 5 ? levela : levelb)), \
238 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 6 ? levela : levelb)), \
239 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 7 ? levela : levelb)), \
240 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 8 ? levela : levelb)), \
241 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 9 ? levela : levelb)), \
242 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >10 ? levela : levelb)), \
243 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >11 ? levela : levelb)), \
244 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >12 ? levela : levelb)), \
245 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >13 ? levela : levelb)), \
246 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >14 ? levela : levelb)), \
247 (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >15 ? levela : levelb)) }
248
249 /* Xthal_vpri_enablemap[XCHAL_NUM_INTLEVELS+1][16]: */
250 {
251 DEFAULT_ENABLEMAP(XCHAL_INTLEVEL0_ANDBELOW_MASK,XCHAL_INTLEVEL0_ANDBELOW_MASK),
252 #if XCHAL_NUM_INTLEVELS >= 1
253 DEFAULT_ENABLEMAP(XCHAL_INTLEVEL0_ANDBELOW_MASK,XCHAL_INTLEVEL1_ANDBELOW_MASK),
254 #endif
255 #if XCHAL_NUM_INTLEVELS >= 2
256 DEFAULT_ENABLEMAP(XCHAL_INTLEVEL1_ANDBELOW_MASK,XCHAL_INTLEVEL2_ANDBELOW_MASK),
257 #endif
258 #if XCHAL_NUM_INTLEVELS >= 3
259 DEFAULT_ENABLEMAP(XCHAL_INTLEVEL2_ANDBELOW_MASK,XCHAL_INTLEVEL3_ANDBELOW_MASK),
260 #endif
261 #if XCHAL_NUM_INTLEVELS >= 4
262 DEFAULT_ENABLEMAP(XCHAL_INTLEVEL3_ANDBELOW_MASK,XCHAL_INTLEVEL4_ANDBELOW_MASK),
263 #endif
264 #if XCHAL_NUM_INTLEVELS >= 5
265 DEFAULT_ENABLEMAP(XCHAL_INTLEVEL4_ANDBELOW_MASK,XCHAL_INTLEVEL5_ANDBELOW_MASK),
266 #endif
267 #if XCHAL_NUM_INTLEVELS >= 6
268 DEFAULT_ENABLEMAP(XCHAL_INTLEVEL5_ANDBELOW_MASK,XCHAL_INTLEVEL6_ANDBELOW_MASK),
269 #endif
270 #if XCHAL_NUM_INTLEVELS >= 7
271 # error Interrupt levels greater than 6 not currently supported in the HAL interrupt routines.
272 #endif
273 },
274
275 /* Xthal_vpri_resolvemap[XCHAL_NUM_INTLEVELS][16]: */
276 {
277 #if XCHAL_NUM_INTLEVELS >= 1 /* set for default soft priority of 4: */
278 {0,0,0,0, XCHAL_INTLEVEL1_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
279 #endif
280 #if XCHAL_NUM_INTLEVELS >= 2 /* set for default soft priority of 4: */
281 {0,0,0,0, XCHAL_INTLEVEL2_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
282 #endif
283 #if XCHAL_NUM_INTLEVELS >= 3 /* set for default soft priority of 4: */
284 {0,0,0,0, XCHAL_INTLEVEL3_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
285 #endif
286 #if XCHAL_NUM_INTLEVELS >= 4 /* set for default soft priority of 4: */
287 {0,0,0,0, XCHAL_INTLEVEL4_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
288 #endif
289 #if XCHAL_NUM_INTLEVELS >= 5 /* set for default soft priority of 4: */
290 {0,0,0,0, XCHAL_INTLEVEL5_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
291 #endif
292 #if XCHAL_NUM_INTLEVELS >= 6 /* set for default soft priority of 4: */
293 {0,0,0,0, XCHAL_INTLEVEL6_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
294 #endif
295 #if XCHAL_NUM_INTLEVELS >= 7 /* set for default soft priority of 4: */
296 # error Interrupt levels greater than 6 not currently supported in the HAL interrupt routines.
297 #endif
298 }
299
300 };
301
302
303 /*
304 * Virtual (software) priority (0x00..0xFF) of each interrupt.
305 * This isn't referenced by assembler.
306 */
307 unsigned char Xthal_int_vpri[32] = {
308 #define DEFAULT_INTVPRI(level) (level ? ((level << 4) | XTHAL_DEFAULT_SOFTPRI) : 0)
309 DEFAULT_INTVPRI( XCHAL_INT0_LEVEL ),
310 DEFAULT_INTVPRI( XCHAL_INT1_LEVEL ),
311 DEFAULT_INTVPRI( XCHAL_INT2_LEVEL ),
312 DEFAULT_INTVPRI( XCHAL_INT3_LEVEL ),
313 DEFAULT_INTVPRI( XCHAL_INT4_LEVEL ),
314 DEFAULT_INTVPRI( XCHAL_INT5_LEVEL ),
315 DEFAULT_INTVPRI( XCHAL_INT6_LEVEL ),
316 DEFAULT_INTVPRI( XCHAL_INT7_LEVEL ),
317 DEFAULT_INTVPRI( XCHAL_INT8_LEVEL ),
318 DEFAULT_INTVPRI( XCHAL_INT9_LEVEL ),
319 DEFAULT_INTVPRI( XCHAL_INT10_LEVEL ),
320 DEFAULT_INTVPRI( XCHAL_INT11_LEVEL ),
321 DEFAULT_INTVPRI( XCHAL_INT12_LEVEL ),
322 DEFAULT_INTVPRI( XCHAL_INT13_LEVEL ),
323 DEFAULT_INTVPRI( XCHAL_INT14_LEVEL ),
324 DEFAULT_INTVPRI( XCHAL_INT15_LEVEL ),
325 DEFAULT_INTVPRI( XCHAL_INT16_LEVEL ),
326 DEFAULT_INTVPRI( XCHAL_INT17_LEVEL ),
327 DEFAULT_INTVPRI( XCHAL_INT18_LEVEL ),
328 DEFAULT_INTVPRI( XCHAL_INT19_LEVEL ),
329 DEFAULT_INTVPRI( XCHAL_INT20_LEVEL ),
330 DEFAULT_INTVPRI( XCHAL_INT21_LEVEL ),
331 DEFAULT_INTVPRI( XCHAL_INT22_LEVEL ),
332 DEFAULT_INTVPRI( XCHAL_INT23_LEVEL ),
333 DEFAULT_INTVPRI( XCHAL_INT24_LEVEL ),
334 DEFAULT_INTVPRI( XCHAL_INT25_LEVEL ),
335 DEFAULT_INTVPRI( XCHAL_INT26_LEVEL ),
336 DEFAULT_INTVPRI( XCHAL_INT27_LEVEL ),
337 DEFAULT_INTVPRI( XCHAL_INT28_LEVEL ),
338 DEFAULT_INTVPRI( XCHAL_INT29_LEVEL ),
339 DEFAULT_INTVPRI( XCHAL_INT30_LEVEL ),
340 DEFAULT_INTVPRI( XCHAL_INT31_LEVEL )
341 };
342
343
344 #if 0
345 /*
346 * A number of things may have already been written not calling
347 * this function, so it isn't straightforward to start requiring it:
348 */
349 void xthal_vpri_init( int default_vpri )
350 {
351 int i, j;
352
353 Xthal_vpri_level = 0; /* vpri */
354 Xthal_vpri_locklevel = 1; /* locklevel */
355 Xthal_vpri_lockvpri = 0x1F; /* lockvpri */
356 Xthal_vpri_enabled = 0x00000000; /* enabled */
357 Xthal_vpri_lockmask = 0x00000000; /* lockmask (unused?) */
358 for( i = 0; i < XCHAL_NUM_INTLEVELS; i++ ) {
359 for( j = 0; j < 16; j++ )
360 Xthal_vpri_enablemap[i][j] = XCHAL_INTLEVEL15_ANDBELOW_MASK
361 & ~Xthal_intlevel_andbelow_mask[i - (j < default_vpri && i > 0)];
362 }
363 for( i = 1; i < XCHAL_NUM_INTLEVELS; i++ ) {
364 for( j = 0; j < 16; j++ )
365 Xthal_vpri_resolvemap[i-1][j] = 0;
366 if( (default_vpri & 1) != 0 )
367 Xthal_vpri_resolvemap[i-1][default_vpri & 0xF] |= Xthal_intlevel_mask[i];
368 if( (default_vpri & 2) != 0 )
369 Xthal_vpri_resolvemap[i-1][default_vpri & 0xE] |= Xthal_intlevel_mask[i];
370 if( (default_vpri & 4) != 0 )
371 Xthal_vpri_resolvemap[i-1][default_vpri & 0xC] |= Xthal_intlevel_mask[i];
372 if( (default_vpri & 8) != 0 )
373 Xthal_vpri_resolvemap[i-1][default_vpri & 0x8] |= Xthal_intlevel_mask[i];
374 }
375 for( i = 0; i < 32; i++ )
376 Xthal_int_vpri[i] = (Xthal_intlevel[i] << 4) | (default_vpri & 0xF);
377 }
378 #endif /*0*/
379
xthal_null_func(void)380 void xthal_null_func(void) { }
381 XtHalVoidFunc *Xthal_tram_trigger_fn = xthal_null_func;
382
383
384 #endif /* XCHAL_HAVE_INTERRUPTS */
385
386
387
388 /*
389 * xthal_vpri_to_intlevel
390 *
391 * Converts a virtual interrupt priority to the closest equivalent
392 * (equal or higher) interrupt level.
393 */
xthal_vpri_to_intlevel(unsigned vpri)394 unsigned xthal_vpri_to_intlevel(unsigned vpri)
395 {
396 #if XCHAL_HAVE_INTERRUPTS
397 return( XTHAL_VPRI_INTLEVEL( vpri ) );
398 #else
399 return( vpri );
400 #endif
401 }
402
403
404
405 /*
406 * xthal_intlevel_to_vpri
407 *
408 * Converts an interrupt level to a virtual interrupt priority.
409 */
xthal_intlevel_to_vpri(unsigned intlevel)410 unsigned xthal_intlevel_to_vpri(unsigned intlevel)
411 {
412 #if XCHAL_HAVE_INTERRUPTS
413 return( XTHAL_VPRI( intlevel, 0xF ) );
414 #else
415 return( intlevel );
416 #endif
417 }
418
419
420
421 /*
422 * xthal_int_enable
423 *
424 * Enables given set of interrupts, and returns previous enabled-state of these interrupts.
425 */
xthal_int_enable(unsigned mask)426 unsigned xthal_int_enable(unsigned mask)
427 {
428 #if XCHAL_HAVE_INTERRUPTS
429 unsigned prev_enabled, syncmask;
430
431 xthal_vpri_lock();
432 prev_enabled = Xthal_vpri_enabled | Xthal_tram_enabled;
433
434 /* Figure out which bits must go in Xthal_tram_enabled: */
435 syncmask = (mask & Xthal_tram_pending & Xthal_tram_sync);
436 if( syncmask != 0 ) {
437 Xthal_tram_enabled |= syncmask;
438 mask &= ~syncmask;
439 /*
440 * If we are re-enabling a pending trampolined interrupt,
441 * there is a possibility that the level-1 software interrupt
442 * is no longer pending, having already occurred (without processing
443 * the trampoline because it was disabled). So we have to
444 * ensure that the level-1 software interrupt used for trampolining
445 * is pending.
446 * We let the BSP do this rather than the HAL, because it could
447 * potentially use an external level-1 interrupt to trampoline
448 * (if proper hardware was available) rather than a software interrupt.
449 */
450 (*Xthal_tram_trigger_fn)();
451 }
452 /* The rest go in the global enabled mask: */
453 Xthal_vpri_enabled |= mask;
454
455 xthal_vpri_unlock(); /* update INTENABLE as per current vpri */
456 return( prev_enabled );
457
458 #else /* XCHAL_HAVE_INTERRUPTS */
459 return( 0 );
460 #endif /* XCHAL_HAVE_INTERRUPTS */
461 }
462
463
464
465 /*
466 * xthal_int_disable
467 *
468 * Disables given set of interrupts, and returns previous enabled-state of these interrupts.
469 */
xthal_int_disable(unsigned mask)470 unsigned xthal_int_disable(unsigned mask)
471 {
472 #if XCHAL_HAVE_INTERRUPTS
473 unsigned prev_enabled;
474
475 xthal_vpri_lock();
476 prev_enabled = Xthal_vpri_enabled | Xthal_tram_enabled;
477 Xthal_vpri_enabled &= ~mask;
478 Xthal_tram_enabled &= ~mask;
479 xthal_vpri_unlock(); /* update INTENABLE as per current vpri */
480 return( prev_enabled );
481 #else
482 return( 0 );
483 #endif
484 }
485
486
487
xthal_set_vpri_locklevel(unsigned intlevel)488 void xthal_set_vpri_locklevel(unsigned intlevel)
489 {
490 #if XCHAL_HAVE_INTERRUPTS
491 if( intlevel < 1 )
492 intlevel = 1;
493 else if( intlevel > XCHAL_NUM_INTLEVELS )
494 intlevel = XCHAL_NUM_INTLEVELS;
495 Xthal_vpri_state.locklevel = intlevel;
496 Xthal_vpri_state.lockvpri = XTHAL_VPRI(intlevel, 15);
497 #endif
498 }
499
500
501
xthal_get_vpri_locklevel(void)502 unsigned xthal_get_vpri_locklevel(void)
503 {
504 #if XCHAL_HAVE_INTERRUPTS
505 return( Xthal_vpri_state.locklevel );
506 #else
507 return( 1 ); /* must return at least 1, some OSes assume this */
508 #endif
509 }
510
511
512
513 /*
514 * xthal_set_int_vpri (was intSetL1Pri)
515 *
516 * Set the virtual (software) priority of an interrupt.
517 * Note: the intlevel of an interrupt CANNOT be changed -- this is
518 * set in hardware according to the core configuration file.
519 *
520 * intnum interrupt number (0..31)
521 * vpri virtual interrupt priority (0..15, or intlevel*16+(0..15) )
522 */
xthal_set_int_vpri(int intnum,int vpri)523 int xthal_set_int_vpri(int intnum, int vpri)
524 {
525 #if XCHAL_HAVE_INTERRUPTS
526 unsigned mask, maskoff, basepri, prevpri, intlevel, *maskp, i;
527
528 /*
529 * Verify parameters:
530 */
531 if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS || (unsigned)vpri > 0xFF )
532 return( 0 ); /* error: bad parameter(s) */
533 /*
534 * If requested priority specifies an intlevel, it must match that
535 * of the interrupt specified; otherwise (0..15) the proper intlevel of
536 * the specified interrupt is assumed, and added to the parameter:
537 */
538 intlevel = Xthal_intlevel[intnum]; /* intnum's intlevel */
539 if( intlevel == 0 || intlevel > XCHAL_NUM_INTLEVELS )
540 return( 0 ); /* error: no support for setting priority of NMI etc. */
541 basepri = intlevel << 4; /* intnum's base soft-pri. */
542 if( vpri > 0x0F ) { /* intlevel portion given? */
543 if( (vpri & 0xF0) != basepri ) /* then it must be correct */
544 return( 0 ); /* error: intlevel mismatch */
545 vpri &= 0x0F; /* remove it */
546 }
547
548 mask = 1L << intnum;
549
550 /*
551 * Lock interrupts during virtual priority data structure updates:
552 */
553 xthal_vpri_lock();
554
555 /*
556 * Update virtual priority of 'intnum':
557 */
558 prevpri = Xthal_int_vpri[intnum]; /* save for return value */
559 Xthal_int_vpri[intnum] = basepri | vpri;
560 /* This interrupt must only be enabled at virtual priorities lower than its own: */
561 for( i = 0; i < vpri; i++ )
562 Xthal_vpri_enablemap[0][basepri++] |= mask;
563 maskoff = ~mask;
564 for( ; i <= 0x0F; i++ )
565 Xthal_vpri_enablemap[0][basepri++] &= maskoff;
566
567 /*
568 * Update the prioritization table used to resolve priorities by binary search:
569 */
570 /* Remove interrupt <intnum> from prioritization table: */
571 maskp = Xthal_vpri_resolvemap[intlevel-1];
572 for (i=0; i<16; i++)
573 maskp[i] &= maskoff;
574 /* Add interrupt <intnum> to prioritization table at its (new) given priority: */
575 if( vpri & 0x1 )
576 maskp[vpri] |= mask;
577 if( vpri & 0x2 )
578 maskp[vpri & 0xE] |= mask;
579 if( vpri & 0x4 )
580 maskp[vpri & 0xC] |= mask;
581 if( vpri & 0x8 )
582 maskp[vpri & 0x8] |= mask;
583
584 /*
585 * Unlock interrupts (back to current level) and update INTENABLE:
586 */
587 xthal_vpri_unlock();
588
589 return( prevpri );
590 #else /* XCHAL_HAVE_INTERRUPTS */
591 return( 0 );
592 #endif /* XCHAL_HAVE_INTERRUPTS */
593 } /* xthal_set_int_vpri */
594
595
596
xthal_get_int_vpri(int intnum)597 int xthal_get_int_vpri(int intnum)
598 {
599 #if XCHAL_HAVE_INTERRUPTS
600 if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS )
601 return( 0 ); /* error: bad parameter */
602 return( Xthal_int_vpri[intnum] );
603 #else
604 return( 0 );
605 #endif
606 }
607
608
609
610
611
612 /*
613 SUPPORT FOR TRAMPOLINES
614
615 NOTE: trampolining is a special case.
616 There are two ways (defined here) to trampoline down
617 from a high-level interrupt to a level-one interrupt.
618
619 a) Synchronous (restrained) trampolining.
620 Trampolining without clearing the high-level interrupt,
621 letting the level-one interrupt handler clear the
622 source of the interrupt.
623 Here the high-level interrupt must be kept disabled
624 while trampolining down, and re-enabled after the
625 level-one interrupt handler completes.
626 This is what one might do to "convert" a high-level
627 interrupt into a level-one interrupt.
628 The high-level interrupt handler code can be generic.
629 [One could argue this type of trampolining isn't required,
630 which may? be true...]
631 b) Asynchronous (free) trampolining.
632 Trampolining when clearing the high-level interrupt
633 right away in the high-level interrupt handler.
634 Here the high-level interrupt is allowed to remain
635 enabled while trampolining occurs. This is very
636 useful when some processing must occur with low
637 latency, but the rest of the processing can occur
638 at lower (eg. level-one) priority. It is particularly
639 useful when the lower-priority processing occurs
640 for only some of the high-level interrupts.
641 Of course this requires custom assembler code to
642 handle the high-level interrupt and clear the source
643 of the interrupt, so the high-level interrupt handler
644 cannot be generic (as opposed to synchronous trampolining).
645
646 In both cases, a level-one software interrupt is used
647 for trampolining (one could also trampoline from level
648 m to n, m > n, n > 1, but that isn't nearly as useful;
649 it's generally the ability to execute C code and
650 to process exceptions that is sought after).
651
652 Default trampolining support is currently implemented as follows.
653
654 Trampoline handler:
655
656 A high-level interrupt is considered enabled if *either*
657 its INTENABLE bit or its xt_tram_ints bit is set
658 (note that both should never be set at the same time).
659
660 */
661
662
663 /* These are described in xtensa/hal.h (assumed initialized to zero, in BSS): */
664 unsigned Xthal_tram_pending;
665 unsigned Xthal_tram_enabled;
666 unsigned Xthal_tram_sync;
667
668
669
xthal_set_tram_trigger_func(XtHalVoidFunc * trigger_fn)670 XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn )
671 {
672 #if XCHAL_HAVE_INTERRUPTS
673 XtHalVoidFunc *fn;
674
675 fn = Xthal_tram_trigger_fn;
676 Xthal_tram_trigger_fn = trigger_fn;
677 return( fn );
678 #else
679 (void)trigger_fn;
680 return( 0 );
681 #endif
682 }
683
684
685 /*
686 * xthal_tram_set_sync
687 *
688 * Configure type of trampoline for a high-level interrupt.
689 * By default any trampoline is asynchronous, this need only
690 * be called to tell the Core HAL that a high-level interrupt
691 * will be using synchronous trampolining (down to a level-1 interrupt).
692 *
693 * intnum interrupt number (0 .. 31)
694 * sync 0 = async, 1 = synchronous
695 *
696 * Returns previous sync state of interrupt (0 or 1)
697 * or -1 if invalid interrupt number provided.
698 */
xthal_tram_set_sync(int intnum,int sync)699 int xthal_tram_set_sync( int intnum, int sync )
700 {
701 #if XCHAL_HAVE_INTERRUPTS
702 unsigned mask;
703 int prev;
704
705 if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS )
706 return( -1 );
707 mask = 1L << intnum;
708 prev = ((Xthal_tram_sync & mask) != 0);
709 if( sync )
710 Xthal_tram_sync |= mask;
711 else
712 Xthal_tram_sync &= ~mask;
713 return( prev );
714 #else /* XCHAL_HAVE_INTERRUPTS */
715 return( 0 );
716 #endif /* XCHAL_HAVE_INTERRUPTS */
717 }
718
719
720 /*
721 * xthal_tram_pending_to_service
722 *
723 * This is called by the trampoline interrupt handler
724 * (eg. by a level-one software interrupt handler)
725 * to obtain the bitmask of high-level interrupts
726 * that it must service.
727 * Returns that bitmask (note: this can sometimes be zero,
728 * eg. if currently executing level-one code disables the high-level
729 * interrupt before the trampoline handler has a chance to run).
730 *
731 * This call automatically clears the trampoline pending
732 * bits for the interrupts in the returned mask.
733 * So the caller *must* process all interrupts that have
734 * a corresponding bit set if the value returned by this function
735 * (otherwise those interrupts may likely be lost).
736 *
737 * This function should be called with level-one interrupts disabled
738 * (via INTENABLE; can't be via PS.INTLEVEL because this is C code).
739 */
xthal_tram_pending_to_service(void)740 unsigned xthal_tram_pending_to_service( void )
741 {
742 #if XCHAL_HAVE_INTERRUPTS
743 unsigned service_mask;
744
745 service_mask = ( Xthal_tram_pending
746 & (Xthal_vpri_enabled | Xthal_tram_enabled) ) ;
747
748 /*
749 * Clear trampoline pending bits.
750 * Each bit must be cleared *before* processing of the corresponding
751 * interrupt occurs, to avoid missing interrupts.
752 * Here we just clear all bits for simplicity and convenience.
753 */
754 Xthal_tram_pending &= ~service_mask;
755
756 return( service_mask );
757 #else /* XCHAL_HAVE_INTERRUPTS */
758 return( 0 );
759 #endif /* XCHAL_HAVE_INTERRUPTS */
760 }
761
762 /*
763 * xthal_tram_done
764 *
765 * This is called by the trampoline interrupt handler
766 * (eg. by a level-one software interrupt handler)
767 * to indicate that processing of a trampolined interrupt
768 * (eg. one or more of the bits it received from
769 * xthal_tram_acknowledge()) has completed.
770 *
771 * For asynchronously trampolined interrupt(s), there is nothing to do.
772 * For synchronously trampolined interrupt(s), the high-level
773 * interrupt(s) must be re-enabled (presumably the level-one
774 * interrupt handler that just completed has cleared the source
775 * of the high-level interrupt).
776 *
777 * This function should be called with level-one interrupts disabled
778 * (via INTENABLE; can't be via PS.INTLEVEL because this is C code).
779 */
xthal_tram_done(unsigned serviced_mask)780 void xthal_tram_done( unsigned serviced_mask )
781 {
782 #if XCHAL_HAVE_INTERRUPTS
783 serviced_mask &= Xthal_tram_enabled; /* sync. trampolined interrupts that completed */
784 Xthal_tram_enabled &= ~serviced_mask;
785 xthal_int_enable( serviced_mask );
786 #endif
787 }
788
789
790
791
792 /**********************************************************************/
793
794 #ifdef INCLUDE_DEPRECATED_HAL_CODE
795 /* These definitions were present in an early beta version of the HAL and should not be used: */
796 const unsigned Xthal_num_int_levels = XCHAL_NUM_INTLEVELS;
797 const unsigned Xthal_num_ints = XCHAL_NUM_INTERRUPTS;
798 __asm__(".global Xthal_int_level_mask\n" ".set Xthal_int_level_mask, Xthal_intlevel_mask+4");
799 __asm__(".global Xthal_int_level1_to_n_mask\n" ".set Xthal_int_level1_to_n_mask, Xthal_intlevel_andbelow_mask+8");
800 /*const unsigned Xthal_int_level_mask[15] = { XCHAL_INTLEVEL_MASKS }; ... minus the first entry ...*/
801 /*const unsigned Xthal_int_level1_to_n_mask[14] = { XCHAL_INTLEVEL_ANDBELOW_MASKS }; ... minus the first two entries ...*/
802 const unsigned Xthal_int_level[32] = { XCHAL_INT_LEVELS };
803 const unsigned Xthal_int_type_edge = XCHAL_INTTYPE_MASK_EXTERN_EDGE;
804 const unsigned Xthal_int_type_level = XCHAL_INTTYPE_MASK_EXTERN_LEVEL;
805 const unsigned Xthal_int_type_timer = XCHAL_INTTYPE_MASK_TIMER;
806 const unsigned Xthal_int_type_software = XCHAL_INTTYPE_MASK_SOFTWARE;
807 #endif /* INCLUDE_DEPRECATED_HAL_CODE */
808
809
810
811