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:
parent
d740b7c7e8
commit
3804454ac0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=205234
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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'
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -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_ */
|
||||||
|
@ -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);
|
||||||
|
@ -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'.
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user