2998afe7f27595ac2e257d6727b1db2a3441bc38
[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                 WvEpFree(ep);\r
106         }\r
107         while ((ah = IndexListRemoveHead(&pProvider->AhIndex)) != NULL) {\r
108                 RemoveEntryList(&ah->Entry);\r
109                 WvAhFree(ah);\r
110         }\r
111         while ((mw = IndexListRemoveHead(&pProvider->MwIndex)) != NULL) {\r
112                 RemoveEntryList(&mw->Entry);\r
113                 WvMwFree(mw);\r
114         }\r
115         while ((qp = IndexListRemoveHead(&pProvider->QpIndex)) != NULL) {\r
116                 RemoveEntryList(&qp->Entry);\r
117                 WvQpFree(qp);\r
118         }\r
119         while ((srq = IndexListRemoveHead(&pProvider->SrqIndex)) != NULL) {\r
120                 RemoveEntryList(&srq->Entry);\r
121                 WvSrqFree(srq);\r
122         }\r
123         while ((pd = IndexListRemoveHead(&pProvider->PdIndex)) != NULL) {\r
124                 RemoveEntryList(&pd->Entry);\r
125                 WvPdFree(pd);\r
126         }\r
127         while ((cq = IndexListRemoveHead(&pProvider->CqIndex)) != NULL) {\r
128                 RemoveEntryList(&cq->Entry);\r
129                 WvCqFree(cq);\r
130         }\r
131         while ((dev = IndexListRemoveHead(&pProvider->DevIndex)) != NULL) {\r
132                 WvDeviceFree(dev);\r
133         }\r
134 \r
135         if (InterlockedDecrement(&pProvider->Ref) > 0) {\r
136                 KeWaitForSingleObject(&pProvider->Event, Executive, KernelMode, FALSE, NULL);\r
137         }\r
138 \r
139         IndexListDestroy(&pProvider->EpIndex);\r
140         IndexListDestroy(&pProvider->AhIndex);\r
141         IndexListDestroy(&pProvider->MwIndex);\r
142         IndexListDestroy(&pProvider->QpIndex);\r
143         IndexListDestroy(&pProvider->SrqIndex);\r
144         IndexListDestroy(&pProvider->PdIndex);\r
145         IndexListDestroy(&pProvider->CqIndex);\r
146         IndexListDestroy(&pProvider->DevIndex);\r
147         WorkQueueDestroy(&pProvider->WorkQueue);\r
148 }\r
149 \r
150 // See comment above WvProviderRemoveHandler.\r
151 static void WvProviderLockRemove(WV_PROVIDER *pProvider)\r
152 {\r
153         KeAcquireGuardedMutex(&pProvider->Lock);\r
154         pProvider->Exclusive++;\r
155         KeClearEvent(&pProvider->SharedEvent);\r
156         while (pProvider->Active > 0) {\r
157                 KeReleaseGuardedMutex(&pProvider->Lock);\r
158                 KeWaitForSingleObject(&pProvider->ExclusiveEvent, Executive, KernelMode,\r
159                                                           FALSE, NULL);\r
160                 KeAcquireGuardedMutex(&pProvider->Lock);\r
161         }\r
162         pProvider->Active++;\r
163         KeReleaseGuardedMutex(&pProvider->Lock);\r
164 }\r
165 \r
166 // See comment above WvProviderRemoveHandler.\r
167 static void WvProviderUnlockRemove(WV_PROVIDER *pProvider)\r
168 {\r
169         KeAcquireGuardedMutex(&pProvider->Lock);\r
170         pProvider->Exclusive--;\r
171         pProvider->Active--;\r
172         if (pProvider->Exclusive > 0) {\r
173                 KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);\r
174         } else if (pProvider->Pending > 0) {\r
175                 KeSetEvent(&pProvider->SharedEvent, 0, FALSE);\r
176         }\r
177         KeReleaseGuardedMutex(&pProvider->Lock);\r
178 }\r
179 \r
180 /*\r
181  * Must hold pProvider->Lock.  Function may release and re-acquire.\r
182  * See comment above WvProviderRemoveHandler.\r
183  */\r
184 void WvProviderDisableRemove(WV_PROVIDER *pProvider)\r
185 {\r
186         while (pProvider->Exclusive > 0) {\r
187                 pProvider->Pending++;\r
188                 KeReleaseGuardedMutex(&pProvider->Lock);\r
189                 KeWaitForSingleObject(&pProvider->SharedEvent, Executive, KernelMode,\r
190                                                           FALSE, NULL);\r
191                 KeAcquireGuardedMutex(&pProvider->Lock);\r
192                 pProvider->Pending--;\r
193         }\r
194         InterlockedIncrement(&pProvider->Active);\r
195 }\r
196 \r
197 /*\r
198  * No need to hold pProvider->Lock when releasing.\r
199  * See comment above WvProviderRemoveHandler.\r
200  */\r
201 void WvProviderEnableRemove(WV_PROVIDER *pProvider)\r
202 {\r
203         InterlockedDecrement(&pProvider->Active);\r
204         if (pProvider->Exclusive > 0) {\r
205                 KeSetEvent(&pProvider->ExclusiveEvent, 0, FALSE);\r
206         }\r
207 }\r
208 \r
209 /*\r
210  * The remove handler blocks all other threads executing through this\r
211  * provider until the remove has been processed.  Because device removal is\r
212  * rare, we want a simple, optimized code path for all calls that access\r
213  * the underlying hardware device, making use of any locks that we would\r
214  * have to acquire anyway.  The locking for exclusive access can be\r
215  * as ugly and slow as needed.\r
216  */\r
217 void WvProviderRemoveHandler(WV_PROVIDER *pProvider, WV_RDMA_DEVICE *pDevice)\r
218 {\r
219         WV_DEVICE *dev;\r
220         SIZE_T i;\r
221 \r
222         WvProviderLockRemove(pProvider);\r
223         IndexListForEach(&pProvider->DevIndex, i) {\r
224                 dev = IndexListAt(&pProvider->DevIndex, i);\r
225                 if (dev->pDevice == pDevice) {\r
226                         WvDeviceRemoveHandler(dev);\r
227                 }\r
228         }\r
229         WvProviderUnlockRemove(pProvider);\r
230 }\r