diff options
-rw-r--r-- | drivers/staging/hv/Channel.c | 1199 | ||||
-rw-r--r-- | drivers/staging/hv/Channel.h | 157 | ||||
-rw-r--r-- | drivers/staging/hv/ChannelInterface.c | 222 | ||||
-rw-r--r-- | drivers/staging/hv/ChannelInterface.h | 41 | ||||
-rw-r--r-- | drivers/staging/hv/ChannelMgmt.c | 826 | ||||
-rw-r--r-- | drivers/staging/hv/ChannelMgmt.h | 156 | ||||
-rw-r--r-- | drivers/staging/hv/Connection.c | 432 | ||||
-rw-r--r-- | drivers/staging/hv/Hv.c | 672 | ||||
-rw-r--r-- | drivers/staging/hv/Hv.h | 184 | ||||
-rw-r--r-- | drivers/staging/hv/RingBuffer.c | 630 | ||||
-rw-r--r-- | drivers/staging/hv/RingBuffer.h | 123 | ||||
-rw-r--r-- | drivers/staging/hv/Sources.c | 31 | ||||
-rw-r--r-- | drivers/staging/hv/VersionInfo.h | 29 | ||||
-rw-r--r-- | drivers/staging/hv/Vmbus.c | 508 | ||||
-rw-r--r-- | drivers/staging/hv/VmbusPrivate.h | 170 | ||||
-rw-r--r-- | drivers/staging/hv/osd.c | 500 | ||||
-rw-r--r-- | drivers/staging/hv/vmbus_drv.c | 1228 |
17 files changed, 7108 insertions, 0 deletions
diff --git a/drivers/staging/hv/Channel.c b/drivers/staging/hv/Channel.c new file mode 100644 index 00000000000..0b78604c40b --- /dev/null +++ b/drivers/staging/hv/Channel.c | |||
@@ -0,0 +1,1199 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include "osd.h" | ||
26 | #include "logging.h" | ||
27 | |||
28 | #include "VmbusPrivate.h" | ||
29 | |||
30 | // | ||
31 | // Internal routines | ||
32 | // | ||
33 | static int | ||
34 | VmbusChannelCreateGpadlHeader( | ||
35 | PVOID Kbuffer, // must be phys and virt contiguous | ||
36 | UINT32 Size, // page-size multiple | ||
37 | VMBUS_CHANNEL_MSGINFO **msgInfo, | ||
38 | UINT32 *MessageCount | ||
39 | ); | ||
40 | |||
41 | static void | ||
42 | DumpVmbusChannel( | ||
43 | VMBUS_CHANNEL *Channel | ||
44 | ); | ||
45 | |||
46 | |||
47 | static void | ||
48 | VmbusChannelSetEvent( | ||
49 | VMBUS_CHANNEL *Channel | ||
50 | ); | ||
51 | |||
52 | |||
53 | #if 0 | ||
54 | static void | ||
55 | DumpMonitorPage( | ||
56 | HV_MONITOR_PAGE *MonitorPage | ||
57 | ) | ||
58 | { | ||
59 | int i=0; | ||
60 | int j=0; | ||
61 | |||
62 | DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d", MonitorPage, MonitorPage->TriggerState); | ||
63 | |||
64 | for (i=0; i<4; i++) | ||
65 | { | ||
66 | DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i, MonitorPage->TriggerGroup[i].AsUINT64); | ||
67 | } | ||
68 | |||
69 | for (i=0; i<4; i++) | ||
70 | { | ||
71 | for (j=0; j<32; j++) | ||
72 | { | ||
73 | DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j, MonitorPage->Latency[i][j]); | ||
74 | } | ||
75 | } | ||
76 | for (i=0; i<4; i++) | ||
77 | { | ||
78 | for (j=0; j<32; j++) | ||
79 | { | ||
80 | DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].ConnectionId.AsUINT32); | ||
81 | DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].FlagNumber); | ||
82 | |||
83 | } | ||
84 | } | ||
85 | } | ||
86 | #endif | ||
87 | |||
88 | /*++ | ||
89 | |||
90 | Name: | ||
91 | VmbusChannelSetEvent() | ||
92 | |||
93 | Description: | ||
94 | Trigger an event notification on the specified channel. | ||
95 | |||
96 | --*/ | ||
97 | static void | ||
98 | VmbusChannelSetEvent( | ||
99 | VMBUS_CHANNEL *Channel | ||
100 | ) | ||
101 | { | ||
102 | HV_MONITOR_PAGE *monitorPage; | ||
103 | |||
104 | DPRINT_ENTER(VMBUS); | ||
105 | |||
106 | if (Channel->OfferMsg.MonitorAllocated) | ||
107 | { | ||
108 | // Each UINT32 represents 32 channels | ||
109 | BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31); | ||
110 | |||
111 | monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; | ||
112 | monitorPage++; // Get the child to parent monitor page | ||
113 | |||
114 | BitSet((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | VmbusSetEvent(Channel->OfferMsg.ChildRelId); | ||
119 | } | ||
120 | |||
121 | DPRINT_EXIT(VMBUS); | ||
122 | } | ||
123 | |||
124 | #if 0 | ||
125 | static void | ||
126 | VmbusChannelClearEvent( | ||
127 | VMBUS_CHANNEL *Channel | ||
128 | ) | ||
129 | { | ||
130 | HV_MONITOR_PAGE *monitorPage; | ||
131 | |||
132 | DPRINT_ENTER(VMBUS); | ||
133 | |||
134 | if (Channel->OfferMsg.MonitorAllocated) | ||
135 | { | ||
136 | // Each UINT32 represents 32 channels | ||
137 | BitClear((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31); | ||
138 | |||
139 | monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; | ||
140 | monitorPage++; // Get the child to parent monitor page | ||
141 | |||
142 | BitClear((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit); | ||
143 | } | ||
144 | |||
145 | DPRINT_EXIT(VMBUS); | ||
146 | } | ||
147 | |||
148 | #endif | ||
149 | /*++; | ||
150 | |||
151 | Name: | ||
152 | VmbusChannelGetDebugInfo() | ||
153 | |||
154 | Description: | ||
155 | Retrieve various channel debug info | ||
156 | |||
157 | --*/ | ||
158 | void | ||
159 | VmbusChannelGetDebugInfo( | ||
160 | VMBUS_CHANNEL *Channel, | ||
161 | VMBUS_CHANNEL_DEBUG_INFO *DebugInfo | ||
162 | ) | ||
163 | { | ||
164 | HV_MONITOR_PAGE *monitorPage; | ||
165 | UINT8 monitorGroup = (UINT8)Channel->OfferMsg.MonitorId / 32; | ||
166 | UINT8 monitorOffset = (UINT8)Channel->OfferMsg.MonitorId % 32; | ||
167 | //UINT32 monitorBit = 1 << monitorOffset; | ||
168 | |||
169 | DebugInfo->RelId = Channel->OfferMsg.ChildRelId; | ||
170 | DebugInfo->State = Channel->State; | ||
171 | memcpy(&DebugInfo->InterfaceType, &Channel->OfferMsg.Offer.InterfaceType, sizeof(GUID)); | ||
172 | memcpy(&DebugInfo->InterfaceInstance, &Channel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID)); | ||
173 | |||
174 | monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; | ||
175 | |||
176 | DebugInfo->MonitorId = Channel->OfferMsg.MonitorId; | ||
177 | |||
178 | DebugInfo->ServerMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending; | ||
179 | DebugInfo->ServerMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset]; | ||
180 | DebugInfo->ServerMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id; | ||
181 | |||
182 | monitorPage++; | ||
183 | |||
184 | DebugInfo->ClientMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending; | ||
185 | DebugInfo->ClientMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset]; | ||
186 | DebugInfo->ClientMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id; | ||
187 | |||
188 | RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound); | ||
189 | RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound); | ||
190 | } | ||
191 | |||
192 | |||
193 | /*++; | ||
194 | |||
195 | Name: | ||
196 | VmbusChannelOpen() | ||
197 | |||
198 | Description: | ||
199 | Open the specified channel. | ||
200 | |||
201 | --*/ | ||
202 | int | ||
203 | VmbusChannelOpen( | ||
204 | VMBUS_CHANNEL *NewChannel, | ||
205 | UINT32 SendRingBufferSize, | ||
206 | UINT32 RecvRingBufferSize, | ||
207 | PVOID UserData, | ||
208 | UINT32 UserDataLen, | ||
209 | PFN_CHANNEL_CALLBACK pfnOnChannelCallback, | ||
210 | PVOID Context | ||
211 | ) | ||
212 | { | ||
213 | int ret=0; | ||
214 | VMBUS_CHANNEL_OPEN_CHANNEL* openMsg; | ||
215 | VMBUS_CHANNEL_MSGINFO* openInfo; | ||
216 | void *in, *out; | ||
217 | |||
218 | DPRINT_ENTER(VMBUS); | ||
219 | |||
220 | // Aligned to page size | ||
221 | ASSERT(!(SendRingBufferSize & (PAGE_SIZE -1))); | ||
222 | ASSERT(!(RecvRingBufferSize & (PAGE_SIZE -1))); | ||
223 | |||
224 | NewChannel->OnChannelCallback = pfnOnChannelCallback; | ||
225 | NewChannel->ChannelCallbackContext = Context; | ||
226 | |||
227 | // Allocate the ring buffer | ||
228 | out = PageAlloc((SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT); | ||
229 | //out = MemAllocZeroed(sendRingBufferSize + recvRingBufferSize); | ||
230 | ASSERT(out); | ||
231 | ASSERT(((ULONG_PTR)out & (PAGE_SIZE-1)) == 0); | ||
232 | |||
233 | in = (void*)((ULONG_PTR)out + SendRingBufferSize); | ||
234 | |||
235 | NewChannel->RingBufferPages = out; | ||
236 | NewChannel->RingBufferPageCount = (SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT; | ||
237 | |||
238 | RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize); | ||
239 | |||
240 | RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize); | ||
241 | |||
242 | // Establish the gpadl for the ring buffer | ||
243 | DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...", NewChannel); | ||
244 | |||
245 | NewChannel->RingBufferGpadlHandle = 0; | ||
246 | |||
247 | ret = VmbusChannelEstablishGpadl(NewChannel, | ||
248 | NewChannel->Outbound.RingBuffer, | ||
249 | SendRingBufferSize + RecvRingBufferSize, | ||
250 | &NewChannel->RingBufferGpadlHandle); | ||
251 | |||
252 | DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p size %d recv ring %p size %d, downstreamoffset %d>", | ||
253 | NewChannel, | ||
254 | NewChannel->OfferMsg.ChildRelId, | ||
255 | NewChannel->RingBufferGpadlHandle, | ||
256 | NewChannel->Outbound.RingBuffer, | ||
257 | NewChannel->Outbound.RingSize, | ||
258 | NewChannel->Inbound.RingBuffer, | ||
259 | NewChannel->Inbound.RingSize, | ||
260 | SendRingBufferSize); | ||
261 | |||
262 | // Create and init the channel open message | ||
263 | openInfo = | ||
264 | (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL)); | ||
265 | ASSERT(openInfo != NULL); | ||
266 | |||
267 | openInfo->WaitEvent = WaitEventCreate(); | ||
268 | |||
269 | openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)openInfo->Msg; | ||
270 | openMsg->Header.MessageType = ChannelMessageOpenChannel; | ||
271 | openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; // FIXME | ||
272 | openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId; | ||
273 | openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle; | ||
274 | ASSERT(openMsg->RingBufferGpadlHandle); | ||
275 | openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >> PAGE_SHIFT; | ||
276 | openMsg->ServerContextAreaGpadlHandle = 0; // TODO | ||
277 | |||
278 | ASSERT(UserDataLen <= MAX_USER_DEFINED_BYTES); | ||
279 | if (UserDataLen) | ||
280 | { | ||
281 | memcpy(openMsg->UserData, UserData, UserDataLen); | ||
282 | } | ||
283 | |||
284 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
285 | INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &openInfo->MsgListEntry); | ||
286 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
287 | |||
288 | DPRINT_DBG(VMBUS, "Sending channel open msg..."); | ||
289 | |||
290 | ret = VmbusPostMessage(openMsg, sizeof(VMBUS_CHANNEL_OPEN_CHANNEL)); | ||
291 | if (ret != 0) | ||
292 | { | ||
293 | DPRINT_ERR(VMBUS, "unable to open channel - %d", ret); | ||
294 | goto Cleanup; | ||
295 | } | ||
296 | |||
297 | // FIXME: Need to time-out here | ||
298 | WaitEventWait(openInfo->WaitEvent); | ||
299 | |||
300 | if (openInfo->Response.OpenResult.Status == 0) | ||
301 | { | ||
302 | DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel); | ||
303 | } | ||
304 | else | ||
305 | { | ||
306 | DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!", NewChannel, openInfo->Response.OpenResult.Status); | ||
307 | } | ||
308 | |||
309 | Cleanup: | ||
310 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
311 | REMOVE_ENTRY_LIST(&openInfo->MsgListEntry); | ||
312 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
313 | |||
314 | WaitEventClose(openInfo->WaitEvent); | ||
315 | MemFree(openInfo); | ||
316 | |||
317 | DPRINT_EXIT(VMBUS); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /*++; | ||
323 | |||
324 | Name: | ||
325 | DumpGpadlBody() | ||
326 | |||
327 | Description: | ||
328 | Dump the gpadl body message to the console for debugging purposes. | ||
329 | |||
330 | --*/ | ||
331 | static void DumpGpadlBody( | ||
332 | VMBUS_CHANNEL_GPADL_BODY *Gpadl, | ||
333 | UINT32 Len) | ||
334 | { | ||
335 | int i=0; | ||
336 | int pfnCount=0; | ||
337 | |||
338 | pfnCount = (Len - sizeof(VMBUS_CHANNEL_GPADL_BODY))/ sizeof(UINT64); | ||
339 | DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount); | ||
340 | |||
341 | for (i=0; i< pfnCount; i++) | ||
342 | { | ||
343 | DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", i, Gpadl->Pfn[i]); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | |||
348 | /*++; | ||
349 | |||
350 | Name: | ||
351 | DumpGpadlHeader() | ||
352 | |||
353 | Description: | ||
354 | Dump the gpadl header message to the console for debugging purposes. | ||
355 | |||
356 | --*/ | ||
357 | static void DumpGpadlHeader( | ||
358 | VMBUS_CHANNEL_GPADL_HEADER *Gpadl | ||
359 | ) | ||
360 | { | ||
361 | int i=0,j=0; | ||
362 | int pageCount=0; | ||
363 | |||
364 | |||
365 | DPRINT_DBG(VMBUS, "gpadl header - relid %d, range count %d, range buflen %d", | ||
366 | Gpadl->ChildRelId, | ||
367 | Gpadl->RangeCount, | ||
368 | Gpadl->RangeBufLen); | ||
369 | for (i=0; i< Gpadl->RangeCount; i++) | ||
370 | { | ||
371 | pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT; | ||
372 | pageCount = (pageCount > 26)? 26 : pageCount; | ||
373 | |||
374 | DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d page count %d", | ||
375 | i, Gpadl->Range[i].ByteCount, Gpadl->Range[i].ByteOffset, pageCount); | ||
376 | |||
377 | for (j=0; j< pageCount; j++) | ||
378 | { | ||
379 | DPRINT_DBG(VMBUS, "%d) pfn %llu", j, Gpadl->Range[i].PfnArray[j]); | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | |||
384 | /*++; | ||
385 | |||
386 | Name: | ||
387 | VmbusChannelCreateGpadlHeader() | ||
388 | |||
389 | Description: | ||
390 | Creates a gpadl for the specified buffer | ||
391 | |||
392 | --*/ | ||
393 | static int | ||
394 | VmbusChannelCreateGpadlHeader( | ||
395 | PVOID Kbuffer, // from kmalloc() | ||
396 | UINT32 Size, // page-size multiple | ||
397 | VMBUS_CHANNEL_MSGINFO **MsgInfo, | ||
398 | UINT32 *MessageCount) | ||
399 | { | ||
400 | int i; | ||
401 | int pageCount; | ||
402 | unsigned long long pfn; | ||
403 | VMBUS_CHANNEL_GPADL_HEADER* gpaHeader; | ||
404 | VMBUS_CHANNEL_GPADL_BODY* gpadlBody; | ||
405 | VMBUS_CHANNEL_MSGINFO* msgHeader; | ||
406 | VMBUS_CHANNEL_MSGINFO* msgBody; | ||
407 | UINT32 msgSize; | ||
408 | |||
409 | int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize; | ||
410 | |||
411 | //ASSERT( (kbuffer & (PAGE_SIZE-1)) == 0); | ||
412 | ASSERT( (Size & (PAGE_SIZE-1)) == 0); | ||
413 | |||
414 | pageCount = Size >> PAGE_SHIFT; | ||
415 | pfn = GetPhysicalAddress(Kbuffer) >> PAGE_SHIFT; | ||
416 | |||
417 | // do we need a gpadl body msg | ||
418 | pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_HEADER) - sizeof(GPA_RANGE); | ||
419 | pfnCount = pfnSize / sizeof(UINT64); | ||
420 | |||
421 | if (pageCount > pfnCount) // we need a gpadl body | ||
422 | { | ||
423 | // fill in the header | ||
424 | msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pfnCount*sizeof(UINT64); | ||
425 | msgHeader = MemAllocZeroed(msgSize); | ||
426 | |||
427 | INITIALIZE_LIST_HEAD(&msgHeader->SubMsgList); | ||
428 | msgHeader->MessageSize=msgSize; | ||
429 | |||
430 | gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg; | ||
431 | gpaHeader->RangeCount = 1; | ||
432 | gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); | ||
433 | gpaHeader->Range[0].ByteOffset = 0; | ||
434 | gpaHeader->Range[0].ByteCount = Size; | ||
435 | for (i=0; i<pfnCount; i++) | ||
436 | { | ||
437 | gpaHeader->Range[0].PfnArray[i] = pfn+i; | ||
438 | } | ||
439 | *MsgInfo = msgHeader; | ||
440 | *MessageCount = 1; | ||
441 | |||
442 | pfnSum = pfnCount; | ||
443 | pfnLeft = pageCount - pfnCount; | ||
444 | |||
445 | // how many pfns can we fit | ||
446 | pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_BODY); | ||
447 | pfnCount = pfnSize / sizeof(UINT64); | ||
448 | |||
449 | // fill in the body | ||
450 | while (pfnLeft) | ||
451 | { | ||
452 | if (pfnLeft > pfnCount) | ||
453 | { | ||
454 | pfnCurr = pfnCount; | ||
455 | } | ||
456 | else | ||
457 | { | ||
458 | pfnCurr = pfnLeft; | ||
459 | } | ||
460 | |||
461 | msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_BODY) + pfnCurr*sizeof(UINT64); | ||
462 | msgBody = MemAllocZeroed(msgSize); | ||
463 | ASSERT(msgBody); | ||
464 | msgBody->MessageSize = msgSize; | ||
465 | (*MessageCount)++; | ||
466 | gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)msgBody->Msg; | ||
467 | |||
468 | // FIXME: Gpadl is UINT32 and we are using a pointer which could be 64-bit | ||
469 | //gpadlBody->Gpadl = kbuffer; | ||
470 | for (i=0; i<pfnCurr; i++) | ||
471 | { | ||
472 | gpadlBody->Pfn[i] = pfn + pfnSum + i; | ||
473 | } | ||
474 | |||
475 | // add to msg header | ||
476 | INSERT_TAIL_LIST(&msgHeader->SubMsgList, &msgBody->MsgListEntry); | ||
477 | pfnSum += pfnCurr; | ||
478 | pfnLeft -= pfnCurr; | ||
479 | } | ||
480 | } | ||
481 | else | ||
482 | { | ||
483 | // everything fits in a header | ||
484 | msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); | ||
485 | msgHeader = MemAllocZeroed(msgSize); | ||
486 | msgHeader->MessageSize=msgSize; | ||
487 | |||
488 | gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg; | ||
489 | gpaHeader->RangeCount = 1; | ||
490 | gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); | ||
491 | gpaHeader->Range[0].ByteOffset = 0; | ||
492 | gpaHeader->Range[0].ByteCount = Size; | ||
493 | for (i=0; i<pageCount; i++) | ||
494 | { | ||
495 | gpaHeader->Range[0].PfnArray[i] = pfn+i; | ||
496 | } | ||
497 | |||
498 | *MsgInfo = msgHeader; | ||
499 | *MessageCount = 1; | ||
500 | } | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | |||
506 | /*++; | ||
507 | |||
508 | Name: | ||
509 | VmbusChannelEstablishGpadl() | ||
510 | |||
511 | Description: | ||
512 | Estabish a GPADL for the specified buffer | ||
513 | |||
514 | --*/ | ||
515 | int | ||
516 | VmbusChannelEstablishGpadl( | ||
517 | VMBUS_CHANNEL *Channel, | ||
518 | PVOID Kbuffer, // from kmalloc() | ||
519 | UINT32 Size, // page-size multiple | ||
520 | UINT32 *GpadlHandle | ||
521 | ) | ||
522 | { | ||
523 | int ret=0; | ||
524 | VMBUS_CHANNEL_GPADL_HEADER* gpadlMsg; | ||
525 | VMBUS_CHANNEL_GPADL_BODY* gpadlBody; | ||
526 | //VMBUS_CHANNEL_GPADL_CREATED* gpadlCreated; | ||
527 | |||
528 | VMBUS_CHANNEL_MSGINFO *msgInfo; | ||
529 | VMBUS_CHANNEL_MSGINFO *subMsgInfo; | ||
530 | |||
531 | UINT32 msgCount; | ||
532 | LIST_ENTRY* anchor; | ||
533 | LIST_ENTRY* curr; | ||
534 | UINT32 nextGpadlHandle; | ||
535 | |||
536 | DPRINT_ENTER(VMBUS); | ||
537 | |||
538 | nextGpadlHandle = gVmbusConnection.NextGpadlHandle; | ||
539 | InterlockedIncrement((int*)&gVmbusConnection.NextGpadlHandle); | ||
540 | |||
541 | VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount); | ||
542 | ASSERT(msgInfo != NULL); | ||
543 | ASSERT(msgCount >0); | ||
544 | |||
545 | msgInfo->WaitEvent = WaitEventCreate(); | ||
546 | gpadlMsg = (VMBUS_CHANNEL_GPADL_HEADER*)msgInfo->Msg; | ||
547 | gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader; | ||
548 | gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId; | ||
549 | gpadlMsg->Gpadl = nextGpadlHandle; | ||
550 | |||
551 | DumpGpadlHeader(gpadlMsg); | ||
552 | |||
553 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
554 | INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry); | ||
555 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
556 | |||
557 | DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d", Kbuffer, Size, msgCount); | ||
558 | |||
559 | DPRINT_DBG(VMBUS, "Sending GPADL Header - len %d", msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | ||
560 | |||
561 | ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | ||
562 | if (ret != 0) | ||
563 | { | ||
564 | DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret); | ||
565 | goto Cleanup; | ||
566 | } | ||
567 | |||
568 | if (msgCount>1) | ||
569 | { | ||
570 | ITERATE_LIST_ENTRIES(anchor, curr, &msgInfo->SubMsgList) | ||
571 | { | ||
572 | subMsgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | ||
573 | gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)subMsgInfo->Msg; | ||
574 | |||
575 | gpadlBody->Header.MessageType = ChannelMessageGpadlBody; | ||
576 | gpadlBody->Gpadl = nextGpadlHandle; | ||
577 | |||
578 | DPRINT_DBG(VMBUS, "Sending GPADL Body - len %d", subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | ||
579 | |||
580 | DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | ||
581 | ret = VmbusPostMessage(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | ||
582 | ASSERT(ret == 0); | ||
583 | } | ||
584 | } | ||
585 | WaitEventWait(msgInfo->WaitEvent); | ||
586 | |||
587 | // At this point, we received the gpadl created msg | ||
588 | DPRINT_DBG(VMBUS, "Received GPADL created (relid %d, status %d handle %x)", | ||
589 | Channel->OfferMsg.ChildRelId, | ||
590 | msgInfo->Response.GpadlCreated.CreationStatus, | ||
591 | gpadlMsg->Gpadl); | ||
592 | |||
593 | *GpadlHandle = gpadlMsg->Gpadl; | ||
594 | |||
595 | Cleanup: | ||
596 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
597 | REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); | ||
598 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
599 | |||
600 | WaitEventClose(msgInfo->WaitEvent); | ||
601 | MemFree(msgInfo); | ||
602 | |||
603 | DPRINT_EXIT(VMBUS); | ||
604 | |||
605 | return ret; | ||
606 | } | ||
607 | |||
608 | |||
609 | |||
610 | /*++; | ||
611 | |||
612 | Name: | ||
613 | VmbusChannelTeardownGpadl() | ||
614 | |||
615 | Description: | ||
616 | Teardown the specified GPADL handle | ||
617 | |||
618 | --*/ | ||
619 | int | ||
620 | VmbusChannelTeardownGpadl( | ||
621 | VMBUS_CHANNEL *Channel, | ||
622 | UINT32 GpadlHandle | ||
623 | ) | ||
624 | { | ||
625 | int ret=0; | ||
626 | VMBUS_CHANNEL_GPADL_TEARDOWN *msg; | ||
627 | VMBUS_CHANNEL_MSGINFO* info; | ||
628 | |||
629 | DPRINT_ENTER(VMBUS); | ||
630 | |||
631 | ASSERT(GpadlHandle != 0); | ||
632 | |||
633 | info = | ||
634 | (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN)); | ||
635 | ASSERT(info != NULL); | ||
636 | |||
637 | info->WaitEvent = WaitEventCreate(); | ||
638 | |||
639 | msg = (VMBUS_CHANNEL_GPADL_TEARDOWN*)info->Msg; | ||
640 | |||
641 | msg->Header.MessageType = ChannelMessageGpadlTeardown; | ||
642 | msg->ChildRelId = Channel->OfferMsg.ChildRelId; | ||
643 | msg->Gpadl = GpadlHandle; | ||
644 | |||
645 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
646 | INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &info->MsgListEntry); | ||
647 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
648 | |||
649 | ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN)); | ||
650 | if (ret != 0) | ||
651 | { | ||
652 | // TODO: | ||
653 | } | ||
654 | |||
655 | WaitEventWait(info->WaitEvent); | ||
656 | |||
657 | // Received a torndown response | ||
658 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
659 | REMOVE_ENTRY_LIST(&info->MsgListEntry); | ||
660 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
661 | |||
662 | WaitEventClose(info->WaitEvent); | ||
663 | MemFree(info); | ||
664 | |||
665 | DPRINT_EXIT(VMBUS); | ||
666 | |||
667 | return ret; | ||
668 | } | ||
669 | |||
670 | |||
671 | /*++ | ||
672 | |||
673 | Name: | ||
674 | VmbusChannelClose() | ||
675 | |||
676 | Description: | ||
677 | Close the specified channel | ||
678 | |||
679 | --*/ | ||
680 | VOID | ||
681 | VmbusChannelClose( | ||
682 | VMBUS_CHANNEL *Channel | ||
683 | ) | ||
684 | { | ||
685 | int ret=0; | ||
686 | VMBUS_CHANNEL_CLOSE_CHANNEL* msg; | ||
687 | VMBUS_CHANNEL_MSGINFO* info; | ||
688 | |||
689 | DPRINT_ENTER(VMBUS); | ||
690 | |||
691 | // Stop callback and cancel the timer asap | ||
692 | Channel->OnChannelCallback = NULL; | ||
693 | TimerStop(Channel->PollTimer); | ||
694 | |||
695 | // Send a closing message | ||
696 | info = | ||
697 | (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL)); | ||
698 | ASSERT(info != NULL); | ||
699 | |||
700 | //info->waitEvent = WaitEventCreate(); | ||
701 | |||
702 | msg = (VMBUS_CHANNEL_CLOSE_CHANNEL*)info->Msg; | ||
703 | msg->Header.MessageType = ChannelMessageCloseChannel; | ||
704 | msg->ChildRelId = Channel->OfferMsg.ChildRelId; | ||
705 | |||
706 | ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL)); | ||
707 | if (ret != 0) | ||
708 | { | ||
709 | // TODO: | ||
710 | } | ||
711 | |||
712 | // Tear down the gpadl for the channel's ring buffer | ||
713 | if (Channel->RingBufferGpadlHandle) | ||
714 | { | ||
715 | VmbusChannelTeardownGpadl(Channel, Channel->RingBufferGpadlHandle); | ||
716 | } | ||
717 | |||
718 | // TODO: Send a msg to release the childRelId | ||
719 | |||
720 | // Cleanup the ring buffers for this channel | ||
721 | RingBufferCleanup(&Channel->Outbound); | ||
722 | RingBufferCleanup(&Channel->Inbound); | ||
723 | |||
724 | PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount); | ||
725 | |||
726 | MemFree(info); | ||
727 | |||
728 | // If we are closing the channel during an error path in opening the channel, don't free the channel | ||
729 | // since the caller will free the channel | ||
730 | if (Channel->State == CHANNEL_OPEN_STATE) | ||
731 | { | ||
732 | SpinlockAcquire(gVmbusConnection.ChannelLock); | ||
733 | REMOVE_ENTRY_LIST(&Channel->ListEntry); | ||
734 | SpinlockRelease(gVmbusConnection.ChannelLock); | ||
735 | |||
736 | FreeVmbusChannel(Channel); | ||
737 | } | ||
738 | |||
739 | DPRINT_EXIT(VMBUS); | ||
740 | } | ||
741 | |||
742 | |||
743 | /*++ | ||
744 | |||
745 | Name: | ||
746 | VmbusChannelSendPacket() | ||
747 | |||
748 | Description: | ||
749 | Send the specified buffer on the given channel | ||
750 | |||
751 | --*/ | ||
752 | int | ||
753 | VmbusChannelSendPacket( | ||
754 | VMBUS_CHANNEL *Channel, | ||
755 | const PVOID Buffer, | ||
756 | UINT32 BufferLen, | ||
757 | UINT64 RequestId, | ||
758 | VMBUS_PACKET_TYPE Type, | ||
759 | UINT32 Flags | ||
760 | ) | ||
761 | { | ||
762 | int ret=0; | ||
763 | VMPACKET_DESCRIPTOR desc; | ||
764 | UINT32 packetLen = sizeof(VMPACKET_DESCRIPTOR) + BufferLen; | ||
765 | UINT32 packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); | ||
766 | SG_BUFFER_LIST bufferList[3]; | ||
767 | UINT64 alignedData=0; | ||
768 | |||
769 | DPRINT_ENTER(VMBUS); | ||
770 | DPRINT_DBG(VMBUS, "channel %p buffer %p len %d", Channel, Buffer, BufferLen); | ||
771 | |||
772 | DumpVmbusChannel(Channel); | ||
773 | |||
774 | ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); | ||
775 | |||
776 | // Setup the descriptor | ||
777 | desc.Type = Type;//VmbusPacketTypeDataInBand; | ||
778 | desc.Flags = Flags;//VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | ||
779 | desc.DataOffset8 = sizeof(VMPACKET_DESCRIPTOR) >> 3; // in 8-bytes granularity | ||
780 | desc.Length8 = (UINT16)(packetLenAligned >> 3); | ||
781 | desc.TransactionId = RequestId; | ||
782 | |||
783 | bufferList[0].Data = &desc; | ||
784 | bufferList[0].Length = sizeof(VMPACKET_DESCRIPTOR); | ||
785 | |||
786 | bufferList[1].Data = Buffer; | ||
787 | bufferList[1].Length = BufferLen; | ||
788 | |||
789 | bufferList[2].Data = &alignedData; | ||
790 | bufferList[2].Length = packetLenAligned - packetLen; | ||
791 | |||
792 | ret = RingBufferWrite( | ||
793 | &Channel->Outbound, | ||
794 | bufferList, | ||
795 | 3); | ||
796 | |||
797 | // TODO: We should determine if this is optional | ||
798 | if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) | ||
799 | { | ||
800 | VmbusChannelSetEvent(Channel); | ||
801 | } | ||
802 | |||
803 | DPRINT_EXIT(VMBUS); | ||
804 | |||
805 | return ret; | ||
806 | } | ||
807 | |||
808 | |||
809 | /*++ | ||
810 | |||
811 | Name: | ||
812 | VmbusChannelSendPacketPageBuffer() | ||
813 | |||
814 | Description: | ||
815 | Send a range of single-page buffer packets using a GPADL Direct packet type. | ||
816 | |||
817 | --*/ | ||
818 | int | ||
819 | VmbusChannelSendPacketPageBuffer( | ||
820 | VMBUS_CHANNEL *Channel, | ||
821 | PAGE_BUFFER PageBuffers[], | ||
822 | UINT32 PageCount, | ||
823 | PVOID Buffer, | ||
824 | UINT32 BufferLen, | ||
825 | UINT64 RequestId | ||
826 | ) | ||
827 | { | ||
828 | int ret=0; | ||
829 | int i=0; | ||
830 | VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc; | ||
831 | UINT32 descSize; | ||
832 | UINT32 packetLen; | ||
833 | UINT32 packetLenAligned; | ||
834 | SG_BUFFER_LIST bufferList[3]; | ||
835 | UINT64 alignedData=0; | ||
836 | |||
837 | DPRINT_ENTER(VMBUS); | ||
838 | |||
839 | ASSERT(PageCount <= MAX_PAGE_BUFFER_COUNT); | ||
840 | |||
841 | DumpVmbusChannel(Channel); | ||
842 | |||
843 | // Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the largest size we support | ||
844 | descSize = sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER) - ((MAX_PAGE_BUFFER_COUNT - PageCount)*sizeof(PAGE_BUFFER)); | ||
845 | packetLen = descSize + BufferLen; | ||
846 | packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); | ||
847 | |||
848 | ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); | ||
849 | |||
850 | // Setup the descriptor | ||
851 | desc.Type = VmbusPacketTypeDataUsingGpaDirect; | ||
852 | desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | ||
853 | desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity | ||
854 | desc.Length8 = (UINT16)(packetLenAligned >> 3); | ||
855 | desc.TransactionId = RequestId; | ||
856 | desc.RangeCount = PageCount; | ||
857 | |||
858 | for (i=0; i<PageCount; i++) | ||
859 | { | ||
860 | desc.Range[i].Length = PageBuffers[i].Length; | ||
861 | desc.Range[i].Offset = PageBuffers[i].Offset; | ||
862 | desc.Range[i].Pfn = PageBuffers[i].Pfn; | ||
863 | } | ||
864 | |||
865 | bufferList[0].Data = &desc; | ||
866 | bufferList[0].Length = descSize; | ||
867 | |||
868 | bufferList[1].Data = Buffer; | ||
869 | bufferList[1].Length = BufferLen; | ||
870 | |||
871 | bufferList[2].Data = &alignedData; | ||
872 | bufferList[2].Length = packetLenAligned - packetLen; | ||
873 | |||
874 | ret = RingBufferWrite( | ||
875 | &Channel->Outbound, | ||
876 | bufferList, | ||
877 | 3); | ||
878 | |||
879 | // TODO: We should determine if this is optional | ||
880 | if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) | ||
881 | { | ||
882 | VmbusChannelSetEvent(Channel); | ||
883 | } | ||
884 | |||
885 | DPRINT_EXIT(VMBUS); | ||
886 | |||
887 | return ret; | ||
888 | } | ||
889 | |||
890 | |||
891 | |||
892 | /*++ | ||
893 | |||
894 | Name: | ||
895 | VmbusChannelSendPacketMultiPageBuffer() | ||
896 | |||
897 | Description: | ||
898 | Send a multi-page buffer packet using a GPADL Direct packet type. | ||
899 | |||
900 | --*/ | ||
901 | int | ||
902 | VmbusChannelSendPacketMultiPageBuffer( | ||
903 | VMBUS_CHANNEL *Channel, | ||
904 | MULTIPAGE_BUFFER *MultiPageBuffer, | ||
905 | PVOID Buffer, | ||
906 | UINT32 BufferLen, | ||
907 | UINT64 RequestId | ||
908 | ) | ||
909 | { | ||
910 | int ret=0; | ||
911 | VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc; | ||
912 | UINT32 descSize; | ||
913 | UINT32 packetLen; | ||
914 | UINT32 packetLenAligned; | ||
915 | SG_BUFFER_LIST bufferList[3]; | ||
916 | UINT64 alignedData=0; | ||
917 | UINT32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset, MultiPageBuffer->Length); | ||
918 | |||
919 | DPRINT_ENTER(VMBUS); | ||
920 | |||
921 | DumpVmbusChannel(Channel); | ||
922 | |||
923 | DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount); | ||
924 | |||
925 | ASSERT(PfnCount > 0); | ||
926 | ASSERT(PfnCount <= MAX_MULTIPAGE_BUFFER_COUNT); | ||
927 | |||
928 | // Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is the largest size we support | ||
929 | descSize = sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) - ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount)*sizeof(UINT64)); | ||
930 | packetLen = descSize + BufferLen; | ||
931 | packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); | ||
932 | |||
933 | ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); | ||
934 | |||
935 | // Setup the descriptor | ||
936 | desc.Type = VmbusPacketTypeDataUsingGpaDirect; | ||
937 | desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | ||
938 | desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity | ||
939 | desc.Length8 = (UINT16)(packetLenAligned >> 3); | ||
940 | desc.TransactionId = RequestId; | ||
941 | desc.RangeCount = 1; | ||
942 | |||
943 | desc.Range.Length = MultiPageBuffer->Length; | ||
944 | desc.Range.Offset = MultiPageBuffer->Offset; | ||
945 | |||
946 | memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray, PfnCount*sizeof(UINT64)); | ||
947 | |||
948 | bufferList[0].Data = &desc; | ||
949 | bufferList[0].Length = descSize; | ||
950 | |||
951 | bufferList[1].Data = Buffer; | ||
952 | bufferList[1].Length = BufferLen; | ||
953 | |||
954 | bufferList[2].Data = &alignedData; | ||
955 | bufferList[2].Length = packetLenAligned - packetLen; | ||
956 | |||
957 | ret = RingBufferWrite( | ||
958 | &Channel->Outbound, | ||
959 | bufferList, | ||
960 | 3); | ||
961 | |||
962 | // TODO: We should determine if this is optional | ||
963 | if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) | ||
964 | { | ||
965 | VmbusChannelSetEvent(Channel); | ||
966 | } | ||
967 | |||
968 | DPRINT_EXIT(VMBUS); | ||
969 | |||
970 | return ret; | ||
971 | } | ||
972 | |||
973 | |||
974 | /*++ | ||
975 | |||
976 | Name: | ||
977 | VmbusChannelRecvPacket() | ||
978 | |||
979 | Description: | ||
980 | Retrieve the user packet on the specified channel | ||
981 | |||
982 | --*/ | ||
983 | // TODO: Do we ever receive a gpa direct packet other than the ones we send ? | ||
984 | int | ||
985 | VmbusChannelRecvPacket( | ||
986 | VMBUS_CHANNEL *Channel, | ||
987 | PVOID Buffer, | ||
988 | UINT32 BufferLen, | ||
989 | UINT32* BufferActualLen, | ||
990 | UINT64* RequestId | ||
991 | ) | ||
992 | { | ||
993 | VMPACKET_DESCRIPTOR desc; | ||
994 | UINT32 packetLen; | ||
995 | UINT32 userLen; | ||
996 | int ret; | ||
997 | |||
998 | DPRINT_ENTER(VMBUS); | ||
999 | |||
1000 | *BufferActualLen = 0; | ||
1001 | *RequestId = 0; | ||
1002 | |||
1003 | SpinlockAcquire(Channel->InboundLock); | ||
1004 | |||
1005 | ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR)); | ||
1006 | if (ret != 0) | ||
1007 | { | ||
1008 | SpinlockRelease(Channel->InboundLock); | ||
1009 | |||
1010 | //DPRINT_DBG(VMBUS, "nothing to read!!"); | ||
1011 | DPRINT_EXIT(VMBUS); | ||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | //VmbusChannelClearEvent(Channel); | ||
1016 | |||
1017 | packetLen = desc.Length8 << 3; | ||
1018 | userLen = packetLen - (desc.DataOffset8 << 3); | ||
1019 | //ASSERT(userLen > 0); | ||
1020 | |||
1021 | DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ", | ||
1022 | Channel, | ||
1023 | Channel->OfferMsg.ChildRelId, | ||
1024 | desc.Type, | ||
1025 | desc.Flags, | ||
1026 | desc.TransactionId, packetLen, userLen); | ||
1027 | |||
1028 | *BufferActualLen = userLen; | ||
1029 | |||
1030 | if (userLen > BufferLen) | ||
1031 | { | ||
1032 | SpinlockRelease(Channel->InboundLock); | ||
1033 | |||
1034 | DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d", BufferLen, userLen); | ||
1035 | DPRINT_EXIT(VMBUS); | ||
1036 | |||
1037 | return -1; | ||
1038 | } | ||
1039 | |||
1040 | *RequestId = desc.TransactionId; | ||
1041 | |||
1042 | // Copy over the packet to the user buffer | ||
1043 | ret = RingBufferRead(&Channel->Inbound, Buffer, userLen, (desc.DataOffset8 << 3)); | ||
1044 | |||
1045 | SpinlockRelease(Channel->InboundLock); | ||
1046 | |||
1047 | DPRINT_EXIT(VMBUS); | ||
1048 | |||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1052 | /*++ | ||
1053 | |||
1054 | Name: | ||
1055 | VmbusChannelRecvPacketRaw() | ||
1056 | |||
1057 | Description: | ||
1058 | Retrieve the raw packet on the specified channel | ||
1059 | |||
1060 | --*/ | ||
1061 | int | ||
1062 | VmbusChannelRecvPacketRaw( | ||
1063 | VMBUS_CHANNEL *Channel, | ||
1064 | PVOID Buffer, | ||
1065 | UINT32 BufferLen, | ||
1066 | UINT32* BufferActualLen, | ||
1067 | UINT64* RequestId | ||
1068 | ) | ||
1069 | { | ||
1070 | VMPACKET_DESCRIPTOR desc; | ||
1071 | UINT32 packetLen; | ||
1072 | UINT32 userLen; | ||
1073 | int ret; | ||
1074 | |||
1075 | DPRINT_ENTER(VMBUS); | ||
1076 | |||
1077 | *BufferActualLen = 0; | ||
1078 | *RequestId = 0; | ||
1079 | |||
1080 | SpinlockAcquire(Channel->InboundLock); | ||
1081 | |||
1082 | ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR)); | ||
1083 | if (ret != 0) | ||
1084 | { | ||
1085 | SpinlockRelease(Channel->InboundLock); | ||
1086 | |||
1087 | //DPRINT_DBG(VMBUS, "nothing to read!!"); | ||
1088 | DPRINT_EXIT(VMBUS); | ||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | //VmbusChannelClearEvent(Channel); | ||
1093 | |||
1094 | packetLen = desc.Length8 << 3; | ||
1095 | userLen = packetLen - (desc.DataOffset8 << 3); | ||
1096 | |||
1097 | DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ", | ||
1098 | Channel, | ||
1099 | Channel->OfferMsg.ChildRelId, | ||
1100 | desc.Type, | ||
1101 | desc.Flags, | ||
1102 | desc.TransactionId, packetLen, userLen); | ||
1103 | |||
1104 | *BufferActualLen = packetLen; | ||
1105 | |||
1106 | if (packetLen > BufferLen) | ||
1107 | { | ||
1108 | SpinlockRelease(Channel->InboundLock); | ||
1109 | |||
1110 | DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen, BufferLen); | ||
1111 | DPRINT_EXIT(VMBUS); | ||
1112 | return -2; | ||
1113 | } | ||
1114 | |||
1115 | *RequestId = desc.TransactionId; | ||
1116 | |||
1117 | // Copy over the entire packet to the user buffer | ||
1118 | ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0); | ||
1119 | |||
1120 | SpinlockRelease(Channel->InboundLock); | ||
1121 | |||
1122 | DPRINT_EXIT(VMBUS); | ||
1123 | |||
1124 | return 0; | ||
1125 | } | ||
1126 | |||
1127 | |||
1128 | /*++ | ||
1129 | |||
1130 | Name: | ||
1131 | VmbusChannelOnChannelEvent() | ||
1132 | |||
1133 | Description: | ||
1134 | Channel event callback | ||
1135 | |||
1136 | --*/ | ||
1137 | void | ||
1138 | VmbusChannelOnChannelEvent( | ||
1139 | VMBUS_CHANNEL *Channel | ||
1140 | ) | ||
1141 | { | ||
1142 | DumpVmbusChannel(Channel); | ||
1143 | ASSERT(Channel->OnChannelCallback); | ||
1144 | #ifdef ENABLE_POLLING | ||
1145 | TimerStop(Channel->PollTimer); | ||
1146 | Channel->OnChannelCallback(Channel->ChannelCallbackContext); | ||
1147 | TimerStart(Channel->PollTimer, 100 /* 100us */); | ||
1148 | #else | ||
1149 | Channel->OnChannelCallback(Channel->ChannelCallbackContext); | ||
1150 | #endif | ||
1151 | } | ||
1152 | |||
1153 | /*++ | ||
1154 | |||
1155 | Name: | ||
1156 | VmbusChannelOnTimer() | ||
1157 | |||
1158 | Description: | ||
1159 | Timer event callback | ||
1160 | |||
1161 | --*/ | ||
1162 | void | ||
1163 | VmbusChannelOnTimer( | ||
1164 | void *Context | ||
1165 | ) | ||
1166 | { | ||
1167 | VMBUS_CHANNEL *channel = (VMBUS_CHANNEL*)Context; | ||
1168 | |||
1169 | if (channel->OnChannelCallback) | ||
1170 | { | ||
1171 | channel->OnChannelCallback(channel->ChannelCallbackContext); | ||
1172 | #ifdef ENABLE_POLLING | ||
1173 | TimerStart(channel->PollTimer, 100 /* 100us */); | ||
1174 | #endif | ||
1175 | } | ||
1176 | } | ||
1177 | |||
1178 | |||
1179 | /*++ | ||
1180 | |||
1181 | Name: | ||
1182 | DumpVmbusChannel() | ||
1183 | |||
1184 | Description: | ||
1185 | Dump vmbus channel info to the console | ||
1186 | |||
1187 | --*/ | ||
1188 | static void | ||
1189 | DumpVmbusChannel( | ||
1190 | VMBUS_CHANNEL *Channel | ||
1191 | ) | ||
1192 | { | ||
1193 | DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId); | ||
1194 | DumpRingInfo(&Channel->Outbound, "Outbound "); | ||
1195 | DumpRingInfo(&Channel->Inbound, "Inbound "); | ||
1196 | } | ||
1197 | |||
1198 | |||
1199 | // eof | ||
diff --git a/drivers/staging/hv/Channel.h b/drivers/staging/hv/Channel.h new file mode 100644 index 00000000000..117b2e1bb7c --- /dev/null +++ b/drivers/staging/hv/Channel.h | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #ifndef _CHANNEL_H_ | ||
26 | #define _CHANNEL_H_ | ||
27 | |||
28 | #include "osd.h" | ||
29 | #include "ChannelMgmt.h" | ||
30 | |||
31 | #pragma pack(push,1) | ||
32 | |||
33 | |||
34 | // The format must be the same as VMDATA_GPA_DIRECT | ||
35 | typedef struct _VMBUS_CHANNEL_PACKET_PAGE_BUFFER { | ||
36 | UINT16 Type; | ||
37 | UINT16 DataOffset8; | ||
38 | UINT16 Length8; | ||
39 | UINT16 Flags; | ||
40 | UINT64 TransactionId; | ||
41 | UINT32 Reserved; | ||
42 | UINT32 RangeCount; | ||
43 | PAGE_BUFFER Range[MAX_PAGE_BUFFER_COUNT]; | ||
44 | } VMBUS_CHANNEL_PACKET_PAGE_BUFFER; | ||
45 | |||
46 | |||
47 | // The format must be the same as VMDATA_GPA_DIRECT | ||
48 | typedef struct _VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER { | ||
49 | UINT16 Type; | ||
50 | UINT16 DataOffset8; | ||
51 | UINT16 Length8; | ||
52 | UINT16 Flags; | ||
53 | UINT64 TransactionId; | ||
54 | UINT32 Reserved; | ||
55 | UINT32 RangeCount; // Always 1 in this case | ||
56 | MULTIPAGE_BUFFER Range; | ||
57 | } VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER; | ||
58 | |||
59 | #pragma pack(pop) | ||
60 | |||
61 | // | ||
62 | // Routines | ||
63 | // | ||
64 | |||
65 | INTERNAL int | ||
66 | VmbusChannelOpen( | ||
67 | VMBUS_CHANNEL *Channel, | ||
68 | UINT32 SendRingBufferSize, | ||
69 | UINT32 RecvRingBufferSize, | ||
70 | PVOID UserData, | ||
71 | UINT32 UserDataLen, | ||
72 | PFN_CHANNEL_CALLBACK pfnOnChannelCallback, | ||
73 | PVOID Context | ||
74 | ); | ||
75 | |||
76 | INTERNAL void | ||
77 | VmbusChannelClose( | ||
78 | VMBUS_CHANNEL *Channel | ||
79 | ); | ||
80 | |||
81 | INTERNAL int | ||
82 | VmbusChannelSendPacket( | ||
83 | VMBUS_CHANNEL *Channel, | ||
84 | const PVOID Buffer, | ||
85 | UINT32 BufferLen, | ||
86 | UINT64 RequestId, | ||
87 | VMBUS_PACKET_TYPE Type, | ||
88 | UINT32 Flags | ||
89 | ); | ||
90 | |||
91 | INTERNAL int | ||
92 | VmbusChannelSendPacketPageBuffer( | ||
93 | VMBUS_CHANNEL *Channel, | ||
94 | PAGE_BUFFER PageBuffers[], | ||
95 | UINT32 PageCount, | ||
96 | PVOID Buffer, | ||
97 | UINT32 BufferLen, | ||
98 | UINT64 RequestId | ||
99 | ); | ||
100 | |||
101 | INTERNAL int | ||
102 | VmbusChannelSendPacketMultiPageBuffer( | ||
103 | VMBUS_CHANNEL *Channel, | ||
104 | MULTIPAGE_BUFFER *MultiPageBuffer, | ||
105 | PVOID Buffer, | ||
106 | UINT32 BufferLen, | ||
107 | UINT64 RequestId | ||
108 | ); | ||
109 | |||
110 | INTERNAL int | ||
111 | VmbusChannelEstablishGpadl( | ||
112 | VMBUS_CHANNEL *Channel, | ||
113 | PVOID Kbuffer, // from kmalloc() | ||
114 | UINT32 Size, // page-size multiple | ||
115 | UINT32 *GpadlHandle | ||
116 | ); | ||
117 | |||
118 | INTERNAL int | ||
119 | VmbusChannelTeardownGpadl( | ||
120 | VMBUS_CHANNEL *Channel, | ||
121 | UINT32 GpadlHandle | ||
122 | ); | ||
123 | |||
124 | INTERNAL int | ||
125 | VmbusChannelRecvPacket( | ||
126 | VMBUS_CHANNEL *Channel, | ||
127 | PVOID Buffer, | ||
128 | UINT32 BufferLen, | ||
129 | UINT32* BufferActualLen, | ||
130 | UINT64* RequestId | ||
131 | ); | ||
132 | |||
133 | INTERNAL int | ||
134 | VmbusChannelRecvPacketRaw( | ||
135 | VMBUS_CHANNEL *Channel, | ||
136 | PVOID Buffer, | ||
137 | UINT32 BufferLen, | ||
138 | UINT32* BufferActualLen, | ||
139 | UINT64* RequestId | ||
140 | ); | ||
141 | |||
142 | INTERNAL void | ||
143 | VmbusChannelOnChannelEvent( | ||
144 | VMBUS_CHANNEL *Channel | ||
145 | ); | ||
146 | |||
147 | INTERNAL void | ||
148 | VmbusChannelGetDebugInfo( | ||
149 | VMBUS_CHANNEL *Channel, | ||
150 | VMBUS_CHANNEL_DEBUG_INFO *DebugInfo | ||
151 | ); | ||
152 | |||
153 | INTERNAL void | ||
154 | VmbusChannelOnTimer( | ||
155 | void *Context | ||
156 | ); | ||
157 | #endif //_CHANNEL_H_ | ||
diff --git a/drivers/staging/hv/ChannelInterface.c b/drivers/staging/hv/ChannelInterface.c new file mode 100644 index 00000000000..1a7663e37e5 --- /dev/null +++ b/drivers/staging/hv/ChannelInterface.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "VmbusPrivate.h" | ||
25 | |||
26 | INTERNAL int | ||
27 | IVmbusChannelOpen( | ||
28 | PDEVICE_OBJECT Device, | ||
29 | UINT32 SendBufferSize, | ||
30 | UINT32 RecvRingBufferSize, | ||
31 | PVOID UserData, | ||
32 | UINT32 UserDataLen, | ||
33 | VMBUS_CHANNEL_CALLBACK ChannelCallback, | ||
34 | PVOID Context | ||
35 | ) | ||
36 | { | ||
37 | return VmbusChannelOpen( (VMBUS_CHANNEL*)Device->context, | ||
38 | SendBufferSize, | ||
39 | RecvRingBufferSize, | ||
40 | UserData, | ||
41 | UserDataLen, | ||
42 | ChannelCallback, | ||
43 | Context); | ||
44 | } | ||
45 | |||
46 | |||
47 | INTERNAL void | ||
48 | IVmbusChannelClose( | ||
49 | PDEVICE_OBJECT Device | ||
50 | ) | ||
51 | { | ||
52 | VmbusChannelClose((VMBUS_CHANNEL*)Device->context); | ||
53 | } | ||
54 | |||
55 | |||
56 | INTERNAL int | ||
57 | IVmbusChannelSendPacket( | ||
58 | PDEVICE_OBJECT Device, | ||
59 | const PVOID Buffer, | ||
60 | UINT32 BufferLen, | ||
61 | UINT64 RequestId, | ||
62 | UINT32 Type, | ||
63 | UINT32 Flags | ||
64 | ) | ||
65 | { | ||
66 | return VmbusChannelSendPacket((VMBUS_CHANNEL*)Device->context, | ||
67 | Buffer, | ||
68 | BufferLen, | ||
69 | RequestId, | ||
70 | Type, | ||
71 | Flags); | ||
72 | } | ||
73 | |||
74 | INTERNAL int | ||
75 | IVmbusChannelSendPacketPageBuffer( | ||
76 | PDEVICE_OBJECT Device, | ||
77 | PAGE_BUFFER PageBuffers[], | ||
78 | UINT32 PageCount, | ||
79 | PVOID Buffer, | ||
80 | UINT32 BufferLen, | ||
81 | UINT64 RequestId | ||
82 | ) | ||
83 | { | ||
84 | return VmbusChannelSendPacketPageBuffer((VMBUS_CHANNEL*)Device->context, | ||
85 | PageBuffers, | ||
86 | PageCount, | ||
87 | Buffer, | ||
88 | BufferLen, | ||
89 | RequestId); | ||
90 | } | ||
91 | |||
92 | INTERNAL int | ||
93 | IVmbusChannelSendPacketMultiPageBuffer( | ||
94 | PDEVICE_OBJECT Device, | ||
95 | MULTIPAGE_BUFFER *MultiPageBuffer, | ||
96 | PVOID Buffer, | ||
97 | UINT32 BufferLen, | ||
98 | UINT64 RequestId | ||
99 | ) | ||
100 | { | ||
101 | return VmbusChannelSendPacketMultiPageBuffer((VMBUS_CHANNEL*)Device->context, | ||
102 | MultiPageBuffer, | ||
103 | Buffer, | ||
104 | BufferLen, | ||
105 | RequestId); | ||
106 | } | ||
107 | |||
108 | INTERNAL int | ||
109 | IVmbusChannelRecvPacket ( | ||
110 | PDEVICE_OBJECT Device, | ||
111 | PVOID Buffer, | ||
112 | UINT32 BufferLen, | ||
113 | UINT32* BufferActualLen, | ||
114 | UINT64* RequestId | ||
115 | ) | ||
116 | { | ||
117 | return VmbusChannelRecvPacket((VMBUS_CHANNEL*)Device->context, | ||
118 | Buffer, | ||
119 | BufferLen, | ||
120 | BufferActualLen, | ||
121 | RequestId); | ||
122 | } | ||
123 | |||
124 | INTERNAL int | ||
125 | IVmbusChannelRecvPacketRaw( | ||
126 | PDEVICE_OBJECT Device, | ||
127 | PVOID Buffer, | ||
128 | UINT32 BufferLen, | ||
129 | UINT32* BufferActualLen, | ||
130 | UINT64* RequestId | ||
131 | ) | ||
132 | { | ||
133 | return VmbusChannelRecvPacketRaw((VMBUS_CHANNEL*)Device->context, | ||
134 | Buffer, | ||
135 | BufferLen, | ||
136 | BufferActualLen, | ||
137 | RequestId); | ||
138 | } | ||
139 | |||
140 | INTERNAL int | ||
141 | IVmbusChannelEstablishGpadl( | ||
142 | PDEVICE_OBJECT Device, | ||
143 | PVOID Buffer, | ||
144 | UINT32 BufferLen, | ||
145 | UINT32* GpadlHandle | ||
146 | ) | ||
147 | { | ||
148 | return VmbusChannelEstablishGpadl((VMBUS_CHANNEL*)Device->context, | ||
149 | Buffer, | ||
150 | BufferLen, | ||
151 | GpadlHandle); | ||
152 | } | ||
153 | |||
154 | INTERNAL int | ||
155 | IVmbusChannelTeardownGpadl( | ||
156 | PDEVICE_OBJECT Device, | ||
157 | UINT32 GpadlHandle | ||
158 | ) | ||
159 | { | ||
160 | return VmbusChannelTeardownGpadl((VMBUS_CHANNEL*)Device->context, | ||
161 | GpadlHandle); | ||
162 | |||
163 | } | ||
164 | |||
165 | INTERNAL void | ||
166 | GetChannelInterface( | ||
167 | VMBUS_CHANNEL_INTERFACE *ChannelInterface | ||
168 | ) | ||
169 | { | ||
170 | ChannelInterface->Open = IVmbusChannelOpen; | ||
171 | ChannelInterface->Close = IVmbusChannelClose; | ||
172 | ChannelInterface->SendPacket = IVmbusChannelSendPacket; | ||
173 | ChannelInterface->SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer; | ||
174 | ChannelInterface->SendPacketMultiPageBuffer = IVmbusChannelSendPacketMultiPageBuffer; | ||
175 | ChannelInterface->RecvPacket = IVmbusChannelRecvPacket; | ||
176 | ChannelInterface->RecvPacketRaw = IVmbusChannelRecvPacketRaw; | ||
177 | ChannelInterface->EstablishGpadl = IVmbusChannelEstablishGpadl; | ||
178 | ChannelInterface->TeardownGpadl = IVmbusChannelTeardownGpadl; | ||
179 | ChannelInterface->GetInfo = GetChannelInfo; | ||
180 | } | ||
181 | |||
182 | |||
183 | INTERNAL void | ||
184 | GetChannelInfo( | ||
185 | PDEVICE_OBJECT Device, | ||
186 | DEVICE_INFO *DeviceInfo | ||
187 | ) | ||
188 | { | ||
189 | VMBUS_CHANNEL_DEBUG_INFO debugInfo; | ||
190 | |||
191 | if (Device->context) | ||
192 | { | ||
193 | VmbusChannelGetDebugInfo((VMBUS_CHANNEL*)Device->context, &debugInfo); | ||
194 | |||
195 | DeviceInfo->ChannelId = debugInfo.RelId; | ||
196 | DeviceInfo->ChannelState = debugInfo.State; | ||
197 | memcpy(&DeviceInfo->ChannelType, &debugInfo.InterfaceType, sizeof(GUID)); | ||
198 | memcpy(&DeviceInfo->ChannelInstance, &debugInfo.InterfaceInstance, sizeof(GUID)); | ||
199 | |||
200 | DeviceInfo->MonitorId = debugInfo.MonitorId; | ||
201 | |||
202 | DeviceInfo->ServerMonitorPending = debugInfo.ServerMonitorPending; | ||
203 | DeviceInfo->ServerMonitorLatency = debugInfo.ServerMonitorLatency; | ||
204 | DeviceInfo->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId; | ||
205 | |||
206 | DeviceInfo->ClientMonitorPending = debugInfo.ClientMonitorPending; | ||
207 | DeviceInfo->ClientMonitorLatency = debugInfo.ClientMonitorLatency; | ||
208 | DeviceInfo->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId; | ||
209 | |||
210 | DeviceInfo->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask; | ||
211 | DeviceInfo->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex; | ||
212 | DeviceInfo->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex; | ||
213 | DeviceInfo->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead; | ||
214 | DeviceInfo->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite; | ||
215 | |||
216 | DeviceInfo->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask; | ||
217 | DeviceInfo->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex; | ||
218 | DeviceInfo->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex; | ||
219 | DeviceInfo->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead; | ||
220 | DeviceInfo->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite; | ||
221 | } | ||
222 | } | ||
diff --git a/drivers/staging/hv/ChannelInterface.h b/drivers/staging/hv/ChannelInterface.h new file mode 100644 index 00000000000..8f5a4a99269 --- /dev/null +++ b/drivers/staging/hv/ChannelInterface.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #ifndef _CHANNEL_INTERFACE_H_ | ||
26 | #define _CHANNEL_INTERFACE_H_ | ||
27 | |||
28 | #include "VmbusApi.h" | ||
29 | |||
30 | INTERNAL void | ||
31 | GetChannelInterface( | ||
32 | VMBUS_CHANNEL_INTERFACE *ChannelInterface | ||
33 | ); | ||
34 | |||
35 | INTERNAL void | ||
36 | GetChannelInfo( | ||
37 | PDEVICE_OBJECT Device, | ||
38 | DEVICE_INFO *DeviceInfo | ||
39 | ); | ||
40 | |||
41 | #endif // _CHANNEL_INTERFACE_H_ | ||
diff --git a/drivers/staging/hv/ChannelMgmt.c b/drivers/staging/hv/ChannelMgmt.c new file mode 100644 index 00000000000..c058d53321c --- /dev/null +++ b/drivers/staging/hv/ChannelMgmt.c | |||
@@ -0,0 +1,826 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include "osd.h" | ||
26 | #include "logging.h" | ||
27 | |||
28 | #include "VmbusPrivate.h" | ||
29 | |||
30 | // | ||
31 | // Defines | ||
32 | // | ||
33 | |||
34 | // | ||
35 | // Data types | ||
36 | // | ||
37 | |||
38 | typedef void (*PFN_CHANNEL_MESSAGE_HANDLER)(VMBUS_CHANNEL_MESSAGE_HEADER* msg); | ||
39 | |||
40 | typedef struct _VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY { | ||
41 | VMBUS_CHANNEL_MESSAGE_TYPE messageType; | ||
42 | PFN_CHANNEL_MESSAGE_HANDLER messageHandler; | ||
43 | } VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY; | ||
44 | |||
45 | // | ||
46 | // Internal routines | ||
47 | // | ||
48 | |||
49 | static void | ||
50 | VmbusChannelOnOffer( | ||
51 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
52 | ); | ||
53 | static void | ||
54 | VmbusChannelOnOpenResult( | ||
55 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
56 | ); | ||
57 | |||
58 | static void | ||
59 | VmbusChannelOnOfferRescind( | ||
60 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
61 | ); | ||
62 | |||
63 | static void | ||
64 | VmbusChannelOnGpadlCreated( | ||
65 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
66 | ); | ||
67 | |||
68 | static void | ||
69 | VmbusChannelOnGpadlTorndown( | ||
70 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
71 | ); | ||
72 | |||
73 | static void | ||
74 | VmbusChannelOnOffersDelivered( | ||
75 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
76 | ); | ||
77 | |||
78 | static void | ||
79 | VmbusChannelOnVersionResponse( | ||
80 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
81 | ); | ||
82 | |||
83 | static void | ||
84 | VmbusChannelProcessOffer( | ||
85 | PVOID context | ||
86 | ); | ||
87 | |||
88 | static void | ||
89 | VmbusChannelProcessRescindOffer( | ||
90 | PVOID context | ||
91 | ); | ||
92 | |||
93 | |||
94 | // | ||
95 | // Globals | ||
96 | // | ||
97 | |||
98 | #define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4 | ||
99 | |||
100 | const GUID gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED]= { | ||
101 | //{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} | ||
102 | {.Data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}},// Storage - SCSI | ||
103 | //{F8615163-DF3E-46c5-913F-F2D2F965ED0E} | ||
104 | {.Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}}, // Network | ||
105 | //{CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} | ||
106 | {.Data = {0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A}}, // Input | ||
107 | //{32412632-86cb-44a2-9b5c-50d1417354f5} | ||
108 | {.Data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}}, // IDE | ||
109 | |||
110 | }; | ||
111 | |||
112 | // Channel message dispatch table | ||
113 | VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY gChannelMessageTable[ChannelMessageCount]= { | ||
114 | {ChannelMessageInvalid, NULL}, | ||
115 | {ChannelMessageOfferChannel, VmbusChannelOnOffer}, | ||
116 | {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind}, | ||
117 | {ChannelMessageRequestOffers, NULL}, | ||
118 | {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered}, | ||
119 | {ChannelMessageOpenChannel, NULL}, | ||
120 | {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult}, | ||
121 | {ChannelMessageCloseChannel, NULL}, | ||
122 | {ChannelMessageGpadlHeader, NULL}, | ||
123 | {ChannelMessageGpadlBody, NULL}, | ||
124 | {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated}, | ||
125 | {ChannelMessageGpadlTeardown, NULL}, | ||
126 | {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown}, | ||
127 | {ChannelMessageRelIdReleased, NULL}, | ||
128 | {ChannelMessageInitiateContact, NULL}, | ||
129 | {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse}, | ||
130 | {ChannelMessageUnload, NULL}, | ||
131 | }; | ||
132 | |||
133 | /*++ | ||
134 | |||
135 | Name: | ||
136 | AllocVmbusChannel() | ||
137 | |||
138 | Description: | ||
139 | Allocate and initialize a vmbus channel object | ||
140 | |||
141 | --*/ | ||
142 | VMBUS_CHANNEL* AllocVmbusChannel(void) | ||
143 | { | ||
144 | VMBUS_CHANNEL* channel; | ||
145 | |||
146 | channel = (VMBUS_CHANNEL*) MemAllocAtomic(sizeof(VMBUS_CHANNEL)); | ||
147 | if (!channel) | ||
148 | { | ||
149 | return NULL; | ||
150 | } | ||
151 | |||
152 | memset(channel, 0,sizeof(VMBUS_CHANNEL)); | ||
153 | channel->InboundLock = SpinlockCreate(); | ||
154 | if (!channel->InboundLock) | ||
155 | { | ||
156 | MemFree(channel); | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | channel->PollTimer = TimerCreate(VmbusChannelOnTimer, channel); | ||
161 | if (!channel->PollTimer) | ||
162 | { | ||
163 | SpinlockClose(channel->InboundLock); | ||
164 | MemFree(channel); | ||
165 | return NULL; | ||
166 | } | ||
167 | |||
168 | //channel->dataWorkQueue = WorkQueueCreate("data"); | ||
169 | channel->ControlWQ = WorkQueueCreate("control"); | ||
170 | if (!channel->ControlWQ) | ||
171 | { | ||
172 | TimerClose(channel->PollTimer); | ||
173 | SpinlockClose(channel->InboundLock); | ||
174 | MemFree(channel); | ||
175 | return NULL; | ||
176 | } | ||
177 | |||
178 | return channel; | ||
179 | } | ||
180 | |||
181 | /*++ | ||
182 | |||
183 | Name: | ||
184 | ReleaseVmbusChannel() | ||
185 | |||
186 | Description: | ||
187 | Release the vmbus channel object itself | ||
188 | |||
189 | --*/ | ||
190 | static inline void ReleaseVmbusChannel(void* Context) | ||
191 | { | ||
192 | VMBUS_CHANNEL* channel = (VMBUS_CHANNEL*)Context; | ||
193 | |||
194 | DPRINT_ENTER(VMBUS); | ||
195 | |||
196 | DPRINT_DBG(VMBUS, "releasing channel (%p)", channel); | ||
197 | WorkQueueClose(channel->ControlWQ); | ||
198 | DPRINT_DBG(VMBUS, "channel released (%p)", channel); | ||
199 | |||
200 | MemFree(channel); | ||
201 | |||
202 | DPRINT_EXIT(VMBUS); | ||
203 | } | ||
204 | |||
205 | /*++ | ||
206 | |||
207 | Name: | ||
208 | FreeVmbusChannel() | ||
209 | |||
210 | Description: | ||
211 | Release the resources used by the vmbus channel object | ||
212 | |||
213 | --*/ | ||
214 | void FreeVmbusChannel(VMBUS_CHANNEL* Channel) | ||
215 | { | ||
216 | SpinlockClose(Channel->InboundLock); | ||
217 | TimerClose(Channel->PollTimer); | ||
218 | |||
219 | // We have to release the channel's workqueue/thread in the vmbus's workqueue/thread context | ||
220 | // ie we can't destroy ourselves. | ||
221 | WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, ReleaseVmbusChannel, (void*)Channel); | ||
222 | } | ||
223 | |||
224 | |||
225 | /*++ | ||
226 | |||
227 | Name: | ||
228 | VmbusChannelProcessOffer() | ||
229 | |||
230 | Description: | ||
231 | Process the offer by creating a channel/device associated with this offer | ||
232 | |||
233 | --*/ | ||
234 | static void | ||
235 | VmbusChannelProcessOffer( | ||
236 | PVOID context | ||
237 | ) | ||
238 | { | ||
239 | int ret=0; | ||
240 | VMBUS_CHANNEL* newChannel=(VMBUS_CHANNEL*)context; | ||
241 | LIST_ENTRY* anchor; | ||
242 | LIST_ENTRY* curr; | ||
243 | BOOL fNew=TRUE; | ||
244 | VMBUS_CHANNEL* channel; | ||
245 | |||
246 | DPRINT_ENTER(VMBUS); | ||
247 | |||
248 | // Make sure this is a new offer | ||
249 | SpinlockAcquire(gVmbusConnection.ChannelLock); | ||
250 | |||
251 | ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList) | ||
252 | { | ||
253 | channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry); | ||
254 | |||
255 | if (!memcmp(&channel->OfferMsg.Offer.InterfaceType, &newChannel->OfferMsg.Offer.InterfaceType,sizeof(GUID)) && | ||
256 | !memcmp(&channel->OfferMsg.Offer.InterfaceInstance, &newChannel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID))) | ||
257 | { | ||
258 | fNew = FALSE; | ||
259 | break; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | if (fNew) | ||
264 | { | ||
265 | INSERT_TAIL_LIST(&gVmbusConnection.ChannelList, &newChannel->ListEntry); | ||
266 | } | ||
267 | SpinlockRelease(gVmbusConnection.ChannelLock); | ||
268 | |||
269 | if (!fNew) | ||
270 | { | ||
271 | DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", newChannel->OfferMsg.ChildRelId); | ||
272 | FreeVmbusChannel(newChannel); | ||
273 | DPRINT_EXIT(VMBUS); | ||
274 | return; | ||
275 | } | ||
276 | |||
277 | // Start the process of binding this offer to the driver | ||
278 | // We need to set the DeviceObject field before calling VmbusChildDeviceAdd() | ||
279 | newChannel->DeviceObject = VmbusChildDeviceCreate( | ||
280 | newChannel->OfferMsg.Offer.InterfaceType, | ||
281 | newChannel->OfferMsg.Offer.InterfaceInstance, | ||
282 | newChannel); | ||
283 | |||
284 | DPRINT_DBG(VMBUS, "child device object allocated - %p", newChannel->DeviceObject); | ||
285 | |||
286 | // Add the new device to the bus. This will kick off device-driver binding | ||
287 | // which eventually invokes the device driver's AddDevice() method. | ||
288 | ret = VmbusChildDeviceAdd(newChannel->DeviceObject); | ||
289 | if (ret != 0) | ||
290 | { | ||
291 | DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)", | ||
292 | newChannel->OfferMsg.ChildRelId); | ||
293 | |||
294 | SpinlockAcquire(gVmbusConnection.ChannelLock); | ||
295 | REMOVE_ENTRY_LIST(&newChannel->ListEntry); | ||
296 | SpinlockRelease(gVmbusConnection.ChannelLock); | ||
297 | |||
298 | FreeVmbusChannel(newChannel); | ||
299 | } | ||
300 | else | ||
301 | { | ||
302 | // This state is used to indicate a successful open so that when we do close the channel normally, | ||
303 | // we can cleanup properly | ||
304 | newChannel->State = CHANNEL_OPEN_STATE; | ||
305 | } | ||
306 | DPRINT_EXIT(VMBUS); | ||
307 | } | ||
308 | |||
309 | /*++ | ||
310 | |||
311 | Name: | ||
312 | VmbusChannelProcessRescindOffer() | ||
313 | |||
314 | Description: | ||
315 | Rescind the offer by initiating a device removal | ||
316 | |||
317 | --*/ | ||
318 | static void | ||
319 | VmbusChannelProcessRescindOffer( | ||
320 | PVOID context | ||
321 | ) | ||
322 | { | ||
323 | VMBUS_CHANNEL* channel=(VMBUS_CHANNEL*)context; | ||
324 | |||
325 | DPRINT_ENTER(VMBUS); | ||
326 | |||
327 | VmbusChildDeviceRemove(channel->DeviceObject); | ||
328 | |||
329 | DPRINT_EXIT(VMBUS); | ||
330 | } | ||
331 | |||
332 | |||
333 | /*++ | ||
334 | |||
335 | Name: | ||
336 | VmbusChannelOnOffer() | ||
337 | |||
338 | Description: | ||
339 | Handler for channel offers from vmbus in parent partition. We ignore all offers except | ||
340 | network and storage offers. For each network and storage offers, we create a channel object | ||
341 | and queue a work item to the channel object to process the offer synchronously | ||
342 | |||
343 | --*/ | ||
344 | static void | ||
345 | VmbusChannelOnOffer( | ||
346 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
347 | ) | ||
348 | { | ||
349 | VMBUS_CHANNEL_OFFER_CHANNEL* offer = (VMBUS_CHANNEL_OFFER_CHANNEL*)hdr; | ||
350 | VMBUS_CHANNEL* newChannel; | ||
351 | |||
352 | GUID *guidType; | ||
353 | GUID *guidInstance; | ||
354 | int i; | ||
355 | int fSupported=0; | ||
356 | |||
357 | DPRINT_ENTER(VMBUS); | ||
358 | |||
359 | for (i=0; i<MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) | ||
360 | { | ||
361 | if (memcmp(&offer->Offer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(GUID)) == 0) | ||
362 | { | ||
363 | fSupported = 1; | ||
364 | break; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | if (!fSupported) | ||
369 | { | ||
370 | DPRINT_DBG(VMBUS, "Ignoring channel offer notification for child relid %d", offer->ChildRelId); | ||
371 | DPRINT_EXIT(VMBUS); | ||
372 | |||
373 | return; | ||
374 | } | ||
375 | |||
376 | guidType = &offer->Offer.InterfaceType; | ||
377 | guidInstance = &offer->Offer.InterfaceInstance; | ||
378 | |||
379 | DPRINT_INFO(VMBUS, "Channel offer notification - child relid %d monitor id %d allocated %d, " | ||
380 | "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x} " | ||
381 | "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | ||
382 | offer->ChildRelId, | ||
383 | offer->MonitorId, | ||
384 | offer->MonitorAllocated, | ||
385 | guidType->Data[3], guidType->Data[2], guidType->Data[1], guidType->Data[0], guidType->Data[5], guidType->Data[4], guidType->Data[7], guidType->Data[6], guidType->Data[8], guidType->Data[9], guidType->Data[10], guidType->Data[11], guidType->Data[12], guidType->Data[13], guidType->Data[14], guidType->Data[15], | ||
386 | guidInstance->Data[3], guidInstance->Data[2], guidInstance->Data[1], guidInstance->Data[0], guidInstance->Data[5], guidInstance->Data[4], guidInstance->Data[7], guidInstance->Data[6], guidInstance->Data[8], guidInstance->Data[9], guidInstance->Data[10], guidInstance->Data[11], guidInstance->Data[12], guidInstance->Data[13], guidInstance->Data[14], guidInstance->Data[15]); | ||
387 | |||
388 | // Allocate the channel object and save this offer. | ||
389 | newChannel = AllocVmbusChannel(); | ||
390 | if (!newChannel) | ||
391 | { | ||
392 | DPRINT_ERR(VMBUS, "unable to allocate channel object"); | ||
393 | return; | ||
394 | } | ||
395 | |||
396 | DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel); | ||
397 | |||
398 | memcpy(&newChannel->OfferMsg, offer, sizeof(VMBUS_CHANNEL_OFFER_CHANNEL)); | ||
399 | newChannel->MonitorGroup = (UINT8)offer->MonitorId / 32; | ||
400 | newChannel->MonitorBit = (UINT8)offer->MonitorId % 32; | ||
401 | |||
402 | // TODO: Make sure the offer comes from our parent partition | ||
403 | WorkQueueQueueWorkItem(newChannel->ControlWQ, VmbusChannelProcessOffer, newChannel); | ||
404 | |||
405 | DPRINT_EXIT(VMBUS); | ||
406 | } | ||
407 | |||
408 | |||
409 | /*++ | ||
410 | |||
411 | Name: | ||
412 | VmbusChannelOnOfferRescind() | ||
413 | |||
414 | Description: | ||
415 | Rescind offer handler. We queue a work item to process this offer | ||
416 | synchronously | ||
417 | |||
418 | --*/ | ||
419 | static void | ||
420 | VmbusChannelOnOfferRescind( | ||
421 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
422 | ) | ||
423 | { | ||
424 | VMBUS_CHANNEL_RESCIND_OFFER* rescind = (VMBUS_CHANNEL_RESCIND_OFFER*)hdr; | ||
425 | VMBUS_CHANNEL* channel; | ||
426 | |||
427 | DPRINT_ENTER(VMBUS); | ||
428 | |||
429 | channel = GetChannelFromRelId(rescind->ChildRelId); | ||
430 | if (channel == NULL) | ||
431 | { | ||
432 | DPRINT_DBG(VMBUS, "channel not found for relId %d", rescind->ChildRelId); | ||
433 | return; | ||
434 | } | ||
435 | |||
436 | WorkQueueQueueWorkItem(channel->ControlWQ, VmbusChannelProcessRescindOffer, channel); | ||
437 | |||
438 | DPRINT_EXIT(VMBUS); | ||
439 | } | ||
440 | |||
441 | |||
442 | /*++ | ||
443 | |||
444 | Name: | ||
445 | VmbusChannelOnOffersDelivered() | ||
446 | |||
447 | Description: | ||
448 | This is invoked when all offers have been delivered. | ||
449 | Nothing to do here. | ||
450 | |||
451 | --*/ | ||
452 | static void | ||
453 | VmbusChannelOnOffersDelivered( | ||
454 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
455 | ) | ||
456 | { | ||
457 | DPRINT_ENTER(VMBUS); | ||
458 | DPRINT_EXIT(VMBUS); | ||
459 | } | ||
460 | |||
461 | |||
462 | /*++ | ||
463 | |||
464 | Name: | ||
465 | VmbusChannelOnOpenResult() | ||
466 | |||
467 | Description: | ||
468 | Open result handler. This is invoked when we received a response | ||
469 | to our channel open request. Find the matching request, copy the | ||
470 | response and signal the requesting thread. | ||
471 | |||
472 | --*/ | ||
473 | static void | ||
474 | VmbusChannelOnOpenResult( | ||
475 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
476 | ) | ||
477 | { | ||
478 | VMBUS_CHANNEL_OPEN_RESULT* result = (VMBUS_CHANNEL_OPEN_RESULT*)hdr; | ||
479 | LIST_ENTRY* anchor; | ||
480 | LIST_ENTRY* curr; | ||
481 | VMBUS_CHANNEL_MSGINFO* msgInfo; | ||
482 | VMBUS_CHANNEL_MESSAGE_HEADER* requestHeader; | ||
483 | VMBUS_CHANNEL_OPEN_CHANNEL* openMsg; | ||
484 | |||
485 | DPRINT_ENTER(VMBUS); | ||
486 | |||
487 | DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status); | ||
488 | |||
489 | // Find the open msg, copy the result and signal/unblock the wait event | ||
490 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
491 | |||
492 | ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) | ||
493 | { | ||
494 | msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | ||
495 | requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | ||
496 | |||
497 | if (requestHeader->MessageType == ChannelMessageOpenChannel) | ||
498 | { | ||
499 | openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)msgInfo->Msg; | ||
500 | if (openMsg->ChildRelId == result->ChildRelId && | ||
501 | openMsg->OpenId == result->OpenId) | ||
502 | { | ||
503 | memcpy(&msgInfo->Response.OpenResult, result, sizeof(VMBUS_CHANNEL_OPEN_RESULT)); | ||
504 | WaitEventSet(msgInfo->WaitEvent); | ||
505 | break; | ||
506 | } | ||
507 | } | ||
508 | } | ||
509 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
510 | |||
511 | DPRINT_EXIT(VMBUS); | ||
512 | } | ||
513 | |||
514 | |||
515 | /*++ | ||
516 | |||
517 | Name: | ||
518 | VmbusChannelOnGpadlCreated() | ||
519 | |||
520 | Description: | ||
521 | GPADL created handler. This is invoked when we received a response | ||
522 | to our gpadl create request. Find the matching request, copy the | ||
523 | response and signal the requesting thread. | ||
524 | |||
525 | --*/ | ||
526 | static void | ||
527 | VmbusChannelOnGpadlCreated( | ||
528 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
529 | ) | ||
530 | { | ||
531 | VMBUS_CHANNEL_GPADL_CREATED *gpadlCreated = (VMBUS_CHANNEL_GPADL_CREATED*)hdr; | ||
532 | LIST_ENTRY *anchor; | ||
533 | LIST_ENTRY *curr; | ||
534 | VMBUS_CHANNEL_MSGINFO *msgInfo; | ||
535 | VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; | ||
536 | VMBUS_CHANNEL_GPADL_HEADER *gpadlHeader; | ||
537 | |||
538 | DPRINT_ENTER(VMBUS); | ||
539 | |||
540 | DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", gpadlCreated->CreationStatus); | ||
541 | |||
542 | // Find the establish msg, copy the result and signal/unblock the wait event | ||
543 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
544 | |||
545 | ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) | ||
546 | { | ||
547 | msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | ||
548 | requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | ||
549 | |||
550 | if (requestHeader->MessageType == ChannelMessageGpadlHeader) | ||
551 | { | ||
552 | gpadlHeader = (VMBUS_CHANNEL_GPADL_HEADER*)requestHeader; | ||
553 | |||
554 | if ((gpadlCreated->ChildRelId == gpadlHeader->ChildRelId) && | ||
555 | (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) | ||
556 | { | ||
557 | memcpy(&msgInfo->Response.GpadlCreated, gpadlCreated, sizeof(VMBUS_CHANNEL_GPADL_CREATED)); | ||
558 | WaitEventSet(msgInfo->WaitEvent); | ||
559 | break; | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
564 | |||
565 | DPRINT_EXIT(VMBUS); | ||
566 | } | ||
567 | |||
568 | |||
569 | /*++ | ||
570 | |||
571 | Name: | ||
572 | VmbusChannelOnGpadlTorndown() | ||
573 | |||
574 | Description: | ||
575 | GPADL torndown handler. This is invoked when we received a response | ||
576 | to our gpadl teardown request. Find the matching request, copy the | ||
577 | response and signal the requesting thread. | ||
578 | |||
579 | --*/ | ||
580 | static void | ||
581 | VmbusChannelOnGpadlTorndown( | ||
582 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
583 | ) | ||
584 | { | ||
585 | VMBUS_CHANNEL_GPADL_TORNDOWN* gpadlTorndown = (VMBUS_CHANNEL_GPADL_TORNDOWN*)hdr; | ||
586 | LIST_ENTRY* anchor; | ||
587 | LIST_ENTRY* curr; | ||
588 | VMBUS_CHANNEL_MSGINFO* msgInfo; | ||
589 | VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; | ||
590 | VMBUS_CHANNEL_GPADL_TEARDOWN *gpadlTeardown; | ||
591 | |||
592 | DPRINT_ENTER(VMBUS); | ||
593 | |||
594 | // Find the open msg, copy the result and signal/unblock the wait event | ||
595 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
596 | |||
597 | ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) | ||
598 | { | ||
599 | msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | ||
600 | requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | ||
601 | |||
602 | if (requestHeader->MessageType == ChannelMessageGpadlTeardown) | ||
603 | { | ||
604 | gpadlTeardown = (VMBUS_CHANNEL_GPADL_TEARDOWN*)requestHeader; | ||
605 | |||
606 | if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) | ||
607 | { | ||
608 | memcpy(&msgInfo->Response.GpadlTorndown, gpadlTorndown, sizeof(VMBUS_CHANNEL_GPADL_TORNDOWN)); | ||
609 | WaitEventSet(msgInfo->WaitEvent); | ||
610 | break; | ||
611 | } | ||
612 | } | ||
613 | } | ||
614 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
615 | |||
616 | DPRINT_EXIT(VMBUS); | ||
617 | } | ||
618 | |||
619 | |||
620 | /*++ | ||
621 | |||
622 | Name: | ||
623 | VmbusChannelOnVersionResponse() | ||
624 | |||
625 | Description: | ||
626 | Version response handler. This is invoked when we received a response | ||
627 | to our initiate contact request. Find the matching request, copy the | ||
628 | response and signal the requesting thread. | ||
629 | |||
630 | --*/ | ||
631 | static void | ||
632 | VmbusChannelOnVersionResponse( | ||
633 | PVMBUS_CHANNEL_MESSAGE_HEADER hdr | ||
634 | ) | ||
635 | { | ||
636 | LIST_ENTRY* anchor; | ||
637 | LIST_ENTRY* curr; | ||
638 | VMBUS_CHANNEL_MSGINFO *msgInfo; | ||
639 | VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; | ||
640 | VMBUS_CHANNEL_INITIATE_CONTACT *initiate; | ||
641 | VMBUS_CHANNEL_VERSION_RESPONSE *versionResponse = (VMBUS_CHANNEL_VERSION_RESPONSE*)hdr; | ||
642 | |||
643 | DPRINT_ENTER(VMBUS); | ||
644 | |||
645 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
646 | |||
647 | ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) | ||
648 | { | ||
649 | msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | ||
650 | requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | ||
651 | |||
652 | if (requestHeader->MessageType == ChannelMessageInitiateContact) | ||
653 | { | ||
654 | initiate = (VMBUS_CHANNEL_INITIATE_CONTACT*)requestHeader; | ||
655 | memcpy(&msgInfo->Response.VersionResponse, versionResponse, sizeof(VMBUS_CHANNEL_VERSION_RESPONSE)); | ||
656 | WaitEventSet(msgInfo->WaitEvent); | ||
657 | } | ||
658 | } | ||
659 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
660 | |||
661 | DPRINT_EXIT(VMBUS); | ||
662 | } | ||
663 | |||
664 | |||
665 | /*++ | ||
666 | |||
667 | Name: | ||
668 | VmbusOnChannelMessage() | ||
669 | |||
670 | Description: | ||
671 | Handler for channel protocol messages. | ||
672 | This is invoked in the vmbus worker thread context. | ||
673 | |||
674 | --*/ | ||
675 | VOID | ||
676 | VmbusOnChannelMessage( | ||
677 | void *Context | ||
678 | ) | ||
679 | { | ||
680 | HV_MESSAGE *msg=(HV_MESSAGE*)Context; | ||
681 | VMBUS_CHANNEL_MESSAGE_HEADER* hdr; | ||
682 | int size; | ||
683 | |||
684 | DPRINT_ENTER(VMBUS); | ||
685 | |||
686 | hdr = (VMBUS_CHANNEL_MESSAGE_HEADER*)msg->u.Payload; | ||
687 | size=msg->Header.PayloadSize; | ||
688 | |||
689 | DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size); | ||
690 | |||
691 | if (hdr->MessageType >= ChannelMessageCount) | ||
692 | { | ||
693 | DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", hdr->MessageType, size); | ||
694 | PrintBytes((unsigned char *)msg->u.Payload, size); | ||
695 | MemFree(msg); | ||
696 | return; | ||
697 | } | ||
698 | |||
699 | if (gChannelMessageTable[hdr->MessageType].messageHandler) | ||
700 | { | ||
701 | gChannelMessageTable[hdr->MessageType].messageHandler(hdr); | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->MessageType); | ||
706 | } | ||
707 | |||
708 | // Free the msg that was allocated in VmbusOnMsgDPC() | ||
709 | MemFree(msg); | ||
710 | DPRINT_EXIT(VMBUS); | ||
711 | } | ||
712 | |||
713 | |||
714 | /*++ | ||
715 | |||
716 | Name: | ||
717 | VmbusChannelRequestOffers() | ||
718 | |||
719 | Description: | ||
720 | Send a request to get all our pending offers. | ||
721 | |||
722 | --*/ | ||
723 | int | ||
724 | VmbusChannelRequestOffers( | ||
725 | VOID | ||
726 | ) | ||
727 | { | ||
728 | int ret=0; | ||
729 | VMBUS_CHANNEL_MESSAGE_HEADER* msg; | ||
730 | VMBUS_CHANNEL_MSGINFO* msgInfo; | ||
731 | |||
732 | DPRINT_ENTER(VMBUS); | ||
733 | |||
734 | msgInfo = | ||
735 | (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_MESSAGE_HEADER)); | ||
736 | ASSERT(msgInfo != NULL); | ||
737 | |||
738 | msgInfo->WaitEvent = WaitEventCreate(); | ||
739 | msg = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | ||
740 | |||
741 | msg->MessageType = ChannelMessageRequestOffers; | ||
742 | |||
743 | /*SpinlockAcquire(gVmbusConnection.channelMsgLock); | ||
744 | INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, &msgInfo->msgListEntry); | ||
745 | SpinlockRelease(gVmbusConnection.channelMsgLock);*/ | ||
746 | |||
747 | ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_MESSAGE_HEADER)); | ||
748 | if (ret != 0) | ||
749 | { | ||
750 | DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret); | ||
751 | |||
752 | /*SpinlockAcquire(gVmbusConnection.channelMsgLock); | ||
753 | REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); | ||
754 | SpinlockRelease(gVmbusConnection.channelMsgLock);*/ | ||
755 | |||
756 | goto Cleanup; | ||
757 | } | ||
758 | //WaitEventWait(msgInfo->waitEvent); | ||
759 | |||
760 | /*SpinlockAcquire(gVmbusConnection.channelMsgLock); | ||
761 | REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); | ||
762 | SpinlockRelease(gVmbusConnection.channelMsgLock);*/ | ||
763 | |||
764 | |||
765 | Cleanup: | ||
766 | if (msgInfo) | ||
767 | { | ||
768 | WaitEventClose(msgInfo->WaitEvent); | ||
769 | MemFree(msgInfo); | ||
770 | } | ||
771 | |||
772 | DPRINT_EXIT(VMBUS); | ||
773 | |||
774 | return ret; | ||
775 | } | ||
776 | |||
777 | /*++ | ||
778 | |||
779 | Name: | ||
780 | VmbusChannelReleaseUnattachedChannels() | ||
781 | |||
782 | Description: | ||
783 | Release channels that are unattached/unconnected ie (no drivers associated) | ||
784 | |||
785 | --*/ | ||
786 | void | ||
787 | VmbusChannelReleaseUnattachedChannels( | ||
788 | VOID | ||
789 | ) | ||
790 | { | ||
791 | LIST_ENTRY *entry; | ||
792 | VMBUS_CHANNEL *channel; | ||
793 | VMBUS_CHANNEL *start=NULL; | ||
794 | |||
795 | SpinlockAcquire(gVmbusConnection.ChannelLock); | ||
796 | |||
797 | while (!IsListEmpty(&gVmbusConnection.ChannelList)) | ||
798 | { | ||
799 | entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList); | ||
800 | channel = CONTAINING_RECORD(entry, VMBUS_CHANNEL, ListEntry); | ||
801 | |||
802 | if (channel == start) | ||
803 | break; | ||
804 | |||
805 | if (!channel->DeviceObject->Driver) | ||
806 | { | ||
807 | REMOVE_ENTRY_LIST(&channel->ListEntry); | ||
808 | DPRINT_INFO(VMBUS, "Releasing unattached device object %p", channel->DeviceObject); | ||
809 | |||
810 | VmbusChildDeviceRemove(channel->DeviceObject); | ||
811 | FreeVmbusChannel(channel); | ||
812 | } | ||
813 | else | ||
814 | { | ||
815 | if (!start) | ||
816 | { | ||
817 | start = channel; | ||
818 | } | ||
819 | } | ||
820 | } | ||
821 | |||
822 | SpinlockRelease(gVmbusConnection.ChannelLock); | ||
823 | } | ||
824 | |||
825 | // eof | ||
826 | |||
diff --git a/drivers/staging/hv/ChannelMgmt.h b/drivers/staging/hv/ChannelMgmt.h new file mode 100644 index 00000000000..d5ba5d13594 --- /dev/null +++ b/drivers/staging/hv/ChannelMgmt.h | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #ifndef _CHANNEL_MGMT_H_ | ||
26 | #define _CHANNEL_MGMT_H_ | ||
27 | |||
28 | #include "osd.h" | ||
29 | #include "List.h" | ||
30 | #include "RingBuffer.h" | ||
31 | |||
32 | #include "VmbusChannelInterface.h" | ||
33 | #include "ChannelMessages.h" | ||
34 | |||
35 | |||
36 | |||
37 | typedef void (*PFN_CHANNEL_CALLBACK)(PVOID context); | ||
38 | |||
39 | typedef enum { | ||
40 | CHANNEL_OFFER_STATE, | ||
41 | CHANNEL_OPENING_STATE, | ||
42 | CHANNEL_OPEN_STATE, | ||
43 | } VMBUS_CHANNEL_STATE; | ||
44 | |||
45 | typedef struct _VMBUS_CHANNEL { | ||
46 | LIST_ENTRY ListEntry; | ||
47 | |||
48 | DEVICE_OBJECT* DeviceObject; | ||
49 | |||
50 | HANDLE PollTimer; // SA-111 workaround | ||
51 | |||
52 | VMBUS_CHANNEL_STATE State; | ||
53 | |||
54 | VMBUS_CHANNEL_OFFER_CHANNEL OfferMsg; | ||
55 | // These are based on the OfferMsg.MonitorId. Save it here for easy access. | ||
56 | UINT8 MonitorGroup; | ||
57 | UINT8 MonitorBit; | ||
58 | |||
59 | UINT32 RingBufferGpadlHandle; | ||
60 | |||
61 | // Allocated memory for ring buffer | ||
62 | VOID* RingBufferPages; | ||
63 | UINT32 RingBufferPageCount; | ||
64 | RING_BUFFER_INFO Outbound; // send to parent | ||
65 | RING_BUFFER_INFO Inbound; // receive from parent | ||
66 | HANDLE InboundLock; | ||
67 | HANDLE ControlWQ; | ||
68 | |||
69 | // Channel callback are invoked in this workqueue context | ||
70 | //HANDLE dataWorkQueue; | ||
71 | |||
72 | PFN_CHANNEL_CALLBACK OnChannelCallback; | ||
73 | PVOID ChannelCallbackContext; | ||
74 | |||
75 | } VMBUS_CHANNEL; | ||
76 | |||
77 | |||
78 | typedef struct _VMBUS_CHANNEL_DEBUG_INFO { | ||
79 | UINT32 RelId; | ||
80 | VMBUS_CHANNEL_STATE State; | ||
81 | GUID InterfaceType; | ||
82 | GUID InterfaceInstance; | ||
83 | UINT32 MonitorId; | ||
84 | UINT32 ServerMonitorPending; | ||
85 | UINT32 ServerMonitorLatency; | ||
86 | UINT32 ServerMonitorConnectionId; | ||
87 | UINT32 ClientMonitorPending; | ||
88 | UINT32 ClientMonitorLatency; | ||
89 | UINT32 ClientMonitorConnectionId; | ||
90 | |||
91 | RING_BUFFER_DEBUG_INFO Inbound; | ||
92 | RING_BUFFER_DEBUG_INFO Outbound; | ||
93 | } VMBUS_CHANNEL_DEBUG_INFO; | ||
94 | |||
95 | |||
96 | typedef union { | ||
97 | VMBUS_CHANNEL_VERSION_SUPPORTED VersionSupported; | ||
98 | VMBUS_CHANNEL_OPEN_RESULT OpenResult; | ||
99 | VMBUS_CHANNEL_GPADL_TORNDOWN GpadlTorndown; | ||
100 | VMBUS_CHANNEL_GPADL_CREATED GpadlCreated; | ||
101 | VMBUS_CHANNEL_VERSION_RESPONSE VersionResponse; | ||
102 | } VMBUS_CHANNEL_MESSAGE_RESPONSE; | ||
103 | |||
104 | |||
105 | // Represents each channel msg on the vmbus connection | ||
106 | // This is a variable-size data structure depending on | ||
107 | // the msg type itself | ||
108 | typedef struct _VMBUS_CHANNEL_MSGINFO { | ||
109 | // Bookkeeping stuff | ||
110 | LIST_ENTRY MsgListEntry; | ||
111 | |||
112 | // So far, this is only used to handle gpadl body message | ||
113 | LIST_ENTRY SubMsgList; | ||
114 | |||
115 | // Synchronize the request/response if needed | ||
116 | HANDLE WaitEvent; | ||
117 | |||
118 | VMBUS_CHANNEL_MESSAGE_RESPONSE Response; | ||
119 | |||
120 | UINT32 MessageSize; | ||
121 | // The channel message that goes out on the "wire". | ||
122 | // It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header | ||
123 | unsigned char Msg[0]; | ||
124 | } VMBUS_CHANNEL_MSGINFO; | ||
125 | |||
126 | |||
127 | // | ||
128 | // Routines | ||
129 | // | ||
130 | |||
131 | INTERNAL VMBUS_CHANNEL* | ||
132 | AllocVmbusChannel( | ||
133 | void | ||
134 | ); | ||
135 | |||
136 | INTERNAL void | ||
137 | FreeVmbusChannel( | ||
138 | VMBUS_CHANNEL *Channel | ||
139 | ); | ||
140 | |||
141 | INTERNAL void | ||
142 | VmbusOnChannelMessage( | ||
143 | void *Context | ||
144 | ); | ||
145 | |||
146 | INTERNAL int | ||
147 | VmbusChannelRequestOffers( | ||
148 | void | ||
149 | ); | ||
150 | |||
151 | INTERNAL void | ||
152 | VmbusChannelReleaseUnattachedChannels( | ||
153 | void | ||
154 | ); | ||
155 | |||
156 | #endif //_CHANNEL_MGMT_H_ | ||
diff --git a/drivers/staging/hv/Connection.c b/drivers/staging/hv/Connection.c new file mode 100644 index 00000000000..fba195aa4b9 --- /dev/null +++ b/drivers/staging/hv/Connection.c | |||
@@ -0,0 +1,432 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include "logging.h" | ||
26 | |||
27 | #include "VmbusPrivate.h" | ||
28 | |||
29 | // | ||
30 | // Globals | ||
31 | // | ||
32 | |||
33 | |||
34 | VMBUS_CONNECTION gVmbusConnection = { | ||
35 | .ConnectState = Disconnected, | ||
36 | .NextGpadlHandle = 0xE1E10, | ||
37 | }; | ||
38 | |||
39 | |||
40 | /*++ | ||
41 | |||
42 | Name: | ||
43 | VmbusConnect() | ||
44 | |||
45 | Description: | ||
46 | Sends a connect request on the partition service connection | ||
47 | |||
48 | --*/ | ||
49 | int | ||
50 | VmbusConnect( | ||
51 | ) | ||
52 | { | ||
53 | int ret=0; | ||
54 | VMBUS_CHANNEL_MSGINFO *msgInfo=NULL; | ||
55 | VMBUS_CHANNEL_INITIATE_CONTACT *msg; | ||
56 | |||
57 | DPRINT_ENTER(VMBUS); | ||
58 | |||
59 | // Make sure we are not connecting or connected | ||
60 | if (gVmbusConnection.ConnectState != Disconnected) | ||
61 | return -1; | ||
62 | |||
63 | // Initialize the vmbus connection | ||
64 | gVmbusConnection.ConnectState = Connecting; | ||
65 | gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ"); | ||
66 | |||
67 | INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList); | ||
68 | gVmbusConnection.ChannelMsgLock = SpinlockCreate(); | ||
69 | |||
70 | INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList); | ||
71 | gVmbusConnection.ChannelLock = SpinlockCreate(); | ||
72 | |||
73 | // Setup the vmbus event connection for channel interrupt abstraction stuff | ||
74 | gVmbusConnection.InterruptPage = PageAlloc(1); | ||
75 | if (gVmbusConnection.InterruptPage == NULL) | ||
76 | { | ||
77 | ret = -1; | ||
78 | goto Cleanup; | ||
79 | } | ||
80 | |||
81 | gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage; | ||
82 | gVmbusConnection.SendInterruptPage = (void*)((ULONG_PTR)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1)); | ||
83 | |||
84 | // Setup the monitor notification facility. The 1st page for parent->child and the 2nd page for child->parent | ||
85 | gVmbusConnection.MonitorPages = PageAlloc(2); | ||
86 | if (gVmbusConnection.MonitorPages == NULL) | ||
87 | { | ||
88 | ret = -1; | ||
89 | goto Cleanup; | ||
90 | } | ||
91 | |||
92 | msgInfo = (VMBUS_CHANNEL_MSGINFO*)MemAllocZeroed(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT)); | ||
93 | if (msgInfo == NULL) | ||
94 | { | ||
95 | ret = -1; | ||
96 | goto Cleanup; | ||
97 | } | ||
98 | |||
99 | msgInfo->WaitEvent = WaitEventCreate(); | ||
100 | msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg; | ||
101 | |||
102 | msg->Header.MessageType = ChannelMessageInitiateContact; | ||
103 | msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER; | ||
104 | msg->InterruptPage = GetPhysicalAddress(gVmbusConnection.InterruptPage); | ||
105 | msg->MonitorPage1 = GetPhysicalAddress(gVmbusConnection.MonitorPages); | ||
106 | msg->MonitorPage2 = GetPhysicalAddress((PVOID)((ULONG_PTR)gVmbusConnection.MonitorPages + PAGE_SIZE)); | ||
107 | |||
108 | // Add to list before we send the request since we may receive the response | ||
109 | // before returning from this routine | ||
110 | SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | ||
111 | INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry); | ||
112 | SpinlockRelease(gVmbusConnection.ChannelMsgLock); | ||
113 | |||
114 | DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx", | ||
115 | msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2); | ||
116 | |||
117 | DPRINT_DBG(VMBUS, "Sending channel initiate msg..."); | ||
118 | |||
119 | ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT)); | ||
120 | if (ret != 0) | ||
121 | { | ||
122 | REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); | ||
123 | goto Cleanup; | ||
124 | } | ||
125 | |||
126 | // Wait for the connection response | ||
127 | WaitEventWait(msgInfo->WaitEvent); | ||
128 | |||
129 | REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); | ||
130 | |||
131 | // Check if successful | ||
132 | if (msgInfo->Response.VersionResponse.VersionSupported) | ||
133 | { | ||
134 | DPRINT_INFO(VMBUS, "Vmbus connected!!"); | ||
135 | gVmbusConnection.ConnectState = Connected; | ||
136 | |||
137 | } | ||
138 | else | ||
139 | { | ||
140 | DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER); | ||
141 | ret = -1; | ||
142 | |||
143 | goto Cleanup; | ||
144 | } | ||
145 | |||
146 | |||
147 | WaitEventClose(msgInfo->WaitEvent); | ||
148 | MemFree(msgInfo); | ||
149 | DPRINT_EXIT(VMBUS); | ||
150 | |||
151 | return 0; | ||
152 | |||
153 | Cleanup: | ||
154 | |||
155 | gVmbusConnection.ConnectState = Disconnected; | ||
156 | |||
157 | WorkQueueClose(gVmbusConnection.WorkQueue); | ||
158 | SpinlockClose(gVmbusConnection.ChannelLock); | ||
159 | SpinlockClose(gVmbusConnection.ChannelMsgLock); | ||
160 | |||
161 | if (gVmbusConnection.InterruptPage) | ||
162 | { | ||
163 | PageFree(gVmbusConnection.InterruptPage, 1); | ||
164 | gVmbusConnection.InterruptPage = NULL; | ||
165 | } | ||
166 | |||
167 | if (gVmbusConnection.MonitorPages) | ||
168 | { | ||
169 | PageFree(gVmbusConnection.MonitorPages, 2); | ||
170 | gVmbusConnection.MonitorPages = NULL; | ||
171 | } | ||
172 | |||
173 | if (msgInfo) | ||
174 | { | ||
175 | if (msgInfo->WaitEvent) | ||
176 | WaitEventClose(msgInfo->WaitEvent); | ||
177 | |||
178 | MemFree(msgInfo); | ||
179 | } | ||
180 | |||
181 | DPRINT_EXIT(VMBUS); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | |||
187 | /*++ | ||
188 | |||
189 | Name: | ||
190 | VmbusDisconnect() | ||
191 | |||
192 | Description: | ||
193 | Sends a disconnect request on the partition service connection | ||
194 | |||
195 | --*/ | ||
196 | int | ||
197 | VmbusDisconnect( | ||
198 | VOID | ||
199 | ) | ||
200 | { | ||
201 | int ret=0; | ||
202 | VMBUS_CHANNEL_UNLOAD *msg; | ||
203 | |||
204 | DPRINT_ENTER(VMBUS); | ||
205 | |||
206 | // Make sure we are connected | ||
207 | if (gVmbusConnection.ConnectState != Connected) | ||
208 | return -1; | ||
209 | |||
210 | msg = MemAllocZeroed(sizeof(VMBUS_CHANNEL_UNLOAD)); | ||
211 | |||
212 | msg->MessageType = ChannelMessageUnload; | ||
213 | |||
214 | ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD)); | ||
215 | |||
216 | if (ret != 0) | ||
217 | { | ||
218 | goto Cleanup; | ||
219 | } | ||
220 | |||
221 | PageFree(gVmbusConnection.InterruptPage, 1); | ||
222 | |||
223 | // TODO: iterate thru the msg list and free up | ||
224 | |||
225 | SpinlockClose(gVmbusConnection.ChannelMsgLock); | ||
226 | |||
227 | WorkQueueClose(gVmbusConnection.WorkQueue); | ||
228 | |||
229 | gVmbusConnection.ConnectState = Disconnected; | ||
230 | |||
231 | DPRINT_INFO(VMBUS, "Vmbus disconnected!!"); | ||
232 | |||
233 | Cleanup: | ||
234 | if (msg) | ||
235 | { | ||
236 | MemFree(msg); | ||
237 | } | ||
238 | |||
239 | DPRINT_EXIT(VMBUS); | ||
240 | |||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | |||
245 | /*++ | ||
246 | |||
247 | Name: | ||
248 | GetChannelFromRelId() | ||
249 | |||
250 | Description: | ||
251 | Get the channel object given its child relative id (ie channel id) | ||
252 | |||
253 | --*/ | ||
254 | VMBUS_CHANNEL* | ||
255 | GetChannelFromRelId( | ||
256 | UINT32 relId | ||
257 | ) | ||
258 | { | ||
259 | VMBUS_CHANNEL* channel; | ||
260 | VMBUS_CHANNEL* foundChannel=NULL; | ||
261 | LIST_ENTRY* anchor; | ||
262 | LIST_ENTRY* curr; | ||
263 | |||
264 | SpinlockAcquire(gVmbusConnection.ChannelLock); | ||
265 | ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList) | ||
266 | { | ||
267 | channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry); | ||
268 | |||
269 | if (channel->OfferMsg.ChildRelId == relId) | ||
270 | { | ||
271 | foundChannel = channel; | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | SpinlockRelease(gVmbusConnection.ChannelLock); | ||
276 | |||
277 | return foundChannel; | ||
278 | } | ||
279 | |||
280 | |||
281 | |||
282 | /*++ | ||
283 | |||
284 | Name: | ||
285 | VmbusProcessChannelEvent() | ||
286 | |||
287 | Description: | ||
288 | Process a channel event notification | ||
289 | |||
290 | --*/ | ||
291 | static void | ||
292 | VmbusProcessChannelEvent( | ||
293 | PVOID context | ||
294 | ) | ||
295 | { | ||
296 | VMBUS_CHANNEL* channel; | ||
297 | UINT32 relId = (UINT32)(ULONG_PTR)context; | ||
298 | |||
299 | ASSERT(relId > 0); | ||
300 | |||
301 | // Find the channel based on this relid and invokes | ||
302 | // the channel callback to process the event | ||
303 | channel = GetChannelFromRelId(relId); | ||
304 | |||
305 | if (channel) | ||
306 | { | ||
307 | VmbusChannelOnChannelEvent(channel); | ||
308 | //WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel); | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | |||
317 | /*++ | ||
318 | |||
319 | Name: | ||
320 | VmbusOnEvents() | ||
321 | |||
322 | Description: | ||
323 | Handler for events | ||
324 | |||
325 | --*/ | ||
326 | VOID | ||
327 | VmbusOnEvents( | ||
328 | VOID | ||
329 | ) | ||
330 | { | ||
331 | int dword; | ||
332 | //int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes | ||
333 | int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; | ||
334 | int bit; | ||
335 | int relid; | ||
336 | UINT32* recvInterruptPage = gVmbusConnection.RecvInterruptPage; | ||
337 | //VMBUS_CHANNEL_MESSAGE* receiveMsg; | ||
338 | |||
339 | DPRINT_ENTER(VMBUS); | ||
340 | |||
341 | // Check events | ||
342 | if (recvInterruptPage) | ||
343 | { | ||
344 | for (dword = 0; dword < maxdword; dword++) | ||
345 | { | ||
346 | if (recvInterruptPage[dword]) | ||
347 | { | ||
348 | for (bit = 0; bit < 32; bit++) | ||
349 | { | ||
350 | if (BitTestAndClear(&recvInterruptPage[dword], bit)) | ||
351 | { | ||
352 | relid = (dword << 5) + bit; | ||
353 | |||
354 | DPRINT_DBG(VMBUS, "event detected for relid - %d", relid); | ||
355 | |||
356 | if (relid == 0) // special case - vmbus channel protocol msg | ||
357 | { | ||
358 | DPRINT_DBG(VMBUS, "invalid relid - %d", relid); | ||
359 | |||
360 | continue; } | ||
361 | else | ||
362 | { | ||
363 | //QueueWorkItem(VmbusProcessEvent, (void*)relid); | ||
364 | //ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); | ||
365 | VmbusProcessChannelEvent((void*)(ULONG_PTR)relid); | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | DPRINT_EXIT(VMBUS); | ||
373 | |||
374 | return; | ||
375 | } | ||
376 | |||
377 | /*++ | ||
378 | |||
379 | Name: | ||
380 | VmbusPostMessage() | ||
381 | |||
382 | Description: | ||
383 | Send a msg on the vmbus's message connection | ||
384 | |||
385 | --*/ | ||
386 | int | ||
387 | VmbusPostMessage( | ||
388 | PVOID buffer, | ||
389 | SIZE_T bufferLen | ||
390 | ) | ||
391 | { | ||
392 | int ret=0; | ||
393 | HV_CONNECTION_ID connId; | ||
394 | |||
395 | |||
396 | connId.AsUINT32 =0; | ||
397 | connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID; | ||
398 | ret = HvPostMessage( | ||
399 | connId, | ||
400 | 1, | ||
401 | buffer, | ||
402 | bufferLen); | ||
403 | |||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | /*++ | ||
408 | |||
409 | Name: | ||
410 | VmbusSetEvent() | ||
411 | |||
412 | Description: | ||
413 | Send an event notification to the parent | ||
414 | |||
415 | --*/ | ||
416 | int | ||
417 | VmbusSetEvent(UINT32 childRelId) | ||
418 | { | ||
419 | int ret=0; | ||
420 | |||
421 | DPRINT_ENTER(VMBUS); | ||
422 | |||
423 | // Each UINT32 represents 32 channels | ||
424 | BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31); | ||
425 | ret = HvSignalEvent(); | ||
426 | |||
427 | DPRINT_EXIT(VMBUS); | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | // EOF | ||
diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c new file mode 100644 index 00000000000..7aec8c94b2e --- /dev/null +++ b/drivers/staging/hv/Hv.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include "logging.h" | ||
26 | #include "VmbusPrivate.h" | ||
27 | |||
28 | // | ||
29 | // Globals | ||
30 | // | ||
31 | |||
32 | // The one and only | ||
33 | HV_CONTEXT gHvContext={ | ||
34 | .SynICInitialized = FALSE, | ||
35 | .HypercallPage = NULL, | ||
36 | .SignalEventParam = NULL, | ||
37 | .SignalEventBuffer = NULL, | ||
38 | }; | ||
39 | |||
40 | |||
41 | /*++ | ||
42 | |||
43 | Name: | ||
44 | HvQueryHypervisorPresence() | ||
45 | |||
46 | Description: | ||
47 | Query the cpuid for presense of windows hypervisor | ||
48 | |||
49 | --*/ | ||
50 | static int | ||
51 | HvQueryHypervisorPresence ( | ||
52 | void | ||
53 | ) | ||
54 | { | ||
55 | unsigned int eax; | ||
56 | unsigned int ebx; | ||
57 | unsigned int ecx; | ||
58 | unsigned int edx; | ||
59 | unsigned int op; | ||
60 | |||
61 | eax = 0; | ||
62 | ebx = 0; | ||
63 | ecx = 0; | ||
64 | edx = 0; | ||
65 | op = HvCpuIdFunctionVersionAndFeatures; | ||
66 | do_cpuid(op, &eax, &ebx, &ecx, &edx); | ||
67 | |||
68 | return (ecx & HV_PRESENT_BIT); | ||
69 | } | ||
70 | |||
71 | |||
72 | /*++ | ||
73 | |||
74 | Name: | ||
75 | HvQueryHypervisorInfo() | ||
76 | |||
77 | Description: | ||
78 | Get version info of the windows hypervisor | ||
79 | |||
80 | --*/ | ||
81 | static int | ||
82 | HvQueryHypervisorInfo ( | ||
83 | void | ||
84 | ) | ||
85 | { | ||
86 | unsigned int eax; | ||
87 | unsigned int ebx; | ||
88 | unsigned int ecx; | ||
89 | unsigned int edx; | ||
90 | unsigned int maxLeaf; | ||
91 | unsigned int op; | ||
92 | |||
93 | // | ||
94 | // Its assumed that this is called after confirming that Viridian is present. | ||
95 | // Query id and revision. | ||
96 | // | ||
97 | |||
98 | eax = 0; | ||
99 | ebx = 0; | ||
100 | ecx = 0; | ||
101 | edx = 0; | ||
102 | op = HvCpuIdFunctionHvVendorAndMaxFunction; | ||
103 | do_cpuid(op, &eax, &ebx, &ecx, &edx); | ||
104 | |||
105 | DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c", | ||
106 | (ebx & 0xFF), | ||
107 | ((ebx >> 8) & 0xFF), | ||
108 | ((ebx >> 16) & 0xFF), | ||
109 | ((ebx >> 24) & 0xFF), | ||
110 | (ecx & 0xFF), | ||
111 | ((ecx >> 8) & 0xFF), | ||
112 | ((ecx >> 16) & 0xFF), | ||
113 | ((ecx >> 24) & 0xFF), | ||
114 | (edx & 0xFF), | ||
115 | ((edx >> 8) & 0xFF), | ||
116 | ((edx >> 16) & 0xFF), | ||
117 | ((edx >> 24) & 0xFF)); | ||
118 | |||
119 | maxLeaf = eax; | ||
120 | eax = 0; | ||
121 | ebx = 0; | ||
122 | ecx = 0; | ||
123 | edx = 0; | ||
124 | op = HvCpuIdFunctionHvInterface; | ||
125 | do_cpuid(op, &eax, &ebx, &ecx, &edx); | ||
126 | |||
127 | DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c", | ||
128 | (eax & 0xFF), | ||
129 | ((eax >> 8) & 0xFF), | ||
130 | ((eax >> 16) & 0xFF), | ||
131 | ((eax >> 24) & 0xFF)); | ||
132 | |||
133 | if (maxLeaf >= HvCpuIdFunctionMsHvVersion) { | ||
134 | eax = 0; | ||
135 | ebx = 0; | ||
136 | ecx = 0; | ||
137 | edx = 0; | ||
138 | op = HvCpuIdFunctionMsHvVersion; | ||
139 | do_cpuid(op, &eax, &ebx, &ecx, &edx); | ||
140 | DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d", | ||
141 | eax, | ||
142 | ebx >> 16, | ||
143 | ebx & 0xFFFF, | ||
144 | ecx, | ||
145 | edx >> 24, | ||
146 | edx & 0xFFFFFF); | ||
147 | } | ||
148 | return maxLeaf; | ||
149 | } | ||
150 | |||
151 | |||
152 | /*++ | ||
153 | |||
154 | Name: | ||
155 | HvDoHypercall() | ||
156 | |||
157 | Description: | ||
158 | Invoke the specified hypercall | ||
159 | |||
160 | --*/ | ||
161 | static UINT64 | ||
162 | HvDoHypercall ( | ||
163 | UINT64 Control, | ||
164 | void* Input, | ||
165 | void* Output | ||
166 | ) | ||
167 | { | ||
168 | #ifdef x86_64 | ||
169 | UINT64 hvStatus=0; | ||
170 | UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0; | ||
171 | UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0; | ||
172 | volatile void* hypercallPage = gHvContext.HypercallPage; | ||
173 | |||
174 | DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>", | ||
175 | Control, | ||
176 | inputAddress, | ||
177 | Input, | ||
178 | outputAddress, | ||
179 | Output, | ||
180 | hypercallPage); | ||
181 | |||
182 | __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8"); | ||
183 | __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage)); | ||
184 | |||
185 | DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus); | ||
186 | |||
187 | return hvStatus; | ||
188 | |||
189 | #else | ||
190 | |||
191 | UINT32 controlHi = Control >> 32; | ||
192 | UINT32 controlLo = Control & 0xFFFFFFFF; | ||
193 | UINT32 hvStatusHi = 1; | ||
194 | UINT32 hvStatusLo = 1; | ||
195 | UINT64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0; | ||
196 | UINT32 inputAddressHi = inputAddress >> 32; | ||
197 | UINT32 inputAddressLo = inputAddress & 0xFFFFFFFF; | ||
198 | UINT64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0; | ||
199 | UINT32 outputAddressHi = outputAddress >> 32; | ||
200 | UINT32 outputAddressLo = outputAddress & 0xFFFFFFFF; | ||
201 | volatile void* hypercallPage = gHvContext.HypercallPage; | ||
202 | |||
203 | DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>", | ||
204 | Control, | ||
205 | Input, | ||
206 | Output); | ||
207 | |||
208 | __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage)); | ||
209 | |||
210 | |||
211 | DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((UINT64)hvStatusHi << 32)); | ||
212 | |||
213 | return (hvStatusLo | ((UINT64)hvStatusHi << 32)); | ||
214 | #endif // x86_64 | ||
215 | } | ||
216 | |||
217 | /*++ | ||
218 | |||
219 | Name: | ||
220 | HvInit() | ||
221 | |||
222 | Description: | ||
223 | Main initialization routine. This routine must be called | ||
224 | before any other routines in here are called | ||
225 | |||
226 | --*/ | ||
227 | static int | ||
228 | HvInit ( | ||
229 | void | ||
230 | ) | ||
231 | { | ||
232 | int ret=0; | ||
233 | int maxLeaf; | ||
234 | HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; | ||
235 | void* virtAddr=0; | ||
236 | ULONG_PTR physAddr=0; | ||
237 | |||
238 | DPRINT_ENTER(VMBUS); | ||
239 | |||
240 | memset(gHvContext.synICEventPage, 0, sizeof(HANDLE)*MAX_NUM_CPUS); | ||
241 | memset(gHvContext.synICMessagePage, 0, sizeof(HANDLE)*MAX_NUM_CPUS); | ||
242 | |||
243 | if (!HvQueryHypervisorPresence()) | ||
244 | { | ||
245 | DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!"); | ||
246 | goto Cleanup; | ||
247 | } | ||
248 | |||
249 | DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info..."); | ||
250 | |||
251 | maxLeaf = HvQueryHypervisorInfo(); | ||
252 | //HvQueryHypervisorFeatures(maxLeaf); | ||
253 | |||
254 | // Determine if we are running on xenlinux (ie x2v shim) or native linux | ||
255 | gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID); | ||
256 | |||
257 | if (gHvContext.GuestId == 0) | ||
258 | { | ||
259 | // Write our OS info | ||
260 | WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); | ||
261 | |||
262 | gHvContext.GuestId = HV_LINUX_GUEST_ID; | ||
263 | } | ||
264 | |||
265 | // See if the hypercall page is already set | ||
266 | hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); | ||
267 | |||
268 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | ||
269 | { | ||
270 | // Allocate the hypercall page memory | ||
271 | //virtAddr = PageAlloc(1); | ||
272 | virtAddr = VirtualAllocExec(PAGE_SIZE); | ||
273 | |||
274 | if (!virtAddr) | ||
275 | { | ||
276 | DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!"); | ||
277 | goto Cleanup; | ||
278 | } | ||
279 | |||
280 | hypercallMsr.Enable = 1; | ||
281 | //hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT; | ||
282 | hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT; | ||
283 | WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | ||
284 | |||
285 | // Confirm that hypercall page did get setup. | ||
286 | hypercallMsr.AsUINT64 = 0; | ||
287 | hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); | ||
288 | |||
289 | if (!hypercallMsr.Enable) | ||
290 | { | ||
291 | DPRINT_ERR(VMBUS, "unable to set hypercall page!!"); | ||
292 | goto Cleanup; | ||
293 | } | ||
294 | |||
295 | gHvContext.HypercallPage = virtAddr; | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId); | ||
300 | goto Cleanup; | ||
301 | } | ||
302 | |||
303 | DPRINT_INFO(VMBUS, "Hypercall page VA=0x%08x, PA=0x%08x", | ||
304 | (unsigned long)gHvContext.HypercallPage, | ||
305 | (unsigned long)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT); | ||
306 | |||
307 | // Setup the global signal event param for the signal event hypercall | ||
308 | gHvContext.SignalEventBuffer = MemAlloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER)); | ||
309 | if (!gHvContext.SignalEventBuffer) | ||
310 | { | ||
311 | goto Cleanup; | ||
312 | } | ||
313 | |||
314 | gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((ULONG_PTR)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN)); | ||
315 | gHvContext.SignalEventParam->ConnectionId.AsUINT32 = 0; | ||
316 | gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID; | ||
317 | gHvContext.SignalEventParam->FlagNumber = 0; | ||
318 | gHvContext.SignalEventParam->RsvdZ = 0; | ||
319 | |||
320 | //DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); | ||
321 | |||
322 | DPRINT_EXIT(VMBUS); | ||
323 | |||
324 | return ret; | ||
325 | |||
326 | Cleanup: | ||
327 | if (virtAddr) | ||
328 | { | ||
329 | if (hypercallMsr.Enable) | ||
330 | { | ||
331 | hypercallMsr.AsUINT64 = 0; | ||
332 | WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | ||
333 | } | ||
334 | |||
335 | VirtualFree(virtAddr); | ||
336 | } | ||
337 | ret = -1; | ||
338 | DPRINT_EXIT(VMBUS); | ||
339 | |||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | |||
344 | /*++ | ||
345 | |||
346 | Name: | ||
347 | HvCleanup() | ||
348 | |||
349 | Description: | ||
350 | Cleanup routine. This routine is called normally during driver unloading or exiting. | ||
351 | |||
352 | --*/ | ||
353 | void | ||
354 | HvCleanup ( | ||
355 | void | ||
356 | ) | ||
357 | { | ||
358 | HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; | ||
359 | |||
360 | DPRINT_ENTER(VMBUS); | ||
361 | |||
362 | if (gHvContext.SignalEventBuffer) | ||
363 | { | ||
364 | MemFree(gHvContext.SignalEventBuffer); | ||
365 | gHvContext.SignalEventBuffer = NULL; | ||
366 | gHvContext.SignalEventParam = NULL; | ||
367 | } | ||
368 | |||
369 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | ||
370 | { | ||
371 | if (gHvContext.HypercallPage) | ||
372 | { | ||
373 | hypercallMsr.AsUINT64 = 0; | ||
374 | WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | ||
375 | VirtualFree(gHvContext.HypercallPage); | ||
376 | gHvContext.HypercallPage = NULL; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | DPRINT_EXIT(VMBUS); | ||
381 | |||
382 | } | ||
383 | |||
384 | |||
385 | /*++ | ||
386 | |||
387 | Name: | ||
388 | HvPostMessage() | ||
389 | |||
390 | Description: | ||
391 | Post a message using the hypervisor message IPC. This | ||
392 | involves a hypercall. | ||
393 | |||
394 | --*/ | ||
395 | HV_STATUS | ||
396 | HvPostMessage( | ||
397 | HV_CONNECTION_ID connectionId, | ||
398 | HV_MESSAGE_TYPE messageType, | ||
399 | PVOID payload, | ||
400 | SIZE_T payloadSize | ||
401 | ) | ||
402 | { | ||
403 | struct alignedInput { | ||
404 | UINT64 alignment8; | ||
405 | HV_INPUT_POST_MESSAGE msg; | ||
406 | }; | ||
407 | |||
408 | PHV_INPUT_POST_MESSAGE alignedMsg; | ||
409 | HV_STATUS status; | ||
410 | ULONG_PTR addr; | ||
411 | |||
412 | if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT) | ||
413 | { | ||
414 | return -1; | ||
415 | } | ||
416 | |||
417 | addr = (ULONG_PTR)MemAllocAtomic(sizeof(struct alignedInput)); | ||
418 | |||
419 | if (!addr) | ||
420 | { | ||
421 | return -1; | ||
422 | } | ||
423 | |||
424 | alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN)); | ||
425 | |||
426 | alignedMsg->ConnectionId = connectionId; | ||
427 | alignedMsg->MessageType = messageType; | ||
428 | alignedMsg->PayloadSize = payloadSize; | ||
429 | memcpy((void*)alignedMsg->Payload, payload, payloadSize); | ||
430 | |||
431 | status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF; | ||
432 | |||
433 | MemFree((void*)addr); | ||
434 | |||
435 | return status; | ||
436 | } | ||
437 | |||
438 | |||
439 | /*++ | ||
440 | |||
441 | Name: | ||
442 | HvSignalEvent() | ||
443 | |||
444 | Description: | ||
445 | Signal an event on the specified connection using the hypervisor event IPC. This | ||
446 | involves a hypercall. | ||
447 | |||
448 | --*/ | ||
449 | HV_STATUS | ||
450 | HvSignalEvent( | ||
451 | ) | ||
452 | { | ||
453 | HV_STATUS status; | ||
454 | |||
455 | status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF; | ||
456 | |||
457 | return status; | ||
458 | } | ||
459 | |||
460 | |||
461 | /*++ | ||
462 | |||
463 | Name: | ||
464 | HvSynicInit() | ||
465 | |||
466 | Description: | ||
467 | Initialize the Synthethic Interrupt Controller. If it is already initialized by | ||
468 | another entity (ie x2v shim), we need to retrieve the initialized message and event pages. | ||
469 | Otherwise, we create and initialize the message and event pages. | ||
470 | |||
471 | --*/ | ||
472 | int | ||
473 | HvSynicInit ( | ||
474 | UINT32 irqVector | ||
475 | ) | ||
476 | { | ||
477 | UINT64 version; | ||
478 | HV_SYNIC_SIMP simp; | ||
479 | HV_SYNIC_SIEFP siefp; | ||
480 | HV_SYNIC_SINT sharedSint; | ||
481 | HV_SYNIC_SCONTROL sctrl; | ||
482 | UINT64 guestID; | ||
483 | int ret=0; | ||
484 | |||
485 | DPRINT_ENTER(VMBUS); | ||
486 | |||
487 | if (!gHvContext.HypercallPage) | ||
488 | { | ||
489 | DPRINT_EXIT(VMBUS); | ||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | // Check the version | ||
494 | version = ReadMsr(HV_X64_MSR_SVERSION); | ||
495 | |||
496 | DPRINT_INFO(VMBUS, "SynIC version: %llx", version); | ||
497 | |||
498 | // TODO: Handle SMP | ||
499 | if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID) | ||
500 | { | ||
501 | DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set."); | ||
502 | |||
503 | simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | ||
504 | siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | ||
505 | |||
506 | DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64); | ||
507 | |||
508 | // Determine if we are running on xenlinux (ie x2v shim) or native linux | ||
509 | guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID); | ||
510 | |||
511 | if (guestID == HV_LINUX_GUEST_ID) | ||
512 | { | ||
513 | gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT); | ||
514 | gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT); | ||
515 | } | ||
516 | else | ||
517 | { | ||
518 | DPRINT_ERR(VMBUS, "unknown guest id!!"); | ||
519 | goto Cleanup; | ||
520 | } | ||
521 | DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]); | ||
522 | } | ||
523 | else | ||
524 | { | ||
525 | gHvContext.synICMessagePage[0] = PageAlloc(1); | ||
526 | if (gHvContext.synICMessagePage[0] == NULL) | ||
527 | { | ||
528 | DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!"); | ||
529 | goto Cleanup; | ||
530 | } | ||
531 | |||
532 | gHvContext.synICEventPage[0] = PageAlloc(1); | ||
533 | if (gHvContext.synICEventPage[0] == NULL) | ||
534 | { | ||
535 | DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!"); | ||
536 | goto Cleanup; | ||
537 | } | ||
538 | |||
539 | // | ||
540 | // Setup the Synic's message page | ||
541 | // | ||
542 | simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | ||
543 | simp.SimpEnabled = 1; | ||
544 | simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT; | ||
545 | |||
546 | DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64); | ||
547 | |||
548 | WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64); | ||
549 | |||
550 | // | ||
551 | // Setup the Synic's event page | ||
552 | // | ||
553 | siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | ||
554 | siefp.SiefpEnabled = 1; | ||
555 | siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT; | ||
556 | |||
557 | DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64); | ||
558 | |||
559 | WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64); | ||
560 | } | ||
561 | // | ||
562 | // Setup the interception SINT. | ||
563 | // | ||
564 | //WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), | ||
565 | // interceptionSint.AsUINT64); | ||
566 | |||
567 | // | ||
568 | // Setup the shared SINT. | ||
569 | // | ||
570 | sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); | ||
571 | |||
572 | sharedSint.AsUINT64 = 0; | ||
573 | sharedSint.Vector = irqVector; //HV_SHARED_SINT_IDT_VECTOR + 0x20; | ||
574 | sharedSint.Masked = FALSE; | ||
575 | sharedSint.AutoEoi = TRUE; | ||
576 | |||
577 | DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64); | ||
578 | |||
579 | WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); | ||
580 | |||
581 | // Enable the global synic bit | ||
582 | sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL); | ||
583 | sctrl.Enable = 1; | ||
584 | |||
585 | WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64); | ||
586 | |||
587 | gHvContext.SynICInitialized = TRUE; | ||
588 | |||
589 | DPRINT_EXIT(VMBUS); | ||
590 | |||
591 | return ret; | ||
592 | |||
593 | Cleanup: | ||
594 | ret = -1; | ||
595 | |||
596 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | ||
597 | { | ||
598 | if (gHvContext.synICEventPage[0]) | ||
599 | { | ||
600 | PageFree(gHvContext.synICEventPage[0],1); | ||
601 | } | ||
602 | |||
603 | if (gHvContext.synICMessagePage[0]) | ||
604 | { | ||
605 | PageFree(gHvContext.synICMessagePage[0], 1); | ||
606 | } | ||
607 | } | ||
608 | |||
609 | DPRINT_EXIT(VMBUS); | ||
610 | |||
611 | return ret; | ||
612 | |||
613 | } | ||
614 | |||
615 | /*++ | ||
616 | |||
617 | Name: | ||
618 | HvSynicCleanup() | ||
619 | |||
620 | Description: | ||
621 | Cleanup routine for HvSynicInit(). | ||
622 | |||
623 | --*/ | ||
624 | VOID | ||
625 | HvSynicCleanup( | ||
626 | VOID | ||
627 | ) | ||
628 | { | ||
629 | HV_SYNIC_SINT sharedSint; | ||
630 | HV_SYNIC_SIMP simp; | ||
631 | HV_SYNIC_SIEFP siefp; | ||
632 | |||
633 | DPRINT_ENTER(VMBUS); | ||
634 | |||
635 | if (!gHvContext.SynICInitialized) | ||
636 | { | ||
637 | DPRINT_EXIT(VMBUS); | ||
638 | return; | ||
639 | } | ||
640 | |||
641 | sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); | ||
642 | |||
643 | sharedSint.Masked = 1; | ||
644 | |||
645 | // Disable the interrupt | ||
646 | WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); | ||
647 | |||
648 | // Disable and free the resources only if we are running as native linux | ||
649 | // since in xenlinux, we are sharing the resources with the x2v shim | ||
650 | if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | ||
651 | { | ||
652 | simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | ||
653 | simp.SimpEnabled = 0; | ||
654 | simp.BaseSimpGpa = 0; | ||
655 | |||
656 | WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64); | ||
657 | |||
658 | siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | ||
659 | siefp.SiefpEnabled = 0; | ||
660 | siefp.BaseSiefpGpa = 0; | ||
661 | |||
662 | WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64); | ||
663 | |||
664 | PageFree(gHvContext.synICMessagePage[0], 1); | ||
665 | PageFree(gHvContext.synICEventPage[0], 1); | ||
666 | } | ||
667 | |||
668 | DPRINT_EXIT(VMBUS); | ||
669 | } | ||
670 | |||
671 | |||
672 | // eof | ||
diff --git a/drivers/staging/hv/Hv.h b/drivers/staging/hv/Hv.h new file mode 100644 index 00000000000..cbc77d2d086 --- /dev/null +++ b/drivers/staging/hv/Hv.h | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #ifndef __HV_H__ | ||
26 | #define __HV_H__ | ||
27 | |||
28 | #include "osd.h" | ||
29 | |||
30 | #include "HvTypes.h" | ||
31 | #include "HvStatus.h" | ||
32 | //#include "HvVmApi.h" | ||
33 | //#include "HvKeApi.h" | ||
34 | //#include "HvMmApi.h" | ||
35 | //#include "HvCpuApi.h" | ||
36 | #include "HvHalApi.h" | ||
37 | #include "HvVpApi.h" | ||
38 | //#include "HvTrApi.h" | ||
39 | #include "HvSynicApi.h" | ||
40 | //#include "HvAmApi.h" | ||
41 | //#include "HvHkApi.h" | ||
42 | //#include "HvValApi.h" | ||
43 | #include "HvHcApi.h" | ||
44 | #include "HvPtApi.h" | ||
45 | |||
46 | enum | ||
47 | { | ||
48 | VMBUS_MESSAGE_CONNECTION_ID = 1, | ||
49 | VMBUS_MESSAGE_PORT_ID = 1, | ||
50 | VMBUS_EVENT_CONNECTION_ID = 2, | ||
51 | VMBUS_EVENT_PORT_ID = 2, | ||
52 | VMBUS_MONITOR_CONNECTION_ID = 3, | ||
53 | VMBUS_MONITOR_PORT_ID = 3, | ||
54 | VMBUS_MESSAGE_SINT = 2 | ||
55 | }; | ||
56 | // | ||
57 | // #defines | ||
58 | // | ||
59 | #define HV_PRESENT_BIT 0x80000000 | ||
60 | |||
61 | #define HV_XENLINUX_GUEST_ID_LO 0x00000000 | ||
62 | #define HV_XENLINUX_GUEST_ID_HI 0x0B00B135 | ||
63 | #define HV_XENLINUX_GUEST_ID (((UINT64)HV_XENLINUX_GUEST_ID_HI << 32) | HV_XENLINUX_GUEST_ID_LO) | ||
64 | |||
65 | #define HV_LINUX_GUEST_ID_LO 0x00000000 | ||
66 | #define HV_LINUX_GUEST_ID_HI 0xB16B00B5 | ||
67 | #define HV_LINUX_GUEST_ID (((UINT64)HV_LINUX_GUEST_ID_HI << 32) | HV_LINUX_GUEST_ID_LO) | ||
68 | |||
69 | #define HV_CPU_POWER_MANAGEMENT (1 << 0) | ||
70 | #define HV_RECOMMENDATIONS_MAX 4 | ||
71 | |||
72 | #define HV_X64_MAX 5 | ||
73 | #define HV_CAPS_MAX 8 | ||
74 | |||
75 | |||
76 | #define HV_HYPERCALL_PARAM_ALIGN sizeof(UINT64) | ||
77 | |||
78 | // | ||
79 | // Service definitions | ||
80 | // | ||
81 | #define HV_SERVICE_PARENT_PORT (0) | ||
82 | #define HV_SERVICE_PARENT_CONNECTION (0) | ||
83 | |||
84 | #define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0) | ||
85 | #define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1) | ||
86 | #define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2) | ||
87 | #define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3) | ||
88 | |||
89 | #define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1) | ||
90 | #define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2) | ||
91 | #define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3) | ||
92 | #define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4) | ||
93 | #define HV_SERVICE_MAX_MESSAGE_ID (4) | ||
94 | |||
95 | #define HV_SERVICE_PROTOCOL_VERSION (0x0010) | ||
96 | #define HV_CONNECT_PAYLOAD_BYTE_COUNT 64 | ||
97 | |||
98 | //#define VMBUS_REVISION_NUMBER 6 | ||
99 | //#define VMBUS_PORT_ID 11 // Our local vmbus's port and connection id. Anything >0 is fine | ||
100 | |||
101 | // 628180B8-308D-4c5e-B7DB-1BEB62E62EF4 | ||
102 | static const GUID VMBUS_SERVICE_ID = {.Data = {0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c, 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4} }; | ||
103 | |||
104 | #define MAX_NUM_CPUS 1 | ||
105 | |||
106 | |||
107 | typedef struct { | ||
108 | UINT64 Align8; | ||
109 | HV_INPUT_SIGNAL_EVENT Event; | ||
110 | } HV_INPUT_SIGNAL_EVENT_BUFFER; | ||
111 | |||
112 | typedef struct { | ||
113 | UINT64 GuestId; // XenLinux or native Linux. If XenLinux, the hypercall and synic pages has already been initialized | ||
114 | void* HypercallPage; | ||
115 | |||
116 | BOOL SynICInitialized; | ||
117 | // This is used as an input param to HvCallSignalEvent hypercall. The input param is immutable | ||
118 | // in our usage and must be dynamic mem (vs stack or global). | ||
119 | HV_INPUT_SIGNAL_EVENT_BUFFER *SignalEventBuffer; | ||
120 | HV_INPUT_SIGNAL_EVENT *SignalEventParam; // 8-bytes aligned of the buffer above | ||
121 | |||
122 | HANDLE synICMessagePage[MAX_NUM_CPUS]; | ||
123 | HANDLE synICEventPage[MAX_NUM_CPUS]; | ||
124 | } HV_CONTEXT; | ||
125 | |||
126 | extern HV_CONTEXT gHvContext; | ||
127 | |||
128 | |||
129 | // | ||
130 | // Inline routines | ||
131 | // | ||
132 | static inline unsigned long long ReadMsr(int msr) | ||
133 | { | ||
134 | unsigned long long val; | ||
135 | |||
136 | RDMSR(msr, val); | ||
137 | |||
138 | return val; | ||
139 | } | ||
140 | |||
141 | static inline void WriteMsr(int msr, UINT64 val) | ||
142 | { | ||
143 | WRMSR(msr, val); | ||
144 | |||
145 | return; | ||
146 | } | ||
147 | |||
148 | // | ||
149 | // Hv Interface | ||
150 | // | ||
151 | INTERNAL int | ||
152 | HvInit( | ||
153 | VOID | ||
154 | ); | ||
155 | |||
156 | INTERNAL VOID | ||
157 | HvCleanup( | ||
158 | VOID | ||
159 | ); | ||
160 | |||
161 | INTERNAL HV_STATUS | ||
162 | HvPostMessage( | ||
163 | HV_CONNECTION_ID connectionId, | ||
164 | HV_MESSAGE_TYPE messageType, | ||
165 | PVOID payload, | ||
166 | SIZE_T payloadSize | ||
167 | ); | ||
168 | |||
169 | INTERNAL HV_STATUS | ||
170 | HvSignalEvent( | ||
171 | VOID | ||
172 | ); | ||
173 | |||
174 | INTERNAL int | ||
175 | HvSynicInit( | ||
176 | UINT32 irqVector | ||
177 | ); | ||
178 | |||
179 | INTERNAL VOID | ||
180 | HvSynicCleanup( | ||
181 | VOID | ||
182 | ); | ||
183 | |||
184 | #endif // __HV_H__ | ||
diff --git a/drivers/staging/hv/RingBuffer.c b/drivers/staging/hv/RingBuffer.c new file mode 100644 index 00000000000..57d944e883b --- /dev/null +++ b/drivers/staging/hv/RingBuffer.c | |||
@@ -0,0 +1,630 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include "logging.h" | ||
26 | #include "RingBuffer.h" | ||
27 | |||
28 | // | ||
29 | // #defines | ||
30 | // | ||
31 | |||
32 | // Amount of space to write to | ||
33 | #define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w)) | ||
34 | |||
35 | |||
36 | /*++ | ||
37 | |||
38 | Name: | ||
39 | GetRingBufferAvailBytes() | ||
40 | |||
41 | Description: | ||
42 | Get number of bytes available to read and to write to | ||
43 | for the specified ring buffer | ||
44 | |||
45 | --*/ | ||
46 | static inline void | ||
47 | GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, UINT32 *read, UINT32 *write) | ||
48 | { | ||
49 | UINT32 read_loc,write_loc; | ||
50 | |||
51 | // Capture the read/write indices before they changed | ||
52 | read_loc = rbi->RingBuffer->ReadIndex; | ||
53 | write_loc = rbi->RingBuffer->WriteIndex; | ||
54 | |||
55 | *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize); | ||
56 | *read = rbi->RingDataSize - *write; | ||
57 | } | ||
58 | |||
59 | /*++ | ||
60 | |||
61 | Name: | ||
62 | GetNextWriteLocation() | ||
63 | |||
64 | Description: | ||
65 | Get the next write location for the specified ring buffer | ||
66 | |||
67 | --*/ | ||
68 | static inline UINT32 | ||
69 | GetNextWriteLocation(RING_BUFFER_INFO* RingInfo) | ||
70 | { | ||
71 | UINT32 next = RingInfo->RingBuffer->WriteIndex; | ||
72 | |||
73 | ASSERT(next < RingInfo->RingDataSize); | ||
74 | |||
75 | return next; | ||
76 | } | ||
77 | |||
78 | /*++ | ||
79 | |||
80 | Name: | ||
81 | SetNextWriteLocation() | ||
82 | |||
83 | Description: | ||
84 | Set the next write location for the specified ring buffer | ||
85 | |||
86 | --*/ | ||
87 | static inline void | ||
88 | SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextWriteLocation) | ||
89 | { | ||
90 | RingInfo->RingBuffer->WriteIndex = NextWriteLocation; | ||
91 | } | ||
92 | |||
93 | /*++ | ||
94 | |||
95 | Name: | ||
96 | GetNextReadLocation() | ||
97 | |||
98 | Description: | ||
99 | Get the next read location for the specified ring buffer | ||
100 | |||
101 | --*/ | ||
102 | static inline UINT32 | ||
103 | GetNextReadLocation(RING_BUFFER_INFO* RingInfo) | ||
104 | { | ||
105 | UINT32 next = RingInfo->RingBuffer->ReadIndex; | ||
106 | |||
107 | ASSERT(next < RingInfo->RingDataSize); | ||
108 | |||
109 | return next; | ||
110 | } | ||
111 | |||
112 | /*++ | ||
113 | |||
114 | Name: | ||
115 | GetNextReadLocationWithOffset() | ||
116 | |||
117 | Description: | ||
118 | Get the next read location + offset for the specified ring buffer. | ||
119 | This allows the caller to skip | ||
120 | |||
121 | --*/ | ||
122 | static inline UINT32 | ||
123 | GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, UINT32 Offset) | ||
124 | { | ||
125 | UINT32 next = RingInfo->RingBuffer->ReadIndex; | ||
126 | |||
127 | ASSERT(next < RingInfo->RingDataSize); | ||
128 | next += Offset; | ||
129 | next %= RingInfo->RingDataSize; | ||
130 | |||
131 | return next; | ||
132 | } | ||
133 | |||
134 | /*++ | ||
135 | |||
136 | Name: | ||
137 | SetNextReadLocation() | ||
138 | |||
139 | Description: | ||
140 | Set the next read location for the specified ring buffer | ||
141 | |||
142 | --*/ | ||
143 | static inline void | ||
144 | SetNextReadLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextReadLocation) | ||
145 | { | ||
146 | RingInfo->RingBuffer->ReadIndex = NextReadLocation; | ||
147 | } | ||
148 | |||
149 | |||
150 | /*++ | ||
151 | |||
152 | Name: | ||
153 | GetRingBuffer() | ||
154 | |||
155 | Description: | ||
156 | Get the start of the ring buffer | ||
157 | |||
158 | --*/ | ||
159 | static inline PVOID | ||
160 | GetRingBuffer(RING_BUFFER_INFO* RingInfo) | ||
161 | { | ||
162 | return (PVOID)RingInfo->RingBuffer->Buffer; | ||
163 | } | ||
164 | |||
165 | |||
166 | /*++ | ||
167 | |||
168 | Name: | ||
169 | GetRingBufferSize() | ||
170 | |||
171 | Description: | ||
172 | Get the size of the ring buffer | ||
173 | |||
174 | --*/ | ||
175 | static inline UINT32 | ||
176 | GetRingBufferSize(RING_BUFFER_INFO* RingInfo) | ||
177 | { | ||
178 | return RingInfo->RingDataSize; | ||
179 | } | ||
180 | |||
181 | /*++ | ||
182 | |||
183 | Name: | ||
184 | GetRingBufferIndices() | ||
185 | |||
186 | Description: | ||
187 | Get the read and write indices as UINT64 of the specified ring buffer | ||
188 | |||
189 | --*/ | ||
190 | static inline UINT64 | ||
191 | GetRingBufferIndices(RING_BUFFER_INFO* RingInfo) | ||
192 | { | ||
193 | return ((UINT64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex; | ||
194 | } | ||
195 | |||
196 | |||
197 | /*++ | ||
198 | |||
199 | Name: | ||
200 | DumpRingInfo() | ||
201 | |||
202 | Description: | ||
203 | Dump out to console the ring buffer info | ||
204 | |||
205 | --*/ | ||
206 | void | ||
207 | DumpRingInfo(RING_BUFFER_INFO* RingInfo, char *Prefix) | ||
208 | { | ||
209 | UINT32 bytesAvailToWrite; | ||
210 | UINT32 bytesAvailToRead; | ||
211 | |||
212 | GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); | ||
213 | |||
214 | DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>", | ||
215 | Prefix, | ||
216 | RingInfo, | ||
217 | RingInfo->RingBuffer->Buffer, | ||
218 | bytesAvailToWrite, | ||
219 | bytesAvailToRead, | ||
220 | RingInfo->RingBuffer->ReadIndex, | ||
221 | RingInfo->RingBuffer->WriteIndex); | ||
222 | } | ||
223 | |||
224 | // | ||
225 | // Internal routines | ||
226 | // | ||
227 | static UINT32 | ||
228 | CopyToRingBuffer( | ||
229 | RING_BUFFER_INFO *RingInfo, | ||
230 | UINT32 StartWriteOffset, | ||
231 | PVOID Src, | ||
232 | UINT32 SrcLen); | ||
233 | |||
234 | static UINT32 | ||
235 | CopyFromRingBuffer( | ||
236 | RING_BUFFER_INFO *RingInfo, | ||
237 | PVOID Dest, | ||
238 | UINT32 DestLen, | ||
239 | UINT32 StartReadOffset); | ||
240 | |||
241 | |||
242 | |||
243 | /*++ | ||
244 | |||
245 | Name: | ||
246 | RingBufferGetDebugInfo() | ||
247 | |||
248 | Description: | ||
249 | Get various debug metrics for the specified ring buffer | ||
250 | |||
251 | --*/ | ||
252 | void | ||
253 | RingBufferGetDebugInfo( | ||
254 | RING_BUFFER_INFO *RingInfo, | ||
255 | RING_BUFFER_DEBUG_INFO *DebugInfo | ||
256 | ) | ||
257 | { | ||
258 | UINT32 bytesAvailToWrite; | ||
259 | UINT32 bytesAvailToRead; | ||
260 | |||
261 | if (RingInfo->RingBuffer) | ||
262 | { | ||
263 | GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); | ||
264 | |||
265 | DebugInfo->BytesAvailToRead = bytesAvailToRead; | ||
266 | DebugInfo->BytesAvailToWrite = bytesAvailToWrite; | ||
267 | DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex; | ||
268 | DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex; | ||
269 | |||
270 | DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | |||
275 | /*++ | ||
276 | |||
277 | Name: | ||
278 | GetRingBufferInterruptMask() | ||
279 | |||
280 | Description: | ||
281 | Get the interrupt mask for the specified ring buffer | ||
282 | |||
283 | --*/ | ||
284 | UINT32 | ||
285 | GetRingBufferInterruptMask( | ||
286 | RING_BUFFER_INFO *rbi | ||
287 | ) | ||
288 | { | ||
289 | return rbi->RingBuffer->InterruptMask; | ||
290 | } | ||
291 | |||
292 | /*++ | ||
293 | |||
294 | Name: | ||
295 | RingBufferInit() | ||
296 | |||
297 | Description: | ||
298 | Initialize the ring buffer | ||
299 | |||
300 | --*/ | ||
301 | int | ||
302 | RingBufferInit( | ||
303 | RING_BUFFER_INFO *RingInfo, | ||
304 | VOID *Buffer, | ||
305 | UINT32 BufferLen | ||
306 | ) | ||
307 | { | ||
308 | ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE); | ||
309 | |||
310 | memset(RingInfo, 0, sizeof(RING_BUFFER_INFO)); | ||
311 | |||
312 | RingInfo->RingBuffer = (RING_BUFFER*)Buffer; | ||
313 | RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0; | ||
314 | |||
315 | RingInfo->RingSize = BufferLen; | ||
316 | RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER); | ||
317 | |||
318 | RingInfo->RingLock = SpinlockCreate(); | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | /*++ | ||
324 | |||
325 | Name: | ||
326 | RingBufferCleanup() | ||
327 | |||
328 | Description: | ||
329 | Cleanup the ring buffer | ||
330 | |||
331 | --*/ | ||
332 | void | ||
333 | RingBufferCleanup( | ||
334 | RING_BUFFER_INFO* RingInfo | ||
335 | ) | ||
336 | { | ||
337 | SpinlockClose(RingInfo->RingLock); | ||
338 | } | ||
339 | |||
340 | /*++ | ||
341 | |||
342 | Name: | ||
343 | RingBufferWrite() | ||
344 | |||
345 | Description: | ||
346 | Write to the ring buffer | ||
347 | |||
348 | --*/ | ||
349 | int | ||
350 | RingBufferWrite( | ||
351 | RING_BUFFER_INFO* OutRingInfo, | ||
352 | SG_BUFFER_LIST SgBuffers[], | ||
353 | UINT32 SgBufferCount | ||
354 | ) | ||
355 | { | ||
356 | int i=0; | ||
357 | UINT32 byteAvailToWrite; | ||
358 | UINT32 byteAvailToRead; | ||
359 | UINT32 totalBytesToWrite=0; | ||
360 | |||
361 | volatile UINT32 nextWriteLocation; | ||
362 | UINT64 prevIndices=0; | ||
363 | |||
364 | DPRINT_ENTER(VMBUS); | ||
365 | |||
366 | for (i=0; i < SgBufferCount; i++) | ||
367 | { | ||
368 | totalBytesToWrite += SgBuffers[i].Length; | ||
369 | } | ||
370 | |||
371 | totalBytesToWrite += sizeof(UINT64); | ||
372 | |||
373 | SpinlockAcquire(OutRingInfo->RingLock); | ||
374 | |||
375 | GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); | ||
376 | |||
377 | DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); | ||
378 | |||
379 | //DumpRingInfo(OutRingInfo, "BEFORE "); | ||
380 | |||
381 | // If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer | ||
382 | // is empty since the read index == write index | ||
383 | if (byteAvailToWrite <= totalBytesToWrite) | ||
384 | { | ||
385 | DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); | ||
386 | |||
387 | SpinlockRelease(OutRingInfo->RingLock); | ||
388 | |||
389 | DPRINT_EXIT(VMBUS); | ||
390 | |||
391 | return -1; | ||
392 | } | ||
393 | |||
394 | // Write to the ring buffer | ||
395 | nextWriteLocation = GetNextWriteLocation(OutRingInfo); | ||
396 | |||
397 | for (i=0; i < SgBufferCount; i++) | ||
398 | { | ||
399 | nextWriteLocation = CopyToRingBuffer(OutRingInfo, | ||
400 | nextWriteLocation, | ||
401 | SgBuffers[i].Data, | ||
402 | SgBuffers[i].Length); | ||
403 | } | ||
404 | |||
405 | // Set previous packet start | ||
406 | prevIndices = GetRingBufferIndices(OutRingInfo); | ||
407 | |||
408 | nextWriteLocation = CopyToRingBuffer(OutRingInfo, | ||
409 | nextWriteLocation, | ||
410 | &prevIndices, | ||
411 | sizeof(UINT64)); | ||
412 | |||
413 | // Make sure we flush all writes before updating the writeIndex | ||
414 | MemoryFence(); | ||
415 | |||
416 | // Now, update the write location | ||
417 | SetNextWriteLocation(OutRingInfo, nextWriteLocation); | ||
418 | |||
419 | //DumpRingInfo(OutRingInfo, "AFTER "); | ||
420 | |||
421 | SpinlockRelease(OutRingInfo->RingLock); | ||
422 | |||
423 | DPRINT_EXIT(VMBUS); | ||
424 | |||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | |||
429 | /*++ | ||
430 | |||
431 | Name: | ||
432 | RingBufferPeek() | ||
433 | |||
434 | Description: | ||
435 | Read without advancing the read index | ||
436 | |||
437 | --*/ | ||
438 | int | ||
439 | RingBufferPeek( | ||
440 | RING_BUFFER_INFO* InRingInfo, | ||
441 | void* Buffer, | ||
442 | UINT32 BufferLen | ||
443 | ) | ||
444 | { | ||
445 | UINT32 bytesAvailToWrite; | ||
446 | UINT32 bytesAvailToRead; | ||
447 | UINT32 nextReadLocation=0; | ||
448 | |||
449 | SpinlockAcquire(InRingInfo->RingLock); | ||
450 | |||
451 | GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); | ||
452 | |||
453 | // Make sure there is something to read | ||
454 | if (bytesAvailToRead < BufferLen ) | ||
455 | { | ||
456 | //DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); | ||
457 | |||
458 | SpinlockRelease(InRingInfo->RingLock); | ||
459 | |||
460 | return -1; | ||
461 | } | ||
462 | |||
463 | // Convert to byte offset | ||
464 | nextReadLocation = GetNextReadLocation(InRingInfo); | ||
465 | |||
466 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | ||
467 | Buffer, | ||
468 | BufferLen, | ||
469 | nextReadLocation); | ||
470 | |||
471 | SpinlockRelease(InRingInfo->RingLock); | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | |||
477 | /*++ | ||
478 | |||
479 | Name: | ||
480 | RingBufferRead() | ||
481 | |||
482 | Description: | ||
483 | Read and advance the read index | ||
484 | |||
485 | --*/ | ||
486 | int | ||
487 | RingBufferRead( | ||
488 | RING_BUFFER_INFO* InRingInfo, | ||
489 | PVOID Buffer, | ||
490 | UINT32 BufferLen, | ||
491 | UINT32 Offset | ||
492 | ) | ||
493 | { | ||
494 | UINT32 bytesAvailToWrite; | ||
495 | UINT32 bytesAvailToRead; | ||
496 | UINT32 nextReadLocation=0; | ||
497 | UINT64 prevIndices=0; | ||
498 | |||
499 | ASSERT(BufferLen > 0); | ||
500 | |||
501 | SpinlockAcquire(InRingInfo->RingLock); | ||
502 | |||
503 | GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); | ||
504 | |||
505 | DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen); | ||
506 | |||
507 | //DumpRingInfo(InRingInfo, "BEFORE "); | ||
508 | |||
509 | // Make sure there is something to read | ||
510 | if (bytesAvailToRead < BufferLen ) | ||
511 | { | ||
512 | DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); | ||
513 | |||
514 | SpinlockRelease(InRingInfo->RingLock); | ||
515 | |||
516 | return -1; | ||
517 | } | ||
518 | |||
519 | nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset); | ||
520 | |||
521 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | ||
522 | Buffer, | ||
523 | BufferLen, | ||
524 | nextReadLocation); | ||
525 | |||
526 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | ||
527 | &prevIndices, | ||
528 | sizeof(UINT64), | ||
529 | nextReadLocation); | ||
530 | |||
531 | // Make sure all reads are done before we update the read index since | ||
532 | // the writer may start writing to the read area once the read index is updated | ||
533 | MemoryFence(); | ||
534 | |||
535 | // Update the read index | ||
536 | SetNextReadLocation(InRingInfo, nextReadLocation); | ||
537 | |||
538 | //DumpRingInfo(InRingInfo, "AFTER "); | ||
539 | |||
540 | SpinlockRelease(InRingInfo->RingLock); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | |||
546 | /*++ | ||
547 | |||
548 | Name: | ||
549 | CopyToRingBuffer() | ||
550 | |||
551 | Description: | ||
552 | Helper routine to copy from source to ring buffer. | ||
553 | Assume there is enough room. Handles wrap-around in dest case only!! | ||
554 | |||
555 | --*/ | ||
556 | UINT32 | ||
557 | CopyToRingBuffer( | ||
558 | RING_BUFFER_INFO *RingInfo, | ||
559 | UINT32 StartWriteOffset, | ||
560 | PVOID Src, | ||
561 | UINT32 SrcLen) | ||
562 | { | ||
563 | PVOID ringBuffer=GetRingBuffer(RingInfo); | ||
564 | UINT32 ringBufferSize=GetRingBufferSize(RingInfo); | ||
565 | UINT32 fragLen; | ||
566 | |||
567 | if (SrcLen > ringBufferSize - StartWriteOffset) // wrap-around detected! | ||
568 | { | ||
569 | DPRINT_DBG(VMBUS, "wrap-around detected!"); | ||
570 | |||
571 | fragLen = ringBufferSize - StartWriteOffset; | ||
572 | memcpy(ringBuffer + StartWriteOffset, Src, fragLen); | ||
573 | memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen); | ||
574 | } | ||
575 | else | ||
576 | { | ||
577 | memcpy(ringBuffer + StartWriteOffset, Src, SrcLen); | ||
578 | } | ||
579 | |||
580 | StartWriteOffset += SrcLen; | ||
581 | StartWriteOffset %= ringBufferSize; | ||
582 | |||
583 | return StartWriteOffset; | ||
584 | } | ||
585 | |||
586 | |||
587 | /*++ | ||
588 | |||
589 | Name: | ||
590 | CopyFromRingBuffer() | ||
591 | |||
592 | Description: | ||
593 | Helper routine to copy to source from ring buffer. | ||
594 | Assume there is enough room. Handles wrap-around in src case only!! | ||
595 | |||
596 | --*/ | ||
597 | UINT32 | ||
598 | CopyFromRingBuffer( | ||
599 | RING_BUFFER_INFO *RingInfo, | ||
600 | PVOID Dest, | ||
601 | UINT32 DestLen, | ||
602 | UINT32 StartReadOffset) | ||
603 | { | ||
604 | PVOID ringBuffer=GetRingBuffer(RingInfo); | ||
605 | UINT32 ringBufferSize=GetRingBufferSize(RingInfo); | ||
606 | |||
607 | UINT32 fragLen; | ||
608 | |||
609 | if (DestLen > ringBufferSize - StartReadOffset) // wrap-around detected at the src | ||
610 | { | ||
611 | DPRINT_DBG(VMBUS, "src wrap-around detected!"); | ||
612 | |||
613 | fragLen = ringBufferSize - StartReadOffset; | ||
614 | |||
615 | memcpy(Dest, ringBuffer + StartReadOffset, fragLen); | ||
616 | memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen); | ||
617 | } | ||
618 | else | ||
619 | { | ||
620 | memcpy(Dest, ringBuffer + StartReadOffset, DestLen); | ||
621 | } | ||
622 | |||
623 | StartReadOffset += DestLen; | ||
624 | StartReadOffset %= ringBufferSize; | ||
625 | |||
626 | return StartReadOffset; | ||
627 | } | ||
628 | |||
629 | |||
630 | // eof | ||
diff --git a/drivers/staging/hv/RingBuffer.h b/drivers/staging/hv/RingBuffer.h new file mode 100644 index 00000000000..9af5df006e3 --- /dev/null +++ b/drivers/staging/hv/RingBuffer.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #ifndef _RING_BUFFER_H_ | ||
26 | #define _RING_BUFFER_H_ | ||
27 | |||
28 | #include "osd.h" | ||
29 | |||
30 | typedef struct _SG_BUFFER_LIST { | ||
31 | PVOID Data; | ||
32 | UINT32 Length; | ||
33 | } SG_BUFFER_LIST; | ||
34 | |||
35 | typedef struct _RING_BUFFER { | ||
36 | volatile UINT32 WriteIndex; // Offset in bytes from the start of ring data below | ||
37 | volatile UINT32 ReadIndex; // Offset in bytes from the start of ring data below | ||
38 | |||
39 | volatile UINT32 InterruptMask; | ||
40 | UINT8 Reserved[4084]; // Pad it to PAGE_SIZE so that data starts on page boundary | ||
41 | // NOTE: The InterruptMask field is used only for channels but since our vmbus connection | ||
42 | // also uses this data structure and its data starts here, we commented out this field. | ||
43 | // volatile UINT32 InterruptMask; | ||
44 | // Ring data starts here + RingDataStartOffset !!! DO NOT place any fields below this !!! | ||
45 | UINT8 Buffer[0]; | ||
46 | } STRUCT_PACKED RING_BUFFER; | ||
47 | |||
48 | typedef struct _RING_BUFFER_INFO { | ||
49 | RING_BUFFER* RingBuffer; | ||
50 | UINT32 RingSize; // Include the shared header | ||
51 | HANDLE RingLock; | ||
52 | |||
53 | UINT32 RingDataSize; // < ringSize | ||
54 | UINT32 RingDataStartOffset; | ||
55 | |||
56 | } RING_BUFFER_INFO; | ||
57 | |||
58 | |||
59 | typedef struct _RING_BUFFER_DEBUG_INFO { | ||
60 | UINT32 CurrentInterruptMask; | ||
61 | UINT32 CurrentReadIndex; | ||
62 | UINT32 CurrentWriteIndex; | ||
63 | UINT32 BytesAvailToRead; | ||
64 | UINT32 BytesAvailToWrite; | ||
65 | }RING_BUFFER_DEBUG_INFO; | ||
66 | |||
67 | |||
68 | // | ||
69 | // Interface | ||
70 | // | ||
71 | |||
72 | INTERNAL int | ||
73 | RingBufferInit( | ||
74 | RING_BUFFER_INFO *RingInfo, | ||
75 | PVOID Buffer, | ||
76 | UINT32 BufferLen | ||
77 | ); | ||
78 | |||
79 | INTERNAL void | ||
80 | RingBufferCleanup( | ||
81 | RING_BUFFER_INFO *RingInfo | ||
82 | ); | ||
83 | |||
84 | INTERNAL int | ||
85 | RingBufferWrite( | ||
86 | RING_BUFFER_INFO *RingInfo, | ||
87 | SG_BUFFER_LIST SgBuffers[], | ||
88 | UINT32 SgBufferCount | ||
89 | ); | ||
90 | |||
91 | INTERNAL int | ||
92 | RingBufferPeek( | ||
93 | RING_BUFFER_INFO *RingInfo, | ||
94 | PVOID Buffer, | ||
95 | UINT32 BufferLen | ||
96 | ); | ||
97 | |||
98 | INTERNAL int | ||
99 | RingBufferRead( | ||
100 | RING_BUFFER_INFO *RingInfo, | ||
101 | PVOID Buffer, | ||
102 | UINT32 BufferLen, | ||
103 | UINT32 Offset | ||
104 | ); | ||
105 | |||
106 | INTERNAL UINT32 | ||
107 | GetRingBufferInterruptMask( | ||
108 | RING_BUFFER_INFO *RingInfo | ||
109 | ); | ||
110 | |||
111 | INTERNAL void | ||
112 | DumpRingInfo( | ||
113 | RING_BUFFER_INFO* RingInfo, | ||
114 | char *Prefix | ||
115 | ); | ||
116 | |||
117 | INTERNAL void | ||
118 | RingBufferGetDebugInfo( | ||
119 | RING_BUFFER_INFO *RingInfo, | ||
120 | RING_BUFFER_DEBUG_INFO *DebugInfo | ||
121 | ); | ||
122 | |||
123 | #endif // _RING_BUFFER_H_ | ||
diff --git a/drivers/staging/hv/Sources.c b/drivers/staging/hv/Sources.c new file mode 100644 index 00000000000..bc154642be7 --- /dev/null +++ b/drivers/staging/hv/Sources.c | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include "Vmbus.c" | ||
26 | #include "Hv.c" | ||
27 | #include "Connection.c" | ||
28 | #include "Channel.c" | ||
29 | #include "ChannelMgmt.c" | ||
30 | #include "ChannelInterface.c" | ||
31 | #include "RingBuffer.c" | ||
diff --git a/drivers/staging/hv/VersionInfo.h b/drivers/staging/hv/VersionInfo.h new file mode 100644 index 00000000000..a827f7fa73b --- /dev/null +++ b/drivers/staging/hv/VersionInfo.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #pragma once | ||
26 | |||
27 | const char VersionDate[]=__DATE__; | ||
28 | const char VersionTime[]=__TIME__; | ||
29 | const char VersionDesc[]= "Version 2.0"; | ||
diff --git a/drivers/staging/hv/Vmbus.c b/drivers/staging/hv/Vmbus.c new file mode 100644 index 00000000000..54a120dc055 --- /dev/null +++ b/drivers/staging/hv/Vmbus.c | |||
@@ -0,0 +1,508 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include "logging.h" | ||
26 | #include "VersionInfo.h" | ||
27 | #include "VmbusPrivate.h" | ||
28 | |||
29 | // | ||
30 | // Globals | ||
31 | // | ||
32 | static const char* gDriverName="vmbus"; | ||
33 | |||
34 | // Windows vmbus does not defined this. We defined this to be consistent with other devices | ||
35 | //{c5295816-f63a-4d5f-8d1a-4daf999ca185} | ||
36 | static const GUID gVmbusDeviceType={ | ||
37 | .Data = {0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85} | ||
38 | }; | ||
39 | |||
40 | //{ac3760fc-9adf-40aa-9427-a70ed6de95c5} | ||
41 | static const GUID gVmbusDeviceId={ | ||
42 | .Data = {0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5} | ||
43 | }; | ||
44 | |||
45 | static DRIVER_OBJECT* gDriver; // vmbus driver object | ||
46 | static DEVICE_OBJECT* gDevice; // vmbus root device | ||
47 | |||
48 | |||
49 | // | ||
50 | // Internal routines | ||
51 | // | ||
52 | |||
53 | static void | ||
54 | VmbusGetChannelInterface( | ||
55 | VMBUS_CHANNEL_INTERFACE *Interface | ||
56 | ); | ||
57 | |||
58 | static void | ||
59 | VmbusGetChannelInfo( | ||
60 | DEVICE_OBJECT *DeviceObject, | ||
61 | DEVICE_INFO *DeviceInfo | ||
62 | ); | ||
63 | |||
64 | static void | ||
65 | VmbusGetChannelOffers( | ||
66 | void | ||
67 | ); | ||
68 | |||
69 | static int | ||
70 | VmbusOnDeviceAdd( | ||
71 | DEVICE_OBJECT *Device, | ||
72 | void *AdditionalInfo | ||
73 | ); | ||
74 | |||
75 | static int | ||
76 | VmbusOnDeviceRemove( | ||
77 | DEVICE_OBJECT* dev | ||
78 | ); | ||
79 | |||
80 | static void | ||
81 | VmbusOnCleanup( | ||
82 | DRIVER_OBJECT* drv | ||
83 | ); | ||
84 | |||
85 | static int | ||
86 | VmbusOnISR( | ||
87 | DRIVER_OBJECT* drv | ||
88 | ); | ||
89 | |||
90 | static void | ||
91 | VmbusOnMsgDPC( | ||
92 | DRIVER_OBJECT* drv | ||
93 | ); | ||
94 | |||
95 | static void | ||
96 | VmbusOnEventDPC( | ||
97 | DRIVER_OBJECT* drv | ||
98 | ); | ||
99 | |||
100 | /*++; | ||
101 | |||
102 | Name: | ||
103 | VmbusInitialize() | ||
104 | |||
105 | Description: | ||
106 | Main entry point | ||
107 | |||
108 | --*/ | ||
109 | int | ||
110 | VmbusInitialize( | ||
111 | DRIVER_OBJECT* drv | ||
112 | ) | ||
113 | { | ||
114 | VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; | ||
115 | int ret=0; | ||
116 | |||
117 | DPRINT_ENTER(VMBUS); | ||
118 | |||
119 | DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime); | ||
120 | DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc); | ||
121 | |||
122 | DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER); | ||
123 | DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT); | ||
124 | |||
125 | DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%d, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%d", | ||
126 | sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)); | ||
127 | |||
128 | drv->name = gDriverName; | ||
129 | memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(GUID)); | ||
130 | |||
131 | // Setup dispatch table | ||
132 | driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; | ||
133 | driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; | ||
134 | driver->Base.OnCleanup = VmbusOnCleanup; | ||
135 | driver->OnIsr = VmbusOnISR; | ||
136 | driver->OnMsgDpc = VmbusOnMsgDPC; | ||
137 | driver->OnEventDpc = VmbusOnEventDPC; | ||
138 | driver->GetChannelOffers = VmbusGetChannelOffers; | ||
139 | driver->GetChannelInterface = VmbusGetChannelInterface; | ||
140 | driver->GetChannelInfo = VmbusGetChannelInfo; | ||
141 | |||
142 | // Hypervisor initialization...setup hypercall page..etc | ||
143 | ret = HvInit(); | ||
144 | if (ret != 0) | ||
145 | { | ||
146 | DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret); | ||
147 | } | ||
148 | |||
149 | gDriver = drv; | ||
150 | |||
151 | DPRINT_EXIT(VMBUS); | ||
152 | |||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | |||
157 | /*++; | ||
158 | |||
159 | Name: | ||
160 | VmbusGetChannelOffers() | ||
161 | |||
162 | Description: | ||
163 | Retrieve the channel offers from the parent partition | ||
164 | |||
165 | --*/ | ||
166 | |||
167 | static void | ||
168 | VmbusGetChannelOffers(void) | ||
169 | { | ||
170 | DPRINT_ENTER(VMBUS); | ||
171 | VmbusChannelRequestOffers(); | ||
172 | DPRINT_EXIT(VMBUS); | ||
173 | } | ||
174 | |||
175 | |||
176 | /*++; | ||
177 | |||
178 | Name: | ||
179 | VmbusGetChannelInterface() | ||
180 | |||
181 | Description: | ||
182 | Get the channel interface | ||
183 | |||
184 | --*/ | ||
185 | static void | ||
186 | VmbusGetChannelInterface( | ||
187 | VMBUS_CHANNEL_INTERFACE *Interface | ||
188 | ) | ||
189 | { | ||
190 | GetChannelInterface(Interface); | ||
191 | } | ||
192 | |||
193 | |||
194 | /*++; | ||
195 | |||
196 | Name: | ||
197 | VmbusGetChannelInterface() | ||
198 | |||
199 | Description: | ||
200 | Get the device info for the specified device object | ||
201 | |||
202 | --*/ | ||
203 | static void | ||
204 | VmbusGetChannelInfo( | ||
205 | DEVICE_OBJECT *DeviceObject, | ||
206 | DEVICE_INFO *DeviceInfo | ||
207 | ) | ||
208 | { | ||
209 | GetChannelInfo(DeviceObject, DeviceInfo); | ||
210 | } | ||
211 | |||
212 | |||
213 | |||
214 | /*++ | ||
215 | |||
216 | Name: | ||
217 | VmbusCreateChildDevice() | ||
218 | |||
219 | Description: | ||
220 | Creates the child device on the bus that represents the channel offer | ||
221 | |||
222 | --*/ | ||
223 | |||
224 | DEVICE_OBJECT* | ||
225 | VmbusChildDeviceCreate( | ||
226 | GUID DeviceType, | ||
227 | GUID DeviceInstance, | ||
228 | void *Context) | ||
229 | { | ||
230 | VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; | ||
231 | |||
232 | return vmbusDriver->OnChildDeviceCreate( | ||
233 | DeviceType, | ||
234 | DeviceInstance, | ||
235 | Context); | ||
236 | } | ||
237 | |||
238 | |||
239 | /*++ | ||
240 | |||
241 | Name: | ||
242 | VmbusChildDeviceAdd() | ||
243 | |||
244 | Description: | ||
245 | Registers the child device with the vmbus | ||
246 | |||
247 | --*/ | ||
248 | int | ||
249 | VmbusChildDeviceAdd( | ||
250 | DEVICE_OBJECT* ChildDevice) | ||
251 | { | ||
252 | VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; | ||
253 | |||
254 | return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice); | ||
255 | } | ||
256 | |||
257 | |||
258 | /*++ | ||
259 | |||
260 | Name: | ||
261 | VmbusChildDeviceRemove() | ||
262 | |||
263 | Description: | ||
264 | Unregisters the child device from the vmbus | ||
265 | |||
266 | --*/ | ||
267 | void | ||
268 | VmbusChildDeviceRemove( | ||
269 | DEVICE_OBJECT* ChildDevice) | ||
270 | { | ||
271 | VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; | ||
272 | |||
273 | vmbusDriver->OnChildDeviceRemove(ChildDevice); | ||
274 | } | ||
275 | |||
276 | /*++ | ||
277 | |||
278 | Name: | ||
279 | VmbusChildDeviceDestroy() | ||
280 | |||
281 | Description: | ||
282 | Release the child device from the vmbus | ||
283 | |||
284 | --*/ | ||
285 | //void | ||
286 | //VmbusChildDeviceDestroy( | ||
287 | // DEVICE_OBJECT* ChildDevice | ||
288 | // ) | ||
289 | //{ | ||
290 | // VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; | ||
291 | // | ||
292 | // vmbusDriver->OnChildDeviceDestroy(ChildDevice); | ||
293 | //} | ||
294 | |||
295 | /*++ | ||
296 | |||
297 | Name: | ||
298 | VmbusOnDeviceAdd() | ||
299 | |||
300 | Description: | ||
301 | Callback when the root bus device is added | ||
302 | |||
303 | --*/ | ||
304 | static int | ||
305 | VmbusOnDeviceAdd( | ||
306 | DEVICE_OBJECT *dev, | ||
307 | void *AdditionalInfo | ||
308 | ) | ||
309 | { | ||
310 | UINT32 *irqvector = (UINT32*) AdditionalInfo; | ||
311 | int ret=0; | ||
312 | |||
313 | DPRINT_ENTER(VMBUS); | ||
314 | |||
315 | gDevice = dev; | ||
316 | |||
317 | memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(GUID)); | ||
318 | memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(GUID)); | ||
319 | |||
320 | //strcpy(dev->name, "vmbus"); | ||
321 | // SynIC setup... | ||
322 | ret = HvSynicInit(*irqvector); | ||
323 | |||
324 | // Connect to VMBus in the root partition | ||
325 | ret = VmbusConnect(); | ||
326 | |||
327 | //VmbusSendEvent(device->localPortId+1); | ||
328 | DPRINT_EXIT(VMBUS); | ||
329 | |||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | |||
334 | /*++ | ||
335 | |||
336 | Name: | ||
337 | VmbusOnDeviceRemove() | ||
338 | |||
339 | Description: | ||
340 | Callback when the root bus device is removed | ||
341 | |||
342 | --*/ | ||
343 | int VmbusOnDeviceRemove( | ||
344 | DEVICE_OBJECT* dev | ||
345 | ) | ||
346 | { | ||
347 | int ret=0; | ||
348 | |||
349 | DPRINT_ENTER(VMBUS); | ||
350 | |||
351 | VmbusChannelReleaseUnattachedChannels(); | ||
352 | |||
353 | VmbusDisconnect(); | ||
354 | |||
355 | HvSynicCleanup(); | ||
356 | |||
357 | DPRINT_EXIT(VMBUS); | ||
358 | |||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | |||
363 | /*++ | ||
364 | |||
365 | Name: | ||
366 | VmbusOnCleanup() | ||
367 | |||
368 | Description: | ||
369 | Perform any cleanup when the driver is removed | ||
370 | |||
371 | --*/ | ||
372 | void | ||
373 | VmbusOnCleanup( | ||
374 | DRIVER_OBJECT* drv | ||
375 | ) | ||
376 | { | ||
377 | //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; | ||
378 | |||
379 | DPRINT_ENTER(VMBUS); | ||
380 | |||
381 | HvCleanup(); | ||
382 | |||
383 | DPRINT_EXIT(VMBUS); | ||
384 | } | ||
385 | |||
386 | |||
387 | /*++ | ||
388 | |||
389 | Name: | ||
390 | VmbusOnMsgDPC() | ||
391 | |||
392 | Description: | ||
393 | DPC routine to handle messages from the hypervisior | ||
394 | |||
395 | --*/ | ||
396 | void | ||
397 | VmbusOnMsgDPC( | ||
398 | DRIVER_OBJECT* drv | ||
399 | ) | ||
400 | { | ||
401 | void *page_addr = gHvContext.synICMessagePage[0]; | ||
402 | |||
403 | HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT; | ||
404 | HV_MESSAGE *copied; | ||
405 | while (1) | ||
406 | { | ||
407 | if (msg->Header.MessageType == HvMessageTypeNone) // no msg | ||
408 | { | ||
409 | break; | ||
410 | } | ||
411 | else | ||
412 | { | ||
413 | copied = MemAllocAtomic(sizeof(HV_MESSAGE)); | ||
414 | if (copied == NULL) | ||
415 | { | ||
416 | continue; | ||
417 | } | ||
418 | |||
419 | memcpy(copied, msg, sizeof(HV_MESSAGE)); | ||
420 | WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, VmbusOnChannelMessage, (void*)copied); | ||
421 | } | ||
422 | |||
423 | msg->Header.MessageType = HvMessageTypeNone; | ||
424 | |||
425 | // Make sure the write to MessageType (ie set to HvMessageTypeNone) happens | ||
426 | // before we read the MessagePending and EOMing. Otherwise, the EOMing will not deliver | ||
427 | // any more messages since there is no empty slot | ||
428 | MemoryFence(); | ||
429 | |||
430 | if (msg->Header.MessageFlags.MessagePending) | ||
431 | { | ||
432 | // This will cause message queue rescan to possibly deliver another msg from the hypervisor | ||
433 | WriteMsr(HV_X64_MSR_EOM, 0); | ||
434 | } | ||
435 | } | ||
436 | } | ||
437 | |||
438 | /*++ | ||
439 | |||
440 | Name: | ||
441 | VmbusOnEventDPC() | ||
442 | |||
443 | Description: | ||
444 | DPC routine to handle events from the hypervisior | ||
445 | |||
446 | --*/ | ||
447 | void | ||
448 | VmbusOnEventDPC( | ||
449 | DRIVER_OBJECT* drv | ||
450 | ) | ||
451 | { | ||
452 | // TODO: Process any events | ||
453 | VmbusOnEvents(); | ||
454 | } | ||
455 | |||
456 | |||
457 | /*++ | ||
458 | |||
459 | Name: | ||
460 | VmbusOnISR() | ||
461 | |||
462 | Description: | ||
463 | ISR routine | ||
464 | |||
465 | --*/ | ||
466 | int | ||
467 | VmbusOnISR( | ||
468 | DRIVER_OBJECT* drv | ||
469 | ) | ||
470 | { | ||
471 | //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; | ||
472 | |||
473 | int ret=0; | ||
474 | //struct page* page; | ||
475 | void *page_addr; | ||
476 | HV_MESSAGE* msg; | ||
477 | HV_SYNIC_EVENT_FLAGS* event; | ||
478 | |||
479 | //page = SynICMessagePage[0]; | ||
480 | //page_addr = page_address(page); | ||
481 | page_addr = gHvContext.synICMessagePage[0]; | ||
482 | msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT; | ||
483 | |||
484 | DPRINT_ENTER(VMBUS); | ||
485 | |||
486 | // Check if there are actual msgs to be process | ||
487 | if (msg->Header.MessageType != HvMessageTypeNone) | ||
488 | { | ||
489 | DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize); | ||
490 | ret |= 0x1; | ||
491 | } | ||
492 | |||
493 | // TODO: Check if there are events to be process | ||
494 | page_addr = gHvContext.synICEventPage[0]; | ||
495 | event = (HV_SYNIC_EVENT_FLAGS*)page_addr + VMBUS_MESSAGE_SINT; | ||
496 | |||
497 | // Since we are a child, we only need to check bit 0 | ||
498 | if (BitTestAndClear(&event->Flags32[0], 0)) | ||
499 | { | ||
500 | DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]); | ||
501 | ret |= 0x2; | ||
502 | } | ||
503 | |||
504 | DPRINT_EXIT(VMBUS); | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | // eof | ||
diff --git a/drivers/staging/hv/VmbusPrivate.h b/drivers/staging/hv/VmbusPrivate.h new file mode 100644 index 00000000000..5e86165dea2 --- /dev/null +++ b/drivers/staging/hv/VmbusPrivate.h | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #ifndef _VMBUS_PRIVATE_H_ | ||
26 | #define _VMBUS_PRIVATE_H_ | ||
27 | |||
28 | #ifndef INTERNAL | ||
29 | #define INTERNAL static | ||
30 | #endif | ||
31 | |||
32 | #include "Hv.h" | ||
33 | #include "VmbusApi.h" | ||
34 | #include "Channel.h" | ||
35 | #include "ChannelMgmt.h" | ||
36 | #include "ChannelInterface.h" | ||
37 | //#include "ChannelMessages.h" | ||
38 | #include "RingBuffer.h" | ||
39 | //#include "Packet.h" | ||
40 | #include "List.h" | ||
41 | |||
42 | // | ||
43 | // Defines | ||
44 | // | ||
45 | |||
46 | // Maximum channels is determined by the size of the interrupt page which is PAGE_SIZE. 1/2 of PAGE_SIZE is for | ||
47 | // send endpoint interrupt and the other is receive endpoint interrupt | ||
48 | #define MAX_NUM_CHANNELS (PAGE_SIZE >> 1) << 3 // 16348 channels | ||
49 | |||
50 | // The value here must be in multiple of 32 | ||
51 | // TODO: Need to make this configurable | ||
52 | #define MAX_NUM_CHANNELS_SUPPORTED 256 | ||
53 | |||
54 | // | ||
55 | // Data types | ||
56 | // | ||
57 | |||
58 | typedef enum { | ||
59 | Disconnected, | ||
60 | Connecting, | ||
61 | Connected, | ||
62 | Disconnecting | ||
63 | } VMBUS_CONNECT_STATE; | ||
64 | |||
65 | #define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT | ||
66 | |||
67 | typedef struct _VMBUS_CONNECTION { | ||
68 | |||
69 | VMBUS_CONNECT_STATE ConnectState; | ||
70 | |||
71 | UINT32 NextGpadlHandle; | ||
72 | |||
73 | // Represents channel interrupts. Each bit position | ||
74 | // represents a channel. | ||
75 | // When a channel sends an interrupt via VMBUS, it | ||
76 | // finds its bit in the sendInterruptPage, set it and | ||
77 | // calls Hv to generate a port event. The other end | ||
78 | // receives the port event and parse the recvInterruptPage | ||
79 | // to see which bit is set | ||
80 | VOID* InterruptPage; | ||
81 | VOID* SendInterruptPage; | ||
82 | VOID* RecvInterruptPage; | ||
83 | |||
84 | // 2 pages - 1st page for parent->child notification and 2nd is child->parent notification | ||
85 | VOID* MonitorPages; | ||
86 | LIST_ENTRY ChannelMsgList; | ||
87 | HANDLE ChannelMsgLock; | ||
88 | |||
89 | // List of channels | ||
90 | LIST_ENTRY ChannelList; | ||
91 | HANDLE ChannelLock; | ||
92 | |||
93 | HANDLE WorkQueue; | ||
94 | } VMBUS_CONNECTION; | ||
95 | |||
96 | |||
97 | typedef struct _VMBUS_MSGINFO { | ||
98 | // Bookkeeping stuff | ||
99 | LIST_ENTRY MsgListEntry; | ||
100 | |||
101 | // Synchronize the request/response if needed | ||
102 | HANDLE WaitEvent; | ||
103 | |||
104 | // The message itself | ||
105 | unsigned char Msg[0]; | ||
106 | } VMBUS_MSGINFO; | ||
107 | |||
108 | |||
109 | // | ||
110 | // Externs | ||
111 | // | ||
112 | extern VMBUS_CONNECTION gVmbusConnection; | ||
113 | |||
114 | // | ||
115 | // General vmbus interface | ||
116 | // | ||
117 | INTERNAL DEVICE_OBJECT* | ||
118 | VmbusChildDeviceCreate( | ||
119 | GUID deviceType, | ||
120 | GUID deviceInstance, | ||
121 | void *context); | ||
122 | |||
123 | INTERNAL int | ||
124 | VmbusChildDeviceAdd( | ||
125 | DEVICE_OBJECT* Device); | ||
126 | |||
127 | INTERNAL void | ||
128 | VmbusChildDeviceRemove( | ||
129 | DEVICE_OBJECT* Device); | ||
130 | |||
131 | //INTERNAL void | ||
132 | //VmbusChildDeviceDestroy( | ||
133 | // DEVICE_OBJECT*); | ||
134 | |||
135 | INTERNAL VMBUS_CHANNEL* | ||
136 | GetChannelFromRelId( | ||
137 | UINT32 relId | ||
138 | ); | ||
139 | |||
140 | // | ||
141 | // Connection interface | ||
142 | // | ||
143 | INTERNAL int | ||
144 | VmbusConnect( | ||
145 | VOID | ||
146 | ); | ||
147 | |||
148 | INTERNAL int | ||
149 | VmbusDisconnect( | ||
150 | VOID | ||
151 | ); | ||
152 | |||
153 | INTERNAL int | ||
154 | VmbusPostMessage( | ||
155 | PVOID buffer, | ||
156 | SIZE_T bufSize | ||
157 | ); | ||
158 | |||
159 | INTERNAL int | ||
160 | VmbusSetEvent( | ||
161 | UINT32 childRelId | ||
162 | ); | ||
163 | |||
164 | INTERNAL VOID | ||
165 | VmbusOnEvents( | ||
166 | VOID | ||
167 | ); | ||
168 | |||
169 | |||
170 | #endif // _VMBUS_PRIVATE_H_ | ||
diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c new file mode 100644 index 00000000000..83885252049 --- /dev/null +++ b/drivers/staging/hv/osd.c | |||
@@ -0,0 +1,500 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/highmem.h> | ||
30 | #include <linux/vmalloc.h> | ||
31 | //#include <linux/config.h> | ||
32 | #include <linux/ioport.h> | ||
33 | #include <linux/irq.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/wait.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/workqueue.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/timer.h> | ||
40 | #include <linux/jiffies.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/time.h> | ||
43 | |||
44 | #include <asm/io.h> | ||
45 | #include <asm/bitops.h> | ||
46 | #include <asm/kmap_types.h> | ||
47 | #include <asm/atomic.h> | ||
48 | |||
49 | #include "osd.h" | ||
50 | |||
51 | // | ||
52 | // Data types | ||
53 | // | ||
54 | typedef struct _TIMER { | ||
55 | struct timer_list timer; | ||
56 | PFN_TIMER_CALLBACK callback; | ||
57 | void* context; | ||
58 | }TIMER; | ||
59 | |||
60 | |||
61 | typedef struct _WAITEVENT { | ||
62 | int condition; | ||
63 | wait_queue_head_t event; | ||
64 | } WAITEVENT; | ||
65 | |||
66 | typedef struct _SPINLOCK { | ||
67 | spinlock_t lock; | ||
68 | unsigned long flags; | ||
69 | } SPINLOCK; | ||
70 | |||
71 | typedef struct _WORKQUEUE { | ||
72 | struct workqueue_struct *queue; | ||
73 | } WORKQUEUE; | ||
74 | |||
75 | typedef struct _WORKITEM { | ||
76 | struct work_struct work; | ||
77 | PFN_WORKITEM_CALLBACK callback; | ||
78 | void* context; | ||
79 | } WORKITEM; | ||
80 | |||
81 | |||
82 | // | ||
83 | // Global | ||
84 | // | ||
85 | |||
86 | void LogMsg(const char *fmt, ...) | ||
87 | { | ||
88 | #ifdef KERNEL_2_6_5 | ||
89 | char buf[1024]; | ||
90 | #endif | ||
91 | va_list args; | ||
92 | |||
93 | va_start(args, fmt); | ||
94 | #ifdef KERNEL_2_6_5 | ||
95 | vsnprintf(buf, 1024, fmt, args); | ||
96 | va_end(args); | ||
97 | printk(buf); | ||
98 | #else | ||
99 | vprintk(fmt, args); | ||
100 | va_end(args); | ||
101 | #endif | ||
102 | } | ||
103 | |||
104 | void BitSet(unsigned int* addr, int bit) | ||
105 | { | ||
106 | set_bit(bit, (unsigned long*)addr); | ||
107 | } | ||
108 | |||
109 | int BitTest(unsigned int* addr, int bit) | ||
110 | { | ||
111 | return test_bit(bit, (unsigned long*)addr); | ||
112 | } | ||
113 | |||
114 | void BitClear(unsigned int* addr, int bit) | ||
115 | { | ||
116 | clear_bit(bit, (unsigned long*)addr); | ||
117 | } | ||
118 | |||
119 | int BitTestAndClear(unsigned int* addr, int bit) | ||
120 | { | ||
121 | return test_and_clear_bit(bit, (unsigned long*)addr); | ||
122 | } | ||
123 | |||
124 | int BitTestAndSet(unsigned int* addr, int bit) | ||
125 | { | ||
126 | return test_and_set_bit(bit, (unsigned long*)addr); | ||
127 | } | ||
128 | |||
129 | |||
130 | int InterlockedIncrement(int *val) | ||
131 | { | ||
132 | #ifdef KERNEL_2_6_5 | ||
133 | int i; | ||
134 | local_irq_disable(); | ||
135 | i = atomic_read((atomic_t*)val); | ||
136 | atomic_set((atomic_t*)val, i+1); | ||
137 | local_irq_enable(); | ||
138 | return i+1; | ||
139 | #else | ||
140 | return atomic_inc_return((atomic_t*)val); | ||
141 | #endif | ||
142 | } | ||
143 | |||
144 | int InterlockedDecrement(int *val) | ||
145 | { | ||
146 | #ifdef KERNEL_2_6_5 | ||
147 | int i; | ||
148 | local_irq_disable(); | ||
149 | i = atomic_read((atomic_t*)val); | ||
150 | atomic_set((atomic_t*)val, i-1); | ||
151 | local_irq_enable(); | ||
152 | return i-1; | ||
153 | #else | ||
154 | return atomic_dec_return((atomic_t*)val); | ||
155 | #endif | ||
156 | } | ||
157 | |||
158 | #ifndef atomic_cmpxchg | ||
159 | #define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new)) | ||
160 | #endif | ||
161 | int InterlockedCompareExchange(int *val, int new, int curr) | ||
162 | { | ||
163 | //return ((int)cmpxchg(((atomic_t*)val), curr, new)); | ||
164 | return atomic_cmpxchg((atomic_t*)val, curr, new); | ||
165 | |||
166 | } | ||
167 | |||
168 | void Sleep(unsigned long usecs) | ||
169 | { | ||
170 | udelay(usecs); | ||
171 | } | ||
172 | |||
173 | void* VirtualAllocExec(unsigned int size) | ||
174 | { | ||
175 | #ifdef __x86_64__ | ||
176 | return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC); | ||
177 | #else | ||
178 | return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX))); | ||
179 | #endif | ||
180 | } | ||
181 | |||
182 | void VirtualFree(void* VirtAddr) | ||
183 | { | ||
184 | return vfree(VirtAddr); | ||
185 | } | ||
186 | |||
187 | void* PageAlloc(unsigned int count) | ||
188 | { | ||
189 | void *p; | ||
190 | p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE)); | ||
191 | if (p) memset(p, 0, count * PAGE_SIZE); | ||
192 | return p; | ||
193 | |||
194 | //struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO); | ||
195 | //void *p; | ||
196 | |||
197 | ////BUGBUG: We need to use kmap in case we are in HIMEM region | ||
198 | //p = page_address(page); | ||
199 | //if (p) memset(p, 0, PAGE_SIZE); | ||
200 | //return p; | ||
201 | } | ||
202 | |||
203 | void PageFree(void* page, unsigned int count) | ||
204 | { | ||
205 | free_pages((unsigned long)page, get_order(count * PAGE_SIZE)); | ||
206 | /*struct page* p = virt_to_page(page); | ||
207 | __free_page(p);*/ | ||
208 | } | ||
209 | |||
210 | |||
211 | void* PageMapVirtualAddress(unsigned long Pfn) | ||
212 | { | ||
213 | return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0); | ||
214 | } | ||
215 | |||
216 | void PageUnmapVirtualAddress(void* VirtAddr) | ||
217 | { | ||
218 | kunmap_atomic(VirtAddr, KM_IRQ0); | ||
219 | } | ||
220 | |||
221 | void* MemAlloc(unsigned int size) | ||
222 | { | ||
223 | return kmalloc(size, GFP_KERNEL); | ||
224 | } | ||
225 | |||
226 | void* MemAllocZeroed(unsigned int size) | ||
227 | { | ||
228 | void *p = kmalloc(size, GFP_KERNEL); | ||
229 | if (p) memset(p, 0, size); | ||
230 | return p; | ||
231 | } | ||
232 | |||
233 | void* MemAllocAtomic(unsigned int size) | ||
234 | { | ||
235 | return kmalloc(size, GFP_ATOMIC); | ||
236 | } | ||
237 | |||
238 | void MemFree(void* buf) | ||
239 | { | ||
240 | kfree(buf); | ||
241 | } | ||
242 | |||
243 | void *MemMapIO(unsigned long phys, unsigned long size) | ||
244 | { | ||
245 | #if X2V_LINUX | ||
246 | #ifdef __x86_64__ | ||
247 | return (void*)(phys + 0xFFFF83000C000000); | ||
248 | #else // i386 | ||
249 | return (void*)(phys + 0xfb000000); | ||
250 | #endif | ||
251 | #else | ||
252 | return (void*)GetVirtualAddress(phys); //return ioremap_nocache(phys, size); | ||
253 | #endif | ||
254 | } | ||
255 | |||
256 | void MemUnmapIO(void *virt) | ||
257 | { | ||
258 | //iounmap(virt); | ||
259 | } | ||
260 | |||
261 | void MemoryFence() | ||
262 | { | ||
263 | mb(); | ||
264 | } | ||
265 | |||
266 | void TimerCallback(unsigned long data) | ||
267 | { | ||
268 | TIMER* t = (TIMER*)data; | ||
269 | |||
270 | t->callback(t->context); | ||
271 | } | ||
272 | |||
273 | HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context) | ||
274 | { | ||
275 | TIMER* t = kmalloc(sizeof(TIMER), GFP_KERNEL); | ||
276 | if (!t) | ||
277 | { | ||
278 | return NULL; | ||
279 | } | ||
280 | |||
281 | t->callback = pfnTimerCB; | ||
282 | t->context = context; | ||
283 | |||
284 | init_timer(&t->timer); | ||
285 | t->timer.data = (unsigned long)t; | ||
286 | t->timer.function = TimerCallback; | ||
287 | |||
288 | return t; | ||
289 | } | ||
290 | |||
291 | void TimerStart(HANDLE hTimer, UINT32 expirationInUs) | ||
292 | { | ||
293 | TIMER* t = (TIMER* )hTimer; | ||
294 | |||
295 | t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs); | ||
296 | add_timer(&t->timer); | ||
297 | } | ||
298 | |||
299 | int TimerStop(HANDLE hTimer) | ||
300 | { | ||
301 | TIMER* t = (TIMER* )hTimer; | ||
302 | |||
303 | return del_timer(&t->timer); | ||
304 | } | ||
305 | |||
306 | void TimerClose(HANDLE hTimer) | ||
307 | { | ||
308 | TIMER* t = (TIMER* )hTimer; | ||
309 | |||
310 | del_timer(&t->timer); | ||
311 | kfree(t); | ||
312 | } | ||
313 | |||
314 | SIZE_T GetTickCount(void) | ||
315 | { | ||
316 | return jiffies; | ||
317 | } | ||
318 | |||
319 | signed long long GetTimestamp(void) | ||
320 | { | ||
321 | struct timeval t; | ||
322 | |||
323 | do_gettimeofday(&t); | ||
324 | |||
325 | return timeval_to_ns(&t); | ||
326 | } | ||
327 | |||
328 | HANDLE WaitEventCreate(void) | ||
329 | { | ||
330 | WAITEVENT* wait = kmalloc(sizeof(WAITEVENT), GFP_KERNEL); | ||
331 | if (!wait) | ||
332 | { | ||
333 | return NULL; | ||
334 | } | ||
335 | |||
336 | wait->condition = 0; | ||
337 | init_waitqueue_head(&wait->event); | ||
338 | return wait; | ||
339 | } | ||
340 | |||
341 | void WaitEventClose(HANDLE hWait) | ||
342 | { | ||
343 | WAITEVENT* waitEvent = (WAITEVENT* )hWait; | ||
344 | kfree(waitEvent); | ||
345 | } | ||
346 | |||
347 | void WaitEventSet(HANDLE hWait) | ||
348 | { | ||
349 | WAITEVENT* waitEvent = (WAITEVENT* )hWait; | ||
350 | waitEvent->condition = 1; | ||
351 | wake_up_interruptible(&waitEvent->event); | ||
352 | } | ||
353 | |||
354 | int WaitEventWait(HANDLE hWait) | ||
355 | { | ||
356 | int ret=0; | ||
357 | WAITEVENT* waitEvent = (WAITEVENT* )hWait; | ||
358 | |||
359 | ret= wait_event_interruptible(waitEvent->event, | ||
360 | waitEvent->condition); | ||
361 | waitEvent->condition = 0; | ||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | int WaitEventWaitEx(HANDLE hWait, UINT32 TimeoutInMs) | ||
366 | { | ||
367 | int ret=0; | ||
368 | WAITEVENT* waitEvent = (WAITEVENT* )hWait; | ||
369 | |||
370 | ret= wait_event_interruptible_timeout(waitEvent->event, | ||
371 | waitEvent->condition, | ||
372 | msecs_to_jiffies(TimeoutInMs)); | ||
373 | waitEvent->condition = 0; | ||
374 | return ret; | ||
375 | } | ||
376 | |||
377 | HANDLE SpinlockCreate(VOID) | ||
378 | { | ||
379 | SPINLOCK* spin = kmalloc(sizeof(SPINLOCK), GFP_KERNEL); | ||
380 | if (!spin) | ||
381 | { | ||
382 | return NULL; | ||
383 | } | ||
384 | spin_lock_init(&spin->lock); | ||
385 | |||
386 | return spin; | ||
387 | } | ||
388 | |||
389 | VOID SpinlockAcquire(HANDLE hSpin) | ||
390 | { | ||
391 | SPINLOCK* spin = (SPINLOCK* )hSpin; | ||
392 | |||
393 | spin_lock_irqsave(&spin->lock, spin->flags); | ||
394 | } | ||
395 | |||
396 | VOID SpinlockRelease(HANDLE hSpin) | ||
397 | { | ||
398 | SPINLOCK* spin = (SPINLOCK* )hSpin; | ||
399 | |||
400 | spin_unlock_irqrestore(&spin->lock, spin->flags); | ||
401 | } | ||
402 | |||
403 | VOID SpinlockClose(HANDLE hSpin) | ||
404 | { | ||
405 | SPINLOCK* spin = (SPINLOCK* )hSpin; | ||
406 | kfree(spin); | ||
407 | } | ||
408 | |||
409 | void* Physical2LogicalAddr(ULONG_PTR PhysAddr) | ||
410 | { | ||
411 | void* logicalAddr = phys_to_virt(PhysAddr); | ||
412 | BUG_ON(!virt_addr_valid(logicalAddr)); | ||
413 | return logicalAddr; | ||
414 | } | ||
415 | |||
416 | ULONG_PTR Logical2PhysicalAddr(PVOID LogicalAddr) | ||
417 | { | ||
418 | BUG_ON(!virt_addr_valid(LogicalAddr)); | ||
419 | return virt_to_phys(LogicalAddr); | ||
420 | } | ||
421 | |||
422 | |||
423 | ULONG_PTR Virtual2Physical(PVOID VirtAddr) | ||
424 | { | ||
425 | ULONG_PTR pfn = vmalloc_to_pfn(VirtAddr); | ||
426 | |||
427 | return pfn << PAGE_SHIFT; | ||
428 | } | ||
429 | |||
430 | #ifdef KERNEL_2_6_27 | ||
431 | void WorkItemCallback(struct work_struct *work) | ||
432 | #else | ||
433 | void WorkItemCallback(void* work) | ||
434 | #endif | ||
435 | { | ||
436 | WORKITEM* w = (WORKITEM*)work; | ||
437 | |||
438 | w->callback(w->context); | ||
439 | |||
440 | kfree(w); | ||
441 | } | ||
442 | |||
443 | HANDLE WorkQueueCreate(char* name) | ||
444 | { | ||
445 | WORKQUEUE *wq = kmalloc(sizeof(WORKQUEUE), GFP_KERNEL); | ||
446 | if (!wq) | ||
447 | { | ||
448 | return NULL; | ||
449 | } | ||
450 | wq->queue = create_workqueue(name); | ||
451 | |||
452 | return wq; | ||
453 | } | ||
454 | |||
455 | void WorkQueueClose(HANDLE hWorkQueue) | ||
456 | { | ||
457 | WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue; | ||
458 | |||
459 | destroy_workqueue(wq->queue); | ||
460 | |||
461 | return; | ||
462 | } | ||
463 | |||
464 | int WorkQueueQueueWorkItem(HANDLE hWorkQueue, PFN_WORKITEM_CALLBACK workItem, void* context) | ||
465 | { | ||
466 | WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue; | ||
467 | |||
468 | WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC); | ||
469 | if (!w) | ||
470 | { | ||
471 | return -1; | ||
472 | } | ||
473 | |||
474 | w->callback = workItem, | ||
475 | w->context = context; | ||
476 | #ifdef KERNEL_2_6_27 | ||
477 | INIT_WORK(&w->work, WorkItemCallback); | ||
478 | #else | ||
479 | INIT_WORK(&w->work, WorkItemCallback, w); | ||
480 | #endif | ||
481 | return queue_work(wq->queue, &w->work); | ||
482 | } | ||
483 | |||
484 | void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context) | ||
485 | { | ||
486 | WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC); | ||
487 | if (!w) | ||
488 | { | ||
489 | return; | ||
490 | } | ||
491 | |||
492 | w->callback = workItem, | ||
493 | w->context = context; | ||
494 | #ifdef KERNEL_2_6_27 | ||
495 | INIT_WORK(&w->work, WorkItemCallback); | ||
496 | #else | ||
497 | INIT_WORK(&w->work, WorkItemCallback, w); | ||
498 | #endif | ||
499 | schedule_work(&w->work); | ||
500 | } | ||
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c new file mode 100644 index 00000000000..0acf42c3566 --- /dev/null +++ b/drivers/staging/hv/vmbus_drv.c | |||
@@ -0,0 +1,1228 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (c) 2009, Microsoft Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
17 | * | ||
18 | * Authors: | ||
19 | * Haiyang Zhang <haiyangz@microsoft.com> | ||
20 | * Hank Janssen <hjanssen@microsoft.com> | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/sysctl.h> | ||
31 | |||
32 | #include "logging.h" | ||
33 | #include "vmbus.h" | ||
34 | |||
35 | // | ||
36 | // Defines | ||
37 | // | ||
38 | |||
39 | // FIXME! We need to do this dynamically for PIC and APIC system | ||
40 | #define VMBUS_IRQ 0x5 | ||
41 | #ifdef KERNEL_2_6_27 | ||
42 | #define VMBUS_IRQ_VECTOR IRQ5_VECTOR | ||
43 | #endif | ||
44 | // | ||
45 | // Data types | ||
46 | // | ||
47 | |||
48 | // Main vmbus driver data structure | ||
49 | struct vmbus_driver_context { | ||
50 | // !! These must be the first 2 fields !! | ||
51 | // The driver field is not used in here. Instead, the bus field is | ||
52 | // used to represent the driver | ||
53 | struct driver_context drv_ctx; | ||
54 | VMBUS_DRIVER_OBJECT drv_obj; | ||
55 | |||
56 | struct bus_type bus; | ||
57 | struct tasklet_struct msg_dpc; | ||
58 | struct tasklet_struct event_dpc; | ||
59 | |||
60 | // The bus root device | ||
61 | struct device_context device_ctx; | ||
62 | }; | ||
63 | |||
64 | // | ||
65 | // Static decl | ||
66 | // | ||
67 | static int vmbus_match(struct device *device, struct device_driver *driver); | ||
68 | static int vmbus_probe(struct device *device); | ||
69 | static int vmbus_remove(struct device *device); | ||
70 | static void vmbus_shutdown(struct device *device); | ||
71 | #if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | ||
72 | #elif defined(KERNEL_2_6_27) | ||
73 | static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env); | ||
74 | #else | ||
75 | static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size); | ||
76 | #endif | ||
77 | static void vmbus_msg_dpc(unsigned long data); | ||
78 | static void vmbus_event_dpc(unsigned long data); | ||
79 | |||
80 | #ifdef KERNEL_2_6_27 | ||
81 | static irqreturn_t vmbus_isr(int irq, void* dev_id); | ||
82 | #else | ||
83 | static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs); | ||
84 | #endif | ||
85 | |||
86 | static void vmbus_device_release(struct device *device); | ||
87 | static void vmbus_bus_release(struct device *device); | ||
88 | |||
89 | static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context); | ||
90 | static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj); | ||
91 | static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj); | ||
92 | static void vmbus_child_device_unregister(DEVICE_OBJECT* child_device_obj); | ||
93 | static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info); | ||
94 | |||
95 | //static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf); | ||
96 | //static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf); | ||
97 | |||
98 | static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf); | ||
99 | |||
100 | // | ||
101 | // Global | ||
102 | // | ||
103 | |||
104 | // Global logging setting | ||
105 | |||
106 | //unsigned int vmbus_loglevel= (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); | ||
107 | //unsigned int vmbus_loglevel= (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); | ||
108 | unsigned int vmbus_loglevel= (ALL_MODULES << 16 | INFO_LVL); | ||
109 | EXPORT_SYMBOL(vmbus_loglevel); | ||
110 | |||
111 | static int vmbus_irq = VMBUS_IRQ; | ||
112 | |||
113 | // Setup /proc/sys/bus/vmbus/vmbus_loglevel | ||
114 | // Allow usage of sysctl cmd to set the logging level | ||
115 | static struct ctl_table_header *vmbus_ctl_table_hdr; | ||
116 | |||
117 | static ctl_table vmbus_dev_ctl_table[] = { | ||
118 | { .ctl_name = 8461, | ||
119 | .procname = "vmbus_loglevel", | ||
120 | .data = &vmbus_loglevel, | ||
121 | .maxlen = sizeof(vmbus_loglevel), | ||
122 | .mode = 0644, | ||
123 | .proc_handler = &proc_dointvec }, | ||
124 | { } | ||
125 | }; | ||
126 | |||
127 | static ctl_table vmbus_ctl_table[] = { | ||
128 | { .ctl_name = CTL_DEV, | ||
129 | .procname = "vmbus", | ||
130 | .mode = 0555, | ||
131 | .child = vmbus_dev_ctl_table }, | ||
132 | { } | ||
133 | }; | ||
134 | |||
135 | static ctl_table vmus_root_ctl_table[] = { | ||
136 | { .ctl_name = CTL_BUS, | ||
137 | .procname = "bus", | ||
138 | .mode = 0555, | ||
139 | .child = vmbus_ctl_table }, | ||
140 | { } | ||
141 | }; | ||
142 | |||
143 | #if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | ||
144 | #else | ||
145 | // | ||
146 | // Set up per device attributes in /sys/bus/vmbus/devices/<bus device> | ||
147 | // | ||
148 | static struct device_attribute vmbus_device_attrs[] = { | ||
149 | __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL), | ||
150 | __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL), | ||
151 | __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL), | ||
152 | __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL), | ||
153 | __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL), | ||
154 | |||
155 | __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), | ||
156 | __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), | ||
157 | __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), | ||
158 | |||
159 | __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), | ||
160 | __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), | ||
161 | __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), | ||
162 | |||
163 | __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), | ||
164 | __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL), | ||
165 | __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL), | ||
166 | __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | ||
167 | __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | ||
168 | |||
169 | __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), | ||
170 | __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL), | ||
171 | __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL), | ||
172 | __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | ||
173 | __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | ||
174 | __ATTR_NULL | ||
175 | }; | ||
176 | #endif | ||
177 | |||
178 | // The one and only one | ||
179 | static struct vmbus_driver_context g_vmbus_drv={ | ||
180 | .bus.name = "vmbus", | ||
181 | .bus.match = vmbus_match, | ||
182 | #if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | ||
183 | #else | ||
184 | .bus.shutdown = vmbus_shutdown, | ||
185 | .bus.remove = vmbus_remove, | ||
186 | .bus.probe = vmbus_probe, | ||
187 | .bus.uevent = vmbus_uevent, | ||
188 | .bus.dev_attrs = vmbus_device_attrs, | ||
189 | #endif | ||
190 | }; | ||
191 | |||
192 | // | ||
193 | // Routines | ||
194 | // | ||
195 | |||
196 | |||
197 | /*++ | ||
198 | |||
199 | Name: vmbus_show_device_attr() | ||
200 | |||
201 | Desc: Show the device attribute in sysfs. This is invoked when user does a "cat /sys/bus/vmbus/devices/<bus device>/<attr name>" | ||
202 | |||
203 | --*/ | ||
204 | static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf) | ||
205 | { | ||
206 | struct device_context *device_ctx = device_to_device_context(dev); | ||
207 | DEVICE_INFO device_info; | ||
208 | |||
209 | memset(&device_info, 0, sizeof(DEVICE_INFO)); | ||
210 | |||
211 | vmbus_child_device_get_info(&device_ctx->device_obj, &device_info); | ||
212 | |||
213 | if (!strcmp(dev_attr->attr.name, "class_id")) | ||
214 | { | ||
215 | return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", | ||
216 | device_info.ChannelType.Data[3], device_info.ChannelType.Data[2], device_info.ChannelType.Data[1], device_info.ChannelType.Data[0], | ||
217 | device_info.ChannelType.Data[5], device_info.ChannelType.Data[4], | ||
218 | device_info.ChannelType.Data[7], device_info.ChannelType.Data[6], | ||
219 | device_info.ChannelType.Data[8], device_info.ChannelType.Data[9], device_info.ChannelType.Data[10], device_info.ChannelType.Data[11], device_info.ChannelType.Data[12], device_info.ChannelType.Data[13], device_info.ChannelType.Data[14], device_info.ChannelType.Data[15]); | ||
220 | |||
221 | } | ||
222 | else if (!strcmp(dev_attr->attr.name, "device_id")) | ||
223 | { | ||
224 | return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", | ||
225 | device_info.ChannelInstance.Data[3], device_info.ChannelInstance.Data[2], device_info.ChannelInstance.Data[1], device_info.ChannelInstance.Data[0], | ||
226 | device_info.ChannelInstance.Data[5], device_info.ChannelInstance.Data[4], | ||
227 | device_info.ChannelInstance.Data[7], device_info.ChannelInstance.Data[6], | ||
228 | device_info.ChannelInstance.Data[8], device_info.ChannelInstance.Data[9], device_info.ChannelInstance.Data[10], device_info.ChannelInstance.Data[11], device_info.ChannelInstance.Data[12], device_info.ChannelInstance.Data[13], device_info.ChannelInstance.Data[14], device_info.ChannelInstance.Data[15]); | ||
229 | } | ||
230 | else if (!strcmp(dev_attr->attr.name, "state")) | ||
231 | { | ||
232 | return sprintf(buf, "%d\n", device_info.ChannelState); | ||
233 | } | ||
234 | else if (!strcmp(dev_attr->attr.name, "id")) | ||
235 | { | ||
236 | return sprintf(buf, "%d\n", device_info.ChannelId); | ||
237 | } | ||
238 | else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) | ||
239 | { | ||
240 | return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask); | ||
241 | } | ||
242 | else if (!strcmp(dev_attr->attr.name, "out_read_index")) | ||
243 | { | ||
244 | return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex); | ||
245 | } | ||
246 | else if (!strcmp(dev_attr->attr.name, "out_write_index")) | ||
247 | { | ||
248 | return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex); | ||
249 | } | ||
250 | else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) | ||
251 | { | ||
252 | return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToRead); | ||
253 | } | ||
254 | else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) | ||
255 | { | ||
256 | return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToWrite); | ||
257 | } | ||
258 | else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) | ||
259 | { | ||
260 | return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask); | ||
261 | } | ||
262 | else if (!strcmp(dev_attr->attr.name, "in_read_index")) | ||
263 | { | ||
264 | return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex); | ||
265 | } | ||
266 | else if (!strcmp(dev_attr->attr.name, "in_write_index")) | ||
267 | { | ||
268 | return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex); | ||
269 | } | ||
270 | else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) | ||
271 | { | ||
272 | return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToRead); | ||
273 | } | ||
274 | else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) | ||
275 | { | ||
276 | return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToWrite); | ||
277 | } | ||
278 | else if (!strcmp(dev_attr->attr.name, "monitor_id")) | ||
279 | { | ||
280 | return sprintf(buf, "%d\n", device_info.MonitorId); | ||
281 | } | ||
282 | else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) | ||
283 | { | ||
284 | return sprintf(buf, "%d\n", device_info.ServerMonitorPending); | ||
285 | } | ||
286 | else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) | ||
287 | { | ||
288 | return sprintf(buf, "%d\n", device_info.ServerMonitorLatency); | ||
289 | } | ||
290 | else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) | ||
291 | { | ||
292 | return sprintf(buf, "%d\n", device_info.ServerMonitorConnectionId); | ||
293 | } | ||
294 | else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) | ||
295 | { | ||
296 | return sprintf(buf, "%d\n", device_info.ClientMonitorPending); | ||
297 | } | ||
298 | else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) | ||
299 | { | ||
300 | return sprintf(buf, "%d\n", device_info.ClientMonitorLatency); | ||
301 | } | ||
302 | else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) | ||
303 | { | ||
304 | return sprintf(buf, "%d\n", device_info.ClientMonitorConnectionId); | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | return 0; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /*++ | ||
313 | |||
314 | Name: vmbus_show_class_id() | ||
315 | |||
316 | Desc: Show the device class id in sysfs | ||
317 | |||
318 | --*/ | ||
319 | //static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf) | ||
320 | //{ | ||
321 | // struct device_context *device_ctx = device_to_device_context(dev); | ||
322 | // return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", | ||
323 | // device_ctx->class_id[3], device_ctx->class_id[2], device_ctx->class_id[1], device_ctx->class_id[0], | ||
324 | // device_ctx->class_id[5], device_ctx->class_id[4], | ||
325 | // device_ctx->class_id[7], device_ctx->class_id[6], | ||
326 | // device_ctx->class_id[8], device_ctx->class_id[9], device_ctx->class_id[10], device_ctx->class_id[11], device_ctx->class_id[12], device_ctx->class_id[13], device_ctx->class_id[14], device_ctx->class_id[15]); | ||
327 | //} | ||
328 | |||
329 | /*++ | ||
330 | |||
331 | Name: vmbus_show_device_id() | ||
332 | |||
333 | Desc: Show the device instance id in sysfs | ||
334 | |||
335 | --*/ | ||
336 | //static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf) | ||
337 | //{ | ||
338 | // struct device_context *device_ctx = device_to_device_context(dev); | ||
339 | // return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", | ||
340 | // device_ctx->device_id[3], device_ctx->device_id[2], device_ctx->device_id[1], device_ctx->device_id[0], | ||
341 | // device_ctx->device_id[5], device_ctx->device_id[4], | ||
342 | // device_ctx->device_id[7], device_ctx->device_id[6], | ||
343 | // device_ctx->device_id[8], device_ctx->device_id[9], device_ctx->device_id[10], device_ctx->device_id[11], device_ctx->device_id[12], device_ctx->device_id[13], device_ctx->device_id[14], device_ctx->device_id[15]); | ||
344 | //} | ||
345 | |||
346 | /*++ | ||
347 | |||
348 | Name: vmbus_bus_init() | ||
349 | |||
350 | Desc: Main vmbus driver initialization routine. Here, we | ||
351 | - initialize the vmbus driver context | ||
352 | - setup various driver entry points | ||
353 | - invoke the vmbus hv main init routine | ||
354 | - get the irq resource | ||
355 | - invoke the vmbus to add the vmbus root device | ||
356 | - setup the vmbus root device | ||
357 | - retrieve the channel offers | ||
358 | --*/ | ||
359 | int vmbus_bus_init(PFN_DRIVERINITIALIZE pfn_drv_init) | ||
360 | { | ||
361 | int ret=0; | ||
362 | unsigned int vector=0; | ||
363 | |||
364 | struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv; | ||
365 | VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | ||
366 | |||
367 | struct device_context *dev_ctx=&g_vmbus_drv.device_ctx; | ||
368 | |||
369 | DPRINT_ENTER(VMBUS_DRV); | ||
370 | |||
371 | // Set this up to allow lower layer to callback to add/remove child devices on the bus | ||
372 | vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create; | ||
373 | vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy; | ||
374 | vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register; | ||
375 | vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister; | ||
376 | |||
377 | // Call to bus driver to initialize | ||
378 | ret = pfn_drv_init(&vmbus_drv_obj->Base); | ||
379 | if (ret != 0) | ||
380 | { | ||
381 | DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret); | ||
382 | goto cleanup; | ||
383 | } | ||
384 | |||
385 | // Sanity checks | ||
386 | if (!vmbus_drv_obj->Base.OnDeviceAdd) | ||
387 | { | ||
388 | DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set"); | ||
389 | ret = -1; | ||
390 | goto cleanup; | ||
391 | } | ||
392 | |||
393 | vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name; | ||
394 | |||
395 | // Initialize the bus context | ||
396 | tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, (unsigned long)vmbus_drv_obj); | ||
397 | tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, (unsigned long)vmbus_drv_obj); | ||
398 | |||
399 | // Now, register the bus driver with LDM | ||
400 | bus_register(&vmbus_drv_ctx->bus); | ||
401 | |||
402 | // Get the interrupt resource | ||
403 | #ifdef KERNEL_2_6_27 | ||
404 | ret = request_irq(vmbus_irq, | ||
405 | vmbus_isr, | ||
406 | IRQF_SAMPLE_RANDOM, | ||
407 | vmbus_drv_obj->Base.name, | ||
408 | NULL); | ||
409 | #else | ||
410 | ret = request_irq(vmbus_irq, | ||
411 | vmbus_isr, | ||
412 | SA_SAMPLE_RANDOM, | ||
413 | vmbus_drv_obj->Base.name, | ||
414 | NULL); | ||
415 | #endif | ||
416 | |||
417 | if (ret != 0) | ||
418 | { | ||
419 | DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", vmbus_irq); | ||
420 | |||
421 | bus_unregister(&vmbus_drv_ctx->bus); | ||
422 | |||
423 | ret = -1; | ||
424 | goto cleanup; | ||
425 | } | ||
426 | #ifdef KERNEL_2_6_27 | ||
427 | vector = VMBUS_IRQ_VECTOR; | ||
428 | #else | ||
429 | #if X2V_LINUX | ||
430 | vector = vmbus_irq + FIRST_DEVICE_VECTOR - 2; | ||
431 | #else | ||
432 | vector = vmbus_irq + FIRST_EXTERNAL_VECTOR; | ||
433 | #endif | ||
434 | #endif | ||
435 | |||
436 | DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector); | ||
437 | |||
438 | // Call to bus driver to add the root device | ||
439 | memset(dev_ctx, 0, sizeof(struct device_context)); | ||
440 | |||
441 | ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector); | ||
442 | if (ret != 0) | ||
443 | { | ||
444 | DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to add vmbus root device"); | ||
445 | |||
446 | free_irq(vmbus_irq, NULL); | ||
447 | |||
448 | bus_unregister(&vmbus_drv_ctx->bus); | ||
449 | |||
450 | ret = -1; | ||
451 | goto cleanup; | ||
452 | } | ||
453 | //strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); | ||
454 | sprintf(dev_ctx->device.bus_id, "vmbus_0_0"); | ||
455 | memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType, sizeof(GUID)); | ||
456 | memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance, sizeof(GUID)); | ||
457 | |||
458 | // No need to bind a driver to the root device. | ||
459 | dev_ctx->device.parent = NULL; | ||
460 | dev_ctx->device.bus = &vmbus_drv_ctx->bus; //NULL; // vmbus_remove() does not get invoked | ||
461 | |||
462 | // Setup the device dispatch table | ||
463 | dev_ctx->device.release = vmbus_bus_release; | ||
464 | |||
465 | // Setup the bus as root device | ||
466 | device_register(&dev_ctx->device); | ||
467 | |||
468 | vmbus_drv_obj->GetChannelOffers(); | ||
469 | |||
470 | cleanup: | ||
471 | DPRINT_EXIT(VMBUS_DRV); | ||
472 | |||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | |||
477 | /*++ | ||
478 | |||
479 | Name: vmbus_bus_exit() | ||
480 | |||
481 | Desc: Terminate the vmbus driver. This routine is opposite of vmbus_bus_init() | ||
482 | |||
483 | --*/ | ||
484 | void vmbus_bus_exit(void) | ||
485 | { | ||
486 | VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | ||
487 | struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv; | ||
488 | |||
489 | struct device_context *dev_ctx=&g_vmbus_drv.device_ctx; | ||
490 | |||
491 | DPRINT_ENTER(VMBUS_DRV); | ||
492 | |||
493 | // Remove the root device | ||
494 | if (vmbus_drv_obj->Base.OnDeviceRemove) | ||
495 | vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj); | ||
496 | |||
497 | if (vmbus_drv_obj->Base.OnCleanup) | ||
498 | vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base); | ||
499 | |||
500 | // Unregister the root bus device | ||
501 | device_unregister(&dev_ctx->device); | ||
502 | |||
503 | bus_unregister(&vmbus_drv_ctx->bus); | ||
504 | |||
505 | free_irq(vmbus_irq, NULL); | ||
506 | |||
507 | tasklet_kill(&vmbus_drv_ctx->msg_dpc); | ||
508 | tasklet_kill(&vmbus_drv_ctx->event_dpc); | ||
509 | |||
510 | DPRINT_EXIT(VMBUS_DRV); | ||
511 | |||
512 | return; | ||
513 | } | ||
514 | |||
515 | /*++ | ||
516 | |||
517 | Name: vmbus_child_driver_register() | ||
518 | |||
519 | Desc: Register a vmbus's child driver | ||
520 | |||
521 | --*/ | ||
522 | void vmbus_child_driver_register(struct driver_context* driver_ctx) | ||
523 | { | ||
524 | VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | ||
525 | |||
526 | DPRINT_ENTER(VMBUS_DRV); | ||
527 | |||
528 | DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", driver_ctx, driver_ctx->driver.name); | ||
529 | |||
530 | // The child driver on this vmbus | ||
531 | driver_ctx->driver.bus = &g_vmbus_drv.bus; | ||
532 | |||
533 | driver_register(&driver_ctx->driver); | ||
534 | |||
535 | vmbus_drv_obj->GetChannelOffers(); | ||
536 | |||
537 | DPRINT_EXIT(VMBUS_DRV); | ||
538 | } | ||
539 | |||
540 | EXPORT_SYMBOL(vmbus_child_driver_register); | ||
541 | |||
542 | /*++ | ||
543 | |||
544 | Name: vmbus_child_driver_unregister() | ||
545 | |||
546 | Desc: Unregister a vmbus's child driver | ||
547 | |||
548 | --*/ | ||
549 | void vmbus_child_driver_unregister(struct driver_context* driver_ctx) | ||
550 | { | ||
551 | DPRINT_ENTER(VMBUS_DRV); | ||
552 | |||
553 | DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", driver_ctx, driver_ctx->driver.name); | ||
554 | |||
555 | driver_unregister(&driver_ctx->driver); | ||
556 | |||
557 | driver_ctx->driver.bus = NULL; | ||
558 | |||
559 | DPRINT_EXIT(VMBUS_DRV); | ||
560 | } | ||
561 | |||
562 | EXPORT_SYMBOL(vmbus_child_driver_unregister); | ||
563 | |||
564 | /*++ | ||
565 | |||
566 | Name: vmbus_get_interface() | ||
567 | |||
568 | Desc: Get the vmbus channel interface. This is invoked by child/client driver that sits | ||
569 | above vmbus | ||
570 | --*/ | ||
571 | void vmbus_get_interface(VMBUS_CHANNEL_INTERFACE *interface) | ||
572 | { | ||
573 | VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | ||
574 | |||
575 | vmbus_drv_obj->GetChannelInterface(interface); | ||
576 | } | ||
577 | |||
578 | EXPORT_SYMBOL(vmbus_get_interface); | ||
579 | |||
580 | |||
581 | /*++ | ||
582 | |||
583 | Name: vmbus_child_device_get_info() | ||
584 | |||
585 | Desc: Get the vmbus child device info. This is invoked to display various device attributes in sysfs. | ||
586 | --*/ | ||
587 | static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info) | ||
588 | { | ||
589 | VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | ||
590 | |||
591 | vmbus_drv_obj->GetChannelInfo(device_obj, device_info); | ||
592 | } | ||
593 | |||
594 | |||
595 | /*++ | ||
596 | |||
597 | Name: vmbus_child_device_create() | ||
598 | |||
599 | Desc: Creates and registers a new child device on the vmbus. | ||
600 | |||
601 | --*/ | ||
602 | static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context) | ||
603 | { | ||
604 | struct device_context *child_device_ctx; | ||
605 | DEVICE_OBJECT* child_device_obj; | ||
606 | |||
607 | DPRINT_ENTER(VMBUS_DRV); | ||
608 | |||
609 | // Allocate the new child device | ||
610 | child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL); | ||
611 | if (!child_device_ctx) | ||
612 | { | ||
613 | DPRINT_ERR(VMBUS_DRV, "unable to allocate device_context for child device"); | ||
614 | DPRINT_EXIT(VMBUS_DRV); | ||
615 | |||
616 | return NULL; | ||
617 | } | ||
618 | |||
619 | DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - " | ||
620 | "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}," | ||
621 | "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | ||
622 | &child_device_ctx->device, | ||
623 | type.Data[3], type.Data[2], type.Data[1], type.Data[0], type.Data[5], type.Data[4], type.Data[7], type.Data[6], type.Data[8], type.Data[9], type.Data[10], type.Data[11], type.Data[12], type.Data[13], type.Data[14], type.Data[15], | ||
624 | instance.Data[3], instance.Data[2], instance.Data[1], instance.Data[0], instance.Data[5], instance.Data[4], instance.Data[7], instance.Data[6], instance.Data[8], instance.Data[9], instance.Data[10], instance.Data[11], instance.Data[12], instance.Data[13], instance.Data[14], instance.Data[15]); | ||
625 | |||
626 | child_device_obj = &child_device_ctx->device_obj; | ||
627 | child_device_obj->context = context; | ||
628 | memcpy(&child_device_obj->deviceType, &type, sizeof(GUID)); | ||
629 | memcpy(&child_device_obj->deviceInstance, &instance, sizeof(GUID)); | ||
630 | |||
631 | memcpy(&child_device_ctx->class_id, &type, sizeof(GUID)); | ||
632 | memcpy(&child_device_ctx->device_id, &instance, sizeof(GUID)); | ||
633 | |||
634 | DPRINT_EXIT(VMBUS_DRV); | ||
635 | |||
636 | return child_device_obj; | ||
637 | } | ||
638 | |||
639 | /*++ | ||
640 | |||
641 | Name: vmbus_child_device_register() | ||
642 | |||
643 | Desc: Register the child device on the specified bus | ||
644 | |||
645 | --*/ | ||
646 | static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj) | ||
647 | { | ||
648 | int ret=0; | ||
649 | struct device_context *root_device_ctx = to_device_context(root_device_obj); | ||
650 | struct device_context *child_device_ctx = to_device_context(child_device_obj); | ||
651 | static int device_num=0; | ||
652 | |||
653 | DPRINT_ENTER(VMBUS_DRV); | ||
654 | |||
655 | DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", child_device_ctx); | ||
656 | // | ||
657 | // Make sure we are not registered already | ||
658 | // | ||
659 | if (child_device_ctx->device.bus_id[0] != '\0') | ||
660 | { | ||
661 | DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, child_device_ctx->device.bus_id); | ||
662 | |||
663 | ret = -1; | ||
664 | goto Cleanup; | ||
665 | } | ||
666 | |||
667 | // Set the device bus id. Otherwise, device_register()will fail. | ||
668 | sprintf(child_device_ctx->device.bus_id, "vmbus_0_%d", InterlockedIncrement(&device_num)); | ||
669 | |||
670 | // The new device belongs to this bus | ||
671 | child_device_ctx->device.bus = &g_vmbus_drv.bus; //device->dev.bus; | ||
672 | child_device_ctx->device.parent = &root_device_ctx->device; | ||
673 | child_device_ctx->device.release = vmbus_device_release; | ||
674 | |||
675 | // Register with the LDM. This will kick off the driver/device binding...which will | ||
676 | // eventually call vmbus_match() and vmbus_probe() | ||
677 | ret = device_register(&child_device_ctx->device); | ||
678 | |||
679 | // vmbus_probe() error does not get propergate to device_register(). | ||
680 | ret = child_device_ctx->probe_error; | ||
681 | |||
682 | if (ret) | ||
683 | DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p) (%d)", &child_device_ctx->device); | ||
684 | else | ||
685 | DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", &child_device_ctx->device); | ||
686 | |||
687 | Cleanup: | ||
688 | DPRINT_EXIT(VMBUS_DRV); | ||
689 | |||
690 | return ret; | ||
691 | } | ||
692 | |||
693 | /*++ | ||
694 | |||
695 | Name: vmbus_child_device_unregister() | ||
696 | |||
697 | Desc: Remove the specified child device from the vmbus. | ||
698 | |||
699 | --*/ | ||
700 | static void vmbus_child_device_unregister(DEVICE_OBJECT* device_obj) | ||
701 | { | ||
702 | struct device_context *device_ctx = to_device_context(device_obj); | ||
703 | |||
704 | DPRINT_ENTER(VMBUS_DRV); | ||
705 | |||
706 | DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", &device_ctx->device); | ||
707 | |||
708 | // Kick off the process of unregistering the device. | ||
709 | // This will call vmbus_remove() and eventually vmbus_device_release() | ||
710 | device_unregister(&device_ctx->device); | ||
711 | |||
712 | DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", &device_ctx->device); | ||
713 | |||
714 | DPRINT_EXIT(VMBUS_DRV); | ||
715 | } | ||
716 | |||
717 | |||
718 | /*++ | ||
719 | |||
720 | Name: vmbus_child_device_destroy() | ||
721 | |||
722 | Desc: Destroy the specified child device on the vmbus. | ||
723 | |||
724 | --*/ | ||
725 | static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj) | ||
726 | { | ||
727 | DPRINT_ENTER(VMBUS_DRV); | ||
728 | |||
729 | DPRINT_EXIT(VMBUS_DRV); | ||
730 | } | ||
731 | |||
732 | /*++ | ||
733 | |||
734 | Name: vmbus_uevent() | ||
735 | |||
736 | Desc: This routine is invoked when a device is added or removed on the vmbus to generate a uevent to udev in the | ||
737 | userspace. The udev will then look at its rule and the uevent generated here to load the appropriate driver | ||
738 | |||
739 | --*/ | ||
740 | #if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | ||
741 | #elif defined(KERNEL_2_6_27) | ||
742 | static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) | ||
743 | { | ||
744 | struct device_context *device_ctx = device_to_device_context(device); | ||
745 | int i=0; | ||
746 | int len=0; | ||
747 | int ret; | ||
748 | |||
749 | DPRINT_ENTER(VMBUS_DRV); | ||
750 | |||
751 | DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | ||
752 | device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], | ||
753 | device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], | ||
754 | device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], | ||
755 | device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], | ||
756 | device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); | ||
757 | |||
758 | env->envp_idx = i; | ||
759 | env->buflen = len; | ||
760 | ret = add_uevent_var(env, | ||
761 | "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | ||
762 | device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], | ||
763 | device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], | ||
764 | device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], | ||
765 | device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], | ||
766 | device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); | ||
767 | |||
768 | if (ret) | ||
769 | { | ||
770 | return ret; | ||
771 | } | ||
772 | |||
773 | ret = add_uevent_var(env, | ||
774 | "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | ||
775 | device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0], | ||
776 | device_ctx->device_id.Data[5], device_ctx->device_id.Data[4], | ||
777 | device_ctx->device_id.Data[7], device_ctx->device_id.Data[6], | ||
778 | device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11], | ||
779 | device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]); | ||
780 | |||
781 | if (ret) | ||
782 | { | ||
783 | return ret; | ||
784 | } | ||
785 | |||
786 | env->envp[env->envp_idx] = NULL; | ||
787 | |||
788 | DPRINT_EXIT(VMBUS_DRV); | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | #else | ||
794 | static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size) | ||
795 | { | ||
796 | struct device_context *device_ctx = device_to_device_context(device); | ||
797 | int i=0; | ||
798 | int len=0; | ||
799 | int ret; | ||
800 | |||
801 | DPRINT_ENTER(VMBUS_DRV); | ||
802 | |||
803 | DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | ||
804 | device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], | ||
805 | device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], | ||
806 | device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], | ||
807 | device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], | ||
808 | device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); | ||
809 | |||
810 | ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | ||
811 | "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | ||
812 | device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], | ||
813 | device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], | ||
814 | device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], | ||
815 | device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], | ||
816 | device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); | ||
817 | |||
818 | if (ret) | ||
819 | { | ||
820 | return ret; | ||
821 | } | ||
822 | |||
823 | ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | ||
824 | "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | ||
825 | device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0], | ||
826 | device_ctx->device_id.Data[5], device_ctx->device_id.Data[4], | ||
827 | device_ctx->device_id.Data[7], device_ctx->device_id.Data[6], | ||
828 | device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11], | ||
829 | device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]); | ||
830 | |||
831 | if (ret) | ||
832 | { | ||
833 | return ret; | ||
834 | } | ||
835 | |||
836 | envp[i] = NULL; | ||
837 | |||
838 | DPRINT_EXIT(VMBUS_DRV); | ||
839 | |||
840 | return 0; | ||
841 | } | ||
842 | #endif | ||
843 | |||
844 | /*++ | ||
845 | |||
846 | Name: vmbus_match() | ||
847 | |||
848 | Desc: Attempt to match the specified device to the specified driver | ||
849 | |||
850 | --*/ | ||
851 | static int vmbus_match(struct device *device, struct device_driver *driver) | ||
852 | { | ||
853 | int match=0; | ||
854 | struct driver_context *driver_ctx = driver_to_driver_context(driver); | ||
855 | struct device_context *device_ctx = device_to_device_context(device); | ||
856 | |||
857 | DPRINT_ENTER(VMBUS_DRV); | ||
858 | |||
859 | // We found our driver ? | ||
860 | if (memcmp(&device_ctx->class_id, &driver_ctx->class_id, sizeof(GUID)) == 0) | ||
861 | { | ||
862 | // !! NOTE: The driver_ctx is not a vmbus_drv_ctx. We typecast it here to access the | ||
863 | // DRIVER_OBJECT field | ||
864 | struct vmbus_driver_context *vmbus_drv_ctx = (struct vmbus_driver_context*)driver_ctx; | ||
865 | device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base; | ||
866 | DPRINT_INFO(VMBUS_DRV, "device object (%p) set to driver object (%p)", &device_ctx->device_obj, device_ctx->device_obj.Driver); | ||
867 | |||
868 | match = 1; | ||
869 | } | ||
870 | |||
871 | DPRINT_EXIT(VMBUS_DRV); | ||
872 | |||
873 | return match; | ||
874 | } | ||
875 | |||
876 | |||
877 | /*++ | ||
878 | |||
879 | Name: vmbus_probe_failed_cb() | ||
880 | |||
881 | Desc: Callback when a driver probe failed in vmbus_probe(). We need a callback because | ||
882 | we cannot invoked device_unregister() inside vmbus_probe() since vmbus_probe() may be | ||
883 | invoked inside device_register() i.e. we cannot call device_unregister() inside | ||
884 | device_register() | ||
885 | --*/ | ||
886 | #ifdef KERNEL_2_6_27 | ||
887 | static void vmbus_probe_failed_cb(struct work_struct *context) | ||
888 | #else | ||
889 | static void vmbus_probe_failed_cb(void* context) | ||
890 | #endif | ||
891 | { | ||
892 | struct device_context *device_ctx = (struct device_context*)context; | ||
893 | |||
894 | |||
895 | DPRINT_ENTER(VMBUS_DRV); | ||
896 | |||
897 | // Kick off the process of unregistering the device. | ||
898 | // This will call vmbus_remove() and eventually vmbus_device_release() | ||
899 | device_unregister(&device_ctx->device); | ||
900 | |||
901 | //put_device(&device_ctx->device); | ||
902 | DPRINT_EXIT(VMBUS_DRV); | ||
903 | } | ||
904 | |||
905 | |||
906 | /*++ | ||
907 | |||
908 | Name: vmbus_probe() | ||
909 | |||
910 | Desc: Add the new vmbus's child device | ||
911 | |||
912 | --*/ | ||
913 | static int vmbus_probe(struct device *child_device) | ||
914 | { | ||
915 | int ret=0; | ||
916 | struct driver_context *driver_ctx = driver_to_driver_context(child_device->driver); | ||
917 | struct device_context *device_ctx = device_to_device_context(child_device); | ||
918 | |||
919 | DPRINT_ENTER(VMBUS_DRV); | ||
920 | |||
921 | // Let the specific open-source driver handles the probe if it can | ||
922 | if (driver_ctx->probe) | ||
923 | { | ||
924 | ret = device_ctx->probe_error = driver_ctx->probe(child_device); | ||
925 | if (ret != 0) | ||
926 | { | ||
927 | DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s (%p) on driver %s (%d)...", child_device->bus_id, child_device, child_device->driver->name, ret); | ||
928 | |||
929 | #ifdef KERNEL_2_6_27 | ||
930 | INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb); | ||
931 | #else | ||
932 | INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb, device_ctx); | ||
933 | #endif | ||
934 | schedule_work(&device_ctx->probe_failed_work_item); | ||
935 | } | ||
936 | } | ||
937 | else | ||
938 | { | ||
939 | DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", child_device->driver->name); | ||
940 | ret = -1; | ||
941 | } | ||
942 | |||
943 | DPRINT_EXIT(VMBUS_DRV); | ||
944 | return ret; | ||
945 | } | ||
946 | |||
947 | |||
948 | /*++ | ||
949 | |||
950 | Name: vmbus_remove() | ||
951 | |||
952 | Desc: Remove a vmbus device | ||
953 | |||
954 | --*/ | ||
955 | static int vmbus_remove(struct device *child_device) | ||
956 | { | ||
957 | int ret=0; | ||
958 | struct driver_context *driver_ctx; | ||
959 | |||
960 | DPRINT_ENTER(VMBUS_DRV); | ||
961 | |||
962 | // Special case root bus device | ||
963 | if (child_device->parent == NULL) | ||
964 | { | ||
965 | // No-op since it is statically defined and handle in vmbus_bus_exit() | ||
966 | DPRINT_EXIT(VMBUS_DRV); | ||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | if (child_device->driver) | ||
971 | { | ||
972 | driver_ctx = driver_to_driver_context(child_device->driver); | ||
973 | |||
974 | // Let the specific open-source driver handles the removal if it can | ||
975 | if (driver_ctx->remove) | ||
976 | { | ||
977 | ret = driver_ctx->remove(child_device); | ||
978 | } | ||
979 | else | ||
980 | { | ||
981 | DPRINT_ERR(VMBUS_DRV, "remove() method not set for driver - %s", child_device->driver->name); | ||
982 | ret = -1; | ||
983 | } | ||
984 | } | ||
985 | else | ||
986 | { | ||
987 | |||
988 | } | ||
989 | |||
990 | DPRINT_EXIT(VMBUS_DRV); | ||
991 | |||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | /*++ | ||
996 | |||
997 | Name: vmbus_shutdown() | ||
998 | |||
999 | Desc: Shutdown a vmbus device | ||
1000 | |||
1001 | --*/ | ||
1002 | static void vmbus_shutdown(struct device *child_device) | ||
1003 | { | ||
1004 | struct driver_context *driver_ctx; | ||
1005 | |||
1006 | DPRINT_ENTER(VMBUS_DRV); | ||
1007 | |||
1008 | // Special case root bus device | ||
1009 | if (child_device->parent == NULL) | ||
1010 | { | ||
1011 | // No-op since it is statically defined and handle in vmbus_bus_exit() | ||
1012 | DPRINT_EXIT(VMBUS_DRV); | ||
1013 | return; | ||
1014 | } | ||
1015 | |||
1016 | // The device may not be attached yet | ||
1017 | if (!child_device->driver) | ||
1018 | { | ||
1019 | DPRINT_EXIT(VMBUS_DRV); | ||
1020 | return; | ||
1021 | } | ||
1022 | |||
1023 | driver_ctx = driver_to_driver_context(child_device->driver); | ||
1024 | |||
1025 | // Let the specific open-source driver handles the removal if it can | ||
1026 | if (driver_ctx->shutdown) | ||
1027 | { | ||
1028 | driver_ctx->shutdown(child_device); | ||
1029 | } | ||
1030 | |||
1031 | DPRINT_EXIT(VMBUS_DRV); | ||
1032 | |||
1033 | return; | ||
1034 | } | ||
1035 | |||
1036 | /*++ | ||
1037 | |||
1038 | Name: vmbus_bus_release() | ||
1039 | |||
1040 | Desc: Final callback release of the vmbus root device | ||
1041 | |||
1042 | --*/ | ||
1043 | static void vmbus_bus_release(struct device *device) | ||
1044 | { | ||
1045 | DPRINT_ENTER(VMBUS_DRV); | ||
1046 | DPRINT_EXIT(VMBUS_DRV); | ||
1047 | } | ||
1048 | |||
1049 | /*++ | ||
1050 | |||
1051 | Name: vmbus_device_release() | ||
1052 | |||
1053 | Desc: Final callback release of the vmbus child device | ||
1054 | |||
1055 | --*/ | ||
1056 | static void vmbus_device_release(struct device *device) | ||
1057 | { | ||
1058 | struct device_context *device_ctx = device_to_device_context(device); | ||
1059 | |||
1060 | DPRINT_ENTER(VMBUS_DRV); | ||
1061 | |||
1062 | //vmbus_child_device_destroy(&device_ctx->device_obj); | ||
1063 | kfree(device_ctx); | ||
1064 | |||
1065 | // !!DO NOT REFERENCE device_ctx anymore at this point!! | ||
1066 | |||
1067 | DPRINT_EXIT(VMBUS_DRV); | ||
1068 | |||
1069 | return; | ||
1070 | } | ||
1071 | |||
1072 | /*++ | ||
1073 | |||
1074 | Name: vmbus_msg_dpc() | ||
1075 | |||
1076 | Desc: Tasklet routine to handle hypervisor messages | ||
1077 | |||
1078 | --*/ | ||
1079 | static void vmbus_msg_dpc(unsigned long data) | ||
1080 | { | ||
1081 | VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data; | ||
1082 | |||
1083 | DPRINT_ENTER(VMBUS_DRV); | ||
1084 | |||
1085 | ASSERT(vmbus_drv_obj->OnMsgDpc != NULL); | ||
1086 | |||
1087 | // Call to bus driver to handle interrupt | ||
1088 | vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base); | ||
1089 | |||
1090 | DPRINT_EXIT(VMBUS_DRV); | ||
1091 | } | ||
1092 | |||
1093 | /*++ | ||
1094 | |||
1095 | Name: vmbus_msg_dpc() | ||
1096 | |||
1097 | Desc: Tasklet routine to handle hypervisor events | ||
1098 | |||
1099 | --*/ | ||
1100 | static void vmbus_event_dpc(unsigned long data) | ||
1101 | { | ||
1102 | VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data; | ||
1103 | |||
1104 | DPRINT_ENTER(VMBUS_DRV); | ||
1105 | |||
1106 | ASSERT(vmbus_drv_obj->OnEventDpc != NULL); | ||
1107 | |||
1108 | // Call to bus driver to handle interrupt | ||
1109 | vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base); | ||
1110 | |||
1111 | DPRINT_EXIT(VMBUS_DRV); | ||
1112 | } | ||
1113 | |||
1114 | /*++ | ||
1115 | |||
1116 | Name: vmbus_msg_dpc() | ||
1117 | |||
1118 | Desc: ISR routine | ||
1119 | |||
1120 | --*/ | ||
1121 | #ifdef KERNEL_2_6_27 | ||
1122 | static irqreturn_t vmbus_isr(int irq, void* dev_id) | ||
1123 | #else | ||
1124 | static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs) | ||
1125 | #endif | ||
1126 | { | ||
1127 | int ret=0; | ||
1128 | VMBUS_DRIVER_OBJECT* vmbus_driver_obj = &g_vmbus_drv.drv_obj; | ||
1129 | |||
1130 | DPRINT_ENTER(VMBUS_DRV); | ||
1131 | |||
1132 | ASSERT(vmbus_driver_obj->OnIsr != NULL); | ||
1133 | |||
1134 | // Call to bus driver to handle interrupt | ||
1135 | ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base); | ||
1136 | |||
1137 | // Schedules a dpc if necessary | ||
1138 | if (ret > 0) | ||
1139 | { | ||
1140 | if (test_bit(0, (unsigned long*)&ret)) | ||
1141 | { | ||
1142 | tasklet_schedule(&g_vmbus_drv.msg_dpc); | ||
1143 | } | ||
1144 | |||
1145 | if (test_bit(1, (unsigned long*)&ret)) | ||
1146 | { | ||
1147 | tasklet_schedule(&g_vmbus_drv.event_dpc); | ||
1148 | } | ||
1149 | |||
1150 | DPRINT_EXIT(VMBUS_DRV); | ||
1151 | return IRQ_HANDLED; | ||
1152 | } | ||
1153 | else | ||
1154 | { | ||
1155 | DPRINT_EXIT(VMBUS_DRV); | ||
1156 | return IRQ_NONE; | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | MODULE_LICENSE("GPL"); | ||
1161 | |||
1162 | |||
1163 | /*++ | ||
1164 | |||
1165 | Name: vmbus_init() | ||
1166 | |||
1167 | Desc: Main vmbus driver entry routine | ||
1168 | |||
1169 | --*/ | ||
1170 | static int __init vmbus_init(void) | ||
1171 | { | ||
1172 | int ret=0; | ||
1173 | |||
1174 | DPRINT_ENTER(VMBUS_DRV); | ||
1175 | |||
1176 | DPRINT_INFO(VMBUS_DRV, | ||
1177 | "Vmbus initializing.... current log level 0x%x (%x,%x)", | ||
1178 | vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel)); | ||
1179 | #ifdef KERNEL_2_6_27 | ||
1180 | //Todo: it is used for loglevel, to be ported to new kernel. | ||
1181 | #else | ||
1182 | vmbus_ctl_table_hdr = register_sysctl_table(vmus_root_ctl_table, 0); | ||
1183 | if (!vmbus_ctl_table_hdr) | ||
1184 | { | ||
1185 | DPRINT_EXIT(VMBUS_DRV); | ||
1186 | return -ENOMEM; | ||
1187 | } | ||
1188 | #endif | ||
1189 | |||
1190 | ret = vmbus_bus_init(VmbusInitialize); | ||
1191 | |||
1192 | DPRINT_EXIT(VMBUS_DRV); | ||
1193 | return ret; | ||
1194 | } | ||
1195 | |||
1196 | |||
1197 | |||
1198 | /*++ | ||
1199 | |||
1200 | Name: vmbus_init() | ||
1201 | |||
1202 | Desc: Main vmbus driver exit routine | ||
1203 | |||
1204 | --*/ | ||
1205 | static void __exit vmbus_exit(void) | ||
1206 | { | ||
1207 | DPRINT_ENTER(VMBUS_DRV); | ||
1208 | |||
1209 | vmbus_bus_exit(); | ||
1210 | #ifdef KERNEL_2_6_27 | ||
1211 | //Todo: it is used for loglevel, to be ported to new kernel. | ||
1212 | #else | ||
1213 | unregister_sysctl_table(vmbus_ctl_table_hdr); | ||
1214 | #endif | ||
1215 | DPRINT_EXIT(VMBUS_DRV); | ||
1216 | |||
1217 | return; | ||
1218 | } | ||
1219 | |||
1220 | #if defined(KERNEL_2_6_5) | ||
1221 | #else | ||
1222 | module_param(vmbus_irq, int, S_IRUGO); | ||
1223 | module_param(vmbus_loglevel, int, S_IRUGO); | ||
1224 | #endif | ||
1225 | |||
1226 | module_init(vmbus_init); | ||
1227 | module_exit(vmbus_exit); | ||
1228 | // eof | ||