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