#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/atomic.h>
#include <sys/xcall.h>
#include <machine/intr.h>
#define IPL_XCALL IPL_SOFTCLOCK
void
cpu_xcall_set(struct xcall *xc, void (*func)(void *), void *arg)
{
xc->xc_func = func;
xc->xc_arg = arg;
}
static inline void
cpu_xcall_self(struct xcall *xc)
{
int s;
s = splraise(IPL_XCALL);
xc->xc_func(xc->xc_arg);
splx(s);
}
#ifdef MULTIPROCESSOR
void
cpu_xcall(struct cpu_info *ci, struct xcall *xc)
{
struct xcall_cpu *xci = &ci->ci_xcall;
size_t i;
if (ci == curcpu()) {
cpu_xcall_self(xc);
return;
}
for (;;) {
for (i = 0; i < nitems(xci->xci_xcalls); i++) {
if (atomic_cas_ptr(&xci->xci_xcalls[i],
NULL, xc) != NULL)
continue;
cpu_xcall_ipi(ci);
return;
}
CPU_BUSY_CYCLE();
}
}
struct xcall_sync {
struct xcall xcs_xc;
struct cond xcs_c;
};
static void
cpu_xcall_done(void *arg)
{
struct xcall_sync *xcs = arg;
struct xcall *xc = &xcs->xcs_xc;
xc->xc_func(xc->xc_arg);
cond_signal(&xcs->xcs_c);
}
void
cpu_xcall_sync(struct cpu_info *ci, void (*func)(void *), void *arg,
const char *wmesg)
{
struct xcall_sync xcs = {
.xcs_xc = XCALL_INITIALIZER(func, arg),
.xcs_c = COND_INITIALIZER(),
};
struct xcall xc = XCALL_INITIALIZER(cpu_xcall_done, &xcs);
cpu_xcall(ci, &xc);
cond_wait(&xcs.xcs_c, wmesg);
}
void
cpu_xcall_dispatch(struct cpu_info *ci)
{
struct xcall_cpu *xci = &ci->ci_xcall;
struct xcall *xc;
size_t i;
for (i = 0; i < nitems(xci->xci_xcalls); i++) {
xc = xci->xci_xcalls[i];
if (xc != NULL) {
xci->xci_xcalls[i] = NULL;
(*xc->xc_func)(xc->xc_arg);
}
}
}
void
cpu_xcall_establish(struct cpu_info *ci)
{
struct xcall_cpu *xci = &ci->ci_xcall;
size_t i;
for (i = 0; i < nitems(xci->xci_xcalls); i++)
xci->xci_xcalls[i] = NULL;
}
#else
void
cpu_xcall(struct cpu_info *ci, struct xcall *xc)
{
cpu_xcall_self(xc);
}
void
cpu_xcall_sync(struct cpu_info *ci, void (*func)(void *), void *arg,
const char *wmesg)
{
int s;
s = splraise(IPL_XCALL);
func(arg);
splx(s);
}
#endif