[ofw] [PATCH][RFC] winverbs/cq: implement CQ:Notify()

Fab Tillier ftillier at windows.microsoft.com
Thu May 1 12:01:27 PDT 2008


>Initial implementation of CQ:Notify() to support asynchronous notification
>of CQ events.
>
>Signed-off-by: Sean Hefty <sean.hefty at intel.com>
>---
>I'm not sure if the WdfObject*Lock() routines for an IO queue work at dispatch
>by default, but that looks easy enough to correct if they don't.
>
>Index: core/winverbs/kernel/wv_cq.c
>===================================================================
>--- core/winverbs/kernel/wv_cq.c        (revision 1090)
>+++ core/winverbs/kernel/wv_cq.c        (working copy)
>@@ -27,6 +27,7 @@
>  * SOFTWARE.
>  */
>
>+#include "wv_driver.h"
> #include "wv_cq.h"
> #include "wv_ioctl.h"
>
>@@ -68,13 +69,32 @@
>
> static void WvCqEventHandler(ib_event_rec_t *pEvent)
> {
>-       pEvent;
>+       WV_COMPLETION_QUEUE *cq = pEvent->context;
>+       WDFREQUEST                      request;
>+       NTSTATUS                        status;
>+
>+       WdfObjectAcquireLock(cq->Queue);
>+       status = WdfIoQueueRetrieveNextRequest(cq->Queue, &request);
>+       WdfObjectReleaseLock(cq->Queue);
>+
>+       if (NT_SUCCESS(status)) {
>+               WdfRequestComplete(request, STATUS_UNEXPECTED_IO_ERROR);
>+       }

What happens if a user has multiple Notify requests outstanding?  You only complete one?

It seems that all should get completed.

Also, why not provide richer status to distinguish overflow from catastrophic error?  Maybe something like STATUS_FAILURE for catastrophic failure, and STATUS_DATA_OVERRUN for CQ overflow?  Both are error status values.  Maybe it doesn't matter, though.

> }
>
> static void WvCqHandler(void *Context)
> {
>-        WV_COMPLETION_QUEUE *pCq = Context;
>-        pCq;
>+       WV_COMPLETION_QUEUE *cq = Context;
>+       WDFREQUEST                      request;
>+       NTSTATUS                        status;
>+
>+       WdfObjectAcquireLock(cq->Queue);
>+       status = WdfIoQueueRetrieveNextRequest(cq->Queue, &request);
>+       WdfObjectReleaseLock(cq->Queue);
>+
>+       if (NT_SUCCESS(status)) {
>+               WdfRequestComplete(request, STATUS_SUCCESS);
>+       }

Same here, all pending requests should get completed.

> }
>
> static NTSTATUS WvCqAlloc(WV_DEVICE *pDevice, UINT32 *pSize,
>@@ -82,8 +102,10 @@
> {
>        ib_api_status_t         ib_status;
>        WV_COMPLETION_QUEUE     *cq;
>+       WDF_IO_QUEUE_CONFIG     config;
>+       NTSTATUS                        status;
>
>-       cq = ExAllocatePoolWithTag(PagedPool, sizeof(WV_COMPLETION_QUEUE), 'qcvw');
>+       cq = ExAllocatePoolWithTag(NonPagedPool, sizeof(WV_COMPLETION_QUEUE), 'qcvw');
>        if (cq == NULL) {
>                return STATUS_NO_MEMORY;
>        }
>@@ -91,10 +113,18 @@
>        cq->Ref = 1;
>        KeInitializeEvent(&cq->Event, NotificationEvent, FALSE);
>
>+       WDF_IO_QUEUE_CONFIG_INIT(&config, WdfIoQueueDispatchManual);
>+       status = WdfIoQueueCreate(ControlDevice, &config,
>+                                                         WDF_NO_OBJECT_ATTRIBUTES, &cq->Queue);
>+       if (!NT_SUCCESS(status)) {
>+               goto err;
>+       }
>+
>        ib_status = pDevice->pVerbs->create_cq(pDevice->hVerbsDevice, cq,
>                                                                                   WvCqEventHandler, WvCqHandler,
>                                                                                   pSize, &cq->hVerbsCq, pVerbsData);
>        if (ib_status != IB_SUCCESS) {
>+               status = STATUS_UNSUCCESSFUL;
>                goto err;
>        }
>
>@@ -104,7 +134,7 @@
>
> err:
>        ExFreePool(cq);
>-       return STATUS_UNSUCCESSFUL;
>+       return status;
> }
>
> void WvCqCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)
>@@ -249,3 +279,38 @@
> complete:
>        WdfRequestCompleteWithInformation(Request, status, len);
> }
>+
>+void WvCqNotify(WV_PROVIDER *pProvider, WDFREQUEST Request)
>+{
>+       WV_IO_ID                                *id;
>+       WV_COMPLETION_QUEUE             *cq;
>+       NTSTATUS                                status;
>+       ib_api_status_t                 ib_status;
>+
>+       status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL);
>+       if (!NT_SUCCESS(status)) {
>+               goto out;
>+       }
>+
>+       cq = WvCqAcquire(pProvider, id->Id);
>+       if (cq == NULL) {
>+               status = STATUS_NOT_FOUND;
>+               goto out;
>+       }
>+
>+       WdfObjectAcquireLock(cq->Queue);
>+       ib_status = cq->pVerbs->enable_cq_notify(cq->hVerbsCq,
>+                                                                                        id->Data ==
>WV_IO_CQ_NOTIFY_SOLICITED);

Are you sure this works - rearming a UM CQ in the kernel?  It should, but looking at the MTHCA code it appears that a doorbell for the CQ is only allocated in the kernel for kernel CQs (mthca_init_cq).

How do you support a client that wants error notifications, but not rearm?

>+       if (ib_status == IB_SUCCESS) {
>+               status = WdfRequestForwardToIoQueue(Request, cq->Queue);
>+       } else {
>+               status = STATUS_UNSUCCESSFUL;
>+       }
>+       WdfObjectReleaseLock(cq->Queue);
>+       WvCqRelease(cq);
>+
>+out:
>+       if (!NT_SUCCESS(status)) {
>+               WdfRequestComplete(Request, status);
>+       }
>+}



More information about the ofw mailing list