Revamp the interrupt code based on the previous commit:

o   Introduce XIV, eXternal Interrupt Vector, to differentiate from
    the interrupts vectors that are offsets in the IVT (Interrupt
    Vector Table). There's a vector for external interrupts, which
    are based on the XIVs.

o   Keep track of allocated and reserved XIVs so that we can assign
    XIVs without hardcoding anything. When XIVs are allocated, an
    interrupt handler and a class is specified for the XIV. Classes
    are:
    1.  architecture-defined: XIV 15 is returned when no external
	interrupt are pending,
    2.  platform-defined: SAL reports which XIV is used to wakeup
	an AP (typically 0xFF, but it's 0x12 for the Altix 350).
    3.  inter-processor interrupts: allocated for SMP support and
	non-redirectable.
    4.  device interrupts (i.e. IRQs): allocated when devices are
	discovered and are redirectable.

o   Rewrite the central interrupt handler to call the per-XIV
    interrupt handler and rename it to ia64_handle_intr(). Move
    the per-XIV handler implementation to the file where we have
    the XIV allocation/reservation. Clock interrupt handling is
    moved to clock.c. IPI handling is moved to mp_machdep.c.

o   Drop support for the Intel 8259A because it was broken. When
    XIV 0 is received, the CPU should initiate an INTA cycle to
    obtain the interrupt vector of the 8259-based interrupt. In
    these cases the interrupt controller we should be talking to
    WRT to masking on signalling EOI is the 8259 and not the I/O
    SAPIC. This requires adriver for the Intel 8259A which isn't
    available for ia64. Thus stop pretending to support ExtINTs
    and instead panic() so that if we come across hardware that
    has an Intel 8259A, so have something real to work with.

o   With XIVs for IPIs dynamically allocatedi and also based on
    priority, define the IPI_* symbols as variables rather than
    constants. The variable holds the XIV allocated for the IPI.

o   IPI_STOP_HARD delivers a NMI if possible. Otherwise the XIV
    assigned to IPI_STOP is delivered.
This commit is contained in:
Marcel Moolenaar 2010-03-17 00:37:15 +00:00
parent d740b7c7e8
commit 3804454ac0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=205234
13 changed files with 434 additions and 389 deletions

View File

@ -29,19 +29,41 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/interrupt.h>
#include <sys/priority.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/bus.h>
#include <sys/timetc.h> #include <sys/timetc.h>
#include <sys/pcpu.h> #include <sys/pcpu.h>
#include <machine/clock.h>
#include <machine/cpu.h> #include <machine/cpu.h>
#include <machine/efi.h> #include <machine/efi.h>
#include <machine/intr.h>
#include <machine/intrcnt.h>
#include <machine/md_var.h> #include <machine/md_var.h>
uint64_t ia64_clock_reload; SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics");
static int adjust_edges = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_edges, CTLFLAG_RD,
&adjust_edges, 0, "Number of times ITC got more than 12.5% behind");
static int adjust_excess = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_excess, CTLFLAG_RD,
&adjust_excess, 0, "Total number of ignored ITC interrupts");
static int adjust_lost = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_lost, CTLFLAG_RD,
&adjust_lost, 0, "Total number of lost ITC interrupts");
static int adjust_ticks = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_ticks, CTLFLAG_RD,
&adjust_ticks, 0, "Total number of ITC interrupts with adjustment");
static u_int ia64_clock_xiv;
static uint64_t ia64_clock_reload;
#ifndef SMP #ifndef SMP
static timecounter_get_t ia64_get_timecount; static timecounter_get_t ia64_get_timecount;
@ -54,13 +76,68 @@ static struct timecounter ia64_timecounter = {
"ITC" /* name */ "ITC" /* name */
}; };
static unsigned static u_int
ia64_get_timecount(struct timecounter* tc) ia64_get_timecount(struct timecounter* tc)
{ {
return ia64_get_itc(); return ia64_get_itc();
} }
#endif #endif
static u_int
ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf)
{
uint64_t adj, clk, itc;
int64_t delta;
int count;
ia64_set_eoi(0);
PCPU_INC(md.stats.pcs_nclks);
intrcnt[INTRCNT_CLOCK]++;
ia64_srlz_d();
itc = ia64_get_itc();
adj = PCPU_GET(md.clockadj);
clk = PCPU_GET(md.clock);
delta = itc - clk;
count = 0;
while (delta >= ia64_clock_reload) {
/* Only the BSP runs the real clock */
if (PCPU_GET(cpuid) == 0)
hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
else
hardclock_cpu(TRAPF_USERMODE(tf));
if (profprocs != 0)
profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
statclock(TRAPF_USERMODE(tf));
delta -= ia64_clock_reload;
clk += ia64_clock_reload;
if (adj != 0)
adjust_ticks++;
count++;
}
ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
if (count > 0) {
adjust_lost += count - 1;
if (delta > (ia64_clock_reload >> 3)) {
if (adj == 0)
adjust_edges++;
adj = ia64_clock_reload >> 4;
} else
adj = 0;
} else {
adj = 0;
adjust_excess++;
}
PCPU_SET(md.clock, clk);
PCPU_SET(md.clockadj, adj);
ia64_srlz_d();
return (0);
}
void void
pcpu_initclock(void) pcpu_initclock(void)
{ {
@ -68,7 +145,7 @@ pcpu_initclock(void)
PCPU_SET(md.clockadj, 0); PCPU_SET(md.clockadj, 0);
PCPU_SET(md.clock, ia64_get_itc()); PCPU_SET(md.clock, ia64_get_itc());
ia64_set_itm(PCPU_GET(md.clock) + ia64_clock_reload); ia64_set_itm(PCPU_GET(md.clock) + ia64_clock_reload);
ia64_set_itv(CLOCK_VECTOR); /* highest priority class */ ia64_set_itv(ia64_clock_xiv);
ia64_srlz_d(); ia64_srlz_d();
} }
@ -81,6 +158,11 @@ cpu_initclocks()
{ {
u_long itc_freq; u_long itc_freq;
ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IRQ,
ia64_ih_clock);
if (ia64_clock_xiv == 0)
panic("No XIV for clock interrupts");
itc_freq = (u_long)ia64_itc_freq() * 1000000ul; itc_freq = (u_long)ia64_itc_freq() * 1000000ul;
stathz = hz; stathz = hz;

View File

@ -1303,7 +1303,7 @@ IVT_END(Break_Instruction)
IVT_ENTRY(External_Interrupt, 0x3000) IVT_ENTRY(External_Interrupt, 0x3000)
{ .mib { .mib
mov r17=cr.ivr // Put the vector in the trap frame. mov r17=cr.ivr // Put the XIV in the trapframe.
mov r16=ip mov r16=ip
br.sptk exception_save br.sptk exception_save
;; ;;
@ -1317,7 +1317,7 @@ IVT_ENTRY(External_Interrupt, 0x3000)
{ .mib { .mib
add out0=16,sp add out0=16,sp
nop 0 nop 0
br.call.sptk rp=interrupt br.call.sptk rp=ia64_handle_intr
;; ;;
} }
{ .mib { .mib

View File

@ -53,7 +53,7 @@ ia64_highfp_ipi(struct pcpu *cpu)
{ {
int error; int error;
ipi_send(cpu, IPI_HIGH_FP); ipi_send(cpu, ia64_ipi_highfp);
error = msleep_spin(&cpu->pc_fpcurthread, &ia64_highfp_mtx, error = msleep_spin(&cpu->pc_fpcurthread, &ia64_highfp_mtx,
"High FP", 0); "High FP", 0);
return (error); return (error);

View File

@ -43,6 +43,7 @@
#include <sys/proc.h> #include <sys/proc.h>
#include <sys/vmmeter.h> #include <sys/vmmeter.h>
#include <sys/bus.h> #include <sys/bus.h>
#include <sys/interrupt.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/ktr.h> #include <sys/ktr.h>
#include <sys/lock.h> #include <sys/lock.h>
@ -52,46 +53,20 @@
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/syslog.h> #include <sys/syslog.h>
#include <machine/clock.h>
#include <machine/cpu.h> #include <machine/cpu.h>
#include <machine/fpu.h> #include <machine/fpu.h>
#include <machine/frame.h> #include <machine/frame.h>
#include <machine/intr.h> #include <machine/intr.h>
#include <machine/intrcnt.h>
#include <machine/md_var.h> #include <machine/md_var.h>
#include <machine/pcb.h> #include <machine/pcb.h>
#include <machine/reg.h> #include <machine/reg.h>
#include <machine/smp.h> #include <machine/smp.h>
#ifdef EVCNT_COUNTERS
struct evcnt clock_intr_evcnt; /* event counter for clock intrs. */
#else
#include <sys/interrupt.h>
#include <machine/intrcnt.h>
#endif
#ifdef DDB #ifdef DDB
#include <ddb/ddb.h> #include <ddb/ddb.h>
#endif #endif
SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics");
static int adjust_edges = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_edges, CTLFLAG_RD,
&adjust_edges, 0, "Number of times ITC got more than 12.5% behind");
static int adjust_excess = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_excess, CTLFLAG_RD,
&adjust_excess, 0, "Total number of ignored ITC interrupts");
static int adjust_lost = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_lost, CTLFLAG_RD,
&adjust_lost, 0, "Total number of lost ITC interrupts");
static int adjust_ticks = 0;
SYSCTL_INT(_debug_clock, OID_AUTO, adjust_ticks, CTLFLAG_RD,
&adjust_ticks, 0, "Total number of ITC interrupts with adjustment");
struct ia64_intr { struct ia64_intr {
struct intr_event *event; /* interrupt event */ struct intr_event *event; /* interrupt event */
volatile long *cntp; /* interrupt counter */ volatile long *cntp; /* interrupt counter */
@ -99,190 +74,120 @@ struct ia64_intr {
u_int irq; u_int irq;
}; };
static struct ia64_intr *ia64_intrs[256]; ia64_ihtype *ia64_handler[IA64_NXIVS];
static enum ia64_xiv_use ia64_xiv[IA64_NXIVS];
static struct ia64_intr *ia64_intrs[IA64_NXIVS];
static void ia64_dispatch_intr(void *, u_int); static ia64_ihtype ia64_ih_invalid;
static ia64_ihtype ia64_ih_irq;
void void
interrupt(struct trapframe *tf) ia64_xiv_init(void)
{ {
struct thread *td; u_int xiv;
uint64_t adj, clk, itc;
int64_t delta;
u_int vector;
int count;
uint8_t inta;
ia64_set_fpsr(IA64_FPSR_DEFAULT); for (xiv = 0; xiv < IA64_NXIVS; xiv++) {
ia64_handler[xiv] = ia64_ih_invalid;
td = curthread; ia64_xiv[xiv] = IA64_XIV_FREE;
ia64_intrs[xiv] = NULL;
PCPU_INC(cnt.v_intr);
vector = tf->tf_special.ifa;
next:
/*
* Handle ExtINT interrupts by generating an INTA cycle to
* read the vector.
*/
if (vector == 0) {
PCPU_INC(md.stats.pcs_nextints);
inta = ia64_ld1(&ia64_pib->ib_inta);
if (inta == 15) {
PCPU_INC(md.stats.pcs_nstrays);
__asm __volatile("mov cr.eoi = r0;; srlz.d");
goto stray;
}
vector = (int)inta;
} else if (vector == 15) {
PCPU_INC(md.stats.pcs_nstrays);
goto stray;
}
if (vector == CLOCK_VECTOR) {/* clock interrupt */
/* CTR0(KTR_INTR, "clock interrupt"); */
itc = ia64_get_itc();
PCPU_INC(md.stats.pcs_nclks);
#ifdef EVCNT_COUNTERS
clock_intr_evcnt.ev_count++;
#else
intrcnt[INTRCNT_CLOCK]++;
#endif
critical_enter();
adj = PCPU_GET(md.clockadj);
clk = PCPU_GET(md.clock);
delta = itc - clk;
count = 0;
while (delta >= ia64_clock_reload) {
/* Only the BSP runs the real clock */
if (PCPU_GET(cpuid) == 0)
hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
else
hardclock_cpu(TRAPF_USERMODE(tf));
if (profprocs != 0)
profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
statclock(TRAPF_USERMODE(tf));
delta -= ia64_clock_reload;
clk += ia64_clock_reload;
if (adj != 0)
adjust_ticks++;
count++;
}
ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
if (count > 0) {
adjust_lost += count - 1;
if (delta > (ia64_clock_reload >> 3)) {
if (adj == 0)
adjust_edges++;
adj = ia64_clock_reload >> 4;
} else
adj = 0;
} else {
adj = 0;
adjust_excess++;
}
PCPU_SET(md.clock, clk);
PCPU_SET(md.clockadj, adj);
critical_exit();
ia64_srlz_d();
#ifdef SMP
} else if (vector == ipi_vector[IPI_AST]) {
PCPU_INC(md.stats.pcs_nasts);
CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid));
} else if (vector == ipi_vector[IPI_HIGH_FP]) {
PCPU_INC(md.stats.pcs_nhighfps);
ia64_highfp_save_ipi();
} else if (vector == ipi_vector[IPI_RENDEZVOUS]) {
PCPU_INC(md.stats.pcs_nrdvs);
CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
enable_intr();
smp_rendezvous_action();
disable_intr();
} else if (vector == ipi_vector[IPI_STOP]) {
PCPU_INC(md.stats.pcs_nstops);
cpumask_t mybit = PCPU_GET(cpumask);
/* Make sure IPI_STOP_HARD is mapped to IPI_STOP. */
KASSERT(IPI_STOP == IPI_STOP_HARD,
("%s: IPI_STOP_HARD not handled.", __func__));
savectx(PCPU_PTR(md.pcb));
atomic_set_int(&stopped_cpus, mybit);
while ((started_cpus & mybit) == 0)
cpu_spinwait();
atomic_clear_int(&started_cpus, mybit);
atomic_clear_int(&stopped_cpus, mybit);
} else if (vector == ipi_vector[IPI_PREEMPT]) {
PCPU_INC(md.stats.pcs_npreempts);
CTR1(KTR_SMP, "IPI_PREEMPT, cpuid=%d", PCPU_GET(cpuid));
__asm __volatile("mov cr.eoi = r0;; srlz.d");
enable_intr();
sched_preempt(curthread);
disable_intr();
goto stray;
#endif
} else {
PCPU_INC(md.stats.pcs_nhwints);
atomic_add_int(&td->td_intr_nesting_level, 1);
ia64_dispatch_intr(tf, vector);
atomic_subtract_int(&td->td_intr_nesting_level, 1);
}
__asm __volatile("mov cr.eoi = r0;; srlz.d");
vector = ia64_get_ivr();
if (vector != 15)
goto next;
stray:
if (TRAPF_USERMODE(tf)) {
enable_intr();
userret(td, tf);
mtx_assert(&Giant, MA_NOTOWNED);
do_ast(tf);
} }
(void)ia64_xiv_reserve(15, IA64_XIV_ARCH, NULL);
} }
int
ia64_xiv_free(u_int xiv, enum ia64_xiv_use what)
{
if (xiv >= IA64_NXIVS)
return (EINVAL);
if (what == IA64_XIV_FREE || what == IA64_XIV_ARCH)
return (EINVAL);
if (ia64_xiv[xiv] != what)
return (ENXIO);
ia64_xiv[xiv] = IA64_XIV_FREE;
ia64_handler[xiv] = ia64_ih_invalid;
return (0);
}
int
ia64_xiv_reserve(u_int xiv, enum ia64_xiv_use what, ia64_ihtype ih)
{
if (xiv >= IA64_NXIVS)
return (EINVAL);
if (what == IA64_XIV_FREE)
return (EINVAL);
if (ia64_xiv[xiv] != IA64_XIV_FREE)
return (EBUSY);
ia64_xiv[xiv] = what;
ia64_handler[xiv] = (ih == NULL) ? ia64_ih_invalid: ih;
if (1 || bootverbose)
printf("XIV %u: use=%u, IH=%p\n", xiv, what, ih);
return (0);
}
u_int
ia64_xiv_alloc(u_int prio, enum ia64_xiv_use what, ia64_ihtype ih)
{
u_int hwprio;
u_int xiv0, xiv;
hwprio = prio >> 2;
if (hwprio > IA64_MAX_HWPRIO)
hwprio = IA64_MAX_HWPRIO;
xiv0 = IA64_NXIVS - (hwprio + 1) * 16;
KASSERT(xiv0 > IA64_MIN_XIV, ("%s: min XIV", __func__));
KASSERT(xiv0 < IA64_NXIVS, ("%s: max XIV", __func__));
xiv = xiv0;
while (xiv < IA64_NXIVS && ia64_xiv_reserve(xiv, what, ih))
xiv++;
if (xiv < IA64_NXIVS)
return (xiv);
xiv = xiv0;
while (xiv >= IA64_MIN_XIV && ia64_xiv_reserve(xiv, what, ih))
xiv--;
return ((xiv >= IA64_MIN_XIV) ? xiv : 0);
}
static void static void
ia64_intr_eoi(void *arg) ia64_intr_eoi(void *arg)
{ {
u_int vector = (uintptr_t)arg; u_int xiv = (uintptr_t)arg;
struct ia64_intr *i; struct ia64_intr *i;
i = ia64_intrs[vector]; i = ia64_intrs[xiv];
if (i != NULL) KASSERT(i != NULL, ("%s", __func__));
sapic_eoi(i->sapic, vector); sapic_eoi(i->sapic, xiv);
} }
static void static void
ia64_intr_mask(void *arg) ia64_intr_mask(void *arg)
{ {
u_int vector = (uintptr_t)arg; u_int xiv = (uintptr_t)arg;
struct ia64_intr *i; struct ia64_intr *i;
i = ia64_intrs[vector]; i = ia64_intrs[xiv];
if (i != NULL) { KASSERT(i != NULL, ("%s", __func__));
sapic_mask(i->sapic, i->irq); sapic_mask(i->sapic, i->irq);
sapic_eoi(i->sapic, vector); sapic_eoi(i->sapic, xiv);
}
} }
static void static void
ia64_intr_unmask(void *arg) ia64_intr_unmask(void *arg)
{ {
u_int vector = (uintptr_t)arg; u_int xiv = (uintptr_t)arg;
struct ia64_intr *i; struct ia64_intr *i;
i = ia64_intrs[vector]; i = ia64_intrs[xiv];
if (i != NULL) KASSERT(i != NULL, ("%s", __func__));
sapic_unmask(i->sapic, i->irq); sapic_unmask(i->sapic, i->irq);
} }
int int
@ -292,7 +197,7 @@ ia64_setup_intr(const char *name, int irq, driver_filter_t filter,
struct ia64_intr *i; struct ia64_intr *i;
struct sapic *sa; struct sapic *sa;
char *intrname; char *intrname;
u_int prio, vector; u_int prio, xiv;
int error; int error;
prio = intr_priority(flags); prio = intr_priority(flags);
@ -301,37 +206,41 @@ ia64_setup_intr(const char *name, int irq, driver_filter_t filter,
/* XXX lock */ /* XXX lock */
/* Get the I/O SAPIC and vector that corresponds to the IRQ. */ /* Get the I/O SAPIC and XIV that corresponds to the IRQ. */
sa = sapic_lookup(irq, &vector); sa = sapic_lookup(irq, &xiv);
if (sa == NULL) { if (sa == NULL) {
/* XXX unlock */ /* XXX unlock */
return (EINVAL); return (EINVAL);
} }
if (vector == 0) { if (xiv == 0) {
/* XXX unlock */ /* XXX unlock */
i = malloc(sizeof(struct ia64_intr), M_DEVBUF, i = malloc(sizeof(struct ia64_intr), M_DEVBUF,
M_ZERO | M_WAITOK); M_ZERO | M_WAITOK);
/* XXX lock */ /* XXX lock */
sa = sapic_lookup(irq, &vector); sa = sapic_lookup(irq, &xiv);
KASSERT(sa != NULL, ("sapic_lookup")); KASSERT(sa != NULL, ("sapic_lookup"));
if (vector != 0) if (xiv != 0)
free(i, M_DEVBUF); free(i, M_DEVBUF);
} }
/* /*
* If the IRQ has no vector assigned to it yet, assign one based * If the IRQ has no XIV assigned to it yet, assign one based
* on the priority. * on the priority.
*/ */
if (vector == 0) { if (xiv == 0) {
vector = (256 - 64) - (prio << 1); xiv = ia64_xiv_alloc(prio, IA64_XIV_IRQ, ia64_ih_irq);
while (vector < 256 && ia64_intrs[vector] != NULL) if (xiv == 0) {
vector++; /* XXX unlock */
free(i, M_DEVBUF);
return (ENOSPC);
}
error = intr_event_create(&i->event, (void *)(uintptr_t)vector, error = intr_event_create(&i->event, (void *)(uintptr_t)xiv,
0, irq, ia64_intr_mask, ia64_intr_unmask, ia64_intr_eoi, 0, irq, ia64_intr_mask, ia64_intr_unmask, ia64_intr_eoi,
NULL, "irq%u:", irq); NULL, "irq%u:", irq);
if (error) { if (error) {
ia64_xiv_free(xiv, IA64_XIV_IRQ);
/* XXX unlock */ /* XXX unlock */
free(i, M_DEVBUF); free(i, M_DEVBUF);
return (error); return (error);
@ -339,25 +248,25 @@ ia64_setup_intr(const char *name, int irq, driver_filter_t filter,
i->sapic = sa; i->sapic = sa;
i->irq = irq; i->irq = irq;
i->cntp = intrcnt + irq + INTRCNT_ISA_IRQ; i->cntp = intrcnt + xiv;
ia64_intrs[vector] = i; ia64_intrs[xiv] = i;
sapic_enable(sa, irq, vector);
/* XXX unlock */ /* XXX unlock */
sapic_enable(sa, irq, xiv);
if (name != NULL && *name != '\0') { if (name != NULL && *name != '\0') {
/* XXX needs abstraction. Too error prone. */ /* XXX needs abstraction. Too error prone. */
intrname = intrnames + intrname = intrnames + xiv * INTRNAME_LEN;
(irq + INTRCNT_ISA_IRQ) * INTRNAME_LEN;
memset(intrname, ' ', INTRNAME_LEN - 1); memset(intrname, ' ', INTRNAME_LEN - 1);
bcopy(name, intrname, strlen(name)); bcopy(name, intrname, strlen(name));
} }
} else { } else {
i = ia64_intrs[vector]; i = ia64_intrs[xiv];
/* XXX unlock */ /* XXX unlock */
} }
KASSERT(i != NULL, ("vector mapping bug")); KASSERT(i != NULL, ("XIV mapping bug"));
error = intr_event_add_handler(i->event, name, filter, handler, arg, error = intr_event_add_handler(i->event, name, filter, handler, arg,
prio, flags, cookiep); prio, flags, cookiep);
@ -371,62 +280,114 @@ ia64_teardown_intr(void *cookie)
return (intr_event_remove_handler(cookie)); return (intr_event_remove_handler(cookie));
} }
static void /*
ia64_dispatch_intr(void *frame, u_int vector) * Interrupt handlers.
*/
void
ia64_handle_intr(struct trapframe *tf)
{
struct thread *td;
u_int rfi, xiv;
td = curthread;
ia64_set_fpsr(IA64_FPSR_DEFAULT);
PCPU_INC(cnt.v_intr);
xiv = tf->tf_special.ifa;
if (xiv == 15) {
PCPU_INC(md.stats.pcs_nstrays);
goto out;
}
while (xiv != 15) {
CTR1(KTR_INTR, "INTR: XIV=%u", xiv);
critical_enter();
rfi = (ia64_handler[xiv])(td, xiv, tf);
if (rfi) {
critical_exit();
return;
}
xiv = ia64_get_ivr();
critical_exit();
ia64_srlz_d();
}
out:
if (TRAPF_USERMODE(tf)) {
while (td->td_flags & (TDF_ASTPENDING|TDF_NEEDRESCHED)) {
enable_intr();
ast(tf);
disable_intr();
}
}
}
static u_int
ia64_ih_invalid(struct thread *td, u_int xiv, struct trapframe *tf)
{
ia64_set_eoi(0);
ia64_srlz_d();
panic("invalid XIV: %u", xiv);
return (1);
}
static u_int
ia64_ih_irq(struct thread *td, u_int xiv, struct trapframe *tf)
{ {
struct ia64_intr *i; struct ia64_intr *i;
struct intr_event *ie; /* our interrupt event */ struct intr_event *ie; /* our interrupt event */
/* PCPU_INC(md.stats.pcs_nhwints);
* Find the interrupt thread for this vector.
*/ /* Find the interrupt thread for this XIV. */
i = ia64_intrs[vector]; i = ia64_intrs[xiv];
KASSERT(i != NULL, ("%s: unassigned vector", __func__)); KASSERT(i != NULL, ("%s: unassigned XIV", __func__));
(*i->cntp)++; (*i->cntp)++;
ie = i->event; ie = i->event;
KASSERT(ie != NULL, ("%s: interrupt without event", __func__)); KASSERT(ie != NULL, ("%s: interrupt without event", __func__));
if (intr_event_handle(ie, frame) != 0) { if (intr_event_handle(ie, tf) != 0) {
/* ia64_intr_mask((void *)(uintptr_t)xiv);
* XXX: The pre-INTR_FILTER code didn't mask stray
* interrupts.
*/
ia64_intr_mask((void *)(uintptr_t)vector);
log(LOG_ERR, "stray irq%u\n", i->irq); log(LOG_ERR, "stray irq%u\n", i->irq);
} }
ia64_set_eoi(0);
ia64_srlz_d();
return (0);
} }
#ifdef DDB #ifdef DDB
static void static void
db_print_vector(u_int vector, int always) db_print_xiv(u_int xiv, int always)
{ {
struct ia64_intr *i; struct ia64_intr *i;
i = ia64_intrs[vector]; i = ia64_intrs[xiv];
if (i != NULL) { if (i != NULL) {
db_printf("vector %u (%p): ", vector, i); db_printf("XIV %u (%p): ", xiv, i);
sapic_print(i->sapic, i->irq); sapic_print(i->sapic, i->irq);
} else if (always) } else if (always)
db_printf("vector %u: unassigned\n", vector); db_printf("XIV %u: unassigned\n", xiv);
} }
DB_SHOW_COMMAND(vector, db_show_vector) DB_SHOW_COMMAND(xiv, db_show_xiv)
{ {
u_int vector; u_int xiv;
if (have_addr) { if (have_addr) {
vector = ((addr >> 4) % 16) * 10 + (addr % 16); xiv = ((addr >> 4) % 16) * 10 + (addr % 16);
if (vector >= 256) if (xiv >= IA64_NXIVS)
db_printf("error: vector %u not in range [0..255]\n", db_printf("error: XIV %u not in range [0..%u]\n",
vector); xiv, IA64_NXIVS - 1);
else else
db_print_vector(vector, 1); db_print_xiv(xiv, 1);
} else { } else {
for (vector = 0; vector < 256; vector++) for (xiv = 0; xiv < IA64_NXIVS; xiv++)
db_print_vector(vector, 0); db_print_xiv(xiv, 0);
} }
} }

View File

@ -26,16 +26,13 @@
* $FreeBSD$ * $FreeBSD$
*/ */
#include <sys/syscall.h>
#include <machine/asm.h> #include <machine/asm.h>
#include <machine/ia64_cpu.h> #include <machine/ia64_cpu.h>
#include <machine/pte.h>
#include <sys/syscall.h>
#include <assym.s>
#ifndef EVCNT_COUNTERS
#define _LOCORE
#include <machine/intrcnt.h> #include <machine/intrcnt.h>
#endif #include <machine/pte.h>
#include <machine/intrcnt.h>
#include <assym.s>
.section .data.proc0,"aw" .section .data.proc0,"aw"
.global kstack .global kstack
@ -310,7 +307,7 @@ EXPORT(intrnames)
.ascii "clock" .ascii "clock"
.fill INTRNAME_LEN - 5 - 1, 1, ' ' .fill INTRNAME_LEN - 5 - 1, 1, ' '
.byte 0 .byte 0
intr_n = 0 intr_n = 1
.rept INTRCNT_COUNT - 1 .rept INTRCNT_COUNT - 1
.ascii "#" .ascii "#"
.byte intr_n / 100 + '0' .byte intr_n / 100 + '0'

View File

@ -371,7 +371,7 @@ cpu_startup(void *dummy)
SYSCTL_ADD_ULONG(&pc->pc_md.sysctl_ctx, SYSCTL_ADD_ULONG(&pc->pc_md.sysctl_ctx,
SYSCTL_CHILDREN(pc->pc_md.sysctl_tree), OID_AUTO, SYSCTL_CHILDREN(pc->pc_md.sysctl_tree), OID_AUTO,
"nstrays", CTLFLAG_RD, &pcs->pcs_nstrays, "nstrays", CTLFLAG_RD, &pcs->pcs_nstrays,
"Number of stray vectors"); "Number of stray interrupts");
} }
} }
SYSINIT(cpu_startup, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); SYSINIT(cpu_startup, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
@ -781,6 +781,7 @@ ia64_init(void)
*/ */
map_pal_code(); map_pal_code();
efi_boot_minimal(bootinfo.bi_systab); efi_boot_minimal(bootinfo.bi_systab);
ia64_xiv_init();
ia64_sal_init(); ia64_sal_init();
calculate_frequencies(); calculate_frequencies();

View File

@ -46,11 +46,6 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/uuid.h> #include <sys/uuid.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_extern.h>
#include <vm/vm_kern.h>
#include <machine/atomic.h> #include <machine/atomic.h>
#include <machine/cpu.h> #include <machine/cpu.h>
#include <machine/fpu.h> #include <machine/fpu.h>
@ -59,10 +54,13 @@ __FBSDID("$FreeBSD$");
#include <machine/md_var.h> #include <machine/md_var.h>
#include <machine/pal.h> #include <machine/pal.h>
#include <machine/pcb.h> #include <machine/pcb.h>
#include <machine/pmap.h>
#include <machine/sal.h> #include <machine/sal.h>
#include <machine/smp.h> #include <machine/smp.h>
#include <i386/include/specialreg.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_extern.h>
#include <vm/vm_kern.h>
MALLOC_DEFINE(M_SMP, "SMP", "SMP related allocations"); MALLOC_DEFINE(M_SMP, "SMP", "SMP related allocations");
@ -81,7 +79,78 @@ volatile int ap_delay;
volatile int ap_awake; volatile int ap_awake;
volatile int ap_spin; volatile int ap_spin;
static void cpu_mp_unleash(void *); int ia64_ipi_ast;
int ia64_ipi_highfp;
int ia64_ipi_nmi;
int ia64_ipi_preempt;
int ia64_ipi_rndzvs;
int ia64_ipi_stop;
static u_int
ia64_ih_ast(struct thread *td, u_int xiv, struct trapframe *tf)
{
ia64_set_eoi(0);
PCPU_INC(md.stats.pcs_nasts);
CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid));
ia64_srlz_d();
return (0);
}
static u_int
ia64_ih_highfp(struct thread *td, u_int xiv, struct trapframe *tf)
{
ia64_set_eoi(0);
PCPU_INC(md.stats.pcs_nhighfps);
ia64_highfp_save_ipi();
ia64_srlz_d();
return (0);
}
static u_int
ia64_ih_preempt(struct thread *td, u_int xiv, struct trapframe *tf)
{
ia64_set_eoi(0);
PCPU_INC(md.stats.pcs_npreempts);
CTR1(KTR_SMP, "IPI_PREEMPT, cpuid=%d", PCPU_GET(cpuid));
sched_preempt(curthread);
ia64_srlz_d();
return (0);
}
static u_int
ia64_ih_rndzvs(struct thread *td, u_int xiv, struct trapframe *tf)
{
ia64_set_eoi(0);
PCPU_INC(md.stats.pcs_nrdvs);
CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
smp_rendezvous_action();
ia64_srlz_d();
return (0);
}
static u_int
ia64_ih_stop(struct thread *td, u_int xiv, struct trapframe *tf)
{
cpumask_t mybit;
ia64_set_eoi(0);
PCPU_INC(md.stats.pcs_nstops);
mybit = PCPU_GET(cpumask);
ia64_srlz_d();
savectx(PCPU_PTR(md.pcb));
atomic_set_int(&stopped_cpus, mybit);
while ((started_cpus & mybit) == 0)
cpu_spinwait();
atomic_clear_int(&started_cpus, mybit);
atomic_clear_int(&stopped_cpus, mybit);
return (0);
}
struct cpu_group * struct cpu_group *
cpu_topo(void) cpu_topo(void)
@ -116,7 +185,6 @@ void
ia64_ap_startup(void) ia64_ap_startup(void)
{ {
uint64_t vhpt; uint64_t vhpt;
int vector;
pcpup = ap_pcpu; pcpup = ap_pcpu;
ia64_set_k4((intptr_t)pcpup); ia64_set_k4((intptr_t)pcpup);
@ -148,18 +216,6 @@ ia64_ap_startup(void)
CTR1(KTR_SMP, "SMP: cpu%d launched", PCPU_GET(cpuid)); CTR1(KTR_SMP, "SMP: cpu%d launched", PCPU_GET(cpuid));
/* Acknowledge and EOI all interrupts. */
vector = ia64_get_ivr();
while (vector != 15) {
ia64_srlz_d();
if (vector == 0)
vector = (int)ia64_ld1(&ia64_pib->ib_inta);
ia64_set_eoi(0);
ia64_srlz_d();
vector = ia64_get_ivr();
}
ia64_srlz_d();
/* kick off the clock on this AP */ /* kick off the clock on this AP */
pcpu_initclock(); pcpu_initclock();
@ -200,7 +256,7 @@ cpu_mp_probe(void)
* case we can have multiple processors, but we simply can't wake * case we can have multiple processors, but we simply can't wake
* them up... * them up...
*/ */
return (mp_ncpus > 1 && ipi_vector[IPI_AP_WAKEUP] != 0); return (mp_ncpus > 1 && ia64_ipi_wakeup != 0);
} }
void void
@ -276,7 +332,7 @@ cpu_mp_start()
if (bootverbose) if (bootverbose)
printf("SMP: waking up cpu%d\n", pc->pc_cpuid); printf("SMP: waking up cpu%d\n", pc->pc_cpuid);
ipi_send(pc, IPI_AP_WAKEUP); ipi_send(pc, ia64_ipi_wakeup);
do { do {
DELAY(1000); DELAY(1000);
@ -300,6 +356,18 @@ cpu_mp_unleash(void *dummy)
if (mp_ncpus <= 1) if (mp_ncpus <= 1)
return; return;
/* Allocate XIVs for IPIs */
ia64_ipi_ast = ia64_xiv_alloc(PI_DULL, IA64_XIV_IPI, ia64_ih_ast);
ia64_ipi_highfp = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_highfp);
ia64_ipi_preempt = ia64_xiv_alloc(PI_SOFT, IA64_XIV_IPI,
ia64_ih_preempt);
ia64_ipi_rndzvs = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_rndzvs);
ia64_ipi_stop = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI, ia64_ih_stop);
/* Reserve the NMI vector for IPI_STOP_HARD if possible */
ia64_ipi_nmi = (ia64_xiv_reserve(2, IA64_XIV_IPI, ia64_ih_stop) != 0)
? ia64_ipi_stop : 0x400; /* DM=NMI, Vector=n/a */
cpus = 0; cpus = 0;
smp_cpus = 0; smp_cpus = 0;
SLIST_FOREACH(pc, &cpuhead, pc_allcpu) { SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
@ -361,20 +429,18 @@ ipi_all_but_self(int ipi)
* fields are used here. * fields are used here.
*/ */
void void
ipi_send(struct pcpu *cpu, int ipi) ipi_send(struct pcpu *cpu, int xiv)
{ {
u_int lid; u_int lid;
uint8_t vector;
KASSERT(xiv != 0, ("ipi_send"));
lid = LID_SAPIC(cpu->pc_md.lid); lid = LID_SAPIC(cpu->pc_md.lid);
vector = ipi_vector[ipi];
KASSERT(vector != 0, ("IPI %d is not assigned a vector", ipi));
ia64_mf(); ia64_mf();
ia64_st8(&(ia64_pib->ib_ipi[lid][0]), vector); ia64_st8(&(ia64_pib->ib_ipi[lid][0]), xiv);
ia64_mf_a(); ia64_mf_a();
CTR4(KTR_SMP, "ipi_send(%p, %ld): cpuid=%d, vector=%u", cpu, ipi, CTR3(KTR_SMP, "ipi_send(%p, %d): cpuid=%d", cpu, xiv, PCPU_GET(cpuid));
PCPU_GET(cpuid), vector);
} }
SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL); SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);

View File

@ -159,41 +159,15 @@ nexus_probe(device_t dev)
device_quiet(dev); /* suppress attach message for neatness */ device_quiet(dev); /* suppress attach message for neatness */
/*
* XXX working notes:
*
* - IRQ resource creation should be moved to the PIC/APIC driver.
* - DRQ resource creation should be moved to the DMAC driver.
* - The above should be sorted to probe earlier than any child busses.
*
* - Leave I/O and memory creation here, as child probes may need them.
* (especially eg. ACPI)
*/
/*
* IRQ's are on the mainboard on old systems, but on the ISA part
* of PCI->ISA bridges. There would be multiple sets of IRQs on
* multi-ISA-bus systems. PCI interrupts are routed to the ISA
* component, so in a way, PCI can be a partial child of an ISA bus(!).
* APIC interrupts are global though.
*
* XXX We depend on the AT PIC driver correctly claiming IRQ 2
* to prevent its reuse elsewhere in the !APIC_IO case.
*/
irq_rman.rm_start = 0;
irq_rman.rm_type = RMAN_ARRAY; irq_rman.rm_type = RMAN_ARRAY;
irq_rman.rm_descr = "Interrupt request lines"; irq_rman.rm_descr = "Interrupt request lines";
irq_rman.rm_end = 255; irq_rman.rm_start = 0;
irq_rman.rm_end = IA64_NXIVS - 1;
if (rman_init(&irq_rman) if (rman_init(&irq_rman)
|| rman_manage_region(&irq_rman, || rman_manage_region(&irq_rman,
irq_rman.rm_start, irq_rman.rm_end)) irq_rman.rm_start, irq_rman.rm_end))
panic("nexus_probe irq_rman"); panic("nexus_probe irq_rman");
/*
* However, IO ports and Memory truely are global at this level,
* as are APIC interrupts (however many IO APICS there turn out
* to be on large systems..)
*/
port_rman.rm_start = 0; port_rman.rm_start = 0;
port_rman.rm_end = 0xffff; port_rman.rm_end = 0xffff;
port_rman.rm_type = RMAN_ARRAY; port_rman.rm_type = RMAN_ARRAY;

View File

@ -29,21 +29,18 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <vm/vm.h> #include <vm/vm.h>
#include <vm/vm_kern.h> #include <vm/vm_kern.h>
#include <machine/efi.h> #include <machine/efi.h>
#include <machine/intr.h>
#include <machine/md_var.h> #include <machine/md_var.h>
#include <machine/sal.h> #include <machine/sal.h>
#include <machine/smp.h> #include <machine/smp.h>
/* int ia64_ipi_wakeup;
* IPIs are used more genericly than only
* for inter-processor interrupts. Don't
* make it a SMP specific thing...
*/
int ipi_vector[IPI_COUNT];
static struct ia64_fdesc sal_fdesc; static struct ia64_fdesc sal_fdesc;
static sal_entry_t fake_sal; static sal_entry_t fake_sal;
@ -66,22 +63,6 @@ fake_sal(u_int64_t a1, u_int64_t a2, u_int64_t a3, u_int64_t a4,
return res; return res;
} }
static void
setup_ipi_vectors(int ceil)
{
int ipi;
ipi_vector[IPI_MCA_RENDEZ] = ceil - 0x10;
ipi = IPI_AST; /* First generic IPI. */
ceil -= 0x20; /* First vector in group. */
while (ipi < IPI_COUNT)
ipi_vector[ipi++] = ceil++;
ipi_vector[IPI_HIGH_FP] = ceil - 0x30;
ipi_vector[IPI_MCA_CMCV] = ceil - 0x30 + 1;
}
void void
ia64_sal_init(void) ia64_sal_init(void)
{ {
@ -89,7 +70,7 @@ ia64_sal_init(void)
48, 32, 16, 32, 16, 16 48, 32, 16, 32, 16, 16
}; };
u_int8_t *p; u_int8_t *p;
int i; int error, i;
sal_systbl = efi_get_table(&sal_table); sal_systbl = efi_get_table(&sal_table);
if (sal_systbl == NULL) if (sal_systbl == NULL)
@ -132,36 +113,19 @@ ia64_sal_init(void)
break; break;
} }
if (dp->sale_vector < 0x10 || dp->sale_vector > 0xff) { /* Reserve the XIV so that we won't use it. */
printf("SAL: invalid AP wake-up vector " error = ia64_xiv_reserve(dp->sale_vector,
"(0x%lx)\n", dp->sale_vector); IA64_XIV_PLAT, NULL);
break; if (error) {
} printf("SAL: invalid AP wake-up XIV (%#lx)\n",
/*
* SAL documents that the wake-up vector should be
* high (close to 255). The MCA rendezvous vector
* should be less than the wake-up vector, but still
* "high". We use the following priority assignment:
* Wake-up: priority of the sale_vector
* Rendezvous: priority-1
* Generic IPIs: priority-2
* Special IPIs: priority-3
* Consequently, the wake-up priority should be at
* least 4 (ie vector >= 0x40).
*/
if (dp->sale_vector < 0x40) {
printf("SAL: AP wake-up vector too low "
"(0x%lx)\n", dp->sale_vector);
break;
}
if (bootverbose)
printf("SAL: AP wake-up vector: 0x%lx\n",
dp->sale_vector); dp->sale_vector);
break;
}
ipi_vector[IPI_AP_WAKEUP] = dp->sale_vector; ia64_ipi_wakeup = dp->sale_vector;
setup_ipi_vectors(dp->sale_vector & 0xf0); if (bootverbose)
printf("SAL: AP wake-up XIV: %#x\n",
ia64_ipi_wakeup);
#ifdef SMP #ifdef SMP
fd = (struct ia64_fdesc *) os_boot_rendez; fd = (struct ia64_fdesc *) os_boot_rendez;
@ -175,7 +139,4 @@ ia64_sal_init(void)
} }
p += sizes[*p]; p += sizes[*p];
} }
if (ipi_vector[IPI_AP_WAKEUP] == 0)
setup_ipi_vectors(0xf0);
} }

View File

@ -9,12 +9,4 @@
#ifndef _MACHINE_CLOCK_H_ #ifndef _MACHINE_CLOCK_H_
#define _MACHINE_CLOCK_H_ #define _MACHINE_CLOCK_H_
#ifdef _KERNEL
#define CLOCK_VECTOR 254
extern uint64_t ia64_clock_reload;
#endif
#endif /* !_MACHINE_CLOCK_H_ */ #endif /* !_MACHINE_CLOCK_H_ */

View File

@ -30,7 +30,14 @@
#ifndef _MACHINE_INTR_H_ #ifndef _MACHINE_INTR_H_
#define _MACHINE_INTR_H_ #define _MACHINE_INTR_H_
#define IA64_NXIVS 256 /* External Interrupt Vectors */
#define IA64_MIN_XIV 16
#define IA64_MAX_HWPRIO 14
struct sapic; struct sapic;
struct thread;
struct trapframe;
/* /*
* Layout of the Processor Interrupt Block. * Layout of the Processor Interrupt Block.
@ -46,12 +53,28 @@ struct ia64_pib
uint8_t _rsvd4[0x1fff0]; uint8_t _rsvd4[0x1fff0];
}; };
enum ia64_xiv_use {
IA64_XIV_FREE,
IA64_XIV_ARCH, /* Architecturally defined. */
IA64_XIV_PLAT, /* Platform defined. */
IA64_XIV_IPI, /* Used for IPIs. */
IA64_XIV_IRQ /* Used for external interrupts. */
};
typedef u_int (ia64_ihtype)(struct thread *, u_int, struct trapframe *);
extern struct ia64_pib *ia64_pib; extern struct ia64_pib *ia64_pib;
void ia64_handle_intr(struct trapframe *);
int ia64_setup_intr(const char *, int, driver_filter_t, driver_intr_t, int ia64_setup_intr(const char *, int, driver_filter_t, driver_intr_t,
void *, enum intr_type, void **); void *, enum intr_type, void **);
int ia64_teardown_intr(void *); int ia64_teardown_intr(void *);
void ia64_xiv_init(void);
u_int ia64_xiv_alloc(u_int, enum ia64_xiv_use, ia64_ihtype);
int ia64_xiv_free(u_int, enum ia64_xiv_use);
int ia64_xiv_reserve(u_int, enum ia64_xiv_use, ia64_ihtype);
int sapic_config_intr(u_int, enum intr_trigger, enum intr_polarity); int sapic_config_intr(u_int, enum intr_trigger, enum intr_polarity);
struct sapic *sapic_create(u_int, u_int, uint64_t); struct sapic *sapic_create(u_int, u_int, uint64_t);
int sapic_enable(struct sapic *, u_int, u_int); int sapic_enable(struct sapic *, u_int, u_int);

View File

@ -29,11 +29,7 @@
*/ */
#define INTRCNT_CLOCK 0 #define INTRCNT_CLOCK 0
#define INTRCNT_ISA_IRQ (INTRCNT_CLOCK + 1) #define INTRCNT_COUNT 256
#define INTRCNT_ISA_IRQ_LEN 16
#define INTRCNT_OTHER_BASE (INTRCNT_ISA_IRQ + INTRCNT_ISA_IRQ_LEN)
#define INTRCNT_OTHER_LEN 240
#define INTRCNT_COUNT (INTRCNT_OTHER_BASE + INTRCNT_OTHER_LEN)
/* /*
* Maximum name length in intrnames table (including terminating '\0'. * Maximum name length in intrnames table (including terminating '\0'.

View File

@ -6,31 +6,23 @@
#ifdef _KERNEL #ifdef _KERNEL
/* #define IPI_AST ia64_ipi_ast
* Interprocessor interrupts for SMP. The following values are indices #define IPI_PREEMPT ia64_ipi_preempt
* into the IPI vector table. The SAL gives us the vector used for AP #define IPI_RENDEZVOUS ia64_ipi_rndzvs
* wake-up. We base the other vectors on that. Keep IPI_AP_WAKEUP at #define IPI_STOP ia64_ipi_stop
* index 0. See sal.c for details. #define IPI_STOP_HARD ia64_ipi_nmi
*/
/* Architecture specific IPIs. */
#define IPI_AP_WAKEUP 0
#define IPI_HIGH_FP 1
#define IPI_MCA_CMCV 2
#define IPI_MCA_RENDEZ 3
/* Machine independent IPIs. */
#define IPI_AST 4
#define IPI_RENDEZVOUS 5
#define IPI_STOP 6
#define IPI_STOP_HARD 6
#define IPI_PREEMPT 7
#define IPI_COUNT 8
#ifndef LOCORE #ifndef LOCORE
struct pcpu; struct pcpu;
extern int ipi_vector[]; extern int ia64_ipi_ast;
extern int ia64_ipi_highfp;
extern int ia64_ipi_nmi;
extern int ia64_ipi_preempt;
extern int ia64_ipi_rndzvs;
extern int ia64_ipi_stop;
extern int ia64_ipi_wakeup;
void ipi_all_but_self(int ipi); void ipi_all_but_self(int ipi);
void ipi_selected(cpumask_t cpus, int ipi); void ipi_selected(cpumask_t cpus, int ipi);