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