[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [win-pv-devel] [PATCH 10/10] Add support for the FIFO event channel ABI



> -----Original Message-----
> From: Paul Durrant [mailto:paul.durrant@xxxxxxxxxx]
> Sent: 06 November 2014 14:31
> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Paul Durrant
> Subject: [PATCH 10/10] Add support for the FIFO event channel ABI
> 
> If it is available then the fifo ABI will be used. If it is not then the
> two-level ABI will be used instead.
> The ABI is released and re-acquired across suspend/resume so this should
> allow moving between hosts with different capabilities.
> 
> Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>

Cc-ing David Vrabel for review.

  Paul

> ---
>  include/xen.h                |  41 ++-
>  src/xen/event_channel.c      | 128 ++++++++
>  src/xenbus/evtchn.c          |  27 +-
>  src/xenbus/evtchn_fifo.c     | 702
> +++++++++++++++++++++++++++++++++++++++++++
>  src/xenbus/evtchn_fifo.h     |  59 ++++
>  src/xenbus/store.c           |  11 +-
>  vs2012/xenbus/xenbus.vcxproj |   1 +
>  vs2013/xenbus/xenbus.vcxproj |   1 +
>  8 files changed, 962 insertions(+), 8 deletions(-)
>  create mode 100644 src/xenbus/evtchn_fifo.c
>  create mode 100644 src/xenbus/evtchn_fifo.h
> 
> diff --git a/include/xen.h b/include/xen.h
> index 674676c..0039d7a 100644
> --- a/include/xen.h
> +++ b/include/xen.h
> @@ -136,17 +136,26 @@ __checkReturn
>  XEN_API
>  NTSTATUS
>  EventChannelBindInterDomain(
> -    IN  domid_t                     RemoteDomain,
> -    IN  evtchn_port_t               RemotePort,
> -    OUT evtchn_port_t               *LocalPort
> +    IN  domid_t         RemoteDomain,
> +    IN  evtchn_port_t   RemotePort,
> +    OUT evtchn_port_t   *LocalPort
>      );
> 
>  __checkReturn
>  XEN_API
>  NTSTATUS
>  EventChannelBindVirq(
> -    IN  uint32_t            Virq,
> -    OUT evtchn_port_t       *LocalPort
> +    IN  uint32_t        Virq,
> +    OUT evtchn_port_t   *LocalPort
> +    );
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +EventChannelQueryInterDomain(
> +    IN  evtchn_port_t   LocalPort,
> +    OUT domid_t         *RemoteDomain,
> +    OUT evtchn_port_t   *RemotePort
>      );
> 
>  __checkReturn
> @@ -156,6 +165,28 @@ EventChannelClose(
>      IN  evtchn_port_t   LocalPort
>      );
> 
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +EventChannelExpandArray(
> +    IN  PFN_NUMBER              Pfn
> +    );
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +EventChannelInitControl(
> +    IN  PFN_NUMBER              Pfn,
> +    IN  unsigned int            vcpu_id
> +    );
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +EventChannelReset(
> +    VOID
> +    );
> +
>  // GRANT TABLE
> 
>  __checkReturn
> diff --git a/src/xen/event_channel.c b/src/xen/event_channel.c
> index 23e4659..aa87fd4 100644
> --- a/src/xen/event_channel.c
> +++ b/src/xen/event_channel.c
> @@ -175,6 +175,47 @@ fail1:
>  __checkReturn
>  XEN_API
>  NTSTATUS
> +EventChannelQueryInterDomain(
> +    IN  evtchn_port_t               LocalPort,
> +    OUT domid_t                     *RemoteDomain,
> +    OUT evtchn_port_t               *RemotePort
> +    )
> +{
> +    struct evtchn_status            op;
> +    LONG_PTR                        rc;
> +    NTSTATUS                        status;
> +
> +    op.dom = DOMID_SELF;
> +    op.port = LocalPort;
> +
> +    rc = EventChannelOp(EVTCHNOP_status, &op);
> +
> +    if (rc < 0) {
> +        ERRNO_TO_STATUS(-rc, status);
> +        goto fail1;
> +    }
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (op.status != EVTCHNSTAT_interdomain)
> +        goto fail2;
> +
> +    *RemoteDomain = op.u.interdomain.dom;
> +    *RemotePort = op.u.interdomain.port;
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    Error("fail2\n");
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
>  EventChannelClose(
>      IN  evtchn_port_t   LocalPort
>      )
> @@ -199,3 +240,90 @@ fail1:
> 
>      return status;
>  }
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +EventChannelExpandArray(
> +    IN  PFN_NUMBER              Pfn
> +    )
> +{
> +    struct evtchn_expand_array  op;
> +    LONG_PTR                    rc;
> +    NTSTATUS                    status;
> +
> +    op.array_gfn = Pfn;
> +
> +    rc = EventChannelOp(EVTCHNOP_expand_array, &op);
> +
> +    if (rc < 0) {
> +        ERRNO_TO_STATUS(-rc, status);
> +        goto fail1;
> +    }
> +
> +    return STATUS_SUCCESS;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +EventChannelInitControl(
> +    IN  PFN_NUMBER              Pfn,
> +    IN  unsigned int            vcpu_id
> +    )
> +{
> +    struct evtchn_init_control  op;
> +    LONG_PTR                    rc;
> +    NTSTATUS                    status;
> +
> +    op.control_gfn = Pfn;
> +    op.offset = 0;
> +    op.vcpu = vcpu_id;
> +
> +    rc = EventChannelOp(EVTCHNOP_init_control, &op);
> +
> +    if (rc < 0) {
> +        ERRNO_TO_STATUS(-rc, status);
> +        goto fail1;
> +    }
> +
> +    return STATUS_SUCCESS;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +__checkReturn
> +XEN_API
> +NTSTATUS
> +EventChannelReset(
> +    VOID
> +    )
> +{
> +    struct evtchn_reset op;
> +    LONG_PTR            rc;
> +    NTSTATUS            status;
> +
> +    op.dom = DOMID_SELF;
> +
> +    rc = EventChannelOp(EVTCHNOP_reset, &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/xenbus/evtchn.c b/src/xenbus/evtchn.c
> index f13667e..2be0da8 100644
> --- a/src/xenbus/evtchn.c
> +++ b/src/xenbus/evtchn.c
> @@ -36,6 +36,7 @@
> 
>  #include "evtchn.h"
>  #include "evtchn_2l.h"
> +#include "evtchn_fifo.h"
>  #include "fdo.h"
>  #include "hash_table.h"
>  #include "dbg_print.h"
> @@ -95,6 +96,7 @@ struct _XENBUS_EVTCHN_CONTEXT {
>      PXENBUS_DEBUG_CALLBACK          DebugCallback;
>      XENBUS_SHARED_INFO_INTERFACE    SharedInfoInterface;
>      PXENBUS_EVTCHN_ABI_CONTEXT      EvtchnTwoLevelContext;
> +    PXENBUS_EVTCHN_ABI_CONTEXT      EvtchnFifoContext;
>      XENBUS_EVTCHN_ABI               EvtchnAbi;
>      PXENBUS_HASH_TABLE              Table;
>      LIST_ENTRY                      List;
> @@ -234,7 +236,9 @@ EvtchnOpenInterDomain(
>      RemotePort = va_arg(Arguments, ULONG);
>      Mask = va_arg(Arguments, BOOLEAN);
> 
> -    status = EventChannelBindInterDomain(RemoteDomain, RemotePort,
> &LocalPort);
> +    status = EventChannelBindInterDomain(RemoteDomain,
> +                                         RemotePort,
> +                                         &LocalPort);
>      if (!NT_SUCCESS(status))
>          goto fail1;
> 
> @@ -666,6 +670,13 @@ EvtchnAbiAcquire(
>  {
>      NTSTATUS                    status;
> 
> +    EvtchnFifoGetAbi(Context->EvtchnFifoContext,
> +                     &Context->EvtchnAbi);
> +
> +    status = XENBUS_EVTCHN_ABI(Acquire, &Context->EvtchnAbi);
> +    if (NT_SUCCESS(status))
> +        goto done;
> +
>      EvtchnTwoLevelGetAbi(Context->EvtchnTwoLevelContext,
>                           &Context->EvtchnAbi);
> 
> @@ -673,6 +684,7 @@ EvtchnAbiAcquire(
>      if (!NT_SUCCESS(status))
>          goto fail1;
> 
> +done:
>      return STATUS_SUCCESS;
> 
>  fail1:
> @@ -1024,6 +1036,10 @@ EvtchnInitialize(
>      if (!NT_SUCCESS(status))
>          goto fail3;
> 
> +    status = EvtchnFifoInitialize(Fdo, &(*Context)->EvtchnFifoContext);
> +    if (!NT_SUCCESS(status))
> +        goto fail4;
> +
>      status = SuspendGetInterface(FdoGetSuspendContext(Fdo),
>                                   XENBUS_SUSPEND_INTERFACE_VERSION_MAX,
>                                   (PINTERFACE)&(*Context)->SuspendInterface,
> @@ -1054,6 +1070,12 @@ EvtchnInitialize(
> 
>      return STATUS_SUCCESS;
> 
> +fail4:
> +    Error("fail4\n");
> +
> +    EvtchnTwoLevelTeardown((*Context)->EvtchnTwoLevelContext);
> +    (*Context)->EvtchnTwoLevelContext = NULL;
> +
>  fail3:
>      Error("fail3\n");
> 
> @@ -1131,6 +1153,9 @@ EvtchnTeardown(
>      RtlZeroMemory(&Context->SuspendInterface,
>                    sizeof (XENBUS_SUSPEND_INTERFACE));
> 
> +    EvtchnFifoTeardown(Context->EvtchnFifoContext);
> +    Context->EvtchnFifoContext = NULL;
> +
>      EvtchnTwoLevelTeardown(Context->EvtchnTwoLevelContext);
>      Context->EvtchnTwoLevelContext = NULL;
> 
> diff --git a/src/xenbus/evtchn_fifo.c b/src/xenbus/evtchn_fifo.c
> new file mode 100644
> index 0000000..d37b1cd
> --- /dev/null
> +++ b/src/xenbus/evtchn_fifo.c
> @@ -0,0 +1,702 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include <ntddk.h>
> +#include <stdarg.h>
> +#include <xen.h>
> +#include <util.h>
> +
> +#include "evtchn_fifo.h"
> +#include "shared_info.h"
> +#include "fdo.h"
> +#include "dbg_print.h"
> +#include "assert.h"
> +
> +#define MAX_HVM_VCPUS   128
> +
> +typedef struct _XENBUS_EVTCHN_FIFO_CONTEXT {
> +    PXENBUS_FDO                     Fdo;
> +    KSPIN_LOCK                      Lock;
> +    LONG                            References;
> +    PMDL                            ControlBlockMdl[MAX_HVM_VCPUS];
> +    PMDL                            *EventPageMdl;
> +    ULONG                           EventPageCount;
> +    ULONG                           Head[EVTCHN_FIFO_MAX_QUEUES];
> +} XENBUS_EVTCHN_FIFO_CONTEXT, *PXENBUS_EVTCHN_FIFO_CONTEXT;
> +
> +#define EVENT_WORDS_PER_PAGE    (PAGE_SIZE / sizeof (event_word_t))
> +
> +#define XENBUS_EVTCHN_FIFO_TAG  'OFIF'
> +
> +static FORCEINLINE PVOID
> +__EvtchnFifoAllocate(
> +    IN  ULONG   Length
> +    )
> +{
> +    return __AllocatePoolWithTag(NonPagedPool, Length,
> XENBUS_EVTCHN_FIFO_TAG);
> +}
> +
> +static FORCEINLINE VOID
> +__EvtchnFifoFree(
> +    IN  PVOID   Buffer
> +    )
> +{
> +    ExFreePoolWithTag(Buffer, XENBUS_EVTCHN_FIFO_TAG);
> +}
> +
> +static event_word_t *
> +EvtchnFifoEventWord(
> +    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context,
> +    IN  ULONG                       Port
> +    )
> +{
> +    ULONG                           Index;
> +    PMDL                            Mdl;
> +    event_word_t                    *EventWord;
> +
> +    Index = Port / EVENT_WORDS_PER_PAGE;
> +    ASSERT3U(Index, <, Context->EventPageCount);
> +
> +    Mdl = Context->EventPageMdl[Index];
> +
> +    EventWord = MmGetSystemAddressForMdlSafe(Mdl,
> NormalPagePriority);
> +    ASSERT(EventWord != NULL);
> +
> +    ASSERT3U(Port, >=, Index * EVENT_WORDS_PER_PAGE);
> +    Port -= Index * EVENT_WORDS_PER_PAGE;
> +
> +    return &EventWord[Port];
> +}
> +
> +static FORCEINLINE BOOLEAN
> +__EvtchnFifoTestFlag(
> +    IN  event_word_t    *EventWord,
> +    IN  ULONG           Flag
> +    )
> +{
> +    KeMemoryBarrier();
> +
> +    return !!(*EventWord & (1 << Flag));
> +}
> +
> +static FORCEINLINE BOOLEAN
> +__EvtchnFifoTestAndSetFlag(
> +    IN  event_word_t    *EventWord,
> +    IN  ULONG           Flag
> +    )
> +{
> +    KeMemoryBarrier();
> +
> +    return !!InterlockedBitTestAndSet((LONG *)EventWord, Flag);
> +}
> +
> +static FORCEINLINE BOOLEAN
> +__EvtchnFifoTestAndClearFlag(
> +    IN  event_word_t    *EventWord,
> +    IN  ULONG           Flag
> +    )
> +{
> +    KeMemoryBarrier();
> +
> +    return !!InterlockedBitTestAndReset((LONG *)EventWord, Flag);
> +}
> +
> +static FORCEINLINE VOID
> +__EvtchnFifoSetFlag(
> +    IN  event_word_t    *EventWord,
> +    IN  ULONG           Flag
> +    )
> +{
> +    *EventWord |= (1 << Flag);
> +    KeMemoryBarrier();
> +}
> +
> +static FORCEINLINE VOID
> +__EvtchnFifoClearFlag(
> +    IN  event_word_t    *EventWord,
> +    IN  ULONG           Flag
> +    )
> +{
> +    *EventWord &= ~(1 << Flag);
> +    KeMemoryBarrier();
> +}
> +
> +static FORCEINLINE ULONG
> +__EvtchnFifoUnlink(
> +    IN  event_word_t    *EventWord
> +    )
> +{
> +    LONG                Old;
> +    LONG                New;
> +
> +    do {
> +        Old = *EventWord;
> +
> +        // Clear linked bit and link value
> +        New = Old & ~((1 << EVTCHN_FIFO_LINKED) |
> EVTCHN_FIFO_LINK_MASK);
> +    } while (InterlockedCompareExchange((LONG *)EventWord, New, Old) !=
> Old);
> +
> +    return Old & EVTCHN_FIFO_LINK_MASK;
> +}
> +
> +static NTSTATUS
> +EvtchnFifoExpand(
> +    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context,
> +    IN  ULONG                       Port
> +    )
> +{
> +    LONG                            Index;
> +    ULONG                           EventPageCount;
> +    PMDL                            *EventPageMdl;
> +    PMDL                            Mdl;
> +    ULONG                           Start;
> +    ULONG                           End;
> +    NTSTATUS                        status;
> +
> +    Index = Port / EVENT_WORDS_PER_PAGE;
> +    ASSERT3U(Index, >=, (LONG)Context->EventPageCount);
> +
> +    EventPageCount = Index + 1;
> +    EventPageMdl = __EvtchnFifoAllocate(sizeof (PMDL) * EventPageCount);
> +
> +    status = STATUS_NO_MEMORY;
> +    if (EventPageMdl == NULL)
> +        goto fail1;
> +
> +    for (Index = 0; Index < (LONG)Context->EventPageCount; Index++)
> +        EventPageMdl[Index] = Context->EventPageMdl[Index];
> +
> +    Index = Context->EventPageCount;
> +    while (Index < (LONG)EventPageCount) {
> +        event_word_t        *EventWord;
> +        PFN_NUMBER          Pfn;
> +        PHYSICAL_ADDRESS    Address;
> +
> +        Mdl = __AllocatePage();
> +
> +        status = STATUS_NO_MEMORY;
> +        if (Mdl == NULL)
> +            goto fail2;
> +
> +        EventWord = MmGetSystemAddressForMdlSafe(Mdl,
> NormalPagePriority);
> +        ASSERT(EventWord != NULL);
> +
> +        for (Port = 0; Port < EVENT_WORDS_PER_PAGE; Port++)
> +            __EvtchnFifoSetFlag(&EventWord[Port], EVTCHN_FIFO_MASKED);
> +
> +        Pfn = MmGetMdlPfnArray(Mdl)[0];
> +
> +        status = EventChannelExpandArray(Pfn);
> +        if (!NT_SUCCESS(status))
> +            goto fail3;
> +
> +        Address.QuadPart = (ULONGLONG)Pfn << PAGE_SHIFT;
> +
> +        LogPrintf(LOG_LEVEL_INFO,
> +                  "EVTCHN_FIFO: EVENTARRAY[%u] @ %08x.%08x\n",
> +                  Index,
> +                  Address.HighPart,
> +                  Address.LowPart);
> +
> +        EventPageMdl[Index++] = Mdl;
> +    }
> +
> +    Start = Context->EventPageCount * EVENT_WORDS_PER_PAGE;
> +    End = (EventPageCount * EVENT_WORDS_PER_PAGE) - 1;
> +
> +    Info("added ports [%08x - %08x]\n", Start, End);
> +
> +    if (Context->EventPageMdl != NULL)
> +        __EvtchnFifoFree(Context->EventPageMdl);
> +
> +    Context->EventPageMdl = EventPageMdl;
> +    Context->EventPageCount = EventPageCount;
> +
> +    return STATUS_SUCCESS;
> +
> +fail3:
> +    Error("fail3\n");
> +
> +    __FreePage(Mdl);
> +
> +fail2:
> +    Error("fail2\n");
> +
> +    while (--Index >= (LONG)Context->EventPageCount) {
> +        Mdl = EventPageMdl[Index];
> +
> +        __FreePage(Mdl);
> +    }
> +
> +    __EvtchnFifoFree(EventPageMdl);
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +static VOID
> +EvtchnFifoContract(
> +    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context
> +    )
> +{
> +    LONG                            Index;
> +
> +    Index = Context->EventPageCount;
> +    while (--Index >= 0) {
> +        PMDL    Mdl;
> +
> +        Mdl = Context->EventPageMdl[Index];
> +
> +        __FreePage(Mdl);
> +    }
> +
> +    __EvtchnFifoFree(Context->EventPageMdl);
> +
> +    Context->EventPageMdl = NULL;
> +    Context->EventPageCount = 0;
> +}
> +
> +static BOOLEAN
> +EvtchnFifoPollPriority(
> +    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context,
> +    IN  evtchn_fifo_control_block_t *ControlBlock,
> +    IN  ULONG                       Priority,
> +    IN  PULONG                      Ready,
> +    IN  XENBUS_EVTCHN_ABI_EVENT     Event,
> +    IN  PVOID                       Argument
> +    )
> +{
> +    ULONG                           Head;
> +    ULONG                           Port;
> +    event_word_t                    *EventWord;
> +    BOOLEAN                         DoneSomething;
> +
> +    Head = Context->Head[Priority];
> +
> +    if (Head == 0) {
> +        KeMemoryBarrier();
> +        Head = ControlBlock->head[Priority];
> +    }
> +
> +    Port = Head;
> +    EventWord = EvtchnFifoEventWord(Context, Port);
> +
> +    Head = __EvtchnFifoUnlink(EventWord);
> +
> +    if (Head == 0)
> +        *Ready &= ~(1ull << Priority);
> +
> +    DoneSomething = FALSE;
> +
> +    if (!__EvtchnFifoTestFlag(EventWord, EVTCHN_FIFO_MASKED) &&
> +        __EvtchnFifoTestFlag(EventWord, EVTCHN_FIFO_PENDING))
> +        DoneSomething = Event(Argument, Port);
> +
> +    Context->Head[Priority] = Head;
> +
> +    return DoneSomething;
> +}
> +
> +static BOOLEAN
> +EvtchnFifoPoll(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
> +    IN  ULONG                       Cpu,
> +    IN  XENBUS_EVTCHN_ABI_EVENT     Event,
> +    IN  PVOID                       Argument
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
> +    unsigned int                    vcpu_id = SystemVirtualCpuIndex(Cpu);
> +    PMDL                            Mdl;
> +    evtchn_fifo_control_block_t     *ControlBlock;
> +    ULONG                           Ready;
> +    ULONG                           Priority;
> +    BOOLEAN                         DoneSomething;
> +
> +    Mdl = Context->ControlBlockMdl[vcpu_id];
> +
> +    ControlBlock = MmGetSystemAddressForMdlSafe(Mdl,
> NormalPagePriority);
> +    ASSERT(ControlBlock != NULL);
> +
> +    Ready = InterlockedExchange((LONG *)&ControlBlock->ready, 0);
> +    DoneSomething = FALSE;
> +
> +    while (_BitScanReverse(&Priority, Ready)) {
> +        DoneSomething |= EvtchnFifoPollPriority(Context,
> +                                                ControlBlock,
> +                                                Priority,
> +                                                &Ready,
> +                                                Event,
> +                                                Argument);
> +        Ready |= InterlockedExchange((LONG *)&ControlBlock->ready, 0);
> +    }
> +
> +    return DoneSomething;
> +}
> +
> +static NTSTATUS
> +EvtchnFifoPortEnable(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
> +    IN  ULONG                       Port
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
> +    KIRQL                           Irql;
> +    NTSTATUS                        status;
> +
> +    KeAcquireSpinLock(&Context->Lock, &Irql);
> +
> +    if (Port / EVENT_WORDS_PER_PAGE >= Context->EventPageCount) {
> +        status = EvtchnFifoExpand(Context, Port);
> +
> +        if (!NT_SUCCESS(status))
> +            goto fail1;
> +    }
> +
> +    KeReleaseSpinLock(&Context->Lock, Irql);
> +
> +    return STATUS_SUCCESS;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    KeReleaseSpinLock(&Context->Lock, Irql);
> +
> +    return status;
> +}
> +
> +static VOID
> +EvtchnFifoPortAck(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
> +    IN  ULONG                       Port
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
> +    event_word_t                    *EventWord;
> +
> +    EventWord = EvtchnFifoEventWord(Context, Port);
> +    __EvtchnFifoClearFlag(&EventWord[Port], EVTCHN_FIFO_PENDING);
> +}
> +
> +static VOID
> +EvtchnFifoPortMask(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
> +    IN  ULONG                       Port
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
> +    event_word_t                    *EventWord;
> +
> +    EventWord = EvtchnFifoEventWord(Context, Port);
> +    __EvtchnFifoSetFlag(&EventWord[Port], EVTCHN_FIFO_MASKED);
> +}
> +
> +static BOOLEAN
> +EvtchnFifoPortUnmask(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
> +    IN  ULONG                       Port
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
> +    event_word_t                    *EventWord;
> +    LONG                            Old;
> +    LONG                            New;
> +
> +    EventWord = EvtchnFifoEventWord(Context, Port);
> +
> +    // Clear masked bit, spinning if busy
> +    do {
> +        Old = *EventWord & ~(1 << EVTCHN_FIFO_BUSY);
> +        New = Old & ~(1 << EVTCHN_FIFO_MASKED);
> +    } while (InterlockedCompareExchange((LONG *)EventWord, New, Old) !=
> Old);
> +
> +    // Check whether the port was masked
> +    if (~Old & (1 << EVTCHN_FIFO_MASKED))
> +        return FALSE;
> +
> +    // If we cleared the mask then check whether something is pending
> +    if (!__EvtchnFifoTestAndClearFlag(EventWord, EVTCHN_FIFO_PENDING))
> +        return FALSE;
> +
> +    return TRUE;
> +}
> +
> +static VOID
> +EvtchnFifoPortDisable(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
> +    IN  ULONG                       Port
> +    )
> +{
> +    EvtchnFifoPortMask(_Context, Port);
> +}
> +
> +static VOID
> +EvtchnFifoReset(
> +    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context
> +    )
> +{
> +    ULONGLONG                       Value;
> +    ULONG                           LocalPort;
> +    ULONG                           RemotePort;
> +    USHORT                          RemoteDomain;
> +    NTSTATUS                        status;
> +
> +    UNREFERENCED_PARAMETER(Context);
> +
> +    status = HvmGetParam(HVM_PARAM_STORE_EVTCHN, &Value);
> +    ASSERT(NT_SUCCESS(status));
> +
> +    LocalPort = (LONG)Value;
> +
> +    //
> +    // When we reset the event channel ABI we will lose our
> +    // binding to the STORE event channel, which was set up
> +    // by the toolstack during domain build.
> +    // We need to get the binding back, so we must query the
> +    // remote domain and port, and then re-bind after the
> +    // reset.
> +    //
> +
> +    status = EventChannelQueryInterDomain(LocalPort,
> +                                          &RemoteDomain,
> +                                          &RemotePort);
> +    ASSERT(NT_SUCCESS(status));
> +
> +    LogPrintf(LOG_LEVEL_INFO, "EVTCHN_FIFO: RESET\n");
> +    (VOID) EventChannelReset();
> +
> +    status = EventChannelBindInterDomain(RemoteDomain,
> +                                         RemotePort,
> +                                         &LocalPort);
> +    ASSERT(NT_SUCCESS(status));
> +
> +    Value = LocalPort;
> +
> +    status = HvmSetParam(HVM_PARAM_STORE_EVTCHN, Value);
> +    ASSERT(NT_SUCCESS(status));
> +}
> +
> +static NTSTATUS
> +EvtchnFifoAcquire(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
> +    KIRQL                           Irql;
> +    LONG                            Cpu;
> +    PMDL                            Mdl;
> +    NTSTATUS                        status;
> +
> +    KeAcquireSpinLock(&Context->Lock, &Irql);
> +
> +    if (Context->References++ != 0)
> +        goto done;
> +
> +    Trace("====>\n");
> +
> +    Cpu = 0;
> +    while (Cpu < KeNumberProcessors) {
> +        unsigned int        vcpu_id;
> +        PFN_NUMBER          Pfn;
> +        PHYSICAL_ADDRESS    Address;
> +
> +        Mdl = __AllocatePage();
> +
> +        status = STATUS_NO_MEMORY;
> +        if (Mdl == NULL)
> +            goto fail1;
> +
> +        vcpu_id = SystemVirtualCpuIndex(Cpu);
> +        Pfn = MmGetMdlPfnArray(Mdl)[0];
> +
> +        status = EventChannelInitControl(Pfn, vcpu_id);
> +        if (!NT_SUCCESS(status))
> +            goto fail2;
> +
> +        Address.QuadPart = (ULONGLONG)Pfn << PAGE_SHIFT;
> +
> +        LogPrintf(LOG_LEVEL_INFO,
> +                  "EVTCHN_FIFO: CONTROLBLOCK[%u] @ %08x.%08x\n",
> +                  vcpu_id,
> +                  Address.HighPart,
> +                  Address.LowPart);
> +
> +        Context->ControlBlockMdl[vcpu_id] = Mdl;
> +        Cpu++;
> +    }
> +
> +    Trace("<====\n");
> +
> +done:
> +    KeReleaseSpinLock(&Context->Lock, Irql);
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    __FreePage(Mdl);
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    (VOID) EventChannelReset();
> +
> +    while (--Cpu >= 0) {
> +        unsigned int    vcpu_id;
> +
> +        vcpu_id = SystemVirtualCpuIndex(Cpu);
> +
> +        Mdl = Context->ControlBlockMdl[vcpu_id];
> +        Context->ControlBlockMdl[vcpu_id] = NULL;
> +
> +        __FreePage(Mdl);
> +    }
> +
> +    --Context->References;
> +    ASSERT3U(Context->References, ==, 0);
> +    KeReleaseSpinLock(&Context->Lock, Irql);
> +
> +    return status;
> +}
> +
> +VOID
> +EvtchnFifoRelease(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
> +    KIRQL                           Irql;
> +    LONG                            Cpu;
> +
> +    KeAcquireSpinLock(&Context->Lock, &Irql);
> +
> +    if (--Context->References > 0)
> +        goto done;
> +
> +    Trace("====>\n");
> +
> +    EvtchnFifoReset(Context);
> +
> +    EvtchnFifoContract(Context);
> +
> +    Cpu = KeNumberProcessors;
> +    while (--Cpu >= 0) {
> +        unsigned int    vcpu_id;
> +        PMDL            Mdl;
> +
> +        vcpu_id = SystemVirtualCpuIndex(Cpu);
> +
> +        Mdl = Context->ControlBlockMdl[vcpu_id];
> +        Context->ControlBlockMdl[vcpu_id] = NULL;
> +
> +        __FreePage(Mdl);
> +    }
> +
> +    Trace("<====\n");
> +
> +done:
> +    KeReleaseSpinLock(&Context->Lock, Irql);
> +}
> +
> +static XENBUS_EVTCHN_ABI EvtchnAbiFifo = {
> +    NULL,
> +    EvtchnFifoAcquire,
> +    EvtchnFifoRelease,
> +    EvtchnFifoPoll,
> +    EvtchnFifoPortEnable,
> +    EvtchnFifoPortDisable,
> +    EvtchnFifoPortAck,
> +    EvtchnFifoPortMask,
> +    EvtchnFifoPortUnmask
> +};
> +
> +NTSTATUS
> +EvtchnFifoInitialize(
> +    IN  PXENBUS_FDO                     Fdo,
> +    OUT PXENBUS_EVTCHN_ABI_CONTEXT      *_Context
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT    Context;
> +    NTSTATUS                            status;
> +
> +    Trace("====>\n");
> +
> +    Context = __EvtchnFifoAllocate(sizeof
> (XENBUS_EVTCHN_FIFO_CONTEXT));
> +
> +    status = STATUS_NO_MEMORY;
> +    if (Context == NULL)
> +        goto fail1;
> +
> +    KeInitializeSpinLock(&Context->Lock);
> +
> +    Context->Fdo = Fdo;
> +
> +    *_Context = (PVOID)Context;
> +
> +    Trace("<====\n");
> +
> +    return STATUS_SUCCESS;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +VOID
> +EvtchnFifoGetAbi(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT      _Context,
> +    OUT PXENBUS_EVTCHN_ABI              Abi)
> +{
> +    *Abi = EvtchnAbiFifo;
> +
> +    Abi->Context = (PVOID)_Context;
> +}
> +
> +VOID
> +EvtchnFifoTeardown(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT      _Context
> +    )
> +{
> +    PXENBUS_EVTCHN_FIFO_CONTEXT    Context = (PVOID)_Context;
> +
> +    Trace("====>\n");
> +
> +    Context->Fdo = NULL;
> +
> +    RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
> +
> +    ASSERT(IsZeroMemory(Context, sizeof
> (XENBUS_EVTCHN_FIFO_CONTEXT)));
> +    __EvtchnFifoFree(Context);
> +
> +    Trace("<====\n");
> +}
> diff --git a/src/xenbus/evtchn_fifo.h b/src/xenbus/evtchn_fifo.h
> new file mode 100644
> index 0000000..bf96b19
> --- /dev/null
> +++ b/src/xenbus/evtchn_fifo.h
> @@ -0,0 +1,59 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _XENBUS_EVTCHN_FIFO_H
> +#define _XENBUS_EVTCHN_FIFO_H
> +
> +#include <ntddk.h>
> +#include <xen.h>
> +
> +#include "evtchn_abi.h"
> +#include "fdo.h"
> +
> +extern NTSTATUS
> +EvtchnFifoInitialize(
> +    IN  PXENBUS_FDO                 Fdo,
> +    OUT PXENBUS_EVTCHN_ABI_CONTEXT  *Context
> +    );
> +
> +extern VOID
> +EvtchnFifoGetAbi(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  Context,
> +    OUT PXENBUS_EVTCHN_ABI          Abi
> +    );
> +
> +extern VOID
> +EvtchnFifoTeardown(
> +    IN  PXENBUS_EVTCHN_ABI_CONTEXT  Context
> +    );
> +
> +#endif  // _XENBUS_EVTCHN_FIFO_H
> +
> diff --git a/src/xenbus/store.c b/src/xenbus/store.c
> index 62ec60b..22c2a12 100644
> --- a/src/xenbus/store.c
> +++ b/src/xenbus/store.c
> @@ -1825,13 +1825,20 @@ StoreEnable(
>      IN PXENBUS_STORE_CONTEXT    Context
>      )
>  {
> -    ULONGLONG                   Port;
> +    ULONGLONG                   Value;
> +    ULONG                       Port;
>      BOOLEAN                     Pending;
>      NTSTATUS                    status;
> 
> -    status = HvmGetParam(HVM_PARAM_STORE_EVTCHN, &Port);
> +    status = HvmGetParam(HVM_PARAM_STORE_EVTCHN, &Value);
>      ASSERT(NT_SUCCESS(status));
> 
> +    Port = (ULONG)Value;
> +
> +    LogPrintf(LOG_LEVEL_INFO,
> +              "STORE: EVTCHN %u\n",
> +              Port);
> +
>      Context->Channel = XENBUS_EVTCHN(Open,
>                                       &Context->EvtchnInterface,
>                                       XENBUS_EVTCHN_TYPE_FIXED,
> diff --git a/vs2012/xenbus/xenbus.vcxproj b/vs2012/xenbus/xenbus.vcxproj
> index 6cd12d1..3c184e0 100644
> --- a/vs2012/xenbus/xenbus.vcxproj
> +++ b/vs2012/xenbus/xenbus.vcxproj
> @@ -89,6 +89,7 @@
>               <ClCompile Include="..\..\src\xenbus\driver.c" />
>               <ClCompile Include="..\..\src\xenbus\evtchn.c" />
>               <ClCompile Include="..\..\src\xenbus\evtchn_2l.c" />
> +             <ClCompile Include="..\..\src\xenbus\evtchn_fifo.c" />
>               <ClCompile Include="..\..\src\xenbus\fdo.c" />
>               <ClCompile Include="..\..\src\xenbus\gnttab.c" />
>               <ClCompile Include="..\..\src\xenbus\pdo.c" />
> diff --git a/vs2013/xenbus/xenbus.vcxproj b/vs2013/xenbus/xenbus.vcxproj
> index 0f37f68..ecb602b 100644
> --- a/vs2013/xenbus/xenbus.vcxproj
> +++ b/vs2013/xenbus/xenbus.vcxproj
> @@ -129,6 +129,7 @@
>      <ClCompile Include="..\..\src\xenbus\driver.c" />
>      <ClCompile Include="..\..\src\xenbus\evtchn.c" />
>      <ClCompile Include="..\..\src\xenbus\evtchn_2l.c" />
> +    <ClCompile Include="..\..\src\xenbus\evtchn_fifo.c" />
>      <ClCompile Include="..\..\src\xenbus\fdo.c" />
>      <ClCompile Include="..\..\src\xenbus\gnttab.c" />
>      <ClCompile Include="..\..\src\xenbus\pdo.c" />
> --
> 2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.