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 #if   defined(__SPLIT__num_intlevels)
159 
160 // the number of interrupt levels
161 const unsigned char Xthal_num_intlevels = XCHAL_NUM_INTLEVELS;
162 
163 #endif
164 
165 #if defined(__SPLIT__num_interrupts)
166 
167 // the number of interrupts
168 const unsigned char Xthal_num_interrupts = XCHAL_NUM_INTERRUPTS;
169 
170 #endif
171 
172 #if defined(__SPLIT__excm_level)
173 
174 // the highest level of interrupts masked by PS.EXCM (if XEA2)
175 const unsigned char Xthal_excm_level = XCHAL_EXCM_LEVEL;
176 
177 #endif
178 
179 #if defined(__SPLIT__intlevel_mask)
180 
181 // mask of interrupts at each intlevel
182 const unsigned Xthal_intlevel_mask[16] = {
183     XCHAL_INTLEVEL_MASKS
184 };
185 
186 #endif
187 
188 #if defined(__SPLIT__intlevel_andbelow_mask)
189 
190 // mask for level 1 to N interrupts
191 const unsigned Xthal_intlevel_andbelow_mask[16] = {
192     XCHAL_INTLEVEL_ANDBELOW_MASKS
193 };
194 
195 #endif
196 
197 #if defined(__SPLIT__intlevel)
198 
199 // level per interrupt
200 const unsigned char Xthal_intlevel[32] = {
201     XCHAL_INT_LEVELS
202 };
203 
204 #endif
205 
206 #if defined(__SPLIT__inttype)
207 
208 // type of each interrupt
209 const unsigned char Xthal_inttype[32] = {
210     XCHAL_INT_TYPES
211 };
212 
213 #endif
214 
215 #if defined(__SPLIT__inttype_mask)
216 
217 const unsigned Xthal_inttype_mask[XTHAL_MAX_INTTYPES] = {
218     XCHAL_INTTYPE_MASKS
219 };
220 
221 #endif
222 
223 #if defined(__SPLIT__timer_interrupt)
224 
225 // interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3), -1 if unassigned
226 const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS] = {
227     XCHAL_TIMER_INTERRUPTS
228 };
229 
230 #endif
231 
232 #if defined(__SPLIT__vpri)
233 
234 #if XCHAL_HAVE_INTERRUPTS
235 
236 /*
237  *  Note:  this structure changes dynamically at run-time,
238  *  but is initialized here for efficiency and simplicity,
239  *  according to configuration.
240  */
241 XtHalVPriState  Xthal_vpri_state = {
242     0x00,	/* vpri */
243     1,		/* locklevel */
244     0x1F,	/* lockvpri */
245     0,		/* pad0 */
246     0x00000000,	/* enabled */
247     0x00000000,	/* lockmask (unused?) */
248     0,		/* pad1 */
249 
250 #define DEFAULT_ENABLEMAP(levela,levelb)	\
251      { (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 0 ? levela : levelb)), \
252        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 1 ? levela : levelb)), \
253        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 2 ? levela : levelb)), \
254        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 3 ? levela : levelb)), \
255        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 4 ? levela : levelb)), \
256        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 5 ? levela : levelb)), \
257        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 6 ? levela : levelb)), \
258        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 7 ? levela : levelb)), \
259        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 8 ? levela : levelb)), \
260        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI > 9 ? levela : levelb)), \
261        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >10 ? levela : levelb)), \
262        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >11 ? levela : levelb)), \
263        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >12 ? levela : levelb)), \
264        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >13 ? levela : levelb)), \
265        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >14 ? levela : levelb)), \
266        (XCHAL_INTLEVEL15_ANDBELOW_MASK & ~(XTHAL_DEFAULT_SOFTPRI >15 ? levela : levelb)) }
267 
268     /*  Xthal_vpri_enablemap[XCHAL_NUM_INTLEVELS+1][16]:  */
269     {
270 	DEFAULT_ENABLEMAP(XCHAL_INTLEVEL0_ANDBELOW_MASK,XCHAL_INTLEVEL0_ANDBELOW_MASK),
271 #if XCHAL_NUM_INTLEVELS >= 1
272 	DEFAULT_ENABLEMAP(XCHAL_INTLEVEL0_ANDBELOW_MASK,XCHAL_INTLEVEL1_ANDBELOW_MASK),
273 #endif
274 #if XCHAL_NUM_INTLEVELS >= 2
275 	DEFAULT_ENABLEMAP(XCHAL_INTLEVEL1_ANDBELOW_MASK,XCHAL_INTLEVEL2_ANDBELOW_MASK),
276 #endif
277 #if XCHAL_NUM_INTLEVELS >= 3
278 	DEFAULT_ENABLEMAP(XCHAL_INTLEVEL2_ANDBELOW_MASK,XCHAL_INTLEVEL3_ANDBELOW_MASK),
279 #endif
280 #if XCHAL_NUM_INTLEVELS >= 4
281 	DEFAULT_ENABLEMAP(XCHAL_INTLEVEL3_ANDBELOW_MASK,XCHAL_INTLEVEL4_ANDBELOW_MASK),
282 #endif
283 #if XCHAL_NUM_INTLEVELS >= 5
284 	DEFAULT_ENABLEMAP(XCHAL_INTLEVEL4_ANDBELOW_MASK,XCHAL_INTLEVEL5_ANDBELOW_MASK),
285 #endif
286 #if XCHAL_NUM_INTLEVELS >= 6
287 	DEFAULT_ENABLEMAP(XCHAL_INTLEVEL5_ANDBELOW_MASK,XCHAL_INTLEVEL6_ANDBELOW_MASK),
288 #endif
289 #if XCHAL_NUM_INTLEVELS >= 7
290 # error	Interrupt levels greater than 6 not currently supported in the HAL interrupt routines.
291 #endif
292     },
293 
294     /*  Xthal_vpri_resolvemap[XCHAL_NUM_INTLEVELS][16]:  */
295     {
296 #if XCHAL_NUM_INTLEVELS >= 1	/* set for default soft priority of 4: */
297      {0,0,0,0, XCHAL_INTLEVEL1_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
298 #endif
299 #if XCHAL_NUM_INTLEVELS >= 2	/* set for default soft priority of 4: */
300      {0,0,0,0, XCHAL_INTLEVEL2_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
301 #endif
302 #if XCHAL_NUM_INTLEVELS >= 3	/* set for default soft priority of 4: */
303      {0,0,0,0, XCHAL_INTLEVEL3_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
304 #endif
305 #if XCHAL_NUM_INTLEVELS >= 4	/* set for default soft priority of 4: */
306      {0,0,0,0, XCHAL_INTLEVEL4_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
307 #endif
308 #if XCHAL_NUM_INTLEVELS >= 5	/* set for default soft priority of 4: */
309      {0,0,0,0, XCHAL_INTLEVEL5_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
310 #endif
311 #if XCHAL_NUM_INTLEVELS >= 6	/* set for default soft priority of 4: */
312      {0,0,0,0, XCHAL_INTLEVEL6_MASK,0,0,0, 0,0,0,0, 0,0,0,0},
313 #endif
314 #if XCHAL_NUM_INTLEVELS >= 7	/* set for default soft priority of 4: */
315 # error	Interrupt levels greater than 6 not currently supported in the HAL interrupt routines.
316 #endif
317     }
318 
319 };
320 
321 
322 /*
323  *  Virtual (software) priority (0x00..0xFF) of each interrupt.
324  *  This isn't referenced by assembler.
325  */
326 unsigned char	Xthal_int_vpri[32] = {
327 #define DEFAULT_INTVPRI(level)	(level ? ((level << 4) | XTHAL_DEFAULT_SOFTPRI) : 0)
328     DEFAULT_INTVPRI( XCHAL_INT0_LEVEL ),
329     DEFAULT_INTVPRI( XCHAL_INT1_LEVEL ),
330     DEFAULT_INTVPRI( XCHAL_INT2_LEVEL ),
331     DEFAULT_INTVPRI( XCHAL_INT3_LEVEL ),
332     DEFAULT_INTVPRI( XCHAL_INT4_LEVEL ),
333     DEFAULT_INTVPRI( XCHAL_INT5_LEVEL ),
334     DEFAULT_INTVPRI( XCHAL_INT6_LEVEL ),
335     DEFAULT_INTVPRI( XCHAL_INT7_LEVEL ),
336     DEFAULT_INTVPRI( XCHAL_INT8_LEVEL ),
337     DEFAULT_INTVPRI( XCHAL_INT9_LEVEL ),
338     DEFAULT_INTVPRI( XCHAL_INT10_LEVEL ),
339     DEFAULT_INTVPRI( XCHAL_INT11_LEVEL ),
340     DEFAULT_INTVPRI( XCHAL_INT12_LEVEL ),
341     DEFAULT_INTVPRI( XCHAL_INT13_LEVEL ),
342     DEFAULT_INTVPRI( XCHAL_INT14_LEVEL ),
343     DEFAULT_INTVPRI( XCHAL_INT15_LEVEL ),
344     DEFAULT_INTVPRI( XCHAL_INT16_LEVEL ),
345     DEFAULT_INTVPRI( XCHAL_INT17_LEVEL ),
346     DEFAULT_INTVPRI( XCHAL_INT18_LEVEL ),
347     DEFAULT_INTVPRI( XCHAL_INT19_LEVEL ),
348     DEFAULT_INTVPRI( XCHAL_INT20_LEVEL ),
349     DEFAULT_INTVPRI( XCHAL_INT21_LEVEL ),
350     DEFAULT_INTVPRI( XCHAL_INT22_LEVEL ),
351     DEFAULT_INTVPRI( XCHAL_INT23_LEVEL ),
352     DEFAULT_INTVPRI( XCHAL_INT24_LEVEL ),
353     DEFAULT_INTVPRI( XCHAL_INT25_LEVEL ),
354     DEFAULT_INTVPRI( XCHAL_INT26_LEVEL ),
355     DEFAULT_INTVPRI( XCHAL_INT27_LEVEL ),
356     DEFAULT_INTVPRI( XCHAL_INT28_LEVEL ),
357     DEFAULT_INTVPRI( XCHAL_INT29_LEVEL ),
358     DEFAULT_INTVPRI( XCHAL_INT30_LEVEL ),
359     DEFAULT_INTVPRI( XCHAL_INT31_LEVEL )
360 };
361 
362 
363 #if 0
364 /*
365  *  A number of things may have already been written not calling
366  *  this function, so it isn't straightforward to start requiring it:
367  */
368 void xthal_vpri_init( int default_vpri )
369 {
370     int i, j;
371 
372     Xthal_vpri_level = 0;		/* vpri */
373     Xthal_vpri_locklevel = 1;		/* locklevel */
374     Xthal_vpri_lockvpri = 0x1F;		/* lockvpri */
375     Xthal_vpri_enabled = 0x00000000;	/* enabled */
376     Xthal_vpri_lockmask = 0x00000000;	/* lockmask (unused?) */
377     for( i = 0; i < XCHAL_NUM_INTLEVELS; i++ ) {
378 	for( j = 0; j < 16; j++ )
379 	    Xthal_vpri_enablemap[i][j] = XCHAL_INTLEVEL15_ANDBELOW_MASK
380 		    & ~Xthal_intlevel_andbelow_mask[i - (j < default_vpri && i > 0)];
381     }
382     for( i = 1; i < XCHAL_NUM_INTLEVELS; i++ ) {
383 	for( j = 0; j < 16; j++ )
384 	    Xthal_vpri_resolvemap[i-1][j] = 0;
385 	if( (default_vpri & 1) != 0 )
386 	    Xthal_vpri_resolvemap[i-1][default_vpri & 0xF] |= Xthal_intlevel_mask[i];
387 	if( (default_vpri & 2) != 0 )
388 	    Xthal_vpri_resolvemap[i-1][default_vpri & 0xE] |= Xthal_intlevel_mask[i];
389 	if( (default_vpri & 4) != 0 )
390 	    Xthal_vpri_resolvemap[i-1][default_vpri & 0xC] |= Xthal_intlevel_mask[i];
391 	if( (default_vpri & 8) != 0 )
392 	    Xthal_vpri_resolvemap[i-1][default_vpri & 0x8] |= Xthal_intlevel_mask[i];
393     }
394     for( i = 0; i < 32; i++ )
395 	Xthal_int_vpri[i] = (Xthal_intlevel[i] << 4) | (default_vpri & 0xF);
396 }
397 #endif /*0*/
398 
xthal_null_func(void)399 void xthal_null_func(void) { }
400 XtHalVoidFunc *Xthal_tram_trigger_fn = xthal_null_func;
401 
402 
403 #endif /* XCHAL_HAVE_INTERRUPTS */
404 
405 #endif
406 
407 #if defined(__SPLIT__vpri_to_intlevel)
408 
409 /*
410  *  xthal_vpri_to_intlevel
411  *
412  *  Converts a virtual interrupt priority to the closest equivalent
413  *  (equal or higher) interrupt level.
414  */
xthal_vpri_to_intlevel(unsigned vpri)415 unsigned xthal_vpri_to_intlevel(unsigned vpri)
416 {
417 #if XCHAL_HAVE_INTERRUPTS
418     return( XTHAL_VPRI_INTLEVEL( vpri ) );
419 #else
420     return( vpri );
421 #endif
422 }
423 
424 #endif
425 
426 #if defined(__SPLIT__intlevel_to_vpri)
427 
428 /*
429  *  xthal_intlevel_to_vpri
430  *
431  *  Converts an interrupt level to a virtual interrupt priority.
432  */
xthal_intlevel_to_vpri(unsigned intlevel)433 unsigned xthal_intlevel_to_vpri(unsigned intlevel)
434 {
435 #if XCHAL_HAVE_INTERRUPTS
436     return( XTHAL_VPRI( intlevel, 0xF ) );
437 #else
438     return( intlevel );
439 #endif
440 }
441 
442 #endif
443 
444 #if defined(__SPLIT__vpri_int_enable)
445 
446 /*
447  *  xthal_int_enable
448  *
449  *  Enables given set of interrupts, and returns previous enabled-state of these interrupts.
450  */
xthal_int_enable(unsigned mask)451 unsigned xthal_int_enable(unsigned mask)
452 {
453 #if XCHAL_HAVE_INTERRUPTS
454     unsigned prev_enabled, syncmask;
455 
456     xthal_vpri_lock();
457     prev_enabled = Xthal_vpri_enabled | Xthal_tram_enabled;
458 
459     /*  Figure out which bits must go in Xthal_tram_enabled:  */
460     syncmask = (mask & Xthal_tram_pending & Xthal_tram_sync);
461     if( syncmask != 0 ) {
462 	Xthal_tram_enabled |= syncmask;
463 	mask &= ~syncmask;
464 	/*
465 	 *  If we are re-enabling a pending trampolined interrupt,
466 	 *  there is a possibility that the level-1 software interrupt
467 	 *  is no longer pending, having already occurred (without processing
468 	 *  the trampoline because it was disabled).  So we have to
469 	 *  ensure that the level-1 software interrupt used for trampolining
470 	 *  is pending.
471 	 *  We let the BSP do this rather than the HAL, because it could
472 	 *  potentially use an external level-1 interrupt to trampoline
473 	 *  (if proper hardware was available) rather than a software interrupt.
474 	 */
475 	(*Xthal_tram_trigger_fn)();
476     }
477     /*  The rest go in the global enabled mask:  */
478     Xthal_vpri_enabled |= mask;
479 
480     xthal_vpri_unlock();	/* update INTENABLE as per current vpri */
481     return( prev_enabled );
482 
483 #else /* XCHAL_HAVE_INTERRUPTS */
484     return( 0 );
485 #endif /* XCHAL_HAVE_INTERRUPTS */
486 }
487 
488 #endif
489 
490 #if defined(__SPLIT__vpri_int_disable)
491 
492 /*
493  *  xthal_int_disable
494  *
495  *  Disables given set of interrupts, and returns previous enabled-state of these interrupts.
496  */
xthal_int_disable(unsigned mask)497 unsigned xthal_int_disable(unsigned mask)
498 {
499 #if XCHAL_HAVE_INTERRUPTS
500     unsigned prev_enabled;
501 
502     xthal_vpri_lock();
503     prev_enabled = Xthal_vpri_enabled | Xthal_tram_enabled;
504     Xthal_vpri_enabled &= ~mask;
505     Xthal_tram_enabled &= ~mask;
506     xthal_vpri_unlock();	/* update INTENABLE as per current vpri */
507     return( prev_enabled );
508 #else
509     return( 0 );
510 #endif
511 }
512 
513 #endif
514 
515 #if defined(__SPLIT__set_vpri_locklevel)
516 
xthal_set_vpri_locklevel(unsigned intlevel)517 void  xthal_set_vpri_locklevel(unsigned intlevel)
518 {
519 #if XCHAL_HAVE_INTERRUPTS
520     if( intlevel < 1 )
521 	intlevel = 1;
522     else if( intlevel > XCHAL_NUM_INTLEVELS )
523 	intlevel = XCHAL_NUM_INTLEVELS;
524     Xthal_vpri_state.locklevel = intlevel;
525     Xthal_vpri_state.lockvpri = XTHAL_VPRI(intlevel, 15);
526 #endif
527 }
528 
529 #endif
530 
531 #if defined(__SPLIT__get_vpri_locklevel)
532 
xthal_get_vpri_locklevel(void)533 unsigned  xthal_get_vpri_locklevel(void)
534 {
535 #if XCHAL_HAVE_INTERRUPTS
536     return( Xthal_vpri_state.locklevel );
537 #else
538     return( 1 );	/* must return at least 1, some OSes assume this */
539 #endif
540 }
541 
542 #endif
543 
544 #if defined(__SPLIT__set_int_vpri)
545 
546 /*
547  *  xthal_set_int_vpri   (was intSetL1Pri)
548  *
549  *  Set the virtual (software) priority of an interrupt.
550  *  Note:  the intlevel of an interrupt CANNOT be changed -- this is
551  *  set in hardware according to the core configuration file.
552  *
553  *	intnum		interrupt number (0..31)
554  *	vpri		virtual interrupt priority (0..15, or intlevel*16+(0..15) )
555  */
xthal_set_int_vpri(int intnum,int vpri)556 int  xthal_set_int_vpri(int intnum, int vpri)
557 {
558 #if XCHAL_HAVE_INTERRUPTS
559     unsigned  mask, maskoff, basepri, prevpri, intlevel, *maskp, i;
560 
561     /*
562      *  Verify parameters:
563      */
564     if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS || (unsigned)vpri > 0xFF )
565 	return( 0 );		/* error: bad parameter(s) */
566     /*
567      *  If requested priority specifies an intlevel, it must match that
568      *  of the interrupt specified; otherwise (0..15) the proper intlevel of
569      *  the specified interrupt is assumed, and added to the parameter:
570      */
571     intlevel = Xthal_intlevel[intnum];	/* intnum's intlevel */
572     if( intlevel == 0 || intlevel > XCHAL_NUM_INTLEVELS )
573     	return( 0 );		/* error: no support for setting priority of NMI etc. */
574     basepri = intlevel << 4;		/* intnum's base soft-pri. */
575     if( vpri > 0x0F ) {			/* intlevel portion given? */
576 	if( (vpri & 0xF0) != basepri )	/* then it must be correct */
577 	    return( 0 );		/* error: intlevel mismatch */
578 	vpri &= 0x0F;			/* remove it */
579     }
580 
581     mask = 1L << intnum;
582 
583     /*
584      *  Lock interrupts during virtual priority data structure updates:
585      */
586     xthal_vpri_lock();
587 
588     /*
589      *  Update virtual priority of 'intnum':
590      */
591     prevpri = Xthal_int_vpri[intnum];	/* save for return value */
592     Xthal_int_vpri[intnum] = basepri | vpri;
593     /*  This interrupt must only be enabled at virtual priorities lower than its own:  */
594     for( i = 0; i < vpri; i++ )
595 	Xthal_vpri_enablemap[0][basepri++] |= mask;
596     maskoff = ~mask;
597     for( ; i <= 0x0F; i++ )
598 	Xthal_vpri_enablemap[0][basepri++] &= maskoff;
599 
600     /*
601      *  Update the prioritization table used to resolve priorities by binary search:
602      */
603     /*  Remove interrupt <intnum> from prioritization table:  */
604     maskp = Xthal_vpri_resolvemap[intlevel-1];
605     for (i=0; i<16; i++)
606 	maskp[i] &= maskoff;
607     /*  Add interrupt <intnum> to prioritization table at its (new) given priority:  */
608     if( vpri & 0x1 )
609 	maskp[vpri] |= mask;
610     if( vpri & 0x2 )
611 	maskp[vpri & 0xE] |= mask;
612     if( vpri & 0x4 )
613 	maskp[vpri & 0xC] |= mask;
614     if( vpri & 0x8 )
615 	maskp[vpri & 0x8] |= mask;
616 
617     /*
618      *  Unlock interrupts (back to current level) and update INTENABLE:
619      */
620     xthal_vpri_unlock();
621 
622     return( prevpri );
623 #else /* XCHAL_HAVE_INTERRUPTS */
624     return( 0 );
625 #endif /* XCHAL_HAVE_INTERRUPTS */
626 } /* xthal_set_int_vpri */
627 
628 #endif
629 
630 #if defined(__SPLIT__get_int_vpri)
631 
xthal_get_int_vpri(int intnum)632 int	xthal_get_int_vpri(int intnum)
633 {
634 #if XCHAL_HAVE_INTERRUPTS
635     if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS )
636 	return( 0 );		/* error: bad parameter */
637     return( Xthal_int_vpri[intnum] );
638 #else
639     return( 0 );
640 #endif
641 }
642 
643 
644 #endif
645 
646 #if defined(__SPLIT__trampolines)
647 
648 
649 	/*
650 	SUPPORT FOR TRAMPOLINES
651 
652 	NOTE:  trampolining is a special case.
653 	There are two ways (defined here) to trampoline down
654 	from a high-level interrupt to a level-one interrupt.
655 
656 	a)  Synchronous (restrained) trampolining.
657 	    Trampolining without clearing the high-level interrupt,
658 	    letting the level-one interrupt handler clear the
659 	    source of the interrupt.
660 	    Here the high-level interrupt must be kept disabled
661 	    while trampolining down, and re-enabled after the
662 	    level-one interrupt handler completes.
663 	    This is what one might do to "convert" a high-level
664 	    interrupt into a level-one interrupt.
665 	    The high-level interrupt handler code can be generic.
666 	    [One could argue this type of trampolining isn't required,
667 	     which may? be true...]
668 	b)  Asynchronous (free) trampolining.
669 	    Trampolining when clearing the high-level interrupt
670 	    right away in the high-level interrupt handler.
671 	    Here the high-level interrupt is allowed to remain
672 	    enabled while trampolining occurs.  This is very
673 	    useful when some processing must occur with low
674 	    latency, but the rest of the processing can occur
675 	    at lower (eg. level-one) priority.  It is particularly
676 	    useful when the lower-priority processing occurs
677 	    for only some of the high-level interrupts.
678 	    Of course this requires custom assembler code to
679 	    handle the high-level interrupt and clear the source
680 	    of the interrupt, so the high-level interrupt handler
681 	    cannot be generic (as opposed to synchronous trampolining).
682 
683 	In both cases, a level-one software interrupt is used
684 	for trampolining (one could also trampoline from level
685 	m to n, m > n, n > 1, but that isn't nearly as useful;
686 	it's generally the ability to execute C code and
687 	to process exceptions that is sought after).
688 
689 	Default trampolining support is currently implemented as follows.
690 
691 	Trampoline handler:
692 
693 	A high-level interrupt is considered enabled if *either*
694 	its INTENABLE bit or its xt_tram_ints bit is set
695 	(note that both should never be set at the same time).
696 
697 	 */
698 
699 
700 /*  These are described in xtensa/hal.h (assumed initialized to zero, in BSS):  */
701 unsigned Xthal_tram_pending;
702 unsigned Xthal_tram_enabled;
703 unsigned Xthal_tram_sync;
704 
705 
706 
xthal_set_tram_trigger_func(XtHalVoidFunc * trigger_fn)707 XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn )
708 {
709 #if XCHAL_HAVE_INTERRUPTS
710     XtHalVoidFunc *fn;
711 
712     fn = Xthal_tram_trigger_fn;
713     Xthal_tram_trigger_fn = trigger_fn;
714     return( fn );
715 #else
716     (void)trigger_fn;
717     return( 0 );
718 #endif
719 }
720 
721 
722 /*
723  *  xthal_tram_set_sync
724  *
725  *  Configure type of trampoline for a high-level interrupt.
726  *  By default any trampoline is asynchronous, this need only
727  *  be called to tell the Core HAL that a high-level interrupt
728  *  will be using synchronous trampolining (down to a level-1 interrupt).
729  *
730  *	intnum		interrupt number (0 .. 31)
731  *	sync		0 = async, 1 = synchronous
732  *
733  *  Returns previous sync state of interrupt (0 or 1)
734  *  or -1 if invalid interrupt number provided.
735  */
xthal_tram_set_sync(int intnum,int sync)736 int  xthal_tram_set_sync( int intnum, int sync )
737 {
738 #if XCHAL_HAVE_INTERRUPTS
739     unsigned mask;
740     int prev;
741 
742     if( (unsigned)intnum >= XCHAL_NUM_INTERRUPTS )
743 	return( -1 );
744     mask = 1L << intnum;
745     prev = ((Xthal_tram_sync & mask) != 0);
746     if( sync )
747 	Xthal_tram_sync |= mask;
748     else
749 	Xthal_tram_sync &= ~mask;
750     return( prev );
751 #else /* XCHAL_HAVE_INTERRUPTS */
752     return( 0 );
753 #endif /* XCHAL_HAVE_INTERRUPTS */
754 }
755 
756 
757 /*
758  *  xthal_tram_pending_to_service
759  *
760  *  This is called by the trampoline interrupt handler
761  *  (eg. by a level-one software interrupt handler)
762  *  to obtain the bitmask of high-level interrupts
763  *  that it must service.
764  *  Returns that bitmask (note: this can sometimes be zero,
765  *  eg. if currently executing level-one code disables the high-level
766  *  interrupt before the trampoline handler has a chance to run).
767  *
768  *  This call automatically clears the trampoline pending
769  *  bits for the interrupts in the returned mask.
770  *  So the caller *must* process all interrupts that have
771  *  a corresponding bit set if the value returned by this function
772  *  (otherwise those interrupts may likely be lost).
773  *
774  *  This function should be called with level-one interrupts disabled
775  *  (via INTENABLE; can't be via PS.INTLEVEL because this is C code).
776  */
xthal_tram_pending_to_service(void)777 unsigned  xthal_tram_pending_to_service( void )
778 {
779 #if XCHAL_HAVE_INTERRUPTS
780     unsigned  service_mask;
781 
782     service_mask = ( Xthal_tram_pending
783 			& (Xthal_vpri_enabled | Xthal_tram_enabled) ) ;
784 
785     /*
786      *  Clear trampoline pending bits.
787      *  Each bit must be cleared *before* processing of the corresponding
788      *  interrupt occurs, to avoid missing interrupts.
789      *  Here we just clear all bits for simplicity and convenience.
790      */
791     Xthal_tram_pending &= ~service_mask;
792 
793     return( service_mask );
794 #else /* XCHAL_HAVE_INTERRUPTS */
795     return( 0 );
796 #endif /* XCHAL_HAVE_INTERRUPTS */
797 }
798 
799 /*
800  *  xthal_tram_done
801  *
802  *  This is called by the trampoline interrupt handler
803  *  (eg. by a level-one software interrupt handler)
804  *  to indicate that processing of a trampolined interrupt
805  *  (eg. one or more of the bits it received from
806  *   xthal_tram_acknowledge()) has completed.
807  *
808  *  For asynchronously trampolined interrupt(s), there is nothing to do.
809  *  For synchronously trampolined interrupt(s), the high-level
810  *  interrupt(s) must be re-enabled (presumably the level-one
811  *  interrupt handler that just completed has cleared the source
812  *  of the high-level interrupt).
813  *
814  *  This function should be called with level-one interrupts disabled
815  *  (via INTENABLE; can't be via PS.INTLEVEL because this is C code).
816  */
xthal_tram_done(unsigned serviced_mask)817 void  xthal_tram_done( unsigned serviced_mask )
818 {
819 #if XCHAL_HAVE_INTERRUPTS
820     serviced_mask &= Xthal_tram_enabled;	/* sync. trampolined interrupts that completed */
821     Xthal_tram_enabled &= ~serviced_mask;
822     xthal_int_enable( serviced_mask );
823 #endif
824 }
825 
826 #endif
827 
828 #if defined(__SPLIT__deprecated)
829 
830 
831 /**********************************************************************/
832 
833 #ifdef INCLUDE_DEPRECATED_HAL_CODE
834 /*  These definitions were present in an early beta version of the HAL and should not be used:  */
835 const unsigned Xthal_num_int_levels = XCHAL_NUM_INTLEVELS;
836 const unsigned Xthal_num_ints = XCHAL_NUM_INTERRUPTS;
837 __asm__(".global Xthal_int_level_mask\n"	".set Xthal_int_level_mask,       Xthal_intlevel_mask+4");
838 __asm__(".global Xthal_int_level1_to_n_mask\n"	".set Xthal_int_level1_to_n_mask, Xthal_intlevel_andbelow_mask+8");
839 /*const unsigned Xthal_int_level_mask[15] = { XCHAL_INTLEVEL_MASKS };			... minus the first entry ...*/
840 /*const unsigned Xthal_int_level1_to_n_mask[14] = { XCHAL_INTLEVEL_ANDBELOW_MASKS };	... minus the first two entries ...*/
841 const unsigned Xthal_int_level[32] = { XCHAL_INT_LEVELS };
842 const unsigned Xthal_int_type_edge = XCHAL_INTTYPE_MASK_EXTERN_EDGE;
843 const unsigned Xthal_int_type_level = XCHAL_INTTYPE_MASK_EXTERN_LEVEL;
844 const unsigned Xthal_int_type_timer = XCHAL_INTTYPE_MASK_TIMER;
845 const unsigned Xthal_int_type_software = XCHAL_INTTYPE_MASK_SOFTWARE;
846 #endif /* INCLUDE_DEPRECATED_HAL_CODE */
847 
848 
849 #endif /* SPLITs */
850 
851