19053a8f618f0edd5f2d00c4f1c49216a2683e5b
[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 NTSTATUS WvProviderInit(WDFDEVICE Device, WV_PROVIDER *pProvider)\r
57 {\r
58         NTSTATUS status;\r
59 \r
60         status = WorkQueueInit(&pProvider->WorkQueue, WdfDeviceWdmGetDeviceObject(Device), 0);\r
61         if (!NT_SUCCESS(status)) {\r
62                 return status;\r
63         }\r
64 \r
65         IndexListInit(&pProvider->DevIndex);\r
66         IndexListInit(&pProvider->CqIndex);\r
67         IndexListInit(&pProvider->PdIndex);\r
68         IndexListInit(&pProvider->SrqIndex);\r
69         IndexListInit(&pProvider->QpIndex);\r
70         IndexListInit(&pProvider->MwIndex);\r
71         IndexListInit(&pProvider->AhIndex);\r
72         IndexListInit(&pProvider->EpIndex);\r
73 \r
74         KeInitializeGuardedMutex(&pProvider->Lock);\r
75         pProvider->Ref = 1;\r
76         KeInitializeEvent(&pProvider->Event, NotificationEvent, FALSE);\r
77 \r
78         pProvider->Pending = 0;\r
79         pProvider->Active = 0;\r
80         KeInitializeEvent(&pProvider->SharedEvent, NotificationEvent, FALSE);\r
81         pProvider->Exclusive = 0;\r
82         KeInitializeEvent(&pProvider->ExclusiveEvent, SynchronizationEvent, FALSE);\r
83         return STATUS_SUCCESS;\r
84 }\r
85 \r
86 void WvProviderCleanup(WV_PROVIDER *pProvider)\r
87 {\r
88         WV_DEVICE                               *dev;\r
89         WV_COMPLETION_QUEUE             *cq;\r
90         WV_PROTECTION_DOMAIN    *pd;\r
91         WV_SHARED_RECEIVE_QUEUE *srq;\r
92         WV_QUEUE_PAIR                   *qp;\r
93         WV_MEMORY_WINDOW                *mw;\r
94         WV_ADDRESS_HANDLE               *ah;\r
95         WV_ENDPOINT                             *ep;\r
96         SIZE_T                                  i;\r
97 \r
98         IndexListForEach(&pProvider->EpIndex, i) {\r
99                 ep = (WV_ENDPOINT *) IndexListAt(&pProvider->EpIndex, i);\r
100                 if (ep->State == WvEpListening) {\r
101                         WvEpCancelListen(ep);\r
102                 }\r
103         }\r
104         while ((ep = IndexListRemoveHead(&pProvider->EpIndex)) != NULL) {\r
105                 RemoveEntryList(&ep->Entry);\r
106                 WvEpFree(ep);\r
107         }\r
108         while ((ah = IndexListRemoveHead(&pProvider->AhIndex)) != NULL) {\r
109                 RemoveEntryList(&ah->Entry);\r
110                 WvAhFree(ah);\r
111         }\r
112         while ((mw = IndexListRemoveHead(&pProvider->MwIndex)) != NULL) {\r
113                 RemoveEntryList(&mw->Entry);\r
114                 WvMwFree(mw);\r
115         }\r
116         while ((qp = IndexListRemoveHead(&pProvider->QpIndex)) != NULL) {\r
117                 RemoveEntryList(&qp->Entry);\r
118                 WvQpFree(qp);\r
119         }\r
120         while ((srq = IndexListRemoveHead(&pProvider->SrqIndex)) != NULL) {\r
121                 RemoveEntryList(&srq->Entry);\r
122                 WvSrqFree(srq);\r
123         }\r
124         while ((pd = IndexListRemoveHead(&pProvider->PdIndex)) != NULL) {\r
125                 RemoveEntryList(&pd->Entry);\r
126                 WvPdFree(pd);\r
127         }\r
128         while ((cq = IndexListRemoveHead(&pProvider->CqIndex)) != NULL) {\r
129                 RemoveEntryList(&cq->Entry);\r
130                 WvCqFree(cq);\r
131         }\r
132         while ((dev = IndexListRemoveHead(&pProvider->DevIndex)) != NULL) {\r
133                 WvDeviceFree(dev);\r
134         }\r
135 \r
136         if (InterlockedDecrement(&pProvider->Ref) > 0) {\r
137                 KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);\r
138         }\r
139 \r
140         IndexListDestroy(&pProvider->EpIndex);\r
141         IndexListDestroy(&pProvider->AhIndex);\r
142         IndexListDestroy(&pProvider->MwIndex);\r
143         IndexListDestroy(&pProvider->QpIndex);\r
144         IndexListDestroy(&pProvider->SrqIndex);\r
145         IndexListDestroy(&pProvider->PdIndex);\r
146         IndexListDestroy(&pProvider->CqIndex);\r
147         IndexListDestroy(&pProvider->DevIndex);\r
148         WorkQueueDestroy(&pProvider->WorkQueue);\r
149 }\r
150 \r
151 // See comment above WvProviderRemoveHandler.\r
152 static void WvProviderLockRemove(WV_PROVIDER *pProvider)\r
153 {\r
154         KeAcquireGuardedMutex(&pProvider->Lock);\r
155         pProvider->Exclusive++;\r
156         KeClearEvent(&pProvider->SharedEvent);\r
157         while (pProvider->Active > 0) {\r
158                 KeReleaseGuardedMutex(&pProvider->Lock);\r
159                 KeWaitForSingleObject(&pProvider->ExclusiveEvent, Executive, KernelMode,\r
160                                                           FALSE, NULL);\r
161                 KeAcquireGuardedMutex(&pProvider->Lock);\r
162         }\r
163         pProvider->Active++;\r
164         KeReleaseGuardedMutex(&pProvider->Lock);\r
165 }\r
166 \r
167 // See comment above WvProviderRemoveHandler.\r
168 static void WvProviderUnlockRemove(WV_PROVIDER *pProvider)\r
169 {\r
170         KeAcquireGuardedMutex(&pProvider->Lock);\r
171         pProvider->Exclusive--;\r
172         pProvider->Active--;\r
173         if (pProvider->Exclusive > 0) {\r
174                 KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);\r
175         } else if (pProvider->Pending > 0) {\r
176                 KeSetEvent(&pProvider->SharedEvent, 0, FALSE);\r
177         }\r
178         KeReleaseGuardedMutex(&pProvider->Lock);\r
179 }\r
180 \r
181 /*\r
182  * Must hold pProvider->Lock.  Function may release and re-acquire.\r
183  * See comment above WvProviderRemoveHandler.\r
184  */\r
185 void WvProviderDisableRemove(WV_PROVIDER *pProvider)\r
186 {\r
187         while (pProvider->Exclusive > 0) {\r
188                 pProvider->Pending++;\r
189                 KeReleaseGuardedMutex(&pProvider->Lock);\r
190                 KeWaitForSingleObject(&pProvider->SharedEvent, Executive, KernelMode,\r
191                                                           FALSE, NULL);\r
192                 KeAcquireGuardedMutex(&pProvider->Lock);\r
193                 pProvider->Pending--;\r
194         }\r
195         InterlockedIncrement(&pProvider->Active);\r
196 }\r
197 \r
198 /*\r
199  * No need to hold pProvider->Lock when releasing.\r
200  * See comment above WvProviderRemoveHandler.\r
201  */\r
202 void WvProviderEnableRemove(WV_PROVIDER *pProvider)\r
203 {\r
204         InterlockedDecrement(&pProvider->Active);\r
205         if (pProvider->Exclusive > 0) {\r
206                 KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);\r
207         }\r
208 }\r
209 \r
210 /*\r
211  * The remove handler blocks all other threads executing through this\r
212  * provider until the remove has been processed.  Because device removal is\r
213  * rare, we want a simple, optimized code path for all calls that access\r
214  * the underlying hardware device, making use of any locks that we would\r
215  * have to acquire anyway.  The locking for exclusive access can be\r
216  * as ugly and slow as needed.\r
217  */\r
218 void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice)\r
219 {\r
220         WV_DEVICE *dev;\r
221         SIZE_T i;\r
222 \r
223         WvProviderLockRemove(pProvider);\r
224         IndexListForEach(&pProvider->DevIndex, i) {\r
225                 dev = IndexListAt(&pProvider->DevIndex, i);\r
226                 if (dev->pDevice == pDevice) {\r
227                         WvDeviceRemoveHandler(dev);\r
228                 }\r
229         }\r
230         WvProviderUnlockRemove(pProvider);\r
231 }\r