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