[opensm] removed opensm\user\include\ib_types.h, even though it was not used, it...
[mirror/winof/.git] / core / winverbs / kernel / wv_provider.c
1 /*\r
2  * Copyright (c) 2008 Intel Corporation. All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\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
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\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
19  *\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
27  * SOFTWARE.\r
28  */\r
29 \r
30 #include <ntstatus.h>\r
31 \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
38 #include "wv_pd.h"\r
39 #include "wv_srq.h"\r
40 #include "wv_cq.h"\r
41 #include "wv_qp.h"\r
42 #include "wv_ep.h"\r
43 \r
44 void WvProviderGet(WV_PROVIDER *pProvider)\r
45 {\r
46         InterlockedIncrement(&pProvider->Ref);\r
47 }\r
48 \r
49 void WvProviderPut(WV_PROVIDER *pProvider)\r
50 {\r
51         if (InterlockedDecrement(&pProvider->Ref) == 0) {\r
52                 KeSetEvent(&pProvider->Event, 0, FALSE);\r
53         }\r
54 }\r
55 \r
56 // See comment above WvProviderRemoveHandler.\r
57 static void WvProviderLockRemove(WV_PROVIDER *pProvider)\r
58 {\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
65                                                           FALSE, NULL);\r
66                 KeAcquireGuardedMutex(&pProvider->Lock);\r
67         }\r
68         pProvider->Active++;\r
69         KeReleaseGuardedMutex(&pProvider->Lock);\r
70 }\r
71 \r
72 // See comment above WvProviderRemoveHandler.\r
73 static void WvProviderUnlockRemove(WV_PROVIDER *pProvider)\r
74 {\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
82         }\r
83         KeReleaseGuardedMutex(&pProvider->Lock);\r
84 }\r
85 \r
86 NTSTATUS WvProviderInit(WDFDEVICE Device, WV_PROVIDER *pProvider)\r
87 {\r
88         NTSTATUS status;\r
89 \r
90         status = WorkQueueInit(&pProvider->WorkQueue, WdfDeviceWdmGetDeviceObject(Device), 0);\r
91         if (!NT_SUCCESS(status)) {\r
92                 return status;\r
93         }\r
94 \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
103 \r
104         KeInitializeGuardedMutex(&pProvider->Lock);\r
105         pProvider->Ref = 1;\r
106         KeInitializeEvent(&pProvider->Event, NotificationEvent, FALSE);\r
107 \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
114 }\r
115 \r
116 /*\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
124  */\r
125 \r
126 void WvProviderCleanup(WV_PROVIDER *pProvider)\r
127 {\r
128         WV_DEVICE                               *dev;\r
129         WV_COMPLETION_QUEUE             *cq;\r
130         WV_PROTECTION_DOMAIN    *pd;\r
131         WV_SHARED_RECEIVE_QUEUE *srq;\r
132         WV_QUEUE_PAIR                   *qp;\r
133         WV_MEMORY_WINDOW                *mw;\r
134         WV_ADDRESS_HANDLE               *ah;\r
135         WV_ENDPOINT                             *ep;\r
136         SIZE_T                                  i;\r
137 \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
143                 }\r
144         }\r
145         while ((ep = IndexListRemoveHead(&pProvider->EpIndex)) != NULL) {\r
146                 WvEpFree(ep);\r
147         }\r
148         while ((ah = IndexListRemoveHead(&pProvider->AhIndex)) != NULL) {\r
149                 RemoveEntryList(&ah->Entry);\r
150                 WvAhFree(ah);\r
151         }\r
152         while ((mw = IndexListRemoveHead(&pProvider->MwIndex)) != NULL) {\r
153                 RemoveEntryList(&mw->Entry);\r
154                 WvMwFree(mw);\r
155         }\r
156         while ((qp = IndexListRemoveHead(&pProvider->QpIndex)) != NULL) {\r
157                 RemoveEntryList(&qp->Entry);\r
158                 WvQpFree(qp);\r
159         }\r
160         while ((srq = IndexListRemoveHead(&pProvider->SrqIndex)) != NULL) {\r
161                 RemoveEntryList(&srq->Entry);\r
162                 WvSrqFree(srq);\r
163         }\r
164         while ((pd = IndexListRemoveHead(&pProvider->PdIndex)) != NULL) {\r
165                 RemoveEntryList(&pd->Entry);\r
166                 WvPdFree(pd);\r
167         }\r
168         while ((cq = IndexListRemoveHead(&pProvider->CqIndex)) != NULL) {\r
169                 RemoveEntryList(&cq->Entry);\r
170                 WvCqFree(cq);\r
171         }\r
172         while ((dev = IndexListRemoveHead(&pProvider->DevIndex)) != NULL) {\r
173                 WvDeviceFree(dev);\r
174         }\r
175         WvProviderUnlockRemove(pProvider);\r
176 \r
177         if (InterlockedDecrement(&pProvider->Ref) > 0) {\r
178                 KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);\r
179         }\r
180 \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
190 }\r
191 \r
192 /*\r
193  * Must hold pProvider->Lock.  Function may release and re-acquire.\r
194  * See comment above WvProviderRemoveHandler.\r
195  */\r
196 void WvProviderDisableRemove(WV_PROVIDER *pProvider)\r
197 {\r
198         while (pProvider->Exclusive > 0) {\r
199                 pProvider->Pending++;\r
200                 KeReleaseGuardedMutex(&pProvider->Lock);\r
201                 KeWaitForSingleObject(&pProvider->SharedEvent, Executive, KernelMode,\r
202                                                           FALSE, NULL);\r
203                 KeAcquireGuardedMutex(&pProvider->Lock);\r
204                 pProvider->Pending--;\r
205         }\r
206         InterlockedIncrement(&pProvider->Active);\r
207 }\r
208 \r
209 /*\r
210  * No need to hold pProvider->Lock when releasing.\r
211  * See comment above WvProviderRemoveHandler.\r
212  */\r
213 void WvProviderEnableRemove(WV_PROVIDER *pProvider)\r
214 {\r
215         InterlockedDecrement(&pProvider->Active);\r
216         if (pProvider->Exclusive > 0) {\r
217                 KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);\r
218         }\r
219 }\r
220 \r
221 /*\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
228  */\r
229 void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice)\r
230 {\r
231         WV_DEVICE *dev;\r
232         SIZE_T i;\r
233 \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
239                 }\r
240         }\r
241         WvProviderUnlockRemove(pProvider);\r
242 }\r