xref: /netbsd-src/sys/arch/arm/gemini/gemini_ipi.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
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.11 2021/08/07 16:18:44 thorpej 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/kmem.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
gemini_ipi_match(device_t parent,cfdata_t cf,void * aux)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
gemini_ipi_attach(device_t parent,device_t self,void * aux)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, CFARGS_NONE);
92 #endif
93 }
94 
95 static inline int
gemini_ipi_intrq_empty(gemini_ipi_softc_t * sc)96 gemini_ipi_intrq_empty(gemini_ipi_softc_t *sc)
97 {
98 	return SIMPLEQ_EMPTY(&sc->sc_intrq);
99 }
100 
101 static inline void *
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 {
104 	gemini_ipi_intrq_t *iqp;
105 
106         iqp = kmem_zalloc(sizeof(*iqp), KM_SLEEP);
107         iqp->iq_func = func;
108         iqp->iq_arg = arg;
109         SIMPLEQ_INSERT_TAIL(&sc->sc_intrq, iqp, iq_q);
110 
111 	return (void *)iqp;
112 }
113 
114 static inline void
gemini_ipi_intrq_remove(gemini_ipi_softc_t * sc,void * cookie)115 gemini_ipi_intrq_remove(gemini_ipi_softc_t *sc, void *cookie)
116 {
117 	gemini_ipi_intrq_t *iqp;
118 
119 	SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) {
120 		if ((void *)iqp == cookie) {
121 			SIMPLEQ_REMOVE(&sc->sc_intrq,
122 				iqp, gemini_ipi_intrq, iq_q);
123 			kmem_free(iqp, sizeof(*iqp));
124 			return;
125 		}
126 	}
127 }
128 
129 static inline int
gemini_ipi_intrq_dispatch(gemini_ipi_softc_t * sc)130 gemini_ipi_intrq_dispatch(gemini_ipi_softc_t *sc)
131 {
132 	gemini_ipi_intrq_t *iqp;
133 	int rv = 0;
134 
135 	SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q)
136 		rv |= (*iqp->iq_func)(iqp->iq_arg);
137 
138 	return (rv != 0);
139 }
140 
141 
142 void *
ipi_intr_establish(int (* func)(void *),void * arg)143 ipi_intr_establish(int (*func)(void *), void *arg)
144 {
145         gemini_ipi_softc_t *sc = gemini_ipi_sc;
146 	void *ih;
147 
148 	if (sc == NULL)
149 		return NULL;
150 
151 	ih = gemini_ipi_intrq_insert(sc, func, arg);
152 	return ih;
153 }
154 
155 void
ipi_intr_disestablish(void * ih)156 ipi_intr_disestablish(void *ih)
157 {
158         gemini_ipi_softc_t *sc = gemini_ipi_sc;
159 
160 	if (sc == NULL)
161 		panic("NULL gemini_ipi_sc");
162 
163         gemini_ipi_intrq_remove(sc, ih);
164 }
165 
166 int
ipi_send(void)167 ipi_send(void)
168 {
169         gemini_ipi_softc_t *sc = gemini_ipi_sc;
170 	uint32_t r;
171 	uint32_t bit;
172 	bus_addr_t off;
173 
174 	if (sc == NULL)
175 		return -1;
176 
177 #if defined(GEMINI_MASTER)
178 	off = GEMINI_GLOBAL_CPU0;
179 	bit = GLOBAL_CPU0_IPICPU1;
180 #elif defined(GEMINI_SLAVE)
181 	off = GEMINI_GLOBAL_CPU1;
182 	bit = GLOBAL_CPU1_IPICPU0;
183 #endif
184 
185 	r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off);
186 	r |= bit;
187 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r);
188 
189 	return 0;
190 }
191 
192 static inline void
ipi_ack(gemini_ipi_softc_t * sc)193 ipi_ack(gemini_ipi_softc_t *sc)
194 {
195 	uint32_t r;
196 	uint32_t bit;
197 	bus_addr_t off;
198 
199 #if defined(GEMINI_MASTER)
200 	off = GEMINI_GLOBAL_CPU1;
201 	bit = GLOBAL_CPU1_IPICPU0;
202 #elif defined(GEMINI_SLAVE)
203 	off = GEMINI_GLOBAL_CPU0;
204 	bit = GLOBAL_CPU0_IPICPU1;
205 #endif
206 
207 	r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off);
208 	r &= ~bit;
209 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r);
210 }
211 
212 static int
gemini_ipiintr(void * arg)213 gemini_ipiintr(void *arg)
214 {
215 	gemini_ipi_softc_t *sc = arg;
216 	int rv;
217 
218 	if (sc == NULL)
219 		return -1;
220 
221 	ipi_ack(sc);
222 
223 	rv = gemini_ipi_intrq_dispatch(sc);
224 
225 	return rv;
226 }
227