#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/mutex.h>
#include <sys/device.h>
#include <sys/atomic.h>
#include <sys/xcall.h>
#include <sys/ipi.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#if 0
#include <machine/fpu.h>
#endif
#include <machine/iomod.h>
#include <machine/intr.h>
#include <machine/mutex.h>
#include <machine/reg.h>
#include <machine/int_fmtio.h>
#include <hppa/hppa/cpuvar.h>
static void hppa_ipi_nop(void);
static void hppa_ipi_halt(void);
void (*ipifunc[HPPA_NIPI])(void) =
{
hppa_ipi_nop,
hppa_ipi_halt,
xc_ipi_handler,
ipi_cpu_handler,
};
const char *ipinames[HPPA_NIPI] = {
"nop ipi",
"halt ipi",
"xcall ipi"
"generic ipi"
};
void
hppa_ipi_init(struct cpu_info *ci)
{
struct cpu_softc *sc = ci->ci_softc;
int i;
evcnt_attach_dynamic(&sc->sc_evcnt_ipi, EVCNT_TYPE_INTR,
NULL, device_xname(sc->sc_dev), "ipi");
for (i = 0; i < HPPA_NIPI; i++) {
evcnt_attach_dynamic(&sc->sc_evcnt_which_ipi[i],
EVCNT_TYPE_INTR, NULL, device_xname(sc->sc_dev),
ipinames[i]);
}
}
int
hppa_ipi_intr(void *arg)
{
struct cpu_info *ci = curcpu();
struct cpu_softc *sc = ci->ci_softc;
u_long ipi_pending;
int bit = 0;
ipi_pending = atomic_swap_ulong(&ci->ci_ipi, 0);
membar_acquire();
KASSERT(ipi_pending);
sc->sc_evcnt_ipi.ev_count++;
while (ipi_pending) {
if (ipi_pending & (1L << bit)) {
sc->sc_evcnt_which_ipi[bit].ev_count++;
(*ipifunc[bit])();
}
ipi_pending &= ~(1L << bit);
bit++;
}
return 1;
}
int
hppa_ipi_send(struct cpu_info *ci, u_long ipi)
{
struct iomod *cpu;
KASSERT(ci->ci_flags & CPUF_RUNNING);
atomic_or_ulong(&ci->ci_ipi, (1L << ipi));
cpu = (struct iomod *)(ci->ci_hpa);
atomic_store_release(&cpu->io_eir, 1);
return 0;
}
int
hppa_ipi_broadcast(u_long ipi)
{
CPU_INFO_ITERATOR cii;
struct cpu_info *ci;
int count = 0;
for (CPU_INFO_FOREACH(cii, ci)) {
if (ci != curcpu() && (ci->ci_flags & CPUF_RUNNING))
if (hppa_ipi_send(ci, ipi))
count++;
}
return count;
}
static void
hppa_ipi_nop(void)
{
}
static void
hppa_ipi_halt(void)
{
struct cpu_info *ci = curcpu();
ci->ci_flags &= ~CPUF_RUNNING;
for (;;)
;
}
void
xc_send_ipi(struct cpu_info *ci)
{
KASSERT(kpreempt_disabled());
KASSERT(curcpu() != ci);
membar_release();
if (ci) {
hppa_ipi_send(ci, HPPA_IPI_XCALL);
} else {
hppa_ipi_broadcast(HPPA_IPI_XCALL);
}
}
void
cpu_ipi(struct cpu_info *ci)
{
KASSERT(kpreempt_disabled());
KASSERT(curcpu() != ci);
membar_release();
if (ci) {
hppa_ipi_send(ci, HPPA_IPI_GENERIC);
} else {
hppa_ipi_broadcast(HPPA_IPI_GENERIC);
}
}