Changeset View
Standalone View
sys/x86/xen/xen_arch_intr.c
Show All 32 Lines | |||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/interrupt.h> | #include <sys/interrupt.h> | ||||
#include <sys/pcpu.h> | #include <sys/pcpu.h> | ||||
#include <sys/proc.h> | |||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/stddef.h> | #include <sys/stddef.h> | ||||
#include <machine/intr_machdep.h> | #include <machine/intr_machdep.h> | ||||
#include <x86/apicvar.h> | #include <x86/apicvar.h> | ||||
#include <xen/xen-os.h> | #include <xen/xen-os.h> | ||||
#include <xen/xen_intr.h> | #include <xen/xen_intr.h> | ||||
#include <machine/xen/arch-intr.h> | #include <machine/xen/arch-intr.h> | ||||
/* | /* | ||||
* Pointers to the interrupt counters | |||||
*/ | |||||
DPCPU_DEFINE_STATIC(u_long *, pintrcnt); | |||||
/* | |||||
* Lock for x86-related structures. Notably modifying | * Lock for x86-related structures. Notably modifying | ||||
* xen_intr_auto_vector_count, and allocating interrupts require this lock be | * xen_intr_auto_vector_count, and allocating interrupts require this lock be | ||||
* held. | * held. | ||||
*/ | */ | ||||
static struct mtx xen_intr_x86_lock; | static struct mtx xen_intr_x86_lock; | ||||
static u_int first_evtchn_irq; | static u_int first_evtchn_irq; | ||||
static u_int xen_intr_auto_vector_count; | static u_int xen_intr_auto_vector_count; | ||||
/* | |||||
* Transition from assembly language, called from | |||||
* sys/{amd64/amd64|i386/i386}/apic_vector.[Ss] | |||||
*/ | |||||
extern void xen_arch_intr_handle_upcall(struct trapframe *); | |||||
void | |||||
xen_arch_intr_handle_upcall(struct trapframe *trap_frame) | |||||
{ | |||||
struct trapframe *old; | |||||
/* | |||||
* Disable preemption in order to always check and fire events | |||||
* on the right vCPU | |||||
*/ | |||||
critical_enter(); | |||||
++*DPCPU_GET(pintrcnt); | |||||
ehem_freebsd_m5p.com: Approach #2 is **here** set `curthread->td_intr_frame = trap_frame;` (which is passed from… | |||||
Done Inline ActionsYep, agreed that this is where you ought to set it. But as I said, you need to save and restore the previous value of td_intr_frame, not set it to NULL. mhorne: Yep, agreed that this is where you ought to set it. But as I said, you need to save and restore… | |||||
Done Inline ActionsOkay, I can believe that. I cringe at how this means it will be saved both here and in intr_event_handle(), but that could well be correct. I was thinking setting it to NULL might be correct at this point the interrupt is returning and there shouldn't be further trap frames on the stack. ehem_freebsd_m5p.com: Okay, I can believe that. I cringe at how this means it will be saved **both** here and in… | |||||
++curthread->td_intr_nesting_level; | |||||
ehem_freebsd_m5p.comAuthorUnsubmitted Done Inline ActionsI'm now guessing this (and the decrement 7 lines below) shouldn't be done. I'm not familiar enough with this to confidently make the call and need advice for whether this is correct. ehem_freebsd_m5p.com: I'm now guessing this (and the decrement 7 lines below) shouldn't be done. I'm not familiar… | |||||
old = curthread->td_intr_frame; | |||||
curthread->td_intr_frame = trap_frame; | |||||
xen_intr_handle_upcall(NULL); | |||||
curthread->td_intr_frame = old; | |||||
--curthread->td_intr_nesting_level; | |||||
if (xen_evtchn_needs_ack) | |||||
lapic_eoi(); | |||||
Done Inline ActionsNote to reviewers (@royger) this is the really significant delta. Previously this would be done if xen_intr_handle_upcall() was invoked for the XenPCI code, but now this will only be invoked for the main Xen interrupt vector. This seems likely correct, but is worthy of reviewer attention. ehem_freebsd_m5p.com: Note to reviewers (@royger) this is the really significant delta. Previously this would be… | |||||
critical_exit(); | |||||
} | |||||
/** | |||||
* Allocate and register a per-cpu Xen upcall interrupt counter. | |||||
* | |||||
* \param cpu The cpu for which to register this interrupt count. | |||||
*/ | |||||
static void | |||||
xen_intr_intrcnt_add(const u_int cpu) | |||||
{ | |||||
char buf[MAXCOMLEN + 1]; | |||||
u_long **ppintrcnt; | |||||
ppintrcnt = DPCPU_ID_PTR(cpu, pintrcnt); | |||||
if (ppintrcnt != NULL) | |||||
return; | |||||
snprintf(buf, sizeof(buf), "cpu%d:xen", cpu); | |||||
intrcnt_add(buf, ppintrcnt); | |||||
} | |||||
static void | |||||
xen_intrcnt_init(void *dummy __unused) | |||||
{ | |||||
unsigned int i; | |||||
if (!xen_domain()) | |||||
return; | |||||
/* | |||||
* Register interrupt count manually as we aren't guaranteed to see a | |||||
* call to xen_intr_assign_cpu() before our first interrupt. | |||||
*/ | |||||
CPU_FOREACH(i) | |||||
xen_intr_intrcnt_add(i); | |||||
} | |||||
SYSINIT(xen_intrcnt_init, SI_SUB_INTR, SI_ORDER_MIDDLE, xen_intrcnt_init, NULL); | |||||
void | void | ||||
xen_intr_alloc_irqs(void) | xen_intr_alloc_irqs(void) | ||||
{ | { | ||||
if (num_io_irqs > UINT_MAX - NR_EVENT_CHANNELS) | if (num_io_irqs > UINT_MAX - NR_EVENT_CHANNELS) | ||||
panic("IRQ allocation overflow (num_msi_irqs too high?)"); | panic("IRQ allocation overflow (num_msi_irqs too high?)"); | ||||
first_evtchn_irq = num_io_irqs; | first_evtchn_irq = num_io_irqs; | ||||
▲ Show 20 Lines • Show All 230 Lines • Show Last 20 Lines |
Approach #2 is here set curthread->td_intr_frame = trap_frame; (which is passed from assembly language). Then after the call set curthread->td_intr_frame = NULL;. I think this is right, but I would need a review...