[ofw] [RFC] [PATCH 4/4] winverbs.sys: partial driver implementation
Sean Hefty
sean.hefty at intel.com
Tue Apr 22 16:48:48 PDT 2008
The driver implements opening/closing/query a device, allocating PDs,
and registering memory. It also handles device removal with active
userspace users.
Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
I had a hard time coming up with the implementation to handle device
removal with active userspace users in a way that had the least impact
on performance. I'd appreciate it if someone could review at least
that relevant code portions. Please see the WvProviderRemoveHandler(),
and the 4 functions immediately above it.
Index: wv_device.c
===================================================================
--- wv_device.c (revision 0)
+++ wv_device.c (revision 0)
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wv_device.h"
+#include "wv_pd.h"
+#include "wv_ioctl.h"
+
+void WvDeviceGet(WV_DEVICE *pDevice)
+{
+ InterlockedIncrement(&pDevice->Ref);
+}
+
+void WvDevicePut(WV_DEVICE *pDevice)
+{
+ if (InterlockedDecrement(&pDevice->Ref) == 0) {
+ KeSetEvent(&pDevice->Event, 0, FALSE);
+ }
+}
+
+WV_DEVICE *WvDeviceAcquire(WV_PROVIDER *pProvider, UINT64 Id)
+{
+ WV_DEVICE *dev;
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) Id);
+ if (dev != NULL) {
+ WvProviderRemoveDisable(pProvider);
+ WvDeviceGet(dev);
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ return dev;
+}
+
+void WvDeviceRelease(WV_DEVICE *pDevice)
+{
+ WvProviderRemoveEnable(pDevice->pProvider);
+ WvDevicePut(pDevice);
+}
+
+WV_DEVICE *WvDeviceAlloc(WV_PROVIDER *pProvider)
+{
+ WV_DEVICE *dev;
+
+ dev = ExAllocatePoolWithTag(PagedPool, sizeof(WV_DEVICE), 'cdvw');
+ if (dev == NULL) {
+ return NULL;
+ }
+
+ dev->hVerbsDevice = NULL;
+ dev->pDevice = NULL;
+ dev->Ref = 1;
+
+ InitializeListHead(&dev->PdList);
+ KeInitializeEvent(&dev->Event, NotificationEvent, FALSE);
+ dev->pProvider = pProvider;
+ WvProviderGet(pProvider);
+ return dev;
+}
+
+NTSTATUS WvDeviceInit(WV_DEVICE *pDevice, UINT64 Guid, ci_umv_buf_t *pVerbsData)
+{
+ WV_RDMA_DEVICE *dev;
+ ib_api_status_t ib_status;
+
+ dev = WvRdmaDeviceGet(Guid);
+ if (dev == NULL) {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ pDevice->pDevice = dev;
+ pDevice->pVerbs = &dev->Interface.Verbs;
+ ib_status = pDevice->pVerbs->um_open_ca(dev->hDevice, pVerbsData,
+ &pDevice->hVerbsDevice);
+ if (ib_status != IB_SUCCESS) {
+ goto err;
+ }
+ return STATUS_SUCCESS;
+
+err:
+ WvRdmaDevicePut(pDevice->pDevice);
+ pDevice->pDevice = NULL;
+ return STATUS_UNSUCCESSFUL;
+}
+
+void WvDeviceDestroy(WV_DEVICE *pDevice)
+{
+ if (InterlockedDecrement(&pDevice->Ref) > 0) {
+ KeWaitForSingleObject(&pDevice->Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ if (pDevice->pDevice != NULL) {
+ pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice,
+ pDevice->hVerbsDevice);
+ WvRdmaDevicePut(pDevice->pDevice);
+ }
+
+ WvProviderPut(pDevice->pProvider);
+ ExFreePool(pDevice);
+}
+
+void WvDeviceRemoveHandler(WV_DEVICE *pDevice)
+{
+ LIST_ENTRY *entry;
+ WV_PROTECTION_DOMAIN *pd;
+
+ for (entry = pDevice->PdList.Flink; entry != &pDevice->PdList;
+ entry = entry->Flink) {
+ pd = CONTAINING_RECORD(entry, WV_PROTECTION_DOMAIN, Entry);
+ WvPdRemoveHandler(pd);
+ }
+
+ pDevice->pVerbs->um_close_ca(pDevice->pDevice->hDevice,
+ pDevice->hVerbsDevice);
+ WvRdmaDevicePut(pDevice->pDevice);
+ pDevice->pDevice = NULL;
+}
+
+static void WvSetDeviceCap(UINT32 *pFlags, ib_ca_attr_t *pCaAttr)
+{
+ *pFlags = 0;
+
+ *pFlags |= pCaAttr->bad_pkey_ctr_support ? WV_IO_BAD_PKEY_COUNTER : 0;
+ *pFlags |= pCaAttr->bad_qkey_ctr_support ? WV_IO_BAD_QKEY_COUNTER : 0;
+ *pFlags |= pCaAttr->apm_support ? WV_IO_PATH_MIGRATION : 0;
+ *pFlags |= pCaAttr->av_port_check ? WV_IO_AH_PORT_CHECKING : 0;
+ *pFlags |= pCaAttr->change_primary_port ? WV_IO_CHANGE_PHYSICAL_PORT : 0;
+ *pFlags |= pCaAttr->modify_wr_depth ? WV_IO_RESIZE_MAX_WR : 0;
+ *pFlags |= pCaAttr->modify_srq_depth ? WV_IO_SRQ_RESIZE : 0;
+ *pFlags |= pCaAttr->current_qp_state_support ? WV_IO_QP_STATE_MODIFIER : 0;
+ *pFlags |= pCaAttr->shutdown_port_capability ? WV_IO_SHUTDOWN_PORT : 0;
+ *pFlags |= pCaAttr->init_type_support ? WV_IO_INIT_TYPE : 0;
+ *pFlags |= pCaAttr->port_active_event_support ? WV_IO_PORT_ACTIVE_EVENT : 0;
+ *pFlags |= pCaAttr->system_image_guid_support ? WV_IO_SYSTEM_IMAGE_GUID : 0;
+ *pFlags |= WV_IO_RC_RNR_NAK_GENERATION;
+ *pFlags |= WV_IO_BATCH_NOTIFY_CQ;
+}
+
+static void WvSetDevicePages(UINT32 *pFlags, ib_ca_attr_t *pCaAttr)
+{
+ unsigned int i;
+ UINT32 size;
+
+ *pFlags = 0;
+
+ for (i = 0; i < pCaAttr->num_page_sizes; i++) {
+ size = pCaAttr->p_page_size[i];
+ *pFlags |= (size & (size - 1)) ? 0 : size;
+ }
+}
+
+static void WvConvertDevAttr(WV_IO_DEVICE_ATTRIBUTES* pAttributes,
+ ib_ca_attr_t *pCaAttr)
+{
+ pAttributes->FwVersion = pCaAttr->fw_ver;
+ pAttributes->NodeGuid = pCaAttr->ca_guid;
+ pAttributes->SystemImageGuid = pCaAttr->system_image_guid;
+ pAttributes->VendorId = pCaAttr->vend_id;
+ pAttributes->VendorPartId = pCaAttr->dev_id;
+ pAttributes->HwVersion = pCaAttr->revision;
+
+ WvSetDeviceCap(&pAttributes->CapabilityFlags, pCaAttr);
+ pAttributes->AtomicCapability = (UINT32) pCaAttr->atomicity;
+ WvSetDevicePages(&pAttributes->PageSizeCapabilityFlags, pCaAttr);
+
+ pAttributes->MaxMrSize = pCaAttr->init_region_size;
+ pAttributes->MaxQp = pCaAttr->max_qps;
+ pAttributes->MaxQpWr = pCaAttr->max_wrs;
+ pAttributes->MaxSge = pCaAttr->max_sges;
+ pAttributes->MaxCq = pCaAttr->max_cqs;
+ pAttributes->MaxCqEntries = pCaAttr->max_cqes;
+ pAttributes->MaxMr = pCaAttr->init_regions;
+ pAttributes->MaxPd = pCaAttr->max_pds;
+ pAttributes->MaxQpResponderResources = pCaAttr->max_qp_resp_res;
+ pAttributes->MaxResponderResources = pCaAttr->max_resp_res;
+ pAttributes->MaxQpInitiatorDepth = pCaAttr->max_qp_init_depth;
+ pAttributes->MaxMw = pCaAttr->init_windows;
+ pAttributes->MaxMulticast = pCaAttr->max_mcast_grps;
+ pAttributes->MaxQpAttach = pCaAttr->max_qps_per_mcast_grp;
+ pAttributes->MaxMulticastQp = pCaAttr->max_mcast_qps;
+ pAttributes->MaxAh = pCaAttr->max_addr_handles;
+ pAttributes->MaxFmr = pCaAttr->max_fmr;
+ pAttributes->MaxMapPerFmr = pCaAttr->max_map_per_fmr;
+ pAttributes->MaxSrq = pCaAttr->max_srq;
+ pAttributes->MaxSrqWr = pCaAttr->max_srq_wrs;
+ pAttributes->MaxSrqSge = pCaAttr->max_srq_sges;
+ pAttributes->MaxPkeys = pCaAttr->max_partitions;
+ pAttributes->LocalAckDelay = pCaAttr->local_ack_delay;
+ pAttributes->PhysPortCount = pCaAttr->num_ports;
+}
+
+static void WvConvertPortCap(UINT32 *pFlags, ib_port_cap_t *pCap)
+{
+ *pFlags = 0;
+
+ *pFlags |= pCap->qkey_ctr ? WV_IO_BAD_QKEY_COUNTER : 0;
+ *pFlags |= pCap->pkey_ctr ? WV_IO_BAD_PKEY_COUNTER : 0;
+ *pFlags |= pCap->apm ? WV_IO_PATH_MIGRATION : 0;
+ *pFlags |= pCap->sysguid ? WV_IO_SYSTEM_IMAGE_GUID : 0;
+ *pFlags |= pCap->port_active ? WV_IO_PORT_ACTIVE_EVENT : 0;
+
+ // cannot determine from ib_port_attr_t:
+ // WV_IO_RESIZE_MAX_WR
+ // WV_IO_CHANGE_PHYSICAL_PORT
+ // WV_IO_AH_PORT_CHECKING
+ *pFlags |= WV_IO_QP_STATE_MODIFIER;
+ // WV_IO_SHUTDOWN_PORT
+ // WV_IO_INIT_TYPE
+ *pFlags |= WV_IO_RC_RNR_NAK_GENERATION;
+ // WV_IO_SRQ_RESIZE
+ *pFlags |= WV_IO_BATCH_NOTIFY_CQ;
+}
+
+static void WvConvertPortAttr(WV_IO_PORT_ATTRIBUTES *pAttributes,
+ ib_port_attr_t *pPortAttr)
+{
+ WvConvertPortCap(&pAttributes->PortCabilityFlags, &pPortAttr->cap);
+ pAttributes->State = pPortAttr->link_state;
+ pAttributes->MaxMtu = 0; // cannot determine from ib_port_attr_t
+ pAttributes->ActiveMtu = pPortAttr->mtu;
+ pAttributes->GidTableLength = pPortAttr->num_gids;
+ pAttributes->MaxMessageSize = (UINT32) pPortAttr->max_msg_size;
+ pAttributes->BadPkeyCounter = pPortAttr->pkey_ctr;
+ pAttributes->QkeyViolationCounter = pPortAttr->qkey_ctr;
+ pAttributes->PkeyTableLength = pPortAttr->num_pkeys;
+ pAttributes->Lid = pPortAttr->lid;
+ pAttributes->SmLid = pPortAttr->sm_lid;
+ pAttributes->Lmc = pPortAttr->lmc;
+ pAttributes->MaxVls = (UINT8) pPortAttr->max_vls;
+ pAttributes->SmSl = pPortAttr->sm_sl;
+ pAttributes->SubneTimeout = pPortAttr->subnet_timeout;
+ pAttributes->InitTypeReply = pPortAttr->init_type_reply;
+ pAttributes->ActiveWidth = pPortAttr->link_width_supported;
+ pAttributes->ActiveSpeed = 0; // cannot determine from ib_port_attr_t
+ pAttributes->PhysicalState = 0; // cannot determine from ib_port_attr_t
+ pAttributes->Reserved[0] = 0;
+ pAttributes->Reserved[1] = 0;
+}
+
+static ib_ca_attr_t *WvQueryCaAttributes(WV_DEVICE *pDevice)
+{
+ ib_ca_attr_t *attr;
+ UINT32 size;
+ ib_api_status_t ib_status;
+
+ size = 0;
+ ib_status = pDevice->pVerbs->query_ca(pDevice->hVerbsDevice, NULL, &size, NULL);
+ if (ib_status != IB_INSUFFICIENT_MEMORY) {
+ attr = NULL;
+ goto out;
+ }
+
+ attr = ExAllocatePoolWithTag(PagedPool, size, 'acvw');
+ if (attr == NULL) {
+ goto out;
+ }
+
+ ib_status = pDevice->pVerbs->query_ca(pDevice->hVerbsDevice, NULL, &size, NULL);
+ if (ib_status != IB_SUCCESS) {
+ ExFreePool(attr);
+ attr = NULL;
+ }
+
+out:
+ return attr;
+}
+
+void WvDeviceQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ UINT64 *id;
+ WV_IO_DEVICE_ATTRIBUTES *attr;
+ WV_DEVICE *dev;
+ ib_ca_attr_t *ca_attr;
+ NTSTATUS status;
+ UINT32 outlen = 0;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_DEVICE_ATTRIBUTES),
+ &attr, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+
+ dev = WvDeviceAcquire(pProvider, *id);
+ if (dev == NULL) {
+ status = STATUS_NO_SUCH_DEVICE;
+ goto complete;
+ }
+
+ ca_attr = WvQueryCaAttributes(dev);
+ if (ca_attr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto release;
+ }
+
+ WvConvertDevAttr(attr, ca_attr);
+ outlen = sizeof(WV_IO_DEVICE_ATTRIBUTES);
+ ExFreePool(ca_attr);
+
+release:
+ WvDeviceRelease(dev);
+complete:
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+}
+
+void WvDevicePortQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_DEVICE_PORT_QUERY *query;
+ WV_IO_PORT_ATTRIBUTES *attr;
+ WV_DEVICE *dev;
+ ib_ca_attr_t *ca_attr;
+ NTSTATUS status;
+ UINT32 outlen = 0;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),
+ &query, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_PORT_ATTRIBUTES),
+ &attr, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+
+ dev = WvDeviceAcquire(pProvider, query->Id);
+ if (dev == NULL) {
+ status = STATUS_NO_SUCH_DEVICE;
+ goto complete;
+ }
+
+ ca_attr = WvQueryCaAttributes(dev);
+ if (ca_attr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto release;
+ }
+
+ if (query->PortNumber >= ca_attr->num_ports) {
+ status = STATUS_INVALID_PORT_HANDLE;
+ goto free;
+ }
+
+ WvConvertPortAttr(attr, &ca_attr->p_port_attr[query->PortNumber]);
+ outlen = sizeof(WV_IO_PORT_ATTRIBUTES);
+
+free:
+ ExFreePool(ca_attr);
+release:
+ WvDeviceRelease(dev);
+complete:
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+}
+
+void WvDeviceGidQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_DEVICE_PORT_QUERY *query;
+ WV_IO_GID *gid;
+ WV_DEVICE *dev;
+ ib_ca_attr_t *ca_attr;
+ ib_port_attr_t *port_attr;
+ NTSTATUS status;
+ UINT32 i, size, outlen = 0;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),
+ &query, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GID), &gid, &size);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+
+ dev = WvDeviceAcquire(pProvider, query->Id);
+ if (dev == NULL) {
+ status = STATUS_NO_SUCH_DEVICE;
+ goto complete;
+ }
+
+ ca_attr = WvQueryCaAttributes(dev);
+ if (ca_attr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto release;
+ }
+
+ if (query->PortNumber >= ca_attr->num_ports) {
+ status = STATUS_INVALID_PORT_HANDLE;
+ goto free;
+ }
+
+ size /= sizeof(WV_IO_GID);
+ port_attr = &ca_attr->p_port_attr[query->PortNumber];
+ for (i = 0; i < size && i < port_attr->num_gids; i++) {
+ RtlCopyMemory(&gid[i], &port_attr->p_gid_table[i], sizeof(WV_IO_GID));
+ }
+
+ outlen = i * sizeof(WV_IO_GID);
+ if (i < port_attr->num_gids) {
+ status = STATUS_MORE_ENTRIES;
+ }
+
+free:
+ ExFreePool(ca_attr);
+release:
+ WvDeviceRelease(dev);
+complete:
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+}
+
+void WvDevicePkeyQuery(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_DEVICE_PORT_QUERY *query;
+ UINT16 *pkey;
+ WV_DEVICE *dev;
+ ib_ca_attr_t *ca_attr;
+ ib_port_attr_t *port_attr;
+ NTSTATUS status;
+ UINT32 i, size, outlen = 0;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_DEVICE_PORT_QUERY),
+ &query, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT16), &pkey, &size);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+
+ dev = WvDeviceAcquire(pProvider, query->Id);
+ if (dev == NULL) {
+ status = STATUS_NO_SUCH_DEVICE;
+ goto complete;
+ }
+
+ ca_attr = WvQueryCaAttributes(dev);
+ if (ca_attr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto release;
+ }
+
+ if (query->PortNumber >= ca_attr->num_ports) {
+ status = STATUS_INVALID_PORT_HANDLE;
+ goto free;
+ }
+
+ size /= sizeof(UINT16);
+ port_attr = &ca_attr->p_port_attr[query->PortNumber];
+ for (i = 0; i < size && i < port_attr->num_pkeys; i++) {
+ pkey[i] = port_attr->p_pkey_table[i];
+ }
+
+ outlen = i * sizeof(UINT16);
+ if (i < port_attr->num_pkeys) {
+ status = STATUS_MORE_ENTRIES;
+ }
+
+free:
+ ExFreePool(ca_attr);
+release:
+ WvDeviceRelease(dev);
+complete:
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+}
+
+void WvPdAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_ID *inid, *outid;
+ size_t inlen, outlen;
+ WV_DEVICE *dev;
+ WV_PROTECTION_DOMAIN *pd;
+ NTSTATUS status;
+ ci_umv_buf_t verbsData;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);
+ if (!NT_SUCCESS(status)) {
+ goto err1;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
+ if (!NT_SUCCESS(status)) {
+ goto err1;
+ }
+
+ dev = WvDeviceAcquire(pProvider, inid->Id);
+ if (dev == NULL) {
+ status = STATUS_NO_SUCH_DEVICE;
+ goto err1;
+ }
+
+ WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),
+ outlen - sizeof(WV_IO_ID), inid + 1);
+ status = WvPdAlloc(dev, &pd, &verbsData);
+ if (!NT_SUCCESS(status)) {
+ goto err2;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ pd->Id = IndexListInsert(&pProvider->PdIndex, pd);
+ if (pd->Id == 0) {
+ status = STATUS_NO_MEMORY;
+ goto err3;
+ }
+ InsertHeadList(&dev->PdList, &pd->Entry);
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ WvDeviceRelease(dev);
+ outid->Id = pd->Id;
+ outid->VerbInfo = verbsData.status;
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+ return;
+
+err3:
+ KeReleaseGuardedMutex(&pProvider->Lock);
+ WvPdDestroy(pd);
+err2:
+ WvDeviceRelease(dev);
+err1:
+ WdfRequestComplete(Request, status);
+}
+
+void WvPdDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_PROTECTION_DOMAIN *pd;
+ UINT64 *id;
+ NTSTATUS status;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ WvProviderRemoveDisable(pProvider);
+ pd = IndexListRemove(&pProvider->PdIndex, (SIZE_T) id);
+ if (pd == NULL) {
+ status = STATUS_NOT_FOUND;
+ } else if (pd->Ref > 1) {
+ status = STATUS_ACCESS_DENIED;
+ } else {
+ RemoveEntryList(&pd->Entry);
+ status = STATUS_SUCCESS;
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ if (NT_SUCCESS(status)) {
+ WvPdDestroy(pd);
+ }
+ WvProviderRemoveEnable(pProvider);
+out:
+ WdfRequestComplete(Request, status);
+}
Index: wv_device.h
===================================================================
--- wv_device.h (revision 1035)
+++ wv_device.h (working copy)
@@ -36,18 +36,40 @@
#include <wdm.h>
#include <iba\ib_types.h>
#include <iba\ib_ci.h>
+
+#include "wv_driver.h"
#include "wv_provider.h"
typedef struct _WV_DEVICE
{
WV_PROVIDER *pProvider;
+ WV_RDMA_DEVICE *pDevice;
+ ci_interface_t *pVerbs;
LIST_ENTRY Entry;
- ci_interface_t Verbs;
ib_ca_handle_t hVerbsDevice;
+ LIST_ENTRY PdList;
SIZE_T Id;
- UINT64 Guid;
- LONG nRef;
+ KEVENT Event;
+ LONG Ref;
} WV_DEVICE;
+struct _WV_DEVICE *WvDeviceAcquire(WV_PROVIDER *pProvider, UINT64 Id);
+void WvDeviceRelease(WV_DEVICE *pDevice);
+void WvDeviceGet(WV_DEVICE *pDevice);
+void WvDevicePut(WV_DEVICE *pDevice);
+
+WV_DEVICE *WvDeviceAlloc(WV_PROVIDER *pProvider);
+NTSTATUS WvDeviceInit(WV_DEVICE *pDevice, UINT64 Guid, ci_umv_buf_t *pVerbsData);
+void WvDeviceDestroy(WV_DEVICE *pDevice);
+void WvDeviceRemoveHandler(WV_DEVICE *pDevice);
+
+void WvDeviceQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvDevicePortQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvDeviceGidQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvDevicePkeyQuery(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
+void WvPdAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvPdDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
#endif // __WV_DEVICE_H_
Index: wv_driver.c
===================================================================
--- wv_driver.c (revision 1035)
+++ wv_driver.c (working copy)
@@ -30,9 +30,10 @@
#include <ntddk.h>
#include <wdf.h>
#include <wdmsec.h>
-#include <winerror.h>
+#include <ntstatus.h>
#include <initguid.h>
+#include <rdma/verbs.h>
#include "wv_driver.h"
#include "wv_ioctl.h"
#include "wv_provider.h"
@@ -44,20 +45,122 @@
#include "wv_listen.h"
#include "wv_ep.h"
-WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_RDMA_DEVICE, WvGetRdmaDevice)
-WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_PROVIDER, WvGetProvider)
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_RDMA_DEVICE, WvRdmaDeviceGetContext)
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WV_PROVIDER, WvProviderGetContext)
-static WDFDEVICE ControlDevice;
-KGUARDED_MUTEX DevLock;
-LIST_ENTRY DevList;
+static WDFDEVICE ControlDevice;
+static LIST_ENTRY DevList;
+static LIST_ENTRY ProvList;
+static KGUARDED_MUTEX Lock;
-static EVT_WDF_DRIVER_DEVICE_ADD WvDeviceAdd;
-static EVT_WDF_OBJECT_CONTEXT_CLEANUP WvDeviceCleanup;
+static EVT_WDF_DRIVER_DEVICE_ADD WvRdmaDeviceAdd;
+static EVT_WDF_OBJECT_CONTEXT_CLEANUP WvRdmaDeviceCleanup;
static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL WvIoDeviceControl;
static EVT_WDF_DEVICE_FILE_CREATE WvFileCreate;
static EVT_WDF_FILE_CLEANUP WvFileCleanup;
static EVT_WDF_FILE_CLOSE WvFileClose;
+static WV_RDMA_DEVICE *WvRdmaDeviceFind(UINT64 Guid)
+{
+ WV_RDMA_DEVICE *dev;
+ LIST_ENTRY *entry;
+
+ for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {
+ dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry);
+ if (dev->Interface.Verbs.guid == Guid) {
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+WV_RDMA_DEVICE *WvRdmaDeviceGet(UINT64 Guid)
+{
+ WV_RDMA_DEVICE *dev;
+
+ KeAcquireGuardedMutex(&Lock);
+ dev = WvRdmaDeviceFind(Guid);
+ if (dev != NULL) {
+ InterlockedIncrement(&dev->Ref);
+ }
+ KeReleaseGuardedMutex(&Lock);
+ return dev;
+}
+
+void WvRdmaDevicePut(WV_RDMA_DEVICE *pDevice)
+{
+ if (InterlockedDecrement(&pDevice->Ref) == 0) {
+ KeSetEvent(&pDevice->Event, 0, FALSE);
+ }
+}
+
+static void WvGuidQuery(WDFREQUEST Request)
+{
+ WV_IO_GUID_LIST *list;
+ size_t len = 0;
+ WV_RDMA_DEVICE *dev;
+ ULONG count, i;
+ LIST_ENTRY *entry;
+ NTSTATUS status;
+
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GUID_LIST),
+ &list, &len);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+
+ count = (len - sizeof(UINT64)) / sizeof(UINT64);
+ i = 0;
+ len = sizeof(UINT64);
+ KeAcquireGuardedMutex(&Lock);
+ for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {
+ dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry);
+ if (i < count) {
+ list->Guid[i] = dev->Interface.Verbs.guid;
+ len += sizeof(UINT64);
+ }
+ i++;
+ }
+ list->Count = i;
+ KeReleaseGuardedMutex(&Lock);
+
+out:
+ WdfRequestCompleteWithInformation(Request, status, len);
+}
+
+static void WvLibraryQuery(WDFREQUEST Request)
+{
+ UINT64 *guid;
+ char *name;
+ size_t len = 0;
+ WV_RDMA_DEVICE *dev;
+ NTSTATUS status;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &guid, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request,
+
sizeof(dev->Interface.Verbs.libname),
+ &name, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+
+ dev = WvRdmaDeviceGet(*guid);
+ if (dev == NULL) {
+ status = STATUS_NO_SUCH_DEVICE;
+ goto out;
+ }
+
+ len = sizeof(dev->Interface.Verbs.libname);
+ RtlCopyMemory(name, dev->Interface.Verbs.libname, len);
+ WvRdmaDevicePut(dev);
+
+out:
+ WdfRequestCompleteWithInformation(Request, status, len);
+}
+
static VOID WvIoDeviceControl(WDFQUEUE Queue, WDFREQUEST Request,
size_t OutLen, size_t InLen, ULONG IoControlCode)
{
@@ -68,25 +171,47 @@
UNREFERENCED_PARAMETER(Queue);
file = WdfRequestGetFileObject(Request);
- prov = WvGetProvider(file);
+ prov = WvProviderGetContext(file);
switch (IoControlCode) {
case WV_IOCTL_GUID_QUERY:
WvGuidQuery(Request);
break;
- //case WV_IOCTL_LIBRARY_QUERY:WvLibraryQuery;break;
- //case WV_IOCTL_DEVICE_OPEN:WvDeviceOpen;break;
- //case WV_IOCTL_DEVICE_CLOSE:WvDeviceClose;break;
- //case WV_IOCTL_DEVICE_QUERY:WvDevideQuery;break;
- //case WV_IOCTL_DEVICE_PORT_QUERY:WvDevicePortQuery;break;
- //case WV_IOCTL_DEVICE_GID_QUERY:WvDeviceGidQuery;break;
- //case WV_IOCTL_DEVICE_PKEY_QUERY:WvDevicePkeyQuery;break;
+ case WV_IOCTL_LIBRARY_QUERY:
+ WvLibraryQuery(Request);
+ break;
+ case WV_IOCTL_DEVICE_OPEN:
+ WvDeviceOpen(prov, Request);
+ break;
+ case WV_IOCTL_DEVICE_CLOSE:
+ WvDeviceClose(prov, Request);
+ break;
+ case WV_IOCTL_DEVICE_QUERY:
+ WvDeviceQuery(prov, Request);
+ break;
+ case WV_IOCTL_DEVICE_PORT_QUERY:
+ WvDevicePortQuery(prov, Request);
+ break;
+ case WV_IOCTL_DEVICE_GID_QUERY:
+ WvDeviceGidQuery(prov, Request);
+ break;
+ case WV_IOCTL_DEVICE_PKEY_QUERY:
+ WvDevicePkeyQuery(prov, Request);
+ break;
//case WV_IOCTL_DEVICE_NOTIFY:WvDeviceNotify;break;
//case WV_IOCTL_DEVICE_CANCEL:WvDeviceCancel;break;
- //case WV_IOCTL_PD_ALLOCATE:WvPdAllocate;break;
- //case WV_IOCTL_PD_DEALLOCATE:WvPdDeallocate;break;
- //case WV_IOCTL_MEMORY_REGISTER:WvMemoryRegister;break;
- //case WV_IOCTL_MEMORY_DEREGISTER:WvmemoryDeregister;break;
+ case WV_IOCTL_PD_ALLOCATE:
+ WvPdAllocate(prov, Request);
+ break;
+ case WV_IOCTL_PD_DEALLOCATE:
+ WvPdDeallocate(prov, Request);
+ break;
+ case WV_IOCTL_MEMORY_REGISTER:
+ WvMemoryRegister(prov, Request);
+ break;
+ case WV_IOCTL_MEMORY_DEREGISTER:
+ WvMemoryDeregister(prov, Request);
+ break;
//case WV_IOCTL_MW_ALLOCATE:WvMwAllocate;break;
//case WV_IOCTL_MW_DEALLOCATE:WvMwDeallocate;break;
//case WV_IOCTL_AH_CREATE:WvAhCreate;break;
@@ -129,7 +254,7 @@
//case WV_IOCTL_LISTEN_GET_REQUEST:WvListenGetRequest;break;
//case WV_IOCTL_LISTEN_CANCEL:WvListenCancel;break;
default:
- WdfRequestComplete(Request, E_NOINTERFACE);
+ WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);
break;
}
}
@@ -137,12 +262,13 @@
static VOID WvFileCreate(WDFDEVICE Device, WDFREQUEST Request,
WDFFILEOBJECT FileObject)
{
- WV_PROVIDER *prov;
-
+ WV_PROVIDER *prov = WvProviderGetContext(FileObject);
UNREFERENCED_PARAMETER(Device);
- prov = WvGetProvider(FileObject);
WvProviderInit(prov);
+ KeAcquireGuardedMutex(&Lock);
+ InsertHeadList(&ProvList, &prov->Entry);
+ KeReleaseGuardedMutex(&Lock);
WdfRequestComplete(Request, STATUS_SUCCESS);
}
@@ -153,10 +279,12 @@
static VOID WvFileClose(WDFFILEOBJECT FileObject)
{
- WV_PROVIDER *prov;
+ WV_PROVIDER *prov = WvProviderGetContext(FileObject);
- prov = WvGetProvider(FileObject);
- WvProviderDestroy(prov);
+ KeAcquireGuardedMutex(&Lock);
+ RemoveEntryList(&prov->Entry);
+ KeReleaseGuardedMutex(&Lock);
+ WvProviderCleanup(prov);
}
static VOID WvCreateControlDevice(WDFDRIVER Driver)
@@ -215,7 +343,7 @@
WdfDeviceInitFree(pinit);
}
-static NTSTATUS WvDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
+static NTSTATUS WvRdmaDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
WDF_OBJECT_ATTRIBUTES attr;
WDFDEVICE dev;
@@ -226,19 +354,30 @@
WdfFdoInitSetFilter(DeviceInit);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, WV_RDMA_DEVICE);
- attr.EvtCleanupCallback = WvDeviceCleanup;
+ attr.EvtCleanupCallback = WvRdmaDeviceCleanup;
status = WdfDeviceCreate(&DeviceInit, &attr, &dev);
if (!NT_SUCCESS(status)) {
return status;
}
- pdev = WvGetRdmaDevice(dev);
- pdev->Guid = 0x1234567890ABCDEF;
+ pdev = WvRdmaDeviceGetContext(dev);
+ RtlZeroMemory(pdev, sizeof *pdev);
+ pdev->Ref = 1;
+ KeInitializeEvent(&pdev->Event, NotificationEvent, FALSE);
- KeAcquireGuardedMutex(&DevLock);
+ status = WdfFdoQueryForInterface(dev, &GUID_RDMA_INTERFACE_VERBS,
+ (PINTERFACE) &pdev->Interface,
+ sizeof(pdev->Interface), VerbsVersion(2, 0),
+ NULL);
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+ pdev->hDevice = pdev->Interface.Verbs.p_hca_dev;
+
+ KeAcquireGuardedMutex(&Lock);
create = IsListEmpty(&DevList);
InsertHeadList(&DevList, &pdev->Entry);
- KeReleaseGuardedMutex(&DevLock);
+ KeReleaseGuardedMutex(&Lock);
if (create) {
WvCreateControlDevice(Driver);
@@ -247,19 +386,38 @@
return status;
}
-static VOID WvDeviceCleanup(WDFDEVICE Device)
+static VOID WvRdmaDeviceCleanup(WDFDEVICE Device)
{
WV_RDMA_DEVICE *pdev;
+ WV_PROVIDER *prov;
+ LIST_ENTRY *entry;
BOOLEAN destroy;
WDFDEVICE ctrldev;
- pdev = WvGetRdmaDevice(Device);
- KeAcquireGuardedMutex(&DevLock);
+ pdev = WvRdmaDeviceGetContext(Device);
+ if (pdev->hDevice == NULL) {
+ return;
+ }
+
+ KeAcquireGuardedMutex(&Lock);
RemoveEntryList(&pdev->Entry);
destroy = IsListEmpty(&DevList);
ctrldev = ControlDevice;
- KeReleaseGuardedMutex(&DevLock);
+ for (entry = ProvList.Flink; entry != &ProvList; entry = entry->Flink) {
+ prov = CONTAINING_RECORD(entry, WV_PROVIDER, Entry);
+ WvProviderRemoveHandler(prov, pdev);
+ }
+
+ KeReleaseGuardedMutex(&Lock);
+
+ if (InterlockedDecrement(&pdev->Ref) > 0) {
+ KeWaitForSingleObject(&pdev->Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ pdev->Interface.InterfaceHeader.
+ InterfaceDereference(pdev->Interface.InterfaceHeader.Context);
+
if (destroy) {
WdfObjectDelete(ctrldev);
}
@@ -272,9 +430,10 @@
WDFDRIVER driv;
InitializeListHead(&DevList);
- KeInitializeGuardedMutex(&DevLock);
+ InitializeListHead(&ProvList);
+ KeInitializeGuardedMutex(&Lock);
- WDF_DRIVER_CONFIG_INIT(&config, WvDeviceAdd);
+ WDF_DRIVER_CONFIG_INIT(&config, WvRdmaDeviceAdd);
status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
&config, &driv);
if (!NT_SUCCESS(status)) {
Index: wv_driver.h
===================================================================
--- wv_driver.h (revision 1035)
+++ wv_driver.h (working copy)
@@ -34,19 +34,33 @@
#include <ntddk.h>
#include <wdm.h>
+
#include <iba\ib_types.h>
#include <iba\ib_ci.h>
+#include <rdma\verbs.h>
typedef struct _WV_RDMA_DEVICE
{
- UINT64 Guid;
- LIST_ENTRY Entry;
- ci_interface_t Verbs;
- ib_ca_handle_t hVerbsDevice;
+ LIST_ENTRY Entry;
+ LONG Ref;
+ KEVENT Event;
+ ib_ca_handle_t hDevice;
+ RDMA_INTERFACE_VERBS Interface;
} WV_RDMA_DEVICE;
-extern KGUARDED_MUTEX DevLock;
-extern LIST_ENTRY DevList;
+WV_RDMA_DEVICE *WvRdmaDeviceGet(UINT64 Guid);
+void WvRdmaDevicePut(WV_RDMA_DEVICE *pDevice);
+static inline void WvInitVerbsData(ci_umv_buf_t *pVerbsData, UINT32 Command,
+ UINT32 InputLength, UINT32 OutputLength,
+ void *pBuffer)
+{
+ pVerbsData->command = Command;
+ pVerbsData->input_size = InputLength;
+ pVerbsData->output_size = OutputLength;
+ pVerbsData->p_inout_buf = pBuffer;
+ pVerbsData->status = 0;
+}
+
#endif // _WV_DRIVER_H_
Index: wv_pd.c
===================================================================
--- wv_pd.c (revision 0)
+++ wv_pd.c (revision 0)
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wv_pd.h"
+#include "wv_ioctl.h"
+
+void WvPdGet(WV_PROTECTION_DOMAIN *pPd)
+{
+ InterlockedIncrement(&pPd->Ref);
+}
+
+void WvPdPut(WV_PROTECTION_DOMAIN *pPd)
+{
+ if (InterlockedDecrement(&pPd->Ref) == 0) {
+ KeSetEvent(&pPd->Event, 0, FALSE);
+ }
+}
+
+WV_PROTECTION_DOMAIN *WvPdAcquire(WV_PROVIDER *pProvider, UINT64 Id)
+{
+ WV_PROTECTION_DOMAIN *pd;
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) Id);
+ if (pd != NULL) {
+ WvProviderRemoveDisable(pProvider);
+ WvPdGet(pd);
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ return pd;
+}
+
+void WvPdRelease(WV_PROTECTION_DOMAIN *pPd)
+{
+ WvProviderRemoveEnable(pPd->pDevice->pProvider);
+ WvPdPut(pPd);
+}
+
+NTSTATUS WvPdAlloc(WV_DEVICE *pDevice, WV_PROTECTION_DOMAIN **ppPd,
+ ci_umv_buf_t *pVerbsData)
+{
+ ib_api_status_t ib_status;
+ WV_PROTECTION_DOMAIN *pd;
+
+ pd = ExAllocatePoolWithTag(PagedPool, sizeof(WV_PROTECTION_DOMAIN), 'apvw');
+ if (pd == NULL) {
+ return STATUS_NO_MEMORY;
+ }
+
+ pd->Ref = 1;
+ KeInitializeEvent(&pd->Event, NotificationEvent, FALSE);
+ pd->pDevice = pDevice;
+ pd->pVerbs = pDevice->pVerbs;
+ cl_qmap_init(&pd->MrMap);
+ KeInitializeGuardedMutex(&pd->Lock);
+
+ ib_status = pDevice->pVerbs->allocate_pd(pDevice->hVerbsDevice, IB_PDT_NORMAL,
+ &pd->hVerbsPd, pVerbsData);
+ if (ib_status != IB_SUCCESS) {
+ goto err;
+ }
+
+ WvDeviceGet(pDevice);
+ *ppPd = pd;
+ return STATUS_SUCCESS;
+
+err:
+ ExFreePool(pd);
+ return STATUS_UNSUCCESSFUL;
+}
+
+void WvPdDestroy(WV_PROTECTION_DOMAIN *pPd)
+{
+ WV_MEMORY_REGION *mr;
+ cl_map_item_t *item;
+
+ for (item = cl_qmap_head(&pPd->MrMap); item != cl_qmap_end(&pPd->MrMap);
+ item = cl_qmap_next(item)) {
+ mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);
+ pPd->pVerbs->deregister_mr(mr->hVerbsMr);
+ mr->hVerbsMr = NULL;
+ }
+
+ if (InterlockedDecrement(&pPd->Ref) > 0) {
+ KeWaitForSingleObject(&pPd->Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ if (pPd->hVerbsPd != NULL) {
+ pPd->pVerbs->deallocate_pd(pPd->hVerbsPd);
+ }
+
+ WvDevicePut(pPd->pDevice);
+ ExFreePool(pPd);
+}
+
+void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd)
+{
+ WV_MEMORY_REGION *mr;
+ cl_map_item_t *item;
+
+ for (item = cl_qmap_head(&pPd->MrMap); item != cl_qmap_end(&pPd->MrMap);
+ item = cl_qmap_next(item)) {
+ mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);
+ pPd->pVerbs->deregister_mr(mr->hVerbsMr);
+ mr->hVerbsMr = NULL;
+ }
+
+ pPd->pVerbs->deallocate_pd(pPd->hVerbsPd);
+ pPd->hVerbsPd = NULL;
+}
+
+void WvMemoryRegister(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_MEMORY_REGISTER *reg;
+ WV_IO_MEMORY_KEYS *keys;
+ WV_PROTECTION_DOMAIN *pd;
+ WV_MEMORY_REGION *mr;
+ ib_mr_create_t attr;
+ NTSTATUS status;
+ ib_api_status_t ib_status;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_MEMORY_REGISTER),
+ ®, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto err1;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_MEMORY_KEYS),
+ &keys, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto err1;
+ }
+
+ pd = WvPdAcquire(pProvider, reg->Id);
+ if (pd == NULL) {
+ status = STATUS_NOT_FOUND;
+ goto err1;
+ }
+
+ mr = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MEMORY_REGION), 'mrvw');
+ if (mr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto err2;
+ }
+
+ attr.access_ctrl = reg->AccessFlags;
+ attr.length = reg->BufferLength;
+ attr.vaddr = (void *) (ULONG_PTR) reg->Address;
+ ib_status = pd->pVerbs->register_mr(pd->hVerbsPd, &attr, &keys->Lkey,
+ &keys->Rkey, &mr->hVerbsMr, TRUE);
+ if (ib_status != IB_SUCCESS) {
+ status = STATUS_UNSUCCESSFUL;
+ goto err3;
+ }
+
+ WvPdGet(pd);
+ KeAcquireGuardedMutex(&pd->Lock);
+ cl_qmap_insert(&pd->MrMap, keys->Lkey, &mr->Item);
+ KeReleaseGuardedMutex(&pd->Lock);
+
+ WvPdRelease(pd);
+ WdfRequestCompleteWithInformation(Request, status, sizeof(WV_IO_MEMORY_KEYS));
+ return;
+
+err3:
+ ExFreePool(mr);
+err2:
+ WvPdRelease(pd);
+err1:
+ WdfRequestComplete(Request, status);
+}
+
+void WvMemoryDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_ID *id;
+ WV_PROTECTION_DOMAIN *pd;
+ WV_MEMORY_REGION *mr;
+ cl_map_item_t *item;
+ NTSTATUS status;
+ ib_api_status_t ib_status;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &id, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto complete;
+ }
+
+ pd = WvPdAcquire(pProvider, id->Id);
+ if (pd == NULL) {
+ status = STATUS_NOT_FOUND;
+ goto complete;
+ }
+
+ KeAcquireGuardedMutex(&pd->Lock);
+ item = cl_qmap_remove(&pd->MrMap, id->Data);
+ KeReleaseGuardedMutex(&pd->Lock);
+
+ if (item == cl_qmap_end(&pd->MrMap)) {
+ status = STATUS_NOT_FOUND;
+ goto release;
+ }
+
+ mr = CONTAINING_RECORD(item, WV_MEMORY_REGION, Item);
+ if (mr->hVerbsMr == NULL) {
+ goto free;
+ }
+
+ ib_status = pd->pVerbs->deregister_mr(mr->hVerbsMr);
+ if (ib_status != IB_SUCCESS) {
+ status = STATUS_UNSUCCESSFUL;
+ KeAcquireGuardedMutex(&pd->Lock);
+ cl_qmap_insert(&pd->MrMap, id->Data, &mr->Item);
+ KeReleaseGuardedMutex(&pd->Lock);
+ goto release;
+ }
+
+free:
+ WvPdPut(pd);
+ ExFreePool(mr);
+release:
+ WvPdRelease(pd);
+complete:
+ WdfRequestComplete(Request, status);
+}
Index: wv_pd.h
===================================================================
--- wv_pd.h (revision 1035)
+++ wv_pd.h (working copy)
@@ -32,22 +32,52 @@
#ifndef _WV_PD_H_
#define _WV_PD_H_
+#include <ntddk.h>
#include <wdm.h>
#include <iba\ib_types.h>
#include <iba\ib_ci.h>
+
#include "wv_device.h"
+#include "wv_provider.h"
typedef struct _WV_PROTECTION_DOMAIN
{
- WV_DEVICE *pDevice;
- ci_interface_t *pVerbs;
- ib_pd_handle_t hVerbsPd;
- UINT64 Id;
- volatile LONG m_nRef;
+ WV_DEVICE *pDevice;
+ ci_interface_t *pVerbs;
+ ib_pd_handle_t hVerbsPd;
+ LIST_ENTRY Entry;
+ KGUARDED_MUTEX Lock;
+ cl_qmap_t MrMap;
+
+ SIZE_T Id;
+ KEVENT Event;
+ LONG Ref;
+
} WV_PROTECTION_DOMAIN;
+struct _WV_PROTECTION_DOMAIN *WvPdAcquire(WV_PROVIDER *pProvider, UINT64 Id);
+void WvPdRelease(WV_PROTECTION_DOMAIN *pPd);
+void WvPdGet(WV_PROTECTION_DOMAIN *pPd);
+void WvPdPut(WV_PROTECTION_DOMAIN *pPd);
+NTSTATUS WvPdAlloc(WV_DEVICE *pDevice, WV_PROTECTION_DOMAIN **ppPd,
+ ci_umv_buf_t *pVerbsData);
+void WvPdDestroy(WV_PROTECTION_DOMAIN *pPd);
+void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd);
+
+void WvMemoryRegister(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvMemoryDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
+
+typedef struct _WV_MEMORY_REGION
+{
+ WV_PROTECTION_DOMAIN *pPd;
+ ib_mr_handle_t hVerbsMr;
+ cl_map_item_t Item;
+
+} WV_MEMORY_REGION;
+
typedef struct _WV_MEMORY_WINDOW
{
WV_PROTECTION_DOMAIN *pPd;
Index: wv_provider.c
===================================================================
--- wv_provider.c (revision 1035)
+++ wv_provider.c (working copy)
@@ -27,62 +27,229 @@
* SOFTWARE.
*/
-#include <winerror.h>
+#include <ntstatus.h>
#include <rdma\wvstatus.h>
#include "wv_driver.h"
#include "wv_ioctl.h"
#include "wv_provider.h"
#include "wv_device.h"
+#include "wv_pd.h"
-void WvGuidQuery(WDFREQUEST Request)
+void WvProviderGet(WV_PROVIDER *pProvider)
{
- WV_IO_GUID_LIST *pioGuids;
- size_t len = 0;
- WV_RDMA_DEVICE *pdev;
- ULONG count, i;
- LIST_ENTRY *pentry;
- NTSTATUS status;
+ InterlockedIncrement(&pProvider->Ref);
+}
- status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_GUID_LIST),
- &pioGuids, &len);
- if (!NT_SUCCESS(status)) {
- goto out;
+void WvProviderPut(WV_PROVIDER *pProvider)
+{
+ if (InterlockedDecrement(&pProvider->Ref) == 0) {
+ KeSetEvent(&pProvider->Event, 0, FALSE);
}
+}
- count = (len - sizeof(UINT64)) / sizeof(UINT64);
- i = 0;
- len = sizeof(UINT64);
- KeAcquireGuardedMutex(&DevLock);
- for (pentry = DevList.Flink; pentry != &DevList; pentry = pentry->Flink) {
- pdev = CONTAINING_RECORD(pentry, WV_RDMA_DEVICE, Entry);
- if (i < count) {
- pioGuids->Guid[i] = pdev->Guid;
- len += sizeof(UINT64);
- }
- i++;
+void WvProviderInit(WV_PROVIDER *pProvider)
+{
+ IndexListInit(&pProvider->DevIndex);
+ IndexListInit(&pProvider->PdIndex);
+
+ KeInitializeGuardedMutex(&pProvider->Lock);
+ pProvider->Ref = 1;
+ KeInitializeEvent(&pProvider->Event, NotificationEvent, FALSE);
+
+ pProvider->Pending = 0;
+ pProvider->Active = 0;
+ KeInitializeEvent(&pProvider->SharedEvent, NotificationEvent, FALSE);
+ pProvider->Exclusive = 0;
+ KeInitializeEvent(&pProvider->ExclusiveEvent, SynchronizationEvent, FALSE);
+}
+
+void WvProviderCleanup(WV_PROVIDER *pProvider)
+{
+ WV_DEVICE *dev;
+ WV_PROTECTION_DOMAIN *pd;
+
+ while ((pd = IndexListRemoveFirst(&pProvider->PdIndex)) != NULL) {
+ WvPdDestroy(pd);
}
- pioGuids->Count = i;
- KeReleaseGuardedMutex(&DevLock);
-out:
- WdfRequestCompleteWithInformation(Request, status, len);
+ while ((dev = IndexListRemoveFirst(&pProvider->DevIndex)) != NULL) {
+ WvDeviceDestroy(dev);
+ }
+
+ if (InterlockedDecrement(&pProvider->Ref) > 0) {
+ KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ IndexListDestroy(&pProvider->PdIndex);
+ IndexListDestroy(&pProvider->DevIndex);
}
-void WvProviderInit(WV_PROVIDER *pProvider)
+// See comment above WvProviderRemoveHandler.
+static void WvProviderRemoveLock(WV_PROVIDER *pProvider)
{
- InitializeListHead(&pProvider->DevList);
- KeInitializeGuardedMutex(&pProvider->Lock);
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ pProvider->Exclusive++;
+ KeClearEvent(&pProvider->SharedEvent);
+ while (pProvider->Active > 0) {
+ KeReleaseGuardedMutex(&pProvider->Lock);
+ KeWaitForSingleObject(&pProvider->ExclusiveEvent, Executive, KernelMode,
+ FALSE, NULL);
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ }
+ pProvider->Active++;
+ KeReleaseGuardedMutex(&pProvider->Lock);
}
-void WvProviderDestroy(WV_PROVIDER *pProvider)
+// See comment above WvProviderRemoveHandler.
+static void WvProviderRemoveUnlock(WV_PROVIDER *pProvider)
{
- LIST_ENTRY *entry;
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ pProvider->Exclusive--;
+ pProvider->Active--;
+ if (pProvider->Exclusive > 0) {
+ KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);
+ } else if (pProvider->Pending > 0) {
+ KeSetEvent(&pProvider->SharedEvent, 0, FALSE);
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+}
+
+/*
+ * Must hold pProvider->Lock. Function may release and re-acquire.
+ * See comment above WvProviderRemoveHandler.
+ */
+void WvProviderRemoveDisable(WV_PROVIDER *pProvider)
+{
+ while (pProvider->Exclusive > 0) {
+ pProvider->Pending++;
+ KeReleaseGuardedMutex(&pProvider->Lock);
+ KeWaitForSingleObject(&pProvider->SharedEvent, Executive, KernelMode,
+ FALSE, NULL);
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ pProvider->Pending--;
+ }
+ InterlockedIncrement(&pProvider->Active);
+}
+
+/*
+ * No need to hold pProvider->Lock when releasing.
+ * See comment above WvProviderRemoveHandler.
+ */
+void WvProviderRemoveEnable(WV_PROVIDER *pProvider)
+{
+ InterlockedDecrement(&pProvider->Active);
+ if (pProvider->Exclusive > 0) {
+ KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);
+ }
+}
+
+/*
+ * The remove handler blocks all other threads executing through this
+ * provider until the remove has been processed. Because device removal is
+ * rare, we want a simple, optimized code path for all calls that access
+ * the underlying hardware device, making use of any locks that we would
+ * have to acquire anyway. The locking for exclusive access can be
+ * as ugly and slow as needed.
+ */
+void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice)
+{
WV_DEVICE *dev;
+ SIZE_T i;
- while (!IsListEmpty(&pProvider->DevList)) {
- entry = RemoveHeadList(&pProvider->DevList);
- dev = CONTAINING_RECORD(entry, WV_DEVICE, Entry);
- //WvDeviceDestroy(dev);
+ WvProviderRemoveLock(pProvider);
+ IndexListForEach(&pProvider->DevIndex, i) {
+ dev = IndexListAt(&pProvider->DevIndex, i);
+ if (dev->pDevice == pDevice) {
+ WvDeviceRemoveHandler(dev);
+ }
}
+ WvProviderRemoveUnlock(pProvider);
}
+
+void WvDeviceOpen(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_ID *inid, *outid;
+ size_t inlen, outlen;
+ WV_DEVICE *dev;
+ NTSTATUS status;
+ ci_umv_buf_t verbsData;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_ID), &inid, &inlen);
+ if (!NT_SUCCESS(status)) {
+ goto err1;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
+ if (!NT_SUCCESS(status)) {
+ goto err1;
+ }
+
+ dev = WvDeviceAlloc(pProvider);
+ if (dev == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto err1;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ WvProviderRemoveDisable(pProvider);
+ dev->Id = IndexListInsert(&pProvider->DevIndex, dev);
+ if (dev->Id == 0) {
+ status = STATUS_NO_MEMORY;
+ goto err2;
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),
+ outlen - sizeof(WV_IO_ID), inid + 1);
+ status = WvDeviceInit(dev, inid->Id, &verbsData);
+ if (!NT_SUCCESS(status)) {
+ goto err3;
+ }
+
+ WvProviderRemoveEnable(pProvider);
+ outid->Id = dev->Id;
+ outid->VerbInfo = verbsData.status;
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+ return;
+
+err3:
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ IndexListRemove(&pProvider->DevIndex, dev->Id);
+err2:
+ KeReleaseGuardedMutex(&pProvider->Lock);
+ WvProviderRemoveEnable(pProvider);
+ WvDeviceDestroy(dev);
+err1:
+ WdfRequestComplete(Request, status);
+}
+
+void WvDeviceClose(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_DEVICE *dev;
+ UINT64 *id;
+ NTSTATUS status;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ WvProviderRemoveDisable(pProvider);
+ dev = IndexListRemove(&pProvider->DevIndex, (SIZE_T) id);
+ if (dev == NULL) {
+ status = STATUS_NO_SUCH_DEVICE;
+ } else if (dev->Ref > 1) {
+ status = STATUS_ACCESS_DENIED;
+ } else {
+ status = STATUS_SUCCESS;
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ if (NT_SUCCESS(status)) {
+ WvDeviceDestroy(dev);
+ }
+ WvProviderRemoveEnable(pProvider);
+out:
+ WdfRequestComplete(Request, status);
+}
Index: wv_provider.h
===================================================================
--- wv_provider.h (revision 1035)
+++ wv_provider.h (working copy)
@@ -36,16 +36,40 @@
#include <wdf.h>
#include <wdm.h>
+#include <complib\cl_qmap.h>
+#include "wv_driver.h"
+#include "index_list.h"
+
+struct _WV_DEVICE;
+struct _WV_PROTECTION_DOMAIN;
+
typedef struct _WV_PROVIDER
{
+ LIST_ENTRY Entry;
+ INDEX_LIST DevIndex;
+ INDEX_LIST PdIndex;
+
KGUARDED_MUTEX Lock;
- LIST_ENTRY DevList;
+ LONG Ref;
+ KEVENT Event;
+ LONG Pending;
+ LONG Active;
+ KEVENT SharedEvent;
+ LONG Exclusive;
+ KEVENT ExclusiveEvent;
} WV_PROVIDER;
+void WvProviderGet(WV_PROVIDER *pProvider);
+void WvProviderPut(WV_PROVIDER *pProvider);
void WvProviderInit(WV_PROVIDER *pProvider);
-void WvProviderDestroy(WV_PROVIDER *pProvider);
+void WvProviderCleanup(WV_PROVIDER *pProvider);
-void WvGuidQuery(WDFREQUEST Request);
+void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice);
+void WvProviderRemoveDisable(WV_PROVIDER *pProvider);
+void WvProviderRemoveEnable(WV_PROVIDER *pProvider);
+void WvDeviceOpen(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvDeviceClose(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
#endif // _WV_PROVIDER_H_
More information about the ofw
mailing list