2 * Copyright (c) 2008 Intel Corporation. All rights reserved.
\r
4 * This software is available to you under the OpenIB.org BSD license
\r
7 * Redistribution and use in source and binary forms, with or
\r
8 * without modification, are permitted provided that the following
\r
9 * conditions are met:
\r
11 * - Redistributions of source code must retain the above
\r
12 * copyright notice, this list of conditions and the following
\r
15 * - Redistributions in binary form must reproduce the above
\r
16 * copyright notice, this list of conditions and the following
\r
17 * disclaimer in the documentation and/or other materials
\r
18 * provided with the distribution.
\r
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
\r
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
30 #include <ntstatus.h>
\r
32 #include "work_queue.c"
\r
33 #include <rdma\wvstatus.h>
\r
34 #include "wv_driver.h"
\r
35 #include "wv_ioctl.h"
\r
36 #include "wv_provider.h"
\r
37 #include "wv_device.h"
\r
44 void WvProviderGet(WV_PROVIDER *pProvider)
\r
46 InterlockedIncrement(&pProvider->Ref);
\r
49 void WvProviderPut(WV_PROVIDER *pProvider)
\r
51 if (InterlockedDecrement(&pProvider->Ref) == 0) {
\r
52 KeSetEvent(&pProvider->Event, 0, FALSE);
\r
56 // See comment above WvProviderRemoveHandler.
\r
57 static void WvProviderLockRemove(WV_PROVIDER *pProvider)
\r
59 KeAcquireGuardedMutex(&pProvider->Lock);
\r
60 pProvider->Exclusive++;
\r
61 KeClearEvent(&pProvider->SharedEvent);
\r
62 while (pProvider->Active > 0) {
\r
63 KeReleaseGuardedMutex(&pProvider->Lock);
\r
64 KeWaitForSingleObject(&pProvider->ExclusiveEvent, Executive, KernelMode,
\r
66 KeAcquireGuardedMutex(&pProvider->Lock);
\r
68 pProvider->Active++;
\r
69 KeReleaseGuardedMutex(&pProvider->Lock);
\r
72 // See comment above WvProviderRemoveHandler.
\r
73 static void WvProviderUnlockRemove(WV_PROVIDER *pProvider)
\r
75 KeAcquireGuardedMutex(&pProvider->Lock);
\r
76 pProvider->Exclusive--;
\r
77 pProvider->Active--;
\r
78 if (pProvider->Exclusive > 0) {
\r
79 KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);
\r
80 } else if (pProvider->Pending > 0) {
\r
81 KeSetEvent(&pProvider->SharedEvent, 0, FALSE);
\r
83 KeReleaseGuardedMutex(&pProvider->Lock);
\r
86 NTSTATUS WvProviderInit(WDFDEVICE Device, WV_PROVIDER *pProvider)
\r
90 status = WorkQueueInit(&pProvider->WorkQueue, WdfDeviceWdmGetDeviceObject(Device), 0);
\r
91 if (!NT_SUCCESS(status)) {
\r
95 IndexListInit(&pProvider->DevIndex);
\r
96 IndexListInit(&pProvider->CqIndex);
\r
97 IndexListInit(&pProvider->PdIndex);
\r
98 IndexListInit(&pProvider->SrqIndex);
\r
99 IndexListInit(&pProvider->QpIndex);
\r
100 IndexListInit(&pProvider->MwIndex);
\r
101 IndexListInit(&pProvider->AhIndex);
\r
102 IndexListInit(&pProvider->EpIndex);
\r
104 KeInitializeGuardedMutex(&pProvider->Lock);
\r
105 pProvider->Ref = 1;
\r
106 KeInitializeEvent(&pProvider->Event, NotificationEvent, FALSE);
\r
108 pProvider->Pending = 0;
\r
109 pProvider->Active = 0;
\r
110 KeInitializeEvent(&pProvider->SharedEvent, NotificationEvent, FALSE);
\r
111 pProvider->Exclusive = 0;
\r
112 KeInitializeEvent(&pProvider->ExclusiveEvent, SynchronizationEvent, FALSE);
\r
113 return STATUS_SUCCESS;
\r
117 * We could be processing asynchronous requests or have them queued
\r
118 * when cleaning up. To synchronize with async request processing,
\r
119 * acquire the provider lock with exclusive access until we're done
\r
120 * destroying all resoureces. This will allow active requests to
\r
121 * complete their processing, but prevent queued requests from
\r
122 * running until cleanup is done. At that point, queue requests will
\r
123 * be unable to acquire any winverbs resources.
\r
126 void WvProviderCleanup(WV_PROVIDER *pProvider)
\r
129 WV_COMPLETION_QUEUE *cq;
\r
130 WV_PROTECTION_DOMAIN *pd;
\r
131 WV_SHARED_RECEIVE_QUEUE *srq;
\r
133 WV_MEMORY_WINDOW *mw;
\r
134 WV_ADDRESS_HANDLE *ah;
\r
138 WvProviderLockRemove(pProvider);
\r
139 IndexListForEach(&pProvider->EpIndex, i) {
\r
140 ep = (WV_ENDPOINT *) IndexListAt(&pProvider->EpIndex, i);
\r
141 if (ep->State == WvEpListening) {
\r
142 WvEpCancelListen(ep);
\r
145 while ((ep = IndexListRemoveHead(&pProvider->EpIndex)) != NULL) {
\r
148 while ((ah = IndexListRemoveHead(&pProvider->AhIndex)) != NULL) {
\r
149 RemoveEntryList(&ah->Entry);
\r
152 while ((mw = IndexListRemoveHead(&pProvider->MwIndex)) != NULL) {
\r
153 RemoveEntryList(&mw->Entry);
\r
156 while ((qp = IndexListRemoveHead(&pProvider->QpIndex)) != NULL) {
\r
157 RemoveEntryList(&qp->Entry);
\r
160 while ((srq = IndexListRemoveHead(&pProvider->SrqIndex)) != NULL) {
\r
161 RemoveEntryList(&srq->Entry);
\r
164 while ((pd = IndexListRemoveHead(&pProvider->PdIndex)) != NULL) {
\r
165 RemoveEntryList(&pd->Entry);
\r
168 while ((cq = IndexListRemoveHead(&pProvider->CqIndex)) != NULL) {
\r
169 RemoveEntryList(&cq->Entry);
\r
172 while ((dev = IndexListRemoveHead(&pProvider->DevIndex)) != NULL) {
\r
175 WvProviderUnlockRemove(pProvider);
\r
177 if (InterlockedDecrement(&pProvider->Ref) > 0) {
\r
178 KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);
\r
181 IndexListDestroy(&pProvider->EpIndex);
\r
182 IndexListDestroy(&pProvider->AhIndex);
\r
183 IndexListDestroy(&pProvider->MwIndex);
\r
184 IndexListDestroy(&pProvider->QpIndex);
\r
185 IndexListDestroy(&pProvider->SrqIndex);
\r
186 IndexListDestroy(&pProvider->PdIndex);
\r
187 IndexListDestroy(&pProvider->CqIndex);
\r
188 IndexListDestroy(&pProvider->DevIndex);
\r
189 WorkQueueDestroy(&pProvider->WorkQueue);
\r
193 * Must hold pProvider->Lock. Function may release and re-acquire.
\r
194 * See comment above WvProviderRemoveHandler.
\r
196 void WvProviderDisableRemove(WV_PROVIDER *pProvider)
\r
198 while (pProvider->Exclusive > 0) {
\r
199 pProvider->Pending++;
\r
200 KeReleaseGuardedMutex(&pProvider->Lock);
\r
201 KeWaitForSingleObject(&pProvider->SharedEvent, Executive, KernelMode,
\r
203 KeAcquireGuardedMutex(&pProvider->Lock);
\r
204 pProvider->Pending--;
\r
206 InterlockedIncrement(&pProvider->Active);
\r
210 * No need to hold pProvider->Lock when releasing.
\r
211 * See comment above WvProviderRemoveHandler.
\r
213 void WvProviderEnableRemove(WV_PROVIDER *pProvider)
\r
215 InterlockedDecrement(&pProvider->Active);
\r
216 if (pProvider->Exclusive > 0) {
\r
217 KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);
\r
222 * The remove handler blocks all other threads executing through this
\r
223 * provider until the remove has been processed. Because device removal is
\r
224 * rare, we want a simple, optimized code path for all calls that access
\r
225 * the underlying hardware device, making use of any locks that we would
\r
226 * have to acquire anyway. The locking for exclusive access can be
\r
227 * as ugly and slow as needed.
\r
229 void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice)
\r
234 WvProviderLockRemove(pProvider);
\r
235 IndexListForEach(&pProvider->DevIndex, i) {
\r
236 dev = IndexListAt(&pProvider->DevIndex, i);
\r
237 if (dev->pDevice == pDevice) {
\r
238 WvDeviceRemoveHandler(dev);
\r
241 WvProviderUnlockRemove(pProvider);
\r