[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



On 07/11/14 14:02, Paul Durrant wrote:
>> -----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.

Moving from FIFO to 2-level is only safe if you use fewer than 4095 (or
1023 on 32-bit) events, but this shouldn't be a problem for a Windows guest

>> 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 @@

>> +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];
>> +}

I'm not at all familiar with Windows kernel memory management but is all
this MDL stuff expensive?  Can you not store the VA instead of looking
it up every time?

>> +
>> +static FORCEINLINE BOOLEAN
>> +__EvtchnFifoTestFlag(
>> +    IN  event_word_t    *EventWord,
>> +    IN  ULONG           Flag
>> +    )
>> +{
>> +    KeMemoryBarrier();

Do you need this barrier?  The doc has a section describing the minimum
number of barriers needed.

>> +
>> +    return !!(*EventWord & (1 << Flag));
>> +}
>> +
>> +static FORCEINLINE BOOLEAN
>> +__EvtchnFifoTestAndSetFlag(
>> +    IN  event_word_t    *EventWord,
>> +    IN  ULONG           Flag
>> +    )
>> +{
>> +    KeMemoryBarrier();

Or this one?  The Interlocked*() functions are also already barriers.

>> +
>> +    return !!InterlockedBitTestAndSet((LONG *)EventWord, Flag);
>> +}
>> +
>> +static FORCEINLINE BOOLEAN
>> +__EvtchnFifoTestAndClearFlag(
>> +    IN  event_word_t    *EventWord,
>> +    IN  ULONG           Flag
>> +    )
>> +{
>> +    KeMemoryBarrier();

ditto.

>> +
>> +    return !!InterlockedBitTestAndReset((LONG *)EventWord, Flag);
>> +}
>> +
>> +static FORCEINLINE VOID
>> +__EvtchnFifoSetFlag(
>> +    IN  event_word_t    *EventWord,
>> +    IN  ULONG           Flag
>> +    )
>> +{
>> +    *EventWord |= (1 << Flag);

This must be atomic.  Remember that Xen may be simultaneously writing to
this word from a different PCPU.

You need an InterlockedBitSet() (which doesn't seem to exist.  Perhaps
make one with InterlockedOr()?)

>> +    KeMemoryBarrier();
>> +}
>> +
>> +static FORCEINLINE VOID
>> +__EvtchnFifoClearFlag(
>> +    IN  event_word_t    *EventWord,
>> +    IN  ULONG           Flag
>> +    )
>> +{
>> +    *EventWord &= ~(1 << Flag);

This must be atomic as well.

>> +static VOID
>> +EvtchnFifoContract(
>> +    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context
>> +    )
>> +{

You can't shrink the event array if it is in use.  I assume this is only
called after an EVTCHNOP_reset hypercall?

>> +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;

The doc says you should do an EVTCHNOP_unmask hypercall here, but
picking up any pending event here is fine.

You may want to be more careful if you unmask an event while running on
a VCPU that is not the one the event is bound to.

>> +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;

You may wish to consider the console event channel as well.  But if you
don't use it, it's ok to leave it unbound.

David

_______________________________________________
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®.