sdboot: support SMP boot
[freedom-sifive.git] / bootrom / sdboot / include / smp.h
1 #ifndef SIFIVE_SMP
2 #define SIFIVE_SMP
3 #include "platform.h"
4
5 // The maximum number of HARTs this code supports
6 #ifndef MAX_HARTS
7 #define MAX_HARTS 32
8 #endif
9 #define CLINT_END_HART_IPI CLINT_CTRL_ADDR + (MAX_HARTS*4)
10 #define CLINT1_END_HART_IPI CLINT1_CTRL_ADDR + (MAX_HARTS*4)
11
12 // The hart that non-SMP tests should run on
13 #ifndef NONSMP_HART
14 #define NONSMP_HART 0
15 #endif
16
17 /* If your test cannot handle multiple-threads, use this:
18 * smp_disable(reg1)
19 */
20 #define smp_disable(reg1, reg2) \
21 csrr reg1, mhartid ;\
22 li reg2, NONSMP_HART ;\
23 beq reg1, reg2, hart0_entry ;\
24 42: ;\
25 wfi ;\
26 j 42b ;\
27 hart0_entry:
28
29 /* If your test needs to temporarily block multiple-threads, do this:
30 * smp_pause(reg1, reg2)
31 * ... single-threaded work ...
32 * smp_resume(reg1, reg2)
33 * ... multi-threaded work ...
34 */
35
36 #define smp_pause(reg1, reg2) \
37 li reg2, 0x8 ;\
38 csrw mie, reg2 ;\
39 li reg1, NONSMP_HART ;\
40 csrr reg2, mhartid ;\
41 bne reg1, reg2, 42f
42
43 #ifdef CLINT1_CTRL_ADDR
44 // If a second CLINT exists, then make sure we:
45 // 1) Trigger a software interrupt on all harts of both CLINTs.
46 // 2) Locate your own hart's software interrupt pending register and clear it.
47 // 3) Wait for all harts on both CLINTs to clear their software interrupt
48 // pending register.
49 // WARNING: This code makes these assumptions, which are only true for Fadu as
50 // of now:
51 // 1) hart0 uses CLINT0 at offset 0
52 // 2) hart2 uses CLINT1 at offset 0
53 // 3) hart3 uses CLINT1 at offset 1
54 // 4) There are no other harts or CLINTs in the system.
55 #define smp_resume(reg1, reg2) \
56 /* Trigger software interrupt on CLINT0 */ \
57 li reg1, CLINT_CTRL_ADDR ;\
58 41: ;\
59 li reg2, 1 ;\
60 sw reg2, 0(reg1) ;\
61 addi reg1, reg1, 4 ;\
62 li reg2, CLINT_END_HART_IPI ;\
63 blt reg1, reg2, 41b ;\
64 /* Trigger software interrupt on CLINT1 */ \
65 li reg1, CLINT1_CTRL_ADDR ;\
66 41: ;\
67 li reg2, 1 ;\
68 sw reg2, 0(reg1) ;\
69 addi reg1, reg1, 4 ;\
70 li reg2, CLINT1_END_HART_IPI ;\
71 blt reg1, reg2, 41b ;\
72 /* Wait to receive software interrupt */ \
73 42: ;\
74 wfi ;\
75 csrr reg2, mip ;\
76 andi reg2, reg2, 0x8 ;\
77 beqz reg2, 42b ;\
78 /* Clear own software interrupt bit */ \
79 csrr reg2, mhartid ;\
80 bnez reg2, 41f; \
81 /* hart0 case: Use CLINT0 */ \
82 li reg1, CLINT_CTRL_ADDR ;\
83 slli reg2, reg2, 2 ;\
84 add reg2, reg2, reg1 ;\
85 sw zero, 0(reg2) ;\
86 j 42f; \
87 41: \
88 /* hart 2, 3 case: Use CLINT1 and remap hart IDs to 0 and 1 */ \
89 li reg1, CLINT1_CTRL_ADDR ;\
90 addi reg2, reg2, -2; \
91 slli reg2, reg2, 2 ;\
92 add reg2, reg2, reg1 ;\
93 sw zero, 0(reg2) ; \
94 42: \
95 /* Wait for all software interrupt bits to be cleared on CLINT0 */ \
96 li reg1, CLINT_CTRL_ADDR ;\
97 41: ;\
98 lw reg2, 0(reg1) ;\
99 bnez reg2, 41b ;\
100 addi reg1, reg1, 4 ;\
101 li reg2, CLINT_END_HART_IPI ;\
102 blt reg1, reg2, 41b; \
103 /* Wait for all software interrupt bits to be cleared on CLINT1 */ \
104 li reg1, CLINT1_CTRL_ADDR ;\
105 41: ;\
106 lw reg2, 0(reg1) ;\
107 bnez reg2, 41b ;\
108 addi reg1, reg1, 4 ;\
109 li reg2, CLINT1_END_HART_IPI ;\
110 blt reg1, reg2, 41b; \
111 /* End smp_resume() */
112
113 #else
114
115 #define smp_resume(reg1, reg2) \
116 li reg1, CLINT_CTRL_ADDR ;\
117 41: ;\
118 li reg2, 1 ;\
119 sw reg2, 0(reg1) ;\
120 addi reg1, reg1, 4 ;\
121 li reg2, CLINT_END_HART_IPI ;\
122 blt reg1, reg2, 41b ;\
123 42: ;\
124 wfi ;\
125 csrr reg2, mip ;\
126 andi reg2, reg2, 0x8 ;\
127 beqz reg2, 42b ;\
128 li reg1, CLINT_CTRL_ADDR ;\
129 csrr reg2, mhartid ;\
130 slli reg2, reg2, 2 ;\
131 add reg2, reg2, reg1 ;\
132 sw zero, 0(reg2) ;\
133 41: ;\
134 lw reg2, 0(reg1) ;\
135 bnez reg2, 41b ;\
136 addi reg1, reg1, 4 ;\
137 li reg2, CLINT_END_HART_IPI ;\
138 blt reg1, reg2, 41b
139
140 #endif /* ifdef CLINT1_CTRL_ADDR */
141
142 #endif