1 #include "opt_gemini.h"
2 #if !defined(GEMINI_MASTER) && !defined(GEMINI_SLAVE)
3 # error IPI needs GEMINI_MASTER or GEMINI_SLAVE
10 __KERNEL_RCSID(0, "$NetBSD$");
12 #include <sys/param.h>
13 #include <sys/systm.h>
14 #include <sys/device.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>
27 # define DPRINTFN(n, x) do { if ((n) >= ipmdebug) printf x ; } while (1)
29 # define DPRINTFN(n, x)
32 typedef struct dispatch_entry
{
36 void (*consume
)(void *, const void *);
37 void (*counter
)(void *, size_t);
39 void *sih
; /* softint handle */
41 } ipm_dispatch_entry_t
;
43 typedef struct gemini_ipm_softc
{
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];
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
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
));
78 gpn_print_gd(desc_src
);
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
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
));
95 gpn_print_gd(desc_src
);
97 KASSERT(desc_src
->tag
!= IPM_TAG_NONE
);
98 *desc_dst
= *desc_src
;
103 gemini_ipm_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
107 if (strcmp(name
, "geminiipm") != 0)
114 gemini_ipm_attach(struct device
*parent
, struct device
*self
, void *aux
)
116 gemini_ipm_softc_t
*sc
= device_private(self
);
120 ih
= ipi_intr_establish(gemini_ipm_intr
, sc
);
122 panic("%s: Cannot establish IPI interrupt\n",
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;
141 # error one of GEMINI_MASTER or GEMINI_SLAVE must be defined
143 sc
->sc_txqavail
= NIPMDESC
;
145 sc
->sc_rxcount
= 0LL;
146 sc
->sc_txcount
= 0LL;
154 config_found(self
, __UNCONST("gpn"), NULL
);
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),
164 gemini_ipm_softc_t
*sc
= gemini_ipm_sc
;
165 ipm_dispatch_entry_t
*disp
;
169 DPRINTFN(1, ("%s:%d: %d %d %ld %p %p %p\n", __FUNCTION__
, __LINE__
,
170 tag
, ipl
, quota
, consume
, counter
, arg
));
172 return NULL
; /* not attached yet */
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
;
183 disp
->consume
= consume
;
184 disp
->counter
= counter
;
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
);
195 restore_interrupts(psw
);
201 gemini_ipm_deregister(void *ipmh
)
203 gemini_ipm_softc_t
*sc
= gemini_ipm_sc
;
204 ipm_dispatch_entry_t
*disp
= ipmh
;
210 psw
= disable_interrupts(I32_bit
);
211 memset(disp
, 0, sizeof(*disp
));
213 softint_disestablish(sc
->sih
);
215 restore_interrupts(psw
);
219 gemini_ipm_dispatch(gemini_ipm_softc_t
*sc
)
221 ipm_dispatch_entry_t
*disp
;
224 ipmqindex_t ix_write
;
227 ix_read
= sc
->sc_rxqueue
->ix_read
;
228 ix_write
= sc
->sc_rxqueue
->ix_write
;
230 if (! ipmqisempty(ix_read
, ix_write
)) {
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
];
239 softint_schedule(disp
->sih
);
241 (*disp
->consume
)(disp
->arg
, &desc
);
243 ix_write
= sc
->sc_rxqueue
->ix_write
;
244 sc
->sc_rxqueue
->ix_read
= ix_read
;
246 } while (! ipmqisempty(ix_read
, ix_write
));
248 DPRINTFN(1, ("%s: ipmqisempty %d %d\n",
249 __FUNCTION__
, ix_read
, ix_write
));
255 gemini_ipm_intr(void *arg
)
257 gemini_ipm_softc_t
*sc
= arg
;
260 rv
= gemini_ipm_dispatch(sc
);
261 gemini_ipm_count_txdone(sc
);
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
;
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
);
290 gemini_ipm_count_txdone(sc
);
296 gemini_ba_to_va(bus_addr_t ba
)
298 return (void *)(GEMINI_ALLMEM_VBASE
+ ba
);
302 gemini_ipm_copyin(void *dst
, bus_addr_t ba
, size_t len
)
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
);
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
);
328 disp
= &sc
->sc_dispatch_tab
[tag
];
329 (*disp
->counter
)(disp
->arg
, count
);
333 void gemini_ipm_stats_print(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
);