[ofw] [RFC] [PATCH 4/4 v2] winverbs.sys: partial driver implementation
Sean Hefty
sean.hefty at intel.com
Thu Apr 24 14:00:34 PDT 2008
The driver implements opening/closing/query a device, allocating PDs,
registering memory, allocating memory windows, and creating address handles.
It also handles device removal with active userspace users.
Major missing verbs functionality includes: CQ, SRQ, and QP.
Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
Changes from V1:
Added MW and AH calls.
Reworked synchronization with device removal. *Acquire() routines only
return success if the RDMA device has not been removed. Locking was reworked
to avoid race conditions.
Cleanup routines only remove kernel widgets from index lists if the widget
is successfully destroyed.
Minor fixes and code restructuring based on review feedback.
Index: index_list.c
===================================================================
--- index_list.c (revision 0)
+++ index_list.c (revision 0)
@@ -0,0 +1,108 @@
+/*
+ * 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 "index_list.h"
+
+static BOOLEAN IndexListGrow(INDEX_LIST *pIndexList)
+{
+ INDEX_ENTRY *array;
+ SIZE_T size, i;
+
+ size = pIndexList->Size + (PAGE_SIZE / sizeof(INDEX_ENTRY));
+ array = ExAllocatePoolWithTag(PagedPool, size * sizeof(INDEX_ENTRY), 'xdni');
+ if (array == NULL) {
+ return FALSE;
+ }
+
+ i = size;
+ while (i-- > pIndexList->Size) {
+ array[i].pItem = NULL;
+ array[i].Next = pIndexList->FreeList;
+ pIndexList->FreeList = i;
+ }
+
+ if (pIndexList->pArray != NULL) {
+ RtlCopyMemory(array, pIndexList->pArray, pIndexList->Size * sizeof(INDEX_ENTRY));
+ ExFreePool(pIndexList->pArray);
+ } else {
+ array[0].Next = 0;
+ array[0].Prev = 0;
+ pIndexList->FreeList = 1;
+ }
+
+ pIndexList->Size = size;
+ pIndexList->pArray = array;
+ return TRUE;
+}
+
+SIZE_T IndexListInsertHead(INDEX_LIST *pIndexList, void *pItem)
+{
+ INDEX_ENTRY *entry;
+ SIZE_T index;
+
+ if (pIndexList->FreeList == 0 && !IndexListGrow(pIndexList)) {
+ return 0;
+ }
+
+ index = pIndexList->FreeList;
+ entry = &pIndexList->pArray[index];
+ pIndexList->FreeList = entry->Next;
+
+ entry->pItem = pItem;
+ entry->Next = pIndexList->pArray[0].Next;
+ pIndexList->pArray[0].Next = index;
+ entry->Prev = 0;
+ pIndexList->pArray[entry->Next].Prev = index;
+
+ return index;
+}
+
+void *IndexListRemove(INDEX_LIST *pIndexList, SIZE_T Index)
+{
+ INDEX_ENTRY *entry;
+ void *item;
+
+ if (Index >= pIndexList->Size) {
+ return NULL;
+ }
+
+ entry = &pIndexList->pArray[Index];
+ if (entry->pItem == NULL) {
+ return NULL;
+ }
+
+ pIndexList->pArray[entry->Next].Prev = entry->Prev;
+ pIndexList->pArray[entry->Prev].Next = entry->Next;
+
+ item = entry->pItem;
+ entry->pItem = NULL;
+ entry->Next = pIndexList->FreeList;
+ pIndexList->FreeList = Index;
+ return item;
+}
Index: index_list.h
===================================================================
--- index_list.h (revision 0)
+++ index_list.h (revision 0)
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef _INDEX_LIST_H_
+#define _INDEX_LIST_H_
+
+#include <ntddk.h>
+
+typedef struct _INDEX_ENTRY
+{
+ SIZE_T Next;
+ SIZE_T Prev;
+ void *pItem;
+
+} INDEX_ENTRY;
+
+// Synchronization must be provided by the caller.
+typedef struct _INDEX_LIST
+{
+ INDEX_ENTRY *pArray; // pArray[0] is list head of used entries
+ SIZE_T FreeList; // singly-linked list of free INDEX_ENTRY's
+ SIZE_T Size;
+
+} INDEX_LIST;
+
+static void IndexListInit(INDEX_LIST *pIndexList)
+{
+ RtlZeroMemory(pIndexList, sizeof(INDEX_LIST));
+}
+
+static void IndexListDestroy(INDEX_LIST *pIndexList)
+{
+ if (pIndexList->pArray != NULL) {
+ ExFreePool(pIndexList->pArray);
+ }
+}
+
+SIZE_T IndexListInsertHead(INDEX_LIST *pIndexList, void *pItem);
+
+static void *IndexListAt(INDEX_LIST *pIndexList, SIZE_T Index)
+{
+ return (Index < pIndexList->Size) ? pIndexList->pArray[Index].pItem : NULL;
+}
+
+void *IndexListRemove(INDEX_LIST *pIndexList, SIZE_T Index);
+
+static void *IndexListRemoveHead(INDEX_LIST *pIndexList)
+{
+ return IndexListRemove(pIndexList, pIndexList->pArray[0].Next);
+}
+
+#define IndexListForEach(pIndexList, Index) \
+ for (Index = (pIndexList)->pArray[0].Next; Index != 0; \
+ Index = (pIndexList)->pArray[Index].Next)
+
+#endif // _INDEX_LIST_H_
Index: wv_device.c
===================================================================
--- wv_device.c (revision 0)
+++ wv_device.c (revision 0)
@@ -0,0 +1,587 @@
+/*
+ * 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);
+ WvProviderDisableRemove(pProvider);
+ dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) Id);
+ if (dev != NULL && dev->hVerbsDevice != NULL) {
+ WvDeviceGet(dev);
+ } else {
+ dev = NULL;
+ WvProviderEnableRemove(pProvider);
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ return dev;
+}
+
+void WvDeviceRelease(WV_DEVICE *pDevice)
+{
+ WvProviderEnableRemove(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->pDevice = NULL;
+ dev->pVerbs = NULL;
+ dev->hVerbsDevice = 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;
+ }
+
+ ib_status = pDevice->pVerbs->um_open_ca(dev->hDevice, pVerbsData,
+ &pDevice->hVerbsDevice);
+ if (ib_status != IB_SUCCESS) {
+ goto err;
+ }
+
+ pDevice->pDevice = dev;
+ pDevice->pVerbs = &dev->Interface.Verbs;
+ return STATUS_SUCCESS;
+
+err:
+ WvRdmaDevicePut(pDevice->pDevice);
+ pDevice->hVerbsDevice = NULL;
+ return STATUS_UNSUCCESSFUL;
+}
+
+void WvDeviceFree(WV_DEVICE *pDevice)
+{
+ if (InterlockedDecrement(&pDevice->Ref) > 0) {
+ KeWaitForSingleObject(&pDevice->Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ if (pDevice->hVerbsDevice != 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;
+ pDevice->pVerbs = NULL;
+ pDevice->hVerbsDevice = 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);
+ WvDeviceRelease(dev);
+
+ if (ca_attr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto complete;
+ }
+
+ WvConvertDevAttr(attr, ca_attr);
+ outlen = sizeof(WV_IO_DEVICE_ATTRIBUTES);
+ ExFreePool(ca_attr);
+
+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);
+ WvDeviceRelease(dev);
+
+ if (ca_attr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto complete;
+ }
+
+ 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);
+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);
+ WvDeviceRelease(dev);
+
+ if (ca_attr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto complete;
+ }
+
+ 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);
+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);
+ WvDeviceRelease(dev);
+
+ if (ca_attr == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto complete;
+ }
+
+ 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);
+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);
+ outid->Id= IndexListInsertHead(&pProvider->PdIndex, pd);
+ if (outid->Id == 0) {
+ status = STATUS_NO_MEMORY;
+ goto err3;
+ }
+ InsertHeadList(&dev->PdList, &pd->Entry);
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ WvDeviceRelease(dev);
+ outid->VerbInfo = verbsData.status;
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+ return;
+
+err3:
+ KeReleaseGuardedMutex(&pProvider->Lock);
+ WvPdFree(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);
+ WvProviderDisableRemove(pProvider);
+ pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) id);
+ if (pd == NULL) {
+ status = STATUS_NOT_FOUND;
+ } else if (pd->Ref > 1) {
+ status = STATUS_ACCESS_DENIED;
+ } else {
+ IndexListRemove(&pProvider->PdIndex, (SIZE_T) id);
+ RemoveEntryList(&pd->Entry);
+ status = STATUS_SUCCESS;
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ if (NT_SUCCESS(status)) {
+ WvPdFree(pd);
+ }
+ WvProviderEnableRemove(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 WvDeviceFree(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,113 @@
#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;
+WV_RDMA_DEVICE *WvRdmaDeviceGet(UINT64 Guid)
+{
+ WV_RDMA_DEVICE *cur_dev, *dev = NULL;
+ LIST_ENTRY *entry;
+
+ KeAcquireGuardedMutex(&Lock);
+ for (entry = DevList.Flink; entry != &DevList; entry = entry->Flink) {
+ cur_dev = CONTAINING_RECORD(entry, WV_RDMA_DEVICE, Entry);
+ if (cur_dev->Interface.Verbs.guid == Guid) {
+ InterlockedIncrement(&cur_dev->Ref);
+ dev = cur_dev;
+ break;
+ }
+ }
+ 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,41 +162,73 @@
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_MW_ALLOCATE:WvMwAllocate;break;
- //case WV_IOCTL_MW_DEALLOCATE:WvMwDeallocate;break;
- //case WV_IOCTL_AH_CREATE:WvAhCreate;break;
- //case WV_IOCTL_AH_DESTROY:WvAhDestroy;break;
+ case WV_IOCTL_PD_ALLOCATE:
+ WvPdAllocate(prov, Request);
+ break;
+ case WV_IOCTL_PD_DEALLOCATE:
+ WvPdDeallocate(prov, Request);
+ break;
+ case WV_IOCTL_MEMORY_REGISTER:
+ WvMrRegister(prov, Request);
+ break;
+ case WV_IOCTL_MEMORY_DEREGISTER:
+ WvMrDeregister(prov, Request);
+ break;
+ case WV_IOCTL_MW_ALLOCATE:
+ WvMwAllocate(prov, Request);
+ break;
+ case WV_IOCTL_MW_DEALLOCATE:
+ WvMwDeallocate(prov, Request);
+ break;
+ case WV_IOCTL_AH_CREATE:
+ WvAhCreate(prov, Request);
+ break;
+ case WV_IOCTL_AH_DESTROY:
+ WvAhDestroy(prov, Request);
+ break;
//case WV_IOCTL_CQ_CREATE:WvCqCreate;break;
//case WV_IOCTL_CQ_DESTROY:WvCqDestroy;break;
//case WV_IOCTL_CQ_RESIZE:WvCqResize;break;
//case WV_IOCTL_CQ_NOTIFY:WvCqNotify;break;
//case WV_IOCTL_CQ_BATCH_NOTIFY:WvCqBatchNotify;break;
//case WV_IOCTL_CQ_CANCEL:WvCqCancel;break;
+
//case WV_IOCTL_SRQ_CREATE :WvSrqCreate;break;
//case WV_IOCTL_SRQ_DESTROY:WvSrqDestroy;break;
//case WV_IOCTL_SRQ_QUERY:WvSrqQuery;break;
//case WV_IOCTL_SRQ_MODIFY:WvSrqModify;break;
//case WV_IOCTL_SRQ_NOTIFY:WvSrqNotify;break;
//case WV_IOCTL_SRQ_CANCEL:WvSrqCancel;break;
+
//case WV_IOCTL_QP_CREATE:WvQpCreate;break;
//case WV_IOCTL_QP_DESTROY:WvQpDestroy;break;
//case WV_IOCTL_QP_QUERY:WvQpQuery;break;
@@ -110,6 +236,7 @@
//case WV_IOCTL_QP_ATTACH:WvQpAttach;break;
//case WV_IOCTL_QP_DETACH:WvQpDetach;break;
//case WV_IOCTL_QP_CANCEL:WvQpCancel;break;
+
//case WV_IOCTL_ADDRESS_QUERY:WvAddressQuery;break;
//case WV_IOCTL_EP_CREATE:WvEpCreate;break;
//case WV_IOCTL_EP_DESTROY:WvEpDestroy;break;
@@ -129,7 +256,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,26 +264,29 @@
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);
}
static VOID WvFileCleanup(WDFFILEOBJECT FileObject)
{
- UNREFERENCED_PARAMETER(FileObject);
+ WV_PROVIDER *prov = WvProviderGetContext(FileObject);
+
+ KeAcquireGuardedMutex(&Lock);
+ RemoveEntryList(&prov->Entry);
+ KeReleaseGuardedMutex(&Lock);
+ WvProviderCleanup(prov);
}
static VOID WvFileClose(WDFFILEOBJECT FileObject)
{
- WV_PROVIDER *prov;
-
- prov = WvGetProvider(FileObject);
- WvProviderDestroy(prov);
+ UNREFERENCED_PARAMETER(FileObject);
}
static VOID WvCreateControlDevice(WDFDRIVER Driver)
@@ -215,7 +345,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 +356,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 +388,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 +432,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,486 @@
+/*
+ * 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);
+ WvProviderDisableRemove(pProvider);
+ pd = IndexListAt(&pProvider->PdIndex, (SIZE_T) Id);
+ if (pd != NULL && pd->hVerbsPd != NULL) {
+ WvPdGet(pd);
+ } else {
+ pd = NULL;
+ WvProviderEnableRemove(pProvider);
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ return pd;
+}
+
+void WvPdRelease(WV_PROTECTION_DOMAIN *pPd)
+{
+ WvProviderEnableRemove(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);
+ InitializeListHead(&pd->MwList);
+ InitializeListHead(&pd->AhList);
+ 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;
+ }
+
+ pd->pDevice = pDevice;
+ pd->pVerbs = pDevice->pVerbs;
+ WvDeviceGet(pDevice);
+ *ppPd = pd;
+ return STATUS_SUCCESS;
+
+err:
+ ExFreePool(pd);
+ return STATUS_UNSUCCESSFUL;
+}
+
+void WvPdFree(WV_PROTECTION_DOMAIN *pPd)
+{
+ WV_MEMORY_REGION *mr;
+ cl_map_item_t *item;
+
+ if (InterlockedDecrement(&pPd->Ref) > 0) {
+ KeWaitForSingleObject(&pPd->Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ 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);
+ if (mr->hVerbsMr != NULL) {
+ pPd->pVerbs->deregister_mr(mr->hVerbsMr);
+ }
+
+ cl_qmap_remove_item(&pPd->MrMap, &mr->Item);
+ ExFreePool(mr);
+ }
+
+ 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->pVerbs = NULL;
+ pPd->hVerbsPd = NULL;
+}
+
+void WvMrRegister(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), 'rmvw');
+ 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;
+ }
+
+ 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 WvMrDeregister(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);
+
+ 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;
+ }
+
+ ExFreePool(mr);
+release:
+ WvPdRelease(pd);
+complete:
+ WdfRequestComplete(Request, status);
+}
+
+void WvMwAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_ID *inid, *outid;
+ size_t inlen, outlen;
+ WV_PROTECTION_DOMAIN *pd;
+ WV_MEMORY_WINDOW *mw;
+ NTSTATUS status;
+ ib_api_status_t ib_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;
+ }
+
+ pd = WvPdAcquire(pProvider, inid->Id);
+ if (pd == NULL) {
+ status = STATUS_NOT_FOUND;
+ goto err1;
+ }
+
+ mw = ExAllocatePoolWithTag(PagedPool, sizeof(WV_MEMORY_WINDOW), 'wmvw');
+ if (mw == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto err2;
+ }
+
+ WvInitVerbsData(&verbsData, inid->VerbInfo, inlen - sizeof(WV_IO_ID),
+ outlen - sizeof(WV_IO_ID), inid + 1);
+ ib_status = pd->pVerbs->create_mw(pd->hVerbsPd, &outid->Data, &mw->hVerbsMw,
+ &verbsData);
+ if (ib_status != IB_SUCCESS) {
+ status = STATUS_UNSUCCESSFUL;
+ goto err3;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ outid->Id = IndexListInsertHead(&pProvider->MwIndex, mw);
+ if (outid->Id == 0) {
+ status = STATUS_NO_MEMORY;
+ goto err3;
+ }
+ InsertHeadList(&pd->MwList, &mw->Entry);
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ mw->pPd = pd;
+ WvPdGet(pd);
+
+ WvPdRelease(pd);
+ outid->VerbInfo = verbsData.status;
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+ return;
+
+err3:
+ KeReleaseGuardedMutex(&pProvider->Lock);
+ WvMwFree(mw);
+err2:
+ WvPdRelease(pd);
+err1:
+ WdfRequestComplete(Request, status);
+}
+
+void WvMwDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_MEMORY_WINDOW *mw;
+ UINT64 *id;
+ NTSTATUS status;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ WvProviderDisableRemove(pProvider);
+ mw = IndexListAt(&pProvider->MwIndex, (SIZE_T) id);
+ if (mw == NULL) {
+ status = STATUS_NOT_FOUND;
+ } else {
+ IndexListRemove(&pProvider->MwIndex, (SIZE_T) id);
+ RemoveEntryList(&mw->Entry);
+ status = STATUS_SUCCESS;
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ if (NT_SUCCESS(status)) {
+ WvMwFree(mw);
+ }
+ WvProviderEnableRemove(pProvider);
+out:
+ WdfRequestComplete(Request, status);
+}
+
+void WvMwFree(WV_MEMORY_WINDOW *pMw)
+{
+ if (pMw->hVerbsMw != NULL) {
+ pMw->pPd->pVerbs->destroy_mw(pMw->hVerbsMw);
+ }
+
+ WvPdPut(pMw->pPd);
+ ExFreePool(pMw);
+}
+
+static void WvVerbsConvertAv(ib_av_attr_t *pVerbsAv, WV_IO_AV *pAv)
+{
+ if (pAv->GrhValid) {
+ RtlCopyMemory(&pVerbsAv->grh, &pAv, sizeof pVerbsAv->grh);
+ pVerbsAv->grh_valid = 1;
+ } else {
+ pVerbsAv->grh_valid = 0;
+ }
+
+ pVerbsAv->port_num = pAv->PortNumber;
+ pVerbsAv->sl = pAv->ServiceLevel;
+ pVerbsAv->dlid = pAv->DLid;
+ pVerbsAv->static_rate = pAv->StaticRate;
+ pVerbsAv->path_bits = pAv->SourcePathBits;
+}
+
+void WvAhCreate(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_IO_ID *outid;
+ size_t inlen, outlen;
+ WV_PROTECTION_DOMAIN *pd;
+ WV_ADDRESS_HANDLE *ah;
+ WV_IO_AH_CREATE *pav;
+ ib_av_attr_t av;
+ NTSTATUS status;
+ ib_api_status_t ib_status;
+ ci_umv_buf_t verbsData;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(WV_IO_AH_CREATE),
+ &pav, &inlen);
+ if (!NT_SUCCESS(status)) {
+ goto err1;
+ }
+ status = WdfRequestRetrieveOutputBuffer(Request, sizeof(WV_IO_ID), &outid, &outlen);
+ if (!NT_SUCCESS(status)) {
+ goto err1;
+ }
+
+ pd = WvPdAcquire(pProvider, pav->Id.Id);
+ if (pd == NULL) {
+ status = STATUS_NOT_FOUND;
+ goto err1;
+ }
+
+ ah = ExAllocatePoolWithTag(PagedPool, sizeof(WV_ADDRESS_HANDLE), 'havw');
+ if (ah == NULL) {
+ status = STATUS_NO_MEMORY;
+ goto err2;
+ }
+
+ WvVerbsConvertAv(&av, &pav->AddressVector);
+ WvInitVerbsData(&verbsData, pav->Id.VerbInfo, inlen - sizeof(WV_IO_AH_CREATE),
+ outlen - sizeof(WV_IO_ID), pav + 1);
+ ib_status = pd->pVerbs->create_av(pd->hVerbsPd, &av, &ah->hVerbsAh, &verbsData);
+ if (ib_status != IB_SUCCESS) {
+ status = STATUS_UNSUCCESSFUL;
+ goto err3;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ outid->Id = IndexListInsertHead(&pProvider->AhIndex, ah);
+ if (outid->Id == 0) {
+ status = STATUS_NO_MEMORY;
+ goto err3;
+ }
+ InsertHeadList(&pd->AhList, &ah->Entry);
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ ah->pPd = pd;
+ WvPdGet(pd);
+
+ WvPdRelease(pd);
+ outid->VerbInfo = verbsData.status;
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+ return;
+
+err3:
+ KeReleaseGuardedMutex(&pProvider->Lock);
+ WvAhFree(ah);
+err2:
+ WvPdRelease(pd);
+err1:
+ WdfRequestComplete(Request, status);
+}
+
+void WvAhDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request)
+{
+ WV_ADDRESS_HANDLE *ah;
+ UINT64 *id;
+ NTSTATUS status;
+
+ status = WdfRequestRetrieveInputBuffer(Request, sizeof(UINT64), &id, NULL);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ WvProviderDisableRemove(pProvider);
+ ah = IndexListAt(&pProvider->AhIndex, (SIZE_T) id);
+ if (ah == NULL) {
+ status = STATUS_NOT_FOUND;
+ } else {
+ IndexListRemove(&pProvider->AhIndex, (SIZE_T) id);
+ RemoveEntryList(&ah->Entry);
+ status = STATUS_SUCCESS;
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ if (NT_SUCCESS(status)) {
+ WvAhFree(ah);
+ }
+ WvProviderEnableRemove(pProvider);
+out:
+ WdfRequestComplete(Request, status);
+}
+
+void WvAhFree(WV_ADDRESS_HANDLE *pAh)
+{
+ if (pAh->hVerbsAh != NULL) {
+ pAh->pPd->pVerbs->destroy_av(pAh->hVerbsAh);
+ }
+
+ WvPdPut(pAh->pPd);
+ ExFreePool(pAh);
+}
Index: wv_pd.h
===================================================================
--- wv_pd.h (revision 1035)
+++ wv_pd.h (working copy)
@@ -32,44 +32,78 @@
#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;
+ LIST_ENTRY MwList;
+ LIST_ENTRY AhList;
+ KGUARDED_MUTEX Lock;
+ cl_qmap_t MrMap;
+
+ 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 WvPdFree(WV_PROTECTION_DOMAIN *pPd);
+void WvPdRemoveHandler(WV_PROTECTION_DOMAIN *pPd);
+
+
+typedef struct _WV_MEMORY_REGION
+{
+ ib_mr_handle_t hVerbsMr;
+ cl_map_item_t Item;
+
+} WV_MEMORY_REGION;
+
+void WvMrRegister(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvMrDeregister(WV_PROVIDER *pProvider, WDFREQUEST Request);
+
+
typedef struct _WV_MEMORY_WINDOW
{
WV_PROTECTION_DOMAIN *pPd;
- ci_interface_t *pVerbs;
ib_mw_handle_t hVerbsMw;
- UINT64 Id;
- UINT32 Rkey;
- volatile LONG nRef;
+ LIST_ENTRY Entry;
} WV_MEMORY_WINDOW;
+void WvMwAllocate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvMwDeallocate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvMwFree(WV_MEMORY_WINDOW *pMw);
+
typedef struct _WV_ADDRESS_HANDLE
{
WV_PROTECTION_DOMAIN *pPd;
- ci_interface_t *pVerbs;
ib_av_handle_t hVerbsAh;
- UINT64 Id;
- volatile LONG m_nRef;
+ LIST_ENTRY Entry;
} WV_ADDRESS_HANDLE;
+void WvAhCreate(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvAhDestroy(WV_PROVIDER *pProvider, WDFREQUEST Request);
+void WvAhFree(WV_ADDRESS_HANDLE *pAh);
+
//void WvVerbsConvertAv(ib_av_attr_t *pVerbsAv, WV_ADDRESS_VECTOR *pAv,
// UINT8 PathMtu, UINT8 LocalAckTimeout,
// UINT8 SequenceErrorRetryCount, UINT8 RnrRetryCount);
Index: wv_provider.c
===================================================================
--- wv_provider.c (revision 1035)
+++ wv_provider.c (working copy)
@@ -27,62 +27,243 @@
* 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);
+ IndexListInit(&pProvider->MwIndex);
+ IndexListInit(&pProvider->AhIndex);
+
+ 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;
+ WV_MEMORY_WINDOW *mw;
+ WV_ADDRESS_HANDLE *ah;
+
+ while ((ah = IndexListRemoveHead(&pProvider->AhIndex)) != NULL) {
+ RemoveEntryList(&ah->Entry);
+ WvAhFree(ah);
}
- pioGuids->Count = i;
- KeReleaseGuardedMutex(&DevLock);
+ while ((mw = IndexListRemoveHead(&pProvider->MwIndex)) != NULL) {
+ RemoveEntryList(&mw->Entry);
+ WvMwFree(mw);
+ }
+ while ((pd = IndexListRemoveHead(&pProvider->PdIndex)) != NULL) {
+ RemoveEntryList(&pd->Entry);
+ WvPdFree(pd);
+ }
+ while ((dev = IndexListRemoveHead(&pProvider->DevIndex)) != NULL) {
+ WvDeviceFree(dev);
+ }
-out:
- WdfRequestCompleteWithInformation(Request, status, len);
+ if (InterlockedDecrement(&pProvider->Ref) > 0) {
+ KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ IndexListDestroy(&pProvider->AhIndex);
+ IndexListDestroy(&pProvider->MwIndex);
+ IndexListDestroy(&pProvider->PdIndex);
+ IndexListDestroy(&pProvider->DevIndex);
}
-void WvProviderInit(WV_PROVIDER *pProvider)
+// See comment above WvProviderRemoveHandler.
+static void WvProviderLockRemove(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 WvProviderUnlockRemove(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 WvProviderDisableRemove(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 WvProviderEnableRemove(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);
+ WvProviderLockRemove(pProvider);
+ IndexListForEach(&pProvider->DevIndex, i) {
+ dev = IndexListAt(&pProvider->DevIndex, i);
+ if (dev->pDevice == pDevice) {
+ WvDeviceRemoveHandler(dev);
+ }
}
+ WvProviderUnlockRemove(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);
+ WvProviderDisableRemove(pProvider);
+ 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 err2;
+ }
+
+ KeAcquireGuardedMutex(&pProvider->Lock);
+ dev->Id = IndexListInsertHead(&pProvider->DevIndex, dev);
+ if (dev->Id == 0) {
+ status = STATUS_NO_MEMORY;
+ goto err2;
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ WvProviderEnableRemove(pProvider);
+ outid->Id = dev->Id;
+ outid->VerbInfo = verbsData.status;
+ WdfRequestCompleteWithInformation(Request, status, outlen);
+ return;
+
+err2:
+ WvDeviceFree(dev);
+ WvProviderEnableRemove(pProvider);
+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);
+ WvProviderDisableRemove(pProvider);
+ dev = IndexListAt(&pProvider->DevIndex, (SIZE_T) id);
+ if (dev == NULL) {
+ status = STATUS_NO_SUCH_DEVICE;
+ } else if (dev->Ref > 1) {
+ status = STATUS_ACCESS_DENIED;
+ } else {
+ IndexListRemove(&pProvider->DevIndex, (SIZE_T) id);
+ status = STATUS_SUCCESS;
+ }
+ KeReleaseGuardedMutex(&pProvider->Lock);
+
+ if (NT_SUCCESS(status)) {
+ WvDeviceFree(dev);
+ }
+ WvProviderEnableRemove(pProvider);
+out:
+ WdfRequestComplete(Request, status);
+}
Index: wv_provider.h
===================================================================
--- wv_provider.h (revision 1035)
+++ wv_provider.h (working copy)
@@ -36,16 +36,42 @@
#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;
+ INDEX_LIST MwIndex;
+ INDEX_LIST AhIndex;
+
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 WvProviderDisableRemove(WV_PROVIDER *pProvider);
+void WvProviderEnableRemove(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