Changeset View
Changeset View
Standalone View
Standalone View
sys/xen/xen_intr.c
Show All 38 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/refcount.h> | #include <sys/refcount.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <machine/smp.h> | #include <machine/smp.h> | ||||
#include <machine/stdarg.h> | #include <machine/stdarg.h> | ||||
Show All 28 Lines | struct xen_intr_pcpu_data { | ||||
u_int last_processed_l1i; | u_int last_processed_l1i; | ||||
/** | /** | ||||
* The last event channel processed within the event channel | * The last event channel processed within the event channel | ||||
* bitmap being scanned. | * bitmap being scanned. | ||||
*/ | */ | ||||
u_int last_processed_l2i; | u_int last_processed_l2i; | ||||
/** Pointer to this CPU's interrupt statistic counter. */ | |||||
u_long *evtchn_intrcnt; | |||||
mhorne: Why is this being removed? | |||||
Done Inline ActionsThis is not being removed, it is moving to x86/xen/xen_arch_intr.c. This appears to be how the interrupt counters are handled on x86 (not ARM). As such this is moving to the x86 side. ehem_freebsd_m5p.com: This is //not// being removed, it is moving to x86/xen/xen_arch_intr.c. This appears to be how… | |||||
/** | /** | ||||
* A bitmap of ports that can be serviced from this CPU. | * A bitmap of ports that can be serviced from this CPU. | ||||
* A set bit means interrupt handling is enabled. | * A set bit means interrupt handling is enabled. | ||||
*/ | */ | ||||
u_long evtchn_enabled[sizeof(u_long) * 8]; | u_long evtchn_enabled[sizeof(u_long) * 8]; | ||||
}; | }; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct xen_intr_pcpu_data *pcpu; | struct xen_intr_pcpu_data *pcpu; | ||||
pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu); | pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu); | ||||
xen_set_bit(port, pcpu->evtchn_enabled); | xen_set_bit(port, pcpu->evtchn_enabled); | ||||
} | } | ||||
/** | /** | ||||
* 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(u_int cpu) | |||||
{ | |||||
char buf[MAXCOMLEN + 1]; | |||||
struct xen_intr_pcpu_data *pcpu; | |||||
pcpu = DPCPU_ID_PTR(cpu, xen_intr_pcpu); | |||||
if (pcpu->evtchn_intrcnt != NULL) | |||||
return; | |||||
snprintf(buf, sizeof(buf), "cpu%d:xen", cpu); | |||||
intrcnt_add(buf, &pcpu->evtchn_intrcnt); | |||||
} | |||||
/** | |||||
* Attempt to free an active Xen interrupt source object. | * Attempt to free an active Xen interrupt source object. | ||||
* | * | ||||
* \param isrc The interrupt source object to release. | * \param isrc The interrupt source object to release. | ||||
* | * | ||||
* \returns EBUSY if the source is still in use, otherwise 0. | * \returns EBUSY if the source is still in use, otherwise 0. | ||||
*/ | */ | ||||
static int | static int | ||||
xen_intr_release_isrc(struct xenisrc *isrc) | xen_intr_release_isrc(struct xenisrc *isrc) | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | return (sh->evtchn_pending[idx] | ||||
& pcpu->evtchn_enabled[idx]); | & pcpu->evtchn_enabled[idx]); | ||||
} | } | ||||
/** | /** | ||||
* Interrupt handler for processing all Xen event channel events. | * Interrupt handler for processing all Xen event channel events. | ||||
* | * | ||||
* \param trap_frame The trap frame context for the current interrupt. | * \param trap_frame The trap frame context for the current interrupt. | ||||
*/ | */ | ||||
void | int | ||||
xen_intr_handle_upcall(struct trapframe *trap_frame) | xen_intr_handle_upcall(void *unused __unused) | ||||
{ | { | ||||
struct trapframe *trap_frame = curthread->td_intr_frame; | |||||
u_int l1i, l2i, port, cpu; | u_int l1i, l2i, port, cpu; | ||||
u_long masked_l1, masked_l2; | u_long masked_l1, masked_l2; | ||||
struct xenisrc *isrc; | struct xenisrc *isrc; | ||||
shared_info_t *s; | shared_info_t *s; | ||||
vcpu_info_t *v; | vcpu_info_t *v; | ||||
struct xen_intr_pcpu_data *pc; | struct xen_intr_pcpu_data *pc; | ||||
u_long l1, l2; | u_long l1, l2; | ||||
/* | int handled = FILTER_STRAY; | ||||
* Disable preemption in order to always check and fire events | |||||
* on the right vCPU | |||||
*/ | |||||
critical_enter(); | |||||
cpu = PCPU_GET(cpuid); | cpu = PCPU_GET(cpuid); | ||||
pc = DPCPU_PTR(xen_intr_pcpu); | pc = DPCPU_PTR(xen_intr_pcpu); | ||||
s = HYPERVISOR_shared_info; | s = HYPERVISOR_shared_info; | ||||
v = DPCPU_GET(vcpu_info); | v = DPCPU_GET(vcpu_info); | ||||
if (!xen_has_percpu_evtchn()) { | if (!xen_has_percpu_evtchn()) { | ||||
KASSERT((cpu == 0), ("Fired PCI event callback on wrong CPU")); | KASSERT((cpu == 0), ("Fired PCI event callback on wrong CPU")); | ||||
} | } | ||||
v->evtchn_upcall_pending = 0; | v->evtchn_upcall_pending = 0; | ||||
#if 0 | #if 0 | ||||
#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */ | #ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */ | ||||
/* Clear master flag /before/ clearing selector flag. */ | /* Clear master flag /before/ clearing selector flag. */ | ||||
wmb(); | wmb(); | ||||
#endif | #endif | ||||
#endif | #endif | ||||
l1 = atomic_readandclear_long(&v->evtchn_pending_sel); | l1 = atomic_readandclear_long(&v->evtchn_pending_sel); | ||||
l1i = pc->last_processed_l1i; | l1i = pc->last_processed_l1i; | ||||
l2i = pc->last_processed_l2i; | l2i = pc->last_processed_l2i; | ||||
(*pc->evtchn_intrcnt)++; | |||||
while (l1 != 0) { | while (l1 != 0) { | ||||
l1i = (l1i + 1) % LONG_BIT; | l1i = (l1i + 1) % LONG_BIT; | ||||
masked_l1 = l1 & ((~0UL) << l1i); | masked_l1 = l1 & ((~0UL) << l1i); | ||||
if (masked_l1 == 0) { | if (masked_l1 == 0) { | ||||
/* | /* | ||||
* if we masked out all events, wrap around | * if we masked out all events, wrap around | ||||
Show All 26 Lines | do { | ||||
if (__predict_false(isrc == NULL)) | if (__predict_false(isrc == NULL)) | ||||
continue; | continue; | ||||
/* Make sure we are firing on the right vCPU */ | /* Make sure we are firing on the right vCPU */ | ||||
KASSERT((isrc->xi_cpu == PCPU_GET(cpuid)), | KASSERT((isrc->xi_cpu == PCPU_GET(cpuid)), | ||||
("Received unexpected event on vCPU#%d, event bound to vCPU#%u", | ("Received unexpected event on vCPU#%d, event bound to vCPU#%u", | ||||
PCPU_GET(cpuid), isrc->xi_cpu)); | PCPU_GET(cpuid), isrc->xi_cpu)); | ||||
xen_arch_intr_execute_handlers(isrc, trap_frame); | if (xen_arch_intr_execute_handlers(isrc, trap_frame)) | ||||
handled = FILTER_HANDLED; | |||||
Done Inline ActionsHere there is a big question. What should be being used for the trap_frame? ehem_freebsd_m5p.com: Here there is a big question. What should be being used for the trap_frame? | |||||
Not Done Inline ActionsIt looks like it's doing the right thing by passing trap_frame. mhorne: It looks like it's doing the right thing by passing `trap_frame`. | |||||
/* | /* | ||||
* If this is the final port processed, | * If this is the final port processed, | ||||
* we'll pick up here+1 next time. | * we'll pick up here+1 next time. | ||||
*/ | */ | ||||
pc->last_processed_l1i = l1i; | pc->last_processed_l1i = l1i; | ||||
pc->last_processed_l2i = l2i; | pc->last_processed_l2i = l2i; | ||||
} while (l2i != LONG_BIT - 1); | } while (l2i != LONG_BIT - 1); | ||||
l2 = xen_intr_active_ports(pc, s, l1i); | l2 = xen_intr_active_ports(pc, s, l1i); | ||||
if (l2 == 0) { | if (l2 == 0) { | ||||
/* | /* | ||||
* We handled all ports, so we can clear the | * We handled all ports, so we can clear the | ||||
* selector bit. | * selector bit. | ||||
*/ | */ | ||||
l1 &= ~(1UL << l1i); | l1 &= ~(1UL << l1i); | ||||
} | } | ||||
} | } | ||||
if (xen_evtchn_needs_ack) | return (handled); | ||||
lapic_eoi(); | |||||
critical_exit(); | |||||
} | } | ||||
static int | static int | ||||
xen_intr_init(void *dummy __unused) | xen_intr_init(void *dummy __unused) | ||||
{ | { | ||||
shared_info_t *s = HYPERVISOR_shared_info; | shared_info_t *s = HYPERVISOR_shared_info; | ||||
struct xen_intr_pcpu_data *pcpu; | struct xen_intr_pcpu_data *pcpu; | ||||
u_int i; | u_int i; | ||||
Show All 19 Lines | xen_intr_init(void *dummy __unused) | ||||
xen_arch_intr_init(); | xen_arch_intr_init(); | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("Xen interrupt system initialized\n"); | printf("Xen interrupt system initialized\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_SECOND, xen_intr_init, NULL); | SYSINIT(xen_intr_init, SI_SUB_INTR, SI_ORDER_SECOND, xen_intr_init, NULL); | ||||
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); | |||||
/*--------------------------- Common PIC Functions ---------------------------*/ | /*--------------------------- Common PIC Functions ---------------------------*/ | ||||
/** | /** | ||||
* Prepare this PIC for system suspension. | * Prepare this PIC for system suspension. | ||||
*/ | */ | ||||
void | void | ||||
xen_intr_suspend(void) | xen_intr_suspend(void) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 660 Lines • Show Last 20 Lines |
Why is this being removed?