[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH 4/4] Use per-CPU event channel upcalls if available
A recent patch to Xen introduced a new HVM op to set a per-vcpu event channel upcall. This patch adds code to make use of the latched interrupts allocated by the FDO code to enable per-vcpu upcalls and adds an extra EvtchnBind operation to a new v2 EVTCHN interface so that events can be steered to a specified CPU. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- include/evtchn_interface.h | 35 ++++++- include/xen.h | 16 +++ src/xen/event_channel.c | 30 ++++++ src/xen/hvm.c | 28 ++++++ src/xenbus/evtchn.c | 239 ++++++++++++++++++++++++++++++++++++++++++--- src/xenbus/store.c | 9 ++ 6 files changed, 341 insertions(+), 16 deletions(-) diff --git a/include/evtchn_interface.h b/include/evtchn_interface.h index 5898e08..4ab2b28 100644 --- a/include/evtchn_interface.h +++ b/include/evtchn_interface.h @@ -112,6 +112,20 @@ typedef PXENBUS_EVTCHN_CHANNEL ... ); +/*! \typedef XENBUS_EVTCHN_BIND + \brief Bind an event channel to a specific CPU + + \param Interface The interface header + \param Channel The channel handle + \param Cpu The CPU that should handle events +*/ +typedef NTSTATUS +(*XENBUS_EVTCHN_BIND)( + IN PINTERFACE Interface, + IN PXENBUS_EVTCHN_CHANNEL Channel, + IN ULONG Cpu + ); + /*! \typedef XENBUS_EVTCHN_UNMASK \brief Unmask an event channel @@ -196,7 +210,24 @@ struct _XENBUS_EVTCHN_INTERFACE_V1 { XENBUS_EVTCHN_CLOSE EvtchnClose; }; -typedef struct _XENBUS_EVTCHN_INTERFACE_V1 XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVTCHN_INTERFACE; +/*! \struct _XENBUS_EVTCHN_INTERFACE_V2 + \brief EVTCHN interface version 2 + \ingroup interfaces +*/ +struct _XENBUS_EVTCHN_INTERFACE_V2 { + INTERFACE Interface; + XENBUS_EVTCHN_ACQUIRE EvtchnAcquire; + XENBUS_EVTCHN_RELEASE EvtchnRelease; + XENBUS_EVTCHN_OPEN EvtchnOpen; + XENBUS_EVTCHN_BIND EvtchnBind; + XENBUS_EVTCHN_UNMASK EvtchnUnmask; + XENBUS_EVTCHN_SEND EvtchnSend; + XENBUS_EVTCHN_TRIGGER EvtchnTrigger; + XENBUS_EVTCHN_GET_PORT EvtchnGetPort; + XENBUS_EVTCHN_CLOSE EvtchnClose; +}; + +typedef struct _XENBUS_EVTCHN_INTERFACE_V2 XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVTCHN_INTERFACE; /*! \def XENBUS_EVTCHN \brief Macro at assist in method invocation @@ -207,7 +238,7 @@ typedef struct _XENBUS_EVTCHN_INTERFACE_V1 XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVT #endif // _WINDLL #define XENBUS_EVTCHN_INTERFACE_VERSION_MIN 1 -#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 1 +#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 2 #endif // _XENBUS_EVTCHN_INTERFACE_H diff --git a/include/xen.h b/include/xen.h index 0dabc74..84197a5 100644 --- a/include/xen.h +++ b/include/xen.h @@ -97,6 +97,14 @@ HvmPagetableDying( IN PHYSICAL_ADDRESS Address ); +__checkReturn +XEN_API +NTSTATUS +HvmSetEvtchnUpcallVector( + IN unsigned int vcpu_id, + IN UCHAR Vector + ); + // MEMORY __checkReturn @@ -196,6 +204,14 @@ EventChannelReset( VOID ); +__checkReturn +XEN_API +NTSTATUS +EventChannelBindVirtualCpu( + IN ULONG LocalPort, + IN unsigned int vcpu_id + ); + // GRANT TABLE __checkReturn diff --git a/src/xen/event_channel.c b/src/xen/event_channel.c index aa87fd4..94a6b82 100644 --- a/src/xen/event_channel.c +++ b/src/xen/event_channel.c @@ -327,3 +327,33 @@ fail1: return status; } + +__checkReturn +XEN_API +NTSTATUS +EventChannelBindVirtualCpu( + IN ULONG LocalPort, + IN unsigned int vcpu_id + ) +{ + struct evtchn_bind_vcpu op; + LONG_PTR rc; + NTSTATUS status; + + op.port = LocalPort; + op.vcpu = vcpu_id; + + rc = EventChannelOp(EVTCHNOP_bind_vcpu, &op); + + if (rc < 0) { + ERRNO_TO_STATUS(-rc, status); + goto fail1; + } + + return STATUS_SUCCESS; + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} diff --git a/src/xen/hvm.c b/src/xen/hvm.c index 8135e97..3e3e12c 100644 --- a/src/xen/hvm.c +++ b/src/xen/hvm.c @@ -166,3 +166,31 @@ HvmPagetableDying( fail1: return status; } + +__checkReturn +XEN_API +NTSTATUS +HvmSetEvtchnUpcallVector( + IN unsigned int vcpu_id, + IN UCHAR Vector + ) +{ + struct xen_hvm_set_evtchn_upcall_vector op; + LONG_PTR rc; + NTSTATUS status; + + op.vcpu = vcpu_id; + op.vector = Vector; + + rc = HvmOp(HVMOP_set_evtchn_upcall_vector, &op); + + if (rc < 0) { + ERRNO_TO_STATUS(-rc, status); + goto fail1; + } + + return STATUS_SUCCESS; + +fail1: + return status; +} diff --git a/src/xenbus/evtchn.c b/src/xenbus/evtchn.c index 44043d4..aa26a31 100644 --- a/src/xenbus/evtchn.c +++ b/src/xenbus/evtchn.c @@ -82,13 +82,16 @@ struct _XENBUS_EVTCHN_CHANNEL { XENBUS_EVTCHN_PARAMETERS Parameters; BOOLEAN Mask; ULONG LocalPort; + PXENBUS_INTERRUPT Interrupt; }; struct _XENBUS_EVTCHN_CONTEXT { PXENBUS_FDO Fdo; KSPIN_LOCK Lock; LONG References; - PXENBUS_INTERRUPT Interrupt; + PXENBUS_INTERRUPT LevelSensitiveInterrupt; + PXENBUS_INTERRUPT LatchedInterrupt[MAXIMUM_PROCESSORS]; + KAFFINITY Affinity; BOOLEAN Enabled; XENBUS_SUSPEND_INTERFACE SuspendInterface; PXENBUS_SUSPEND_CALLBACK SuspendCallbackEarly; @@ -127,15 +130,39 @@ EvtchnInterruptEnable( IN PXENBUS_EVTCHN_CONTEXT Context ) { + LONG Cpu; ULONG Line; NTSTATUS status; - Trace("<===>\n"); + Trace("====>\n"); + + ASSERT3U(Context->Affinity, ==, 0); + + Cpu = 0; + while (Cpu < KeNumberProcessors) { + unsigned int vcpu_id; + UCHAR Vector; + + vcpu_id = SystemVirtualCpuIndex(Cpu); + Vector = FdoGetInterruptVector(Context->Fdo, + Context->LatchedInterrupt[Cpu]); + + status = HvmSetEvtchnUpcallVector(vcpu_id, Vector); + if (NT_SUCCESS(status)) { + Info("CPU %u\n", Cpu); + Context->Affinity |= (KAFFINITY)1 << Cpu; + } + + Cpu++; + } - Line = FdoGetInterruptLine(Context->Fdo, Context->Interrupt); + Line = FdoGetInterruptLine(Context->Fdo, + Context->LevelSensitiveInterrupt); status = HvmSetParam(HVM_PARAM_CALLBACK_IRQ, Line); ASSERT(NT_SUCCESS(status)); + + Trace("<====\n"); } static VOID @@ -143,14 +170,29 @@ EvtchnInterruptDisable( IN PXENBUS_EVTCHN_CONTEXT Context ) { + LONG Cpu; NTSTATUS status; UNREFERENCED_PARAMETER(Context); - Trace("<===>\n"); + Trace("====>\n"); status = HvmSetParam(HVM_PARAM_CALLBACK_IRQ, 0); ASSERT(NT_SUCCESS(status)); + + Cpu = KeNumberProcessors; + while (--Cpu >= 0) { + unsigned int vcpu_id; + + vcpu_id = SystemVirtualCpuIndex(Cpu); + + (VOID) HvmSetEvtchnUpcallVector(vcpu_id, 0); + Context->Affinity &= ~((KAFFINITY)1 << Cpu); + } + + ASSERT3U(Context->Affinity, ==, 0); + + Trace("<====\n"); } static FORCEINLINE @@ -159,10 +201,11 @@ _IRQL_saves_ _IRQL_raises_(HIGH_LEVEL) KIRQL __EvtchnAcquireInterruptLock( - IN PXENBUS_EVTCHN_CONTEXT Context + IN PXENBUS_EVTCHN_CONTEXT Context, + IN PXENBUS_EVTCHN_CHANNEL Channel ) { - return FdoAcquireInterruptLock(Context->Fdo, Context->Interrupt); + return FdoAcquireInterruptLock(Context->Fdo, Channel->Interrupt); } static FORCEINLINE @@ -170,10 +213,11 @@ __drv_requiresIRQL(HIGH_LEVEL) VOID __EvtchnReleaseInterruptLock( IN PXENBUS_EVTCHN_CONTEXT Context, + IN PXENBUS_EVTCHN_CHANNEL Channel, IN __drv_restoresIRQL KIRQL Irql ) { - FdoReleaseInterruptLock(Context->Fdo, Context->Interrupt, Irql); + FdoReleaseInterruptLock(Context->Fdo, Channel->Interrupt, Irql); } static NTSTATUS @@ -358,6 +402,10 @@ EvtchnOpen( LocalPort = Channel->LocalPort; + Channel->Interrupt = (Context->Affinity != 0) ? // Latched available + Context->LatchedInterrupt[0] : + Context->LevelSensitiveInterrupt; + status = XENBUS_EVTCHN_ABI(PortEnable, &Context->EvtchnAbi, LocalPort); @@ -422,6 +470,89 @@ fail1: return NULL; } +#define EVTCHN_SWAP_POINTER(_X, _Y) \ + do { \ + (_X) = (PVOID)((ULONG_PTR)(_X) ^ (ULONG_PTR)(_Y)); \ + (_Y) = (PVOID)((ULONG_PTR)(_X) ^ (ULONG_PTR)(_Y)); \ + (_X) = (PVOID)((ULONG_PTR)(_X) ^ (ULONG_PTR)(_Y)); \ + } while (FALSE) + +static NTSTATUS +EvtchnBind( + IN PINTERFACE Interface, + IN PXENBUS_EVTCHN_CHANNEL Channel, + IN ULONG Cpu + ) +{ + PXENBUS_EVTCHN_CONTEXT Context = Interface->Context; + PXENBUS_INTERRUPT Interrupt; + ULONG LocalPort; + unsigned int vcpu_id; + KIRQL Irql; + NTSTATUS status; + + status = STATUS_INVALID_PARAMETER; + if (Cpu >= (ULONG)KeNumberProcessors) + goto fail1; + + ASSERT(Context->Enabled); + + status = STATUS_NOT_SUPPORTED; + if (~Context->Affinity & ((KAFFINITY)1 << Cpu)) + goto fail2; + + Interrupt = Context->LatchedInterrupt[Cpu]; + + if (Channel->Interrupt == Interrupt) + goto done; + + KeRaiseIrql(HIGH_LEVEL, &Irql); + + // Make sure we always lock in a consistent order + if ((ULONG_PTR)Interrupt < (ULONG_PTR)Channel->Interrupt) { + (VOID) FdoAcquireInterruptLock(Context->Fdo, Interrupt); + (VOID) FdoAcquireInterruptLock(Context->Fdo, Channel->Interrupt); + } else { + (VOID) FdoAcquireInterruptLock(Context->Fdo, Channel->Interrupt); + (VOID) FdoAcquireInterruptLock(Context->Fdo, Interrupt); + } + + LocalPort = Channel->LocalPort; + vcpu_id = SystemVirtualCpuIndex(Cpu); + + status = EventChannelBindVirtualCpu(LocalPort, vcpu_id); + if (!NT_SUCCESS(status)) + goto fail3; + + EVTCHN_SWAP_POINTER(Channel->Interrupt, Interrupt); + + FdoReleaseInterruptLock(Context->Fdo, Channel->Interrupt, HIGH_LEVEL); + FdoReleaseInterruptLock(Context->Fdo, Interrupt, HIGH_LEVEL); + + KeLowerIrql(Irql); + + Info("[%u]: CPU %u\n", LocalPort, Cpu); + +done: + return STATUS_SUCCESS; + +fail3: + Error("fail3\n"); + + FdoReleaseInterruptLock(Context->Fdo, Channel->Interrupt, HIGH_LEVEL); + FdoReleaseInterruptLock(Context->Fdo, Interrupt, HIGH_LEVEL); + + KeLowerIrql(Irql); + +fail2: + Error("fail2\n"); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + static BOOLEAN EvtchnUnmask( IN PINTERFACE Interface, @@ -516,7 +647,7 @@ EvtchnTrigger( ASSERT3U(Channel->Magic, ==, XENBUS_EVTCHN_CHANNEL_MAGIC); - Irql = __EvtchnAcquireInterruptLock(Context); + Irql = __EvtchnAcquireInterruptLock(Context, Channel); ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL); @@ -527,7 +658,7 @@ EvtchnTrigger( DoneSomething = FALSE; } - __EvtchnReleaseInterruptLock(Context, Irql); + __EvtchnReleaseInterruptLock(Context, Channel, Irql); return DoneSomething; } @@ -575,6 +706,8 @@ EvtchnClose( ASSERT(NT_SUCCESS(status)); } + Channel->Interrupt = NULL; + Channel->LocalPort = 0; RtlZeroMemory(&Channel->Parameters, sizeof (XENBUS_EVTCHN_PARAMETERS)); @@ -617,6 +750,8 @@ EvtchnPollCallback( BOOLEAN DoneSomething; NTSTATUS status; + DoneSomething = FALSE; + status = HashTableLookup(Context->Table, LocalPort, (PULONG_PTR)&Channel); @@ -628,10 +763,20 @@ EvtchnPollCallback( &Context->EvtchnAbi, LocalPort); - DoneSomething = FALSE; goto done; } + if (Context->Affinity != 0) { + ULONG Cpu; + + ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL); + Cpu = KeGetCurrentProcessorNumber(); + + // Only handle events on the correct CPU + if (Channel->Interrupt != Context->LatchedInterrupt[Cpu]) + goto done; + } + if (Channel->Mask) XENBUS_EVTCHN_ABI(PortMask, &Context->EvtchnAbi, @@ -767,8 +912,10 @@ EvtchnSuspendCallbackLate( status = EvtchnAbiAcquire(Context); ASSERT(NT_SUCCESS(status)); - if (Context->Enabled) + if (Context->Enabled) { + EvtchnInterruptDisable(Context); EvtchnInterruptEnable(Context); + } } static VOID @@ -862,6 +1009,7 @@ EvtchnAcquire( PXENBUS_EVTCHN_CONTEXT Context = Interface->Context; PXENBUS_FDO Fdo = Context->Fdo; KIRQL Irql; + LONG Cpu; NTSTATUS status; KeAcquireSpinLock(&Context->Lock, &Irql); @@ -919,10 +1067,24 @@ EvtchnAcquire( 0, EvtchnInterruptCallback, Context, - &Context->Interrupt); + &Context->LevelSensitiveInterrupt); if (!NT_SUCCESS(status)) goto fail8; + Cpu = 0; + while (Cpu < KeNumberProcessors) { + status = FdoAllocateInterrupt(Fdo, + Latched, + Cpu, + EvtchnInterruptCallback, + Context, + &Context->LatchedInterrupt[Cpu]); + if (!NT_SUCCESS(status)) + goto fail9; + + Cpu++; + } + Trace("<====\n"); done: @@ -930,6 +1092,17 @@ done: return STATUS_SUCCESS; +fail9: + Error("fail9\n"); + + while (--Cpu >= 0) { + FdoFreeInterrupt(Fdo, Context->LatchedInterrupt[Cpu]); + Context->LatchedInterrupt[Cpu] = NULL; + } + + FdoFreeInterrupt(Fdo, Context->LevelSensitiveInterrupt); + Context->LevelSensitiveInterrupt = NULL; + fail8: Error("fail8\n"); @@ -990,7 +1163,9 @@ EvtchnRelease( ) { PXENBUS_EVTCHN_CONTEXT Context = Interface->Context; + PXENBUS_FDO Fdo = Context->Fdo; KIRQL Irql; + LONG Cpu; KeAcquireSpinLock(&Context->Lock, &Irql); @@ -1002,8 +1177,14 @@ EvtchnRelease( if (!IsListEmpty(&Context->List)) BUG("OUTSTANDING EVENT CHANNELS"); - FdoFreeInterrupt(Context->Fdo, Context->Interrupt); - Context->Interrupt = NULL; + Cpu = KeNumberProcessors; + while (--Cpu >= 0) { + FdoFreeInterrupt(Fdo, Context->LatchedInterrupt[Cpu]); + Context->LatchedInterrupt[Cpu] = NULL; + } + + FdoFreeInterrupt(Fdo, Context->LevelSensitiveInterrupt); + Context->LevelSensitiveInterrupt = NULL; EvtchnAbiRelease(Context); @@ -1046,6 +1227,19 @@ static struct _XENBUS_EVTCHN_INTERFACE_V1 EvtchnInterfaceVersion1 = { EvtchnClose }; +static struct _XENBUS_EVTCHN_INTERFACE_V2 EvtchnInterfaceVersion2 = { + { sizeof (struct _XENBUS_EVTCHN_INTERFACE_V2), 2, NULL, NULL, NULL }, + EvtchnAcquire, + EvtchnRelease, + EvtchnOpen, + EvtchnBind, + EvtchnUnmask, + EvtchnSend, + EvtchnTrigger, + EvtchnGetPort, + EvtchnClose +}; + NTSTATUS EvtchnInitialize( IN PXENBUS_FDO Fdo, @@ -1171,6 +1365,23 @@ EvtchnGetInterface( status = STATUS_SUCCESS; break; } + case 2: { + struct _XENBUS_EVTCHN_INTERFACE_V2 *EvtchnInterface; + + EvtchnInterface = (struct _XENBUS_EVTCHN_INTERFACE_V2 *)Interface; + + status = STATUS_BUFFER_OVERFLOW; + if (Size < sizeof (struct _XENBUS_EVTCHN_INTERFACE_V2)) + break; + + *EvtchnInterface = EvtchnInterfaceVersion2; + + ASSERT3U(Interface->Version, ==, Version); + Interface->Context = Context; + + status = STATUS_SUCCESS; + break; + } default: status = STATUS_NOT_SUPPORTED; break; diff --git a/src/xenbus/store.c b/src/xenbus/store.c index 22c2a12..04fce3a 100644 --- a/src/xenbus/store.c +++ b/src/xenbus/store.c @@ -1848,6 +1848,15 @@ StoreEnable( FALSE); ASSERT(Context->Channel != NULL); + // + // Attempt to use some CPU other than 0 for events from + // xenstored. + // + (VOID) XENBUS_EVTCHN(Bind, + &Context->EvtchnInterface, + Context->Channel, + KeNumberProcessors - 1); + Pending = XENBUS_EVTCHN(Unmask, &Context->EvtchnInterface, Context->Channel, -- 2.1.1 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |