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