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