| @@ -1,237 +1,237 @@ | | | @@ -1,237 +1,237 @@ |
1 | #include "opt_gemini.h" | | 1 | #include "opt_gemini.h" |
2 | #if !defined(GEMINI_MASTER) && !defined(GEMINI_SLAVE) | | 2 | #if !defined(GEMINI_MASTER) && !defined(GEMINI_SLAVE) |
3 | # error IPI needs GEMINI_MASTER or GEMINI_SLAVE | | 3 | # error IPI needs GEMINI_MASTER or GEMINI_SLAVE |
4 | #endif | | 4 | #endif |
5 | #include "locators.h" | | 5 | #include "locators.h" |
6 | #include "geminiipm.h" | | 6 | #include "geminiipm.h" |
7 | | | 7 | |
8 | #include <sys/cdefs.h> | | 8 | #include <sys/cdefs.h> |
9 | | | 9 | |
10 | __KERNEL_RCSID(0, "$NetBSD: gemini_ipi.c,v 1.6 2012/10/27 17:17:38 chs Exp $"); | | 10 | __KERNEL_RCSID(0, "$NetBSD: gemini_ipi.c,v 1.7 2019/08/30 00:33:55 riastradh Exp $"); |
11 | | | 11 | |
12 | #include <sys/param.h> | | 12 | #include <sys/param.h> |
13 | #include <sys/systm.h> | | 13 | #include <sys/systm.h> |
14 | #include <sys/device.h> | | 14 | #include <sys/device.h> |
15 | #include <sys/intr.h> | | 15 | #include <sys/intr.h> |
16 | #include <sys/malloc.h> | | 16 | #include <sys/malloc.h> |
17 | #include <arch/arm/gemini/gemini_obiovar.h> | | 17 | #include <arch/arm/gemini/gemini_obiovar.h> |
18 | #include <arch/arm/gemini/gemini_ipivar.h> | | 18 | #include <arch/arm/gemini/gemini_ipivar.h> |
19 | #include <arch/arm/gemini/gemini_reg.h> | | 19 | #include <arch/arm/gemini/gemini_reg.h> |
20 | | | 20 | |
21 | static int gemini_ipi_match(device_t, cfdata_t, void *); | | 21 | static int gemini_ipi_match(device_t, cfdata_t, void *); |
22 | static void gemini_ipi_attach(device_t, device_t, void *); | | 22 | static void gemini_ipi_attach(device_t, device_t, void *); |
23 | static int gemini_ipiintr(void *); | | 23 | static int gemini_ipiintr(void *); |
24 | | | 24 | |
25 | CFATTACH_DECL_NEW(geminiipi, sizeof(struct gemini_ipi_softc), | | 25 | CFATTACH_DECL_NEW(geminiipi, sizeof(struct gemini_ipi_softc), |
26 | gemini_ipi_match, gemini_ipi_attach, NULL, NULL); | | 26 | gemini_ipi_match, gemini_ipi_attach, NULL, NULL); |
27 | | | 27 | |
28 | static gemini_ipi_softc_t *gemini_ipi_sc; | | 28 | static gemini_ipi_softc_t *gemini_ipi_sc; |
29 | | | 29 | |
30 | | | 30 | |
31 | static int | | 31 | static int |
32 | gemini_ipi_match(device_t parent, cfdata_t cf, void *aux) | | 32 | gemini_ipi_match(device_t parent, cfdata_t cf, void *aux) |
33 | { | | 33 | { |
34 | struct obio_attach_args *obio = aux; | | 34 | struct obio_attach_args *obio = aux; |
35 | | | 35 | |
36 | if (obio->obio_intr == LPCCF_INTR_DEFAULT) | | 36 | if (obio->obio_intr == LPCCF_INTR_DEFAULT) |
37 | panic("ipi must specify intr in config."); | | 37 | panic("ipi must specify intr in config."); |
38 | | | 38 | |
39 | return 1; | | 39 | return 1; |
40 | } | | 40 | } |
41 | | | 41 | |
42 | static void | | 42 | static void |
43 | gemini_ipi_attach(device_t parent, device_t self, void *aux) | | 43 | gemini_ipi_attach(device_t parent, device_t self, void *aux) |
44 | { | | 44 | { |
45 | gemini_ipi_softc_t *sc = device_private(self); | | 45 | gemini_ipi_softc_t *sc = device_private(self); |
46 | struct obio_attach_args *obio = aux; | | 46 | struct obio_attach_args *obio = aux; |
47 | bus_space_tag_t iot; | | 47 | bus_space_tag_t iot; |
48 | bus_space_handle_t ioh; | | 48 | bus_space_handle_t ioh; |
49 | bus_size_t size; | | 49 | bus_size_t size; |
50 | bus_addr_t addr; | | 50 | bus_addr_t addr; |
51 | void *ih; | | 51 | void *ih; |
52 | | | 52 | |
53 | iot = obio->obio_iot; | | 53 | iot = obio->obio_iot; |
54 | addr = GEMINI_GLOBAL_BASE; | | 54 | addr = GEMINI_GLOBAL_BASE; |
55 | size = 4096; /* XXX */ | | 55 | size = 4096; /* XXX */ |
56 | | | 56 | |
57 | if (bus_space_map(iot, addr, size, 0, &ioh)) | | 57 | if (bus_space_map(iot, addr, size, 0, &ioh)) |
58 | panic("%s: Cannot map registers", device_xname(self)); | | 58 | panic("%s: Cannot map registers", device_xname(self)); |
59 | | | 59 | |
60 | /* | | 60 | /* |
61 | * NOTE: we are using IPL_NET, not IPL_HIGH use of IPI on this system | | 61 | * NOTE: we are using IPL_NET, not IPL_HIGH use of IPI on this system |
62 | * is (mainly) networking keep simple (for now) and force all IPIs | | 62 | * is (mainly) networking keep simple (for now) and force all IPIs |
63 | * to same level so splnet() can block them as any other NIC. | | 63 | * to same level so splnet() can block them as any other NIC. |
64 | */ | | 64 | */ |
65 | #if 0 | | 65 | #if 0 |
66 | ih = intr_establish(obio->obio_intr, IPL_NET, IST_LEVEL_HIGH, | | 66 | ih = intr_establish(obio->obio_intr, IPL_NET, IST_LEVEL_HIGH, |
67 | gemini_ipiintr, sc); | | 67 | gemini_ipiintr, sc); |
68 | #else | | 68 | #else |
69 | ih = intr_establish(obio->obio_intr, IPL_NET, IST_EDGE_RISING, | | 69 | ih = intr_establish(obio->obio_intr, IPL_NET, IST_EDGE_RISING, |
70 | gemini_ipiintr, sc); | | 70 | gemini_ipiintr, sc); |
71 | #endif | | 71 | #endif |
72 | if (ih == NULL) | | 72 | if (ih == NULL) |
73 | panic("%s: Cannot establish interrupt %d\n", | | 73 | panic("%s: Cannot establish interrupt %d\n", |
74 | device_xname(self), obio->obio_intr); | | 74 | device_xname(self), obio->obio_intr); |
75 | | | 75 | |
76 | SIMPLEQ_INIT(&sc->sc_intrq); | | 76 | SIMPLEQ_INIT(&sc->sc_intrq); |
77 | | | 77 | |
78 | sc->sc_iot = iot; | | 78 | sc->sc_iot = iot; |
79 | sc->sc_ioh = ioh; | | 79 | sc->sc_ioh = ioh; |
80 | sc->sc_addr = addr; | | 80 | sc->sc_addr = addr; |
81 | sc->sc_size = size; | | 81 | sc->sc_size = size; |
82 | sc->sc_intr = obio->obio_intr; | | 82 | sc->sc_intr = obio->obio_intr; |
83 | sc->sc_ih = ih; | | 83 | sc->sc_ih = ih; |
84 | | | 84 | |
85 | gemini_ipi_sc = sc; | | 85 | gemini_ipi_sc = sc; |
86 | | | 86 | |
87 | aprint_normal("\n"); | | 87 | aprint_normal("\n"); |
88 | aprint_naive("\n"); | | 88 | aprint_naive("\n"); |
89 | | | 89 | |
90 | #if NGEMINIIPM > 0 | | 90 | #if NGEMINIIPM > 0 |
91 | config_found(self, __UNCONST("geminiipm"), NULL); | | 91 | config_found(self, __UNCONST("geminiipm"), NULL); |
92 | #endif | | 92 | #endif |
93 | } | | 93 | } |
94 | | | 94 | |
95 | static inline int | | 95 | static inline int |
96 | gemini_ipi_intrq_empty(gemini_ipi_softc_t *sc) | | 96 | gemini_ipi_intrq_empty(gemini_ipi_softc_t *sc) |
97 | { | | 97 | { |
98 | return SIMPLEQ_EMPTY(&sc->sc_intrq); | | 98 | return SIMPLEQ_EMPTY(&sc->sc_intrq); |
99 | } | | 99 | } |
100 | | | 100 | |
101 | static inline void * | | 101 | static inline void * |
102 | gemini_ipi_intrq_insert(gemini_ipi_softc_t *sc, int (*func)(void *), void *arg) | | 102 | gemini_ipi_intrq_insert(gemini_ipi_softc_t *sc, int (*func)(void *), void *arg) |
103 | { | | 103 | { |
104 | gemini_ipi_intrq_t *iqp; | | 104 | gemini_ipi_intrq_t *iqp; |
105 | | | 105 | |
106 | iqp = malloc(sizeof(*iqp), M_DEVBUF, M_NOWAIT|M_ZERO); | | 106 | iqp = malloc(sizeof(*iqp), M_DEVBUF, M_NOWAIT|M_ZERO); |
107 | if (iqp == NULL) { | | 107 | if (iqp == NULL) { |
108 | printf("gemini_ipi_intrq_insert: malloc failed\n"); | | 108 | printf("gemini_ipi_intrq_insert: malloc failed\n"); |
109 | return NULL; | | 109 | return NULL; |
110 | } | | 110 | } |
111 | | | 111 | |
112 | iqp->iq_func = func; | | 112 | iqp->iq_func = func; |
113 | iqp->iq_arg = arg; | | 113 | iqp->iq_arg = arg; |
114 | SIMPLEQ_INSERT_TAIL(&sc->sc_intrq, iqp, iq_q); | | 114 | SIMPLEQ_INSERT_TAIL(&sc->sc_intrq, iqp, iq_q); |
115 | | | 115 | |
116 | return (void *)iqp; | | 116 | return (void *)iqp; |
117 | } | | 117 | } |
118 | | | 118 | |
119 | static inline void | | 119 | static inline void |
120 | gemini_ipi_intrq_remove(gemini_ipi_softc_t *sc, void *cookie) | | 120 | gemini_ipi_intrq_remove(gemini_ipi_softc_t *sc, void *cookie) |
121 | { | | 121 | { |
122 | gemini_ipi_intrq_t *iqp; | | 122 | gemini_ipi_intrq_t *iqp; |
123 | | | 123 | |
124 | SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) { | | 124 | SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) { |
125 | if ((void *)iqp == cookie) { | | 125 | if ((void *)iqp == cookie) { |
126 | SIMPLEQ_REMOVE(&sc->sc_intrq, | | 126 | SIMPLEQ_REMOVE(&sc->sc_intrq, |
127 | iqp, gemini_ipi_intrq, iq_q); | | 127 | iqp, gemini_ipi_intrq, iq_q); |
128 | free(iqp, M_DEVBUF); | | 128 | free(iqp, M_DEVBUF); |
129 | return; | | 129 | return; |
130 | } | | 130 | } |
131 | } | | 131 | } |
132 | } | | 132 | } |
133 | | | 133 | |
134 | static inline int | | 134 | static inline int |
135 | gemini_ipi_intrq_dispatch(gemini_ipi_softc_t *sc) | | 135 | gemini_ipi_intrq_dispatch(gemini_ipi_softc_t *sc) |
136 | { | | 136 | { |
137 | gemini_ipi_intrq_t *iqp; | | 137 | gemini_ipi_intrq_t *iqp; |
138 | int rv = 0; | | 138 | int rv = 0; |
139 | | | 139 | |
140 | SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) | | 140 | SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) |
141 | rv |= (*iqp->iq_func)(iqp->iq_arg); | | 141 | rv |= (*iqp->iq_func)(iqp->iq_arg); |
142 | | | 142 | |
143 | return (rv != 0); | | 143 | return (rv != 0); |
144 | } | | 144 | } |
145 | | | 145 | |
146 | | | 146 | |
147 | void * | | 147 | void * |
148 | ipi_intr_establish(int (*func)(void *), void *arg) | | 148 | ipi_intr_establish(int (*func)(void *), void *arg) |
149 | { | | 149 | { |
150 | gemini_ipi_softc_t *sc = gemini_ipi_sc; | | 150 | gemini_ipi_softc_t *sc = gemini_ipi_sc; |
151 | void *ih; | | 151 | void *ih; |
152 | | | 152 | |
153 | if (sc == NULL) | | 153 | if (sc == NULL) |
154 | return NULL; | | 154 | return NULL; |
155 | | | 155 | |
156 | ih = gemini_ipi_intrq_insert(sc, func, arg); | | 156 | ih = gemini_ipi_intrq_insert(sc, func, arg); |
157 | #ifdef DEBUG | | 157 | #ifdef DEBUG |
158 | if (ih == NULL) | | 158 | if (ih == NULL) |
159 | panic("%s: gemini_ipi_intrq_insert failed", | | 159 | panic("%s: gemini_ipi_intrq_insert failed", |
160 | device_xname(sc->sc_dev)); | | 160 | device_xname(sc->sc_dev)); |
161 | #endif | | 161 | #endif |
162 | | | 162 | |
163 | return ih; | | 163 | return ih; |
164 | } | | 164 | } |
165 | | | 165 | |
166 | void | | 166 | void |
167 | ipi_intr_disestablish(void *ih) | | 167 | ipi_intr_disestablish(void *ih) |
168 | { | | 168 | { |
169 | gemini_ipi_softc_t *sc = gemini_ipi_sc; | | 169 | gemini_ipi_softc_t *sc = gemini_ipi_sc; |
170 | | | 170 | |
171 | if (sc == NULL) | | 171 | if (sc == NULL) |
172 | panic("%s: NULL gemini_ipi_sc", device_xname(sc->sc_dev)); | | 172 | panic("NULL gemini_ipi_sc"); |
173 | | | 173 | |
174 | gemini_ipi_intrq_remove(sc, ih); | | 174 | gemini_ipi_intrq_remove(sc, ih); |
175 | } | | 175 | } |
176 | | | 176 | |
177 | int | | 177 | int |
178 | ipi_send(void) | | 178 | ipi_send(void) |
179 | { | | 179 | { |
180 | gemini_ipi_softc_t *sc = gemini_ipi_sc; | | 180 | gemini_ipi_softc_t *sc = gemini_ipi_sc; |
181 | uint32_t r; | | 181 | uint32_t r; |
182 | uint32_t bit; | | 182 | uint32_t bit; |
183 | bus_addr_t off; | | 183 | bus_addr_t off; |
184 | | | 184 | |
185 | if (sc == NULL) | | 185 | if (sc == NULL) |
186 | return -1; | | 186 | return -1; |
187 | | | 187 | |
188 | #if defined(GEMINI_MASTER) | | 188 | #if defined(GEMINI_MASTER) |
189 | off = GEMINI_GLOBAL_CPU0; | | 189 | off = GEMINI_GLOBAL_CPU0; |
190 | bit = GLOBAL_CPU0_IPICPU1; | | 190 | bit = GLOBAL_CPU0_IPICPU1; |
191 | #elif defined(GEMINI_SLAVE) | | 191 | #elif defined(GEMINI_SLAVE) |
192 | off = GEMINI_GLOBAL_CPU1; | | 192 | off = GEMINI_GLOBAL_CPU1; |
193 | bit = GLOBAL_CPU1_IPICPU0; | | 193 | bit = GLOBAL_CPU1_IPICPU0; |
194 | #endif | | 194 | #endif |
195 | | | 195 | |
196 | r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); | | 196 | r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); |
197 | r |= bit; | | 197 | r |= bit; |
198 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); | | 198 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); |
199 | | | 199 | |
200 | return 0; | | 200 | return 0; |
201 | } | | 201 | } |
202 | | | 202 | |
203 | static inline void | | 203 | static inline void |
204 | ipi_ack(gemini_ipi_softc_t *sc) | | 204 | ipi_ack(gemini_ipi_softc_t *sc) |
205 | { | | 205 | { |
206 | uint32_t r; | | 206 | uint32_t r; |
207 | uint32_t bit; | | 207 | uint32_t bit; |
208 | bus_addr_t off; | | 208 | bus_addr_t off; |
209 | | | 209 | |
210 | #if defined(GEMINI_MASTER) | | 210 | #if defined(GEMINI_MASTER) |
211 | off = GEMINI_GLOBAL_CPU1; | | 211 | off = GEMINI_GLOBAL_CPU1; |
212 | bit = GLOBAL_CPU1_IPICPU0; | | 212 | bit = GLOBAL_CPU1_IPICPU0; |
213 | #elif defined(GEMINI_SLAVE) | | 213 | #elif defined(GEMINI_SLAVE) |
214 | off = GEMINI_GLOBAL_CPU0; | | 214 | off = GEMINI_GLOBAL_CPU0; |
215 | bit = GLOBAL_CPU0_IPICPU1; | | 215 | bit = GLOBAL_CPU0_IPICPU1; |
216 | #endif | | 216 | #endif |
217 | | | 217 | |
218 | r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); | | 218 | r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); |
219 | r &= ~bit; | | 219 | r &= ~bit; |
220 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); | | 220 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); |
221 | } | | 221 | } |
222 | | | 222 | |
223 | static int | | 223 | static int |
224 | gemini_ipiintr(void *arg) | | 224 | gemini_ipiintr(void *arg) |
225 | { | | 225 | { |
226 | gemini_ipi_softc_t *sc = arg; | | 226 | gemini_ipi_softc_t *sc = arg; |
227 | int rv; | | 227 | int rv; |
228 | | | 228 | |
229 | if (sc == NULL) | | 229 | if (sc == NULL) |
230 | return -1; | | 230 | return -1; |
231 | | | 231 | |
232 | ipi_ack(sc); | | 232 | ipi_ack(sc); |
233 | | | 233 | |
234 | rv = gemini_ipi_intrq_dispatch(sc); | | 234 | rv = gemini_ipi_intrq_dispatch(sc); |
235 | | | 235 | |
236 | return rv; | | 236 | return rv; |
237 | } | | 237 | } |