#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/reboot.h>
#include <uvm/uvm_extern.h>
#include <machine/atomic.h>
#include <machine/alpha_cpu.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <machine/prom.h>
#include <machine/rpb.h>
typedef void (*ipifunc_t)(struct cpu_info *, struct trapframe *);
void alpha_ipi_halt(struct cpu_info *, struct trapframe *);
void alpha_ipi_imb(struct cpu_info *, struct trapframe *);
void alpha_ipi_ast(struct cpu_info *, struct trapframe *);
void alpha_ipi_synch_fpu(struct cpu_info *, struct trapframe *);
void alpha_ipi_discard_fpu(struct cpu_info *, struct trapframe *);
void alpha_ipi_pause(struct cpu_info *, struct trapframe *);
const ipifunc_t ipifuncs[ALPHA_NIPIS] = {
alpha_ipi_halt,
pmap_do_tlb_shootdown,
alpha_ipi_imb,
alpha_ipi_ast,
alpha_ipi_synch_fpu,
alpha_ipi_discard_fpu,
alpha_ipi_pause
};
void
alpha_ipi_process(struct cpu_info *ci, struct trapframe *framep)
{
u_long pending_ipis, bit;
while ((pending_ipis = atomic_loadlatch_ulong(&ci->ci_ipis, 0)) != 0) {
for (bit = 0; bit < ALPHA_NIPIS; bit++) {
if (pending_ipis & (1UL << bit)) {
(*ipifuncs[bit])(ci, framep);
}
}
}
}
void
alpha_send_ipi(u_long cpu_id, u_long ipimask)
{
#ifdef DIAGNOSTIC
if (cpu_id >= hwrpb->rpb_pcs_cnt ||
cpu_info[cpu_id] == NULL)
panic("alpha_send_ipi: bogus cpu_id");
if (((1UL << cpu_id) & cpus_running) == 0)
panic("alpha_send_ipi: CPU %ld not running", cpu_id);
#endif
atomic_setbits_ulong(&cpu_info[cpu_id]->ci_ipis, ipimask);
alpha_pal_wripir(cpu_id);
}
void
alpha_broadcast_ipi(u_long ipimask)
{
struct cpu_info *ci;
CPU_INFO_ITERATOR cii;
u_long cpu_id = cpu_number();
u_long cpumask;
cpumask = cpus_running & ~(1UL << cpu_id);
if (cpumask == 0)
return;
CPU_INFO_FOREACH(cii, ci) {
if ((cpumask & (1UL << ci->ci_cpuid)) == 0)
continue;
alpha_send_ipi(ci->ci_cpuid, ipimask);
}
}
void
alpha_multicast_ipi(u_long cpumask, u_long ipimask)
{
struct cpu_info *ci;
CPU_INFO_ITERATOR cii;
u_long cpu_id = cpu_number();
cpumask &= cpus_running;
cpumask &= ~(1UL << cpu_id);
if (cpumask == 0)
return;
CPU_INFO_FOREACH(cii, ci) {
if ((cpumask & (1UL << ci->ci_cpuid)) == 0)
continue;
alpha_send_ipi(ci->ci_cpuid, ipimask);
}
}
void
alpha_ipi_halt(struct cpu_info *ci, struct trapframe *framep)
{
SCHED_ASSERT_UNLOCKED();
fpusave_cpu(ci, 1);
(void)splhigh();
cpu_halt();
}
void
alpha_ipi_imb(struct cpu_info *ci, struct trapframe *framep)
{
alpha_pal_imb();
}
void
alpha_ipi_ast(struct cpu_info *ci, struct trapframe *framep)
{
#if 0
cpu_unidle(ci);
#endif
}
void
alpha_ipi_synch_fpu(struct cpu_info *ci, struct trapframe *framep)
{
if (ci->ci_flags & CPUF_FPUSAVE)
return;
fpusave_cpu(ci, 1);
}
void
alpha_ipi_discard_fpu(struct cpu_info *ci, struct trapframe *framep)
{
if (ci->ci_flags & CPUF_FPUSAVE)
return;
fpusave_cpu(ci, 0);
}
void
alpha_ipi_pause(struct cpu_info *ci, struct trapframe *framep)
{
u_long cpumask = (1UL << ci->ci_cpuid);
int s;
s = splhigh();
ci->ci_db_regs = framep;
atomic_setbits_ulong(&ci->ci_flags, CPUF_PAUSED);
do {
alpha_mb();
} while (cpus_paused & cpumask);
atomic_clearbits_ulong(&ci->ci_flags, CPUF_PAUSED);
ci->ci_db_regs = NULL;
splx(s);
alpha_pal_imb();
}