Keep interrupts disabled while handling external interrupts.
There's no advantage in allowing nested external interrupts. In fact, it leads to a potential stack overrun. While here, put the interrupt vector in the trapframe, so as to compensate for the 36 cycle latency of reading cr.ivr. Further simplify assembly code by dealing with ASTs from C. Approved by: re (blanket)
This commit is contained in:
parent
b5e8f167b9
commit
78afae27e5
@ -636,22 +636,22 @@ END(exception_restore)
|
||||
{ .mib ; \
|
||||
mov r17=_ifa_ ; \
|
||||
mov r16=ip ; \
|
||||
br.sptk exception_save ; \
|
||||
br.sptk exception_save ;; \
|
||||
} ; \
|
||||
{ .mmi ; \
|
||||
(p11) ssm psr.i ;; \
|
||||
alloc r15=ar.pfs,0,0,2,0 ; \
|
||||
alloc r15=ar.pfs,0,0,2,0 ;; \
|
||||
(p11) ssm psr.i ; \
|
||||
mov out0=_n_ ;; \
|
||||
} ; \
|
||||
{ .mfb ; \
|
||||
{ .mib ; \
|
||||
(p11) srlz.d ; \
|
||||
add out1=16,sp ; \
|
||||
nop 0 ; \
|
||||
br.call.sptk rp=_func_ ; \
|
||||
br.call.sptk rp=_func_ ;; \
|
||||
} ; \
|
||||
{ .mfb ; \
|
||||
nop 0 ; \
|
||||
nop 0 ; \
|
||||
br.sptk exception_restore ; \
|
||||
br.sptk exception_restore ;; \
|
||||
}
|
||||
|
||||
#define IVT_ENTRY(name, offset) \
|
||||
@ -1233,13 +1233,19 @@ IVT_ENTRY(Break_Instruction, 0x2c00)
|
||||
{ .mmi
|
||||
alloc r15=ar.pfs,0,0,2,0
|
||||
;;
|
||||
flushrs
|
||||
(p11) ssm psr.i
|
||||
mov out0=11
|
||||
;;
|
||||
}
|
||||
{ .mib
|
||||
(p11) ssm psr.i
|
||||
{ .mmi
|
||||
flushrs
|
||||
;;
|
||||
(p11) srlz.d
|
||||
add out1=16,sp
|
||||
}
|
||||
{ .mfb
|
||||
nop 0
|
||||
nop 0
|
||||
br.call.sptk rp=trap
|
||||
;;
|
||||
}
|
||||
@ -1253,50 +1259,21 @@ IVT_END(Break_Instruction)
|
||||
|
||||
IVT_ENTRY(External_Interrupt, 0x3000)
|
||||
{ .mib
|
||||
mov r17=cr.lid // cr.iim and cr.ifa are undefined.
|
||||
mov r17=cr.ivr // Put the vector in the trap frame.
|
||||
mov r16=ip
|
||||
br.sptk exception_save
|
||||
;;
|
||||
}
|
||||
alloc r14=ar.pfs,0,0,2,0
|
||||
cmp4.eq p14,p0=0,r0
|
||||
;;
|
||||
1:
|
||||
{ .mii
|
||||
mov out0=cr.ivr // Get interrupt vector
|
||||
add out1=16,sp
|
||||
;;
|
||||
cmp.eq p15,p0=15,out0 // check for spurious vector number
|
||||
}
|
||||
{ .mbb
|
||||
ssm psr.i // re-enable interrupts
|
||||
(p15) br.dpnt.few 2f // if spurious, we are done
|
||||
br.call.sptk.many rp=interrupt // call high-level handler
|
||||
;;
|
||||
}
|
||||
{ .mmi
|
||||
rsm psr.i // disable interrupts
|
||||
;;
|
||||
srlz.d
|
||||
{ .mfb
|
||||
alloc r15=ar.pfs,0,0,1,0
|
||||
nop 0
|
||||
}
|
||||
{ .mmi
|
||||
mov cr.eoi=r0 // ack the interrupt
|
||||
;;
|
||||
srlz.d
|
||||
nop 0
|
||||
;;
|
||||
}
|
||||
{ .mfb
|
||||
cmp4.eq p14,p0=0,r8 // Return to kernel mode?
|
||||
nop 0
|
||||
br.sptk 1b // loop for more
|
||||
;;
|
||||
}
|
||||
2:
|
||||
{ .mbb
|
||||
add out0=16,sp
|
||||
(p14) br.sptk exception_restore
|
||||
br.call.sptk rp=do_ast
|
||||
nop 0
|
||||
br.call.sptk rp=interrupt
|
||||
;;
|
||||
}
|
||||
{ .mfb
|
||||
|
@ -127,34 +127,44 @@ 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");
|
||||
|
||||
int
|
||||
interrupt(u_int vector, struct trapframe *tf)
|
||||
void
|
||||
interrupt(struct trapframe *tf)
|
||||
{
|
||||
struct thread *td;
|
||||
volatile struct ia64_interrupt_block *ib = IA64_INTERRUPT_BLOCK;
|
||||
uint64_t adj, clk, itc;
|
||||
int64_t delta;
|
||||
u_int vector;
|
||||
int count;
|
||||
|
||||
uint8_t inta;
|
||||
ia64_set_fpsr(IA64_FPSR_DEFAULT);
|
||||
|
||||
td = curthread;
|
||||
atomic_add_int(&td->td_intr_nesting_level, 1);
|
||||
|
||||
vector = tf->tf_special.ifa;
|
||||
|
||||
next:
|
||||
/*
|
||||
* Handle ExtINT interrupts by generating an INTA cycle to
|
||||
* read the vector.
|
||||
*/
|
||||
if (vector == 0) {
|
||||
vector = ib->ib_inta;
|
||||
printf("ExtINT interrupt: vector=%u\n", vector);
|
||||
if (vector == 15)
|
||||
inta = ib->ib_inta;
|
||||
printf("ExtINT interrupt: vector=%u\n", (int)inta);
|
||||
if (inta == 15) {
|
||||
__asm __volatile("mov cr.eoi = r0;; srlz.d");
|
||||
goto stray;
|
||||
}
|
||||
}
|
||||
vector = (int)inta;
|
||||
} else if (vector == 15)
|
||||
goto stray;
|
||||
|
||||
if (vector == CLOCK_VECTOR) {/* clock interrupt */
|
||||
/* CTR0(KTR_INTR, "clock interrupt"); */
|
||||
|
||||
itc = ia64_get_itc();
|
||||
|
||||
PCPU_INC(cnt.v_intr);
|
||||
#ifdef EVCNT_COUNTERS
|
||||
clock_intr_evcnt.ev_count++;
|
||||
@ -166,8 +176,6 @@ interrupt(u_int vector, struct trapframe *tf)
|
||||
critical_enter();
|
||||
|
||||
adj = PCPU_GET(clockadj);
|
||||
itc = ia64_get_itc();
|
||||
ia64_set_itm(itc + ia64_clock_reload - adj);
|
||||
clk = PCPU_GET(clock);
|
||||
delta = itc - clk;
|
||||
count = 0;
|
||||
@ -186,6 +194,7 @@ interrupt(u_int vector, struct trapframe *tf)
|
||||
adjust_ticks++;
|
||||
count++;
|
||||
}
|
||||
ia64_set_itm(itc + ia64_clock_reload - adj);
|
||||
if (count > 0) {
|
||||
adjust_lost += count - 1;
|
||||
if (delta > (ia64_clock_reload >> 3)) {
|
||||
@ -200,8 +209,8 @@ interrupt(u_int vector, struct trapframe *tf)
|
||||
}
|
||||
PCPU_SET(clock, clk);
|
||||
PCPU_SET(clockadj, adj);
|
||||
|
||||
critical_exit();
|
||||
ia64_srlz_d();
|
||||
|
||||
#ifdef SMP
|
||||
} else if (vector == ipi_vector[IPI_AST]) {
|
||||
@ -221,17 +230,14 @@ interrupt(u_int vector, struct trapframe *tf)
|
||||
CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
|
||||
smp_rendezvous_action();
|
||||
} else if (vector == ipi_vector[IPI_STOP]) {
|
||||
register_t intr;
|
||||
cpumask_t mybit = PCPU_GET(cpumask);
|
||||
|
||||
intr = intr_disable();
|
||||
savectx(PCPU_PTR(pcb));
|
||||
atomic_set_int(&stopped_cpus, mybit);
|
||||
while ((started_cpus & mybit) == 0)
|
||||
/* spin */;
|
||||
cpu_spinwait();
|
||||
atomic_clear_int(&started_cpus, mybit);
|
||||
atomic_clear_int(&stopped_cpus, mybit);
|
||||
intr_restore(intr);
|
||||
} else if (vector == ipi_vector[IPI_TEST]) {
|
||||
CTR1(KTR_SMP, "IPI_TEST, cpuid=%d", PCPU_GET(cpuid));
|
||||
mp_ipi_test++;
|
||||
@ -241,9 +247,20 @@ interrupt(u_int vector, struct trapframe *tf)
|
||||
ia64_dispatch_intr(tf, vector);
|
||||
}
|
||||
|
||||
__asm __volatile("mov cr.eoi = r0;; srlz.d");
|
||||
vector = ia64_get_ivr();
|
||||
if (vector != 15)
|
||||
goto next;
|
||||
|
||||
stray:
|
||||
atomic_subtract_int(&td->td_intr_nesting_level, 1);
|
||||
return (TRAPF_USERMODE(tf));
|
||||
|
||||
if (TRAPF_USERMODE(tf)) {
|
||||
enable_intr();
|
||||
userret(td, tf);
|
||||
mtx_assert(&Giant, MA_NOTOWNED);
|
||||
do_ast(tf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -271,22 +288,21 @@ ia64_intr_eoi(void *arg)
|
||||
sapic_eoi(i->sapic, vector);
|
||||
}
|
||||
|
||||
#ifdef INTR_FILTER
|
||||
static void
|
||||
ia64_intr_disable(void *arg)
|
||||
ia64_intr_mask(void *arg)
|
||||
{
|
||||
u_int vector = (uintptr_t)arg;
|
||||
struct ia64_intr *i;
|
||||
|
||||
i = ia64_intrs[vector];
|
||||
if (i != NULL) {
|
||||
sapic_eoi(i->sapic, vector);
|
||||
sapic_mask(i->sapic, i->irq);
|
||||
sapic_eoi(i->sapic, vector);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ia64_intr_enable(void *arg)
|
||||
ia64_intr_unmask(void *arg)
|
||||
{
|
||||
u_int vector = (uintptr_t)arg;
|
||||
struct ia64_intr *i;
|
||||
@ -295,7 +311,6 @@ ia64_intr_enable(void *arg)
|
||||
if (i != NULL)
|
||||
sapic_unmask(i->sapic, i->irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
ia64_setup_intr(const char *name, int irq, driver_filter_t filter,
|
||||
@ -324,14 +339,12 @@ ia64_setup_intr(const char *name, int irq, driver_filter_t filter,
|
||||
if (i == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
error = intr_event_create(&i->event, (void *)(uintptr_t)vector,
|
||||
0, ia64_intr_unmask,
|
||||
#ifdef INTR_FILTER
|
||||
error = intr_event_create(&i->event, (void *)(uintptr_t)vector,
|
||||
0, ia64_intr_enable, ia64_intr_eoi, ia64_intr_disable,
|
||||
"irq%u:", irq);
|
||||
#else
|
||||
error = intr_event_create(&i->event, (void *)(uintptr_t)vector,
|
||||
0, ia64_intr_eoi, "irq%u:", irq);
|
||||
ia64_intr_eoi, ia64_intr_mask,
|
||||
#endif
|
||||
"irq%u:", irq);
|
||||
if (error) {
|
||||
free(i, M_DEVBUF);
|
||||
return (error);
|
||||
@ -393,7 +406,7 @@ ia64_dispatch_intr(void *frame, u_int vector)
|
||||
|
||||
#ifdef INTR_FILTER
|
||||
if (intr_event_handle(ie, frame) != 0) {
|
||||
ia64_intr_disable((void *)(uintptr_t)vector);
|
||||
ia64_intr_mask((void *)(uintptr_t)vector);
|
||||
log(LOG_ERR, "stray irq%u\n", i->irq);
|
||||
}
|
||||
#else
|
||||
@ -431,6 +444,7 @@ ia64_dispatch_intr(void *frame, u_int vector)
|
||||
critical_exit();
|
||||
|
||||
if (thread) {
|
||||
ia64_intr_mask((void *)(uintptr_t)vector);
|
||||
error = intr_event_schedule_thread(ie);
|
||||
KASSERT(error == 0, ("%s: impossible stray", __func__));
|
||||
} else
|
||||
|
@ -84,7 +84,7 @@ int ia64_highfp_drop(struct thread *);
|
||||
int ia64_highfp_save(struct thread *);
|
||||
void ia64_init(void);
|
||||
void ia64_probe_sapics(void);
|
||||
int interrupt(u_int, struct trapframe *);
|
||||
void interrupt(struct trapframe *);
|
||||
void map_gateway_page(void);
|
||||
void map_pal_code(void);
|
||||
void map_vhpt(uintptr_t);
|
||||
|
Loading…
Reference in New Issue
Block a user