No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / arm / gemini / gemini_ipm.c
blobddc6daf7dea837797d16d672159c04311d683138
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 "gpn.h"
8 #include <sys/cdefs.h>
10 __KERNEL_RCSID(0, "$NetBSD$");
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 <arm/cpufunc.h>
18 #include <arch/arm/gemini/gemini_obiovar.h>
19 #include <arch/arm/gemini/gemini_ipivar.h>
20 #include <arch/arm/gemini/gemini_ipm.h>
21 #include <arch/arm/gemini/gemini_ipmvar.h>
22 #include <evbarm/gemini/gemini.h>
24 // #define IPMDEBUG
25 #if defined IPMDEBUG
26 static int ipmdebug;
27 # define DPRINTFN(n, x) do { if ((n) >= ipmdebug) printf x ; } while (1)
28 #else
29 # define DPRINTFN(n, x)
30 #endif
32 typedef struct dispatch_entry {
33 unsigned int ipl;
34 size_t quota;
35 void *arg;
36 void (*consume)(void *, const void *);
37 void (*counter)(void *, size_t);
38 #ifdef NOTYET
39 void *sih; /* softint handle */
40 #endif
41 } ipm_dispatch_entry_t;
43 typedef struct gemini_ipm_softc {
44 device_t sc_dev;
45 void *sc_ih;
46 ipm_queue_t *sc_rxqueue;
47 ipm_queue_t *sc_txqueue;
48 size_t sc_txqavail; /* quota available */
49 unsigned long long sc_rxcount;
50 unsigned long long sc_txcount;
51 ipm_dispatch_entry_t sc_dispatch_tab[256];
52 } gemini_ipm_softc_t;
55 static int gemini_ipm_match(struct device *, struct cfdata *, void *);
56 static void gemini_ipm_attach(struct device *, struct device *, void *);
57 static int gemini_ipm_intr(void *);
58 static void gemini_ipm_count_txdone(gemini_ipm_softc_t *);
61 CFATTACH_DECL_NEW(geminiipm, sizeof(struct gemini_ipm_softc),
62 gemini_ipm_match, gemini_ipm_attach, NULL, NULL);
64 gemini_ipm_softc_t *gemini_ipm_sc = NULL;
68 * copy from shared queue to private copy
69 * SW coherency would go here if desc_src were in cached mem
71 static inline void
72 gemini_ipm_desc_read(ipm_desc_t *desc_dst, const ipm_desc_t *desc_src)
74 extern void gpn_print_gd(const void *); /* XXX DEBUG */
75 DPRINTFN(2, ("%s: %p %p\n", __FUNCTION__, desc_dst, desc_src));
76 #ifdef IPMDEBUG
77 if (ipmdebug >= 3)
78 gpn_print_gd(desc_src);
79 #endif
80 *desc_dst = *desc_src;
81 KASSERT(desc_dst->tag != IPM_TAG_NONE);
85 * copy from private copy to shared queue
86 * SW coherency would go here if desc_dst were in cached mem
88 static inline void
89 gemini_ipm_desc_write(ipm_desc_t *desc_dst, const ipm_desc_t *desc_src)
91 extern void gpn_print_gd(const void *); /* XXX DEBUG */
92 DPRINTFN(2, ("%s: %p %p\n", __FUNCTION__, desc_dst, desc_src));
93 #ifdef IPMDEBUG
94 if (ipmdebug >= 3)
95 gpn_print_gd(desc_src);
96 #endif
97 KASSERT(desc_src->tag != IPM_TAG_NONE);
98 *desc_dst = *desc_src;
102 static int
103 gemini_ipm_match(struct device *parent, struct cfdata *cf, void *aux)
105 char *name = aux;
107 if (strcmp(name, "geminiipm") != 0)
108 return 0;
110 return 1;
113 static void
114 gemini_ipm_attach(struct device *parent, struct device *self, void *aux)
116 gemini_ipm_softc_t *sc = device_private(self);
117 void *ih;
119 sc->sc_dev = self;
120 ih = ipi_intr_establish(gemini_ipm_intr, sc);
121 if (ih == NULL)
122 panic("%s: Cannot establish IPI interrupt\n",
123 device_xname(self));
124 sc->sc_ih = ih;
125 memset(&sc->sc_dispatch_tab, 0, sizeof(sc->sc_dispatch_tab));
129 * queues are flipped tx/rx for mater/slave
131 KASSERT(GEMINI_IPMQ_SIZE == (2 * sizeof(ipm_queue_t)));
132 #if defined(GEMINI_MASTER)
133 sc->sc_rxqueue = (ipm_queue_t *)GEMINI_IPMQ_VBASE;
134 sc->sc_txqueue = sc->sc_rxqueue + 1;
135 memset(sc->sc_rxqueue, 0, sizeof(ipm_queue_t));
136 memset(sc->sc_txqueue, 0, sizeof(ipm_queue_t));
137 #elif defined(GEMINI_SLAVE)
138 sc->sc_txqueue = (ipm_queue_t *)GEMINI_IPMQ_VBASE;
139 sc->sc_rxqueue = sc->sc_txqueue + 1;
140 #else
141 # error one of GEMINI_MASTER or GEMINI_SLAVE must be defined
142 #endif
143 sc->sc_txqavail = NIPMDESC;
145 sc->sc_rxcount = 0LL;
146 sc->sc_txcount = 0LL;
148 gemini_ipm_sc = sc;
150 aprint_normal("\n");
151 aprint_naive("\n");
153 #if NGPN > 0
154 config_found(self, __UNCONST("gpn"), NULL);
155 #endif
158 void *
159 gemini_ipm_register(uint8_t tag, unsigned int ipl, size_t quota,
160 void (*consume)(void *, const void *),
161 void (*counter)(void *, size_t),
162 void *arg)
164 gemini_ipm_softc_t *sc = gemini_ipm_sc;
165 ipm_dispatch_entry_t *disp;
166 void *ipmh = NULL;
167 int psw;
169 DPRINTFN(1, ("%s:%d: %d %d %ld %p %p %p\n", __FUNCTION__, __LINE__,
170 tag, ipl, quota, consume, counter, arg));
171 if (sc == NULL)
172 return NULL; /* not attached yet */
174 if (tag == 0)
175 return NULL; /* tag #0 is reserved */
177 psw = disable_interrupts(I32_bit);
178 disp = &sc->sc_dispatch_tab[tag];
179 if (disp->consume == 0) {
180 if (sc->sc_txqavail >= quota) {
181 sc->sc_txqavail -= quota;
182 disp->ipl = ipl;
183 disp->consume = consume;
184 disp->counter = counter;
185 disp->arg = arg;
186 #ifdef NOTYET
187 if (ipl > SOFTINT_LVLMASK)
188 panic("%s: bad level %d",
189 device_xname(sc->sc_dev), ipl);
190 disp->sih = softint_establish(ipl, consume, arg);
191 #endif
192 ipmh = disp;
195 restore_interrupts(psw);
197 return ipmh;
200 void
201 gemini_ipm_deregister(void *ipmh)
203 gemini_ipm_softc_t *sc = gemini_ipm_sc;
204 ipm_dispatch_entry_t *disp = ipmh;
205 int psw;
207 if (sc == NULL)
208 return;
210 psw = disable_interrupts(I32_bit);
211 memset(disp, 0, sizeof(*disp));
212 #ifdef NOTYET
213 softint_disestablish(sc->sih);
214 #endif
215 restore_interrupts(psw);
218 static inline int
219 gemini_ipm_dispatch(gemini_ipm_softc_t *sc)
221 ipm_dispatch_entry_t *disp;
222 ipm_desc_t desc;
223 ipmqindex_t ix_read;
224 ipmqindex_t ix_write;
225 int rv = 0;
227 ix_read = sc->sc_rxqueue->ix_read;
228 ix_write = sc->sc_rxqueue->ix_write;
230 if (! ipmqisempty(ix_read, ix_write)) {
231 rv = 1;
232 do {
233 gemini_ipm_desc_read(&desc,
234 &sc->sc_rxqueue->ipm_desc[ix_read]);
235 ix_read = ipmqnext(ix_read);
236 KASSERT(desc.tag != IPM_TAG_NONE);
237 disp = &sc->sc_dispatch_tab[desc.tag];
238 #ifdef NOTYET
239 softint_schedule(disp->sih);
240 #else
241 (*disp->consume)(disp->arg, &desc);
242 #endif
243 ix_write = sc->sc_rxqueue->ix_write;
244 sc->sc_rxqueue->ix_read = ix_read;
245 sc->sc_rxcount++;
246 } while (! ipmqisempty(ix_read, ix_write));
247 } else {
248 DPRINTFN(1, ("%s: ipmqisempty %d %d\n",
249 __FUNCTION__, ix_read, ix_write));
251 return rv;
254 static int
255 gemini_ipm_intr(void *arg)
257 gemini_ipm_softc_t *sc = arg;
258 int rv;
260 rv = gemini_ipm_dispatch(sc);
261 gemini_ipm_count_txdone(sc);
263 return rv;
267 gemini_ipm_produce(const void *adescp, size_t ndesc)
269 const ipm_desc_t *descp = adescp;
270 gemini_ipm_softc_t *sc = gemini_ipm_sc;
271 ipmqindex_t ix_read;
272 ipmqindex_t ix_write;
274 KASSERT(ndesc == 1); /* XXX TMP */
276 DPRINTFN(2, ("%s:%d: %p %ld, tag %d\n",
277 __FUNCTION__, __LINE__, descp, ndesc, descp->tag));
278 ix_read = sc->sc_txqueue->ix_read;
279 ix_write = sc->sc_txqueue->ix_write;
280 if (ipmqisfull(ix_read, ix_write)) {
281 /* we expect this to "never" happen; check your quotas */
282 panic("%s: queue full\n", device_xname(sc->sc_dev));
284 gemini_ipm_desc_write(&sc->sc_txqueue->ipm_desc[ix_write], descp);
285 sc->sc_txqueue->ix_write = ipmqnext(ix_write);
286 sc->sc_txcount++;
288 ipi_send();
290 gemini_ipm_count_txdone(sc);
292 return 0;
295 static void *
296 gemini_ba_to_va(bus_addr_t ba)
298 return (void *)(GEMINI_ALLMEM_VBASE + ba);
301 void
302 gemini_ipm_copyin(void *dst, bus_addr_t ba, size_t len)
304 void *src;
306 DPRINTFN(2, ("%s:%d: %p %#lx %ld\n",
307 __FUNCTION__, __LINE__, dst, ba, len));
308 src = gemini_ba_to_va(ba);
309 memcpy(dst, src, len);
310 cpu_dcache_inv_range((vaddr_t)src, len);
314 static void
315 gemini_ipm_count_txdone(gemini_ipm_softc_t *sc)
317 ipmqindex_t count = 0; /* XXX must count per tag */
318 ipm_dispatch_entry_t *disp;
319 ipmqindex_t ixr = sc->sc_txqueue->ix_read;
320 uint8_t tag = IPM_TAG_GPN;
321 static ipmqindex_t oixr = 0;
323 while (oixr != ixr) {
324 oixr = ipmqnext(oixr);
325 count++;
327 if (count != 0) {
328 disp = &sc->sc_dispatch_tab[tag];
329 (*disp->counter)(disp->arg, count);
333 void gemini_ipm_stats_print(void);
334 void
335 gemini_ipm_stats_print(void)
337 gemini_ipm_softc_t *sc = gemini_ipm_sc;
339 printf("rxcount %lld, txcount %lld\n", sc->sc_rxcount, sc->sc_txcount);