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