]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.drivers/staging-hv-add-the-hyper-v-virtual-bus.patch
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.drivers / staging-hv-add-the-hyper-v-virtual-bus.patch
1 From foo@baz Mon Jul 13 16:02:34 PDT 2009
2 Date: Mon, 13 Jul 2009 16:02:34 -0700
3 From: Hank Janssen <hjanssen@microsoft.com>
4 Subject: Staging: hv: add the Hyper-V virtual bus
5
6 From: Hank Janssen <hjanssen@microsoft.com>
7
8 This is the virtual bus that all of the Linux Hyper-V drivers use.
9
10 Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
11 Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
12 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
13
14 ---
15 drivers/staging/hv/Channel.c | 1199 +++++++++++++++++++++++++++++++++
16 drivers/staging/hv/Channel.h | 157 ++++
17 drivers/staging/hv/ChannelInterface.c | 222 ++++++
18 drivers/staging/hv/ChannelInterface.h | 41 +
19 drivers/staging/hv/ChannelMgmt.c | 826 ++++++++++++++++++++++
20 drivers/staging/hv/ChannelMgmt.h | 156 ++++
21 drivers/staging/hv/Connection.c | 432 +++++++++++
22 drivers/staging/hv/Hv.c | 672 ++++++++++++++++++
23 drivers/staging/hv/Hv.h | 184 +++++
24 drivers/staging/hv/RingBuffer.c | 630 +++++++++++++++++
25 drivers/staging/hv/RingBuffer.h | 123 +++
26 drivers/staging/hv/Sources.c | 31
27 drivers/staging/hv/VersionInfo.h | 29
28 drivers/staging/hv/Vmbus.c | 508 ++++++++++++++
29 drivers/staging/hv/VmbusPrivate.h | 170 ++++
30 drivers/staging/hv/osd.c | 500 +++++++++++++
31 drivers/staging/hv/vmbus_drv.c | 1228 ++++++++++++++++++++++++++++++++++
32 17 files changed, 7108 insertions(+)
33
34 --- /dev/null
35 +++ b/drivers/staging/hv/Channel.c
36 @@ -0,0 +1,1199 @@
37 +/*
38 + *
39 + * Copyright (c) 2009, Microsoft Corporation.
40 + *
41 + * This program is free software; you can redistribute it and/or modify it
42 + * under the terms and conditions of the GNU General Public License,
43 + * version 2, as published by the Free Software Foundation.
44 + *
45 + * This program is distributed in the hope it will be useful, but WITHOUT
46 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
47 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
48 + * more details.
49 + *
50 + * You should have received a copy of the GNU General Public License along with
51 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
52 + * Place - Suite 330, Boston, MA 02111-1307 USA.
53 + *
54 + * Authors:
55 + * Haiyang Zhang <haiyangz@microsoft.com>
56 + * Hank Janssen <hjanssen@microsoft.com>
57 + *
58 + */
59 +
60 +
61 +#include "osd.h"
62 +#include "logging.h"
63 +
64 +#include "VmbusPrivate.h"
65 +
66 +//
67 +// Internal routines
68 +//
69 +static int
70 +VmbusChannelCreateGpadlHeader(
71 + PVOID Kbuffer, // must be phys and virt contiguous
72 + UINT32 Size, // page-size multiple
73 + VMBUS_CHANNEL_MSGINFO **msgInfo,
74 + UINT32 *MessageCount
75 + );
76 +
77 +static void
78 +DumpVmbusChannel(
79 + VMBUS_CHANNEL *Channel
80 + );
81 +
82 +
83 +static void
84 +VmbusChannelSetEvent(
85 + VMBUS_CHANNEL *Channel
86 + );
87 +
88 +
89 +#if 0
90 +static void
91 +DumpMonitorPage(
92 + HV_MONITOR_PAGE *MonitorPage
93 + )
94 +{
95 + int i=0;
96 + int j=0;
97 +
98 + DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d", MonitorPage, MonitorPage->TriggerState);
99 +
100 + for (i=0; i<4; i++)
101 + {
102 + DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i, MonitorPage->TriggerGroup[i].AsUINT64);
103 + }
104 +
105 + for (i=0; i<4; i++)
106 + {
107 + for (j=0; j<32; j++)
108 + {
109 + DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j, MonitorPage->Latency[i][j]);
110 + }
111 + }
112 + for (i=0; i<4; i++)
113 + {
114 + for (j=0; j<32; j++)
115 + {
116 + DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].ConnectionId.AsUINT32);
117 + DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].FlagNumber);
118 +
119 + }
120 + }
121 +}
122 +#endif
123 +
124 +/*++
125 +
126 +Name:
127 + VmbusChannelSetEvent()
128 +
129 +Description:
130 + Trigger an event notification on the specified channel.
131 +
132 +--*/
133 +static void
134 +VmbusChannelSetEvent(
135 + VMBUS_CHANNEL *Channel
136 + )
137 +{
138 + HV_MONITOR_PAGE *monitorPage;
139 +
140 + DPRINT_ENTER(VMBUS);
141 +
142 + if (Channel->OfferMsg.MonitorAllocated)
143 + {
144 + // Each UINT32 represents 32 channels
145 + BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31);
146 +
147 + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
148 + monitorPage++; // Get the child to parent monitor page
149 +
150 + BitSet((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit);
151 + }
152 + else
153 + {
154 + VmbusSetEvent(Channel->OfferMsg.ChildRelId);
155 + }
156 +
157 + DPRINT_EXIT(VMBUS);
158 +}
159 +
160 +#if 0
161 +static void
162 +VmbusChannelClearEvent(
163 + VMBUS_CHANNEL *Channel
164 + )
165 +{
166 + HV_MONITOR_PAGE *monitorPage;
167 +
168 + DPRINT_ENTER(VMBUS);
169 +
170 + if (Channel->OfferMsg.MonitorAllocated)
171 + {
172 + // Each UINT32 represents 32 channels
173 + BitClear((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31);
174 +
175 + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
176 + monitorPage++; // Get the child to parent monitor page
177 +
178 + BitClear((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit);
179 + }
180 +
181 + DPRINT_EXIT(VMBUS);
182 +}
183 +
184 +#endif
185 +/*++;
186 +
187 +Name:
188 + VmbusChannelGetDebugInfo()
189 +
190 +Description:
191 + Retrieve various channel debug info
192 +
193 +--*/
194 +void
195 +VmbusChannelGetDebugInfo(
196 + VMBUS_CHANNEL *Channel,
197 + VMBUS_CHANNEL_DEBUG_INFO *DebugInfo
198 + )
199 +{
200 + HV_MONITOR_PAGE *monitorPage;
201 + UINT8 monitorGroup = (UINT8)Channel->OfferMsg.MonitorId / 32;
202 + UINT8 monitorOffset = (UINT8)Channel->OfferMsg.MonitorId % 32;
203 + //UINT32 monitorBit = 1 << monitorOffset;
204 +
205 + DebugInfo->RelId = Channel->OfferMsg.ChildRelId;
206 + DebugInfo->State = Channel->State;
207 + memcpy(&DebugInfo->InterfaceType, &Channel->OfferMsg.Offer.InterfaceType, sizeof(GUID));
208 + memcpy(&DebugInfo->InterfaceInstance, &Channel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID));
209 +
210 + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
211 +
212 + DebugInfo->MonitorId = Channel->OfferMsg.MonitorId;
213 +
214 + DebugInfo->ServerMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending;
215 + DebugInfo->ServerMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset];
216 + DebugInfo->ServerMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id;
217 +
218 + monitorPage++;
219 +
220 + DebugInfo->ClientMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending;
221 + DebugInfo->ClientMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset];
222 + DebugInfo->ClientMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id;
223 +
224 + RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound);
225 + RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound);
226 +}
227 +
228 +
229 +/*++;
230 +
231 +Name:
232 + VmbusChannelOpen()
233 +
234 +Description:
235 + Open the specified channel.
236 +
237 +--*/
238 +int
239 +VmbusChannelOpen(
240 + VMBUS_CHANNEL *NewChannel,
241 + UINT32 SendRingBufferSize,
242 + UINT32 RecvRingBufferSize,
243 + PVOID UserData,
244 + UINT32 UserDataLen,
245 + PFN_CHANNEL_CALLBACK pfnOnChannelCallback,
246 + PVOID Context
247 + )
248 +{
249 + int ret=0;
250 + VMBUS_CHANNEL_OPEN_CHANNEL* openMsg;
251 + VMBUS_CHANNEL_MSGINFO* openInfo;
252 + void *in, *out;
253 +
254 + DPRINT_ENTER(VMBUS);
255 +
256 + // Aligned to page size
257 + ASSERT(!(SendRingBufferSize & (PAGE_SIZE -1)));
258 + ASSERT(!(RecvRingBufferSize & (PAGE_SIZE -1)));
259 +
260 + NewChannel->OnChannelCallback = pfnOnChannelCallback;
261 + NewChannel->ChannelCallbackContext = Context;
262 +
263 + // Allocate the ring buffer
264 + out = PageAlloc((SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT);
265 + //out = MemAllocZeroed(sendRingBufferSize + recvRingBufferSize);
266 + ASSERT(out);
267 + ASSERT(((ULONG_PTR)out & (PAGE_SIZE-1)) == 0);
268 +
269 + in = (void*)((ULONG_PTR)out + SendRingBufferSize);
270 +
271 + NewChannel->RingBufferPages = out;
272 + NewChannel->RingBufferPageCount = (SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT;
273 +
274 + RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize);
275 +
276 + RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize);
277 +
278 + // Establish the gpadl for the ring buffer
279 + DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...", NewChannel);
280 +
281 + NewChannel->RingBufferGpadlHandle = 0;
282 +
283 + ret = VmbusChannelEstablishGpadl(NewChannel,
284 + NewChannel->Outbound.RingBuffer,
285 + SendRingBufferSize + RecvRingBufferSize,
286 + &NewChannel->RingBufferGpadlHandle);
287 +
288 + DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p size %d recv ring %p size %d, downstreamoffset %d>",
289 + NewChannel,
290 + NewChannel->OfferMsg.ChildRelId,
291 + NewChannel->RingBufferGpadlHandle,
292 + NewChannel->Outbound.RingBuffer,
293 + NewChannel->Outbound.RingSize,
294 + NewChannel->Inbound.RingBuffer,
295 + NewChannel->Inbound.RingSize,
296 + SendRingBufferSize);
297 +
298 + // Create and init the channel open message
299 + openInfo =
300 + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL));
301 + ASSERT(openInfo != NULL);
302 +
303 + openInfo->WaitEvent = WaitEventCreate();
304 +
305 + openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)openInfo->Msg;
306 + openMsg->Header.MessageType = ChannelMessageOpenChannel;
307 + openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; // FIXME
308 + openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId;
309 + openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle;
310 + ASSERT(openMsg->RingBufferGpadlHandle);
311 + openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >> PAGE_SHIFT;
312 + openMsg->ServerContextAreaGpadlHandle = 0; // TODO
313 +
314 + ASSERT(UserDataLen <= MAX_USER_DEFINED_BYTES);
315 + if (UserDataLen)
316 + {
317 + memcpy(openMsg->UserData, UserData, UserDataLen);
318 + }
319 +
320 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
321 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &openInfo->MsgListEntry);
322 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
323 +
324 + DPRINT_DBG(VMBUS, "Sending channel open msg...");
325 +
326 + ret = VmbusPostMessage(openMsg, sizeof(VMBUS_CHANNEL_OPEN_CHANNEL));
327 + if (ret != 0)
328 + {
329 + DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
330 + goto Cleanup;
331 + }
332 +
333 + // FIXME: Need to time-out here
334 + WaitEventWait(openInfo->WaitEvent);
335 +
336 + if (openInfo->Response.OpenResult.Status == 0)
337 + {
338 + DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel);
339 + }
340 + else
341 + {
342 + DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!", NewChannel, openInfo->Response.OpenResult.Status);
343 + }
344 +
345 +Cleanup:
346 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
347 + REMOVE_ENTRY_LIST(&openInfo->MsgListEntry);
348 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
349 +
350 + WaitEventClose(openInfo->WaitEvent);
351 + MemFree(openInfo);
352 +
353 + DPRINT_EXIT(VMBUS);
354 +
355 + return 0;
356 +}
357 +
358 +/*++;
359 +
360 +Name:
361 + DumpGpadlBody()
362 +
363 +Description:
364 + Dump the gpadl body message to the console for debugging purposes.
365 +
366 +--*/
367 +static void DumpGpadlBody(
368 + VMBUS_CHANNEL_GPADL_BODY *Gpadl,
369 + UINT32 Len)
370 +{
371 + int i=0;
372 + int pfnCount=0;
373 +
374 + pfnCount = (Len - sizeof(VMBUS_CHANNEL_GPADL_BODY))/ sizeof(UINT64);
375 + DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount);
376 +
377 + for (i=0; i< pfnCount; i++)
378 + {
379 + DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", i, Gpadl->Pfn[i]);
380 + }
381 +}
382 +
383 +
384 +/*++;
385 +
386 +Name:
387 + DumpGpadlHeader()
388 +
389 +Description:
390 + Dump the gpadl header message to the console for debugging purposes.
391 +
392 +--*/
393 +static void DumpGpadlHeader(
394 + VMBUS_CHANNEL_GPADL_HEADER *Gpadl
395 + )
396 +{
397 + int i=0,j=0;
398 + int pageCount=0;
399 +
400 +
401 + DPRINT_DBG(VMBUS, "gpadl header - relid %d, range count %d, range buflen %d",
402 + Gpadl->ChildRelId,
403 + Gpadl->RangeCount,
404 + Gpadl->RangeBufLen);
405 + for (i=0; i< Gpadl->RangeCount; i++)
406 + {
407 + pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT;
408 + pageCount = (pageCount > 26)? 26 : pageCount;
409 +
410 + DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d page count %d",
411 + i, Gpadl->Range[i].ByteCount, Gpadl->Range[i].ByteOffset, pageCount);
412 +
413 + for (j=0; j< pageCount; j++)
414 + {
415 + DPRINT_DBG(VMBUS, "%d) pfn %llu", j, Gpadl->Range[i].PfnArray[j]);
416 + }
417 + }
418 +}
419 +
420 +/*++;
421 +
422 +Name:
423 + VmbusChannelCreateGpadlHeader()
424 +
425 +Description:
426 + Creates a gpadl for the specified buffer
427 +
428 +--*/
429 +static int
430 +VmbusChannelCreateGpadlHeader(
431 + PVOID Kbuffer, // from kmalloc()
432 + UINT32 Size, // page-size multiple
433 + VMBUS_CHANNEL_MSGINFO **MsgInfo,
434 + UINT32 *MessageCount)
435 +{
436 + int i;
437 + int pageCount;
438 + unsigned long long pfn;
439 + VMBUS_CHANNEL_GPADL_HEADER* gpaHeader;
440 + VMBUS_CHANNEL_GPADL_BODY* gpadlBody;
441 + VMBUS_CHANNEL_MSGINFO* msgHeader;
442 + VMBUS_CHANNEL_MSGINFO* msgBody;
443 + UINT32 msgSize;
444 +
445 + int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize;
446 +
447 + //ASSERT( (kbuffer & (PAGE_SIZE-1)) == 0);
448 + ASSERT( (Size & (PAGE_SIZE-1)) == 0);
449 +
450 + pageCount = Size >> PAGE_SHIFT;
451 + pfn = GetPhysicalAddress(Kbuffer) >> PAGE_SHIFT;
452 +
453 + // do we need a gpadl body msg
454 + pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_HEADER) - sizeof(GPA_RANGE);
455 + pfnCount = pfnSize / sizeof(UINT64);
456 +
457 + if (pageCount > pfnCount) // we need a gpadl body
458 + {
459 + // fill in the header
460 + msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pfnCount*sizeof(UINT64);
461 + msgHeader = MemAllocZeroed(msgSize);
462 +
463 + INITIALIZE_LIST_HEAD(&msgHeader->SubMsgList);
464 + msgHeader->MessageSize=msgSize;
465 +
466 + gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg;
467 + gpaHeader->RangeCount = 1;
468 + gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64);
469 + gpaHeader->Range[0].ByteOffset = 0;
470 + gpaHeader->Range[0].ByteCount = Size;
471 + for (i=0; i<pfnCount; i++)
472 + {
473 + gpaHeader->Range[0].PfnArray[i] = pfn+i;
474 + }
475 + *MsgInfo = msgHeader;
476 + *MessageCount = 1;
477 +
478 + pfnSum = pfnCount;
479 + pfnLeft = pageCount - pfnCount;
480 +
481 + // how many pfns can we fit
482 + pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_BODY);
483 + pfnCount = pfnSize / sizeof(UINT64);
484 +
485 + // fill in the body
486 + while (pfnLeft)
487 + {
488 + if (pfnLeft > pfnCount)
489 + {
490 + pfnCurr = pfnCount;
491 + }
492 + else
493 + {
494 + pfnCurr = pfnLeft;
495 + }
496 +
497 + msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_BODY) + pfnCurr*sizeof(UINT64);
498 + msgBody = MemAllocZeroed(msgSize);
499 + ASSERT(msgBody);
500 + msgBody->MessageSize = msgSize;
501 + (*MessageCount)++;
502 + gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)msgBody->Msg;
503 +
504 + // FIXME: Gpadl is UINT32 and we are using a pointer which could be 64-bit
505 + //gpadlBody->Gpadl = kbuffer;
506 + for (i=0; i<pfnCurr; i++)
507 + {
508 + gpadlBody->Pfn[i] = pfn + pfnSum + i;
509 + }
510 +
511 + // add to msg header
512 + INSERT_TAIL_LIST(&msgHeader->SubMsgList, &msgBody->MsgListEntry);
513 + pfnSum += pfnCurr;
514 + pfnLeft -= pfnCurr;
515 + }
516 + }
517 + else
518 + {
519 + // everything fits in a header
520 + msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pageCount*sizeof(UINT64);
521 + msgHeader = MemAllocZeroed(msgSize);
522 + msgHeader->MessageSize=msgSize;
523 +
524 + gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg;
525 + gpaHeader->RangeCount = 1;
526 + gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64);
527 + gpaHeader->Range[0].ByteOffset = 0;
528 + gpaHeader->Range[0].ByteCount = Size;
529 + for (i=0; i<pageCount; i++)
530 + {
531 + gpaHeader->Range[0].PfnArray[i] = pfn+i;
532 + }
533 +
534 + *MsgInfo = msgHeader;
535 + *MessageCount = 1;
536 + }
537 +
538 + return 0;
539 +}
540 +
541 +
542 +/*++;
543 +
544 +Name:
545 + VmbusChannelEstablishGpadl()
546 +
547 +Description:
548 + Estabish a GPADL for the specified buffer
549 +
550 +--*/
551 +int
552 +VmbusChannelEstablishGpadl(
553 + VMBUS_CHANNEL *Channel,
554 + PVOID Kbuffer, // from kmalloc()
555 + UINT32 Size, // page-size multiple
556 + UINT32 *GpadlHandle
557 + )
558 +{
559 + int ret=0;
560 + VMBUS_CHANNEL_GPADL_HEADER* gpadlMsg;
561 + VMBUS_CHANNEL_GPADL_BODY* gpadlBody;
562 + //VMBUS_CHANNEL_GPADL_CREATED* gpadlCreated;
563 +
564 + VMBUS_CHANNEL_MSGINFO *msgInfo;
565 + VMBUS_CHANNEL_MSGINFO *subMsgInfo;
566 +
567 + UINT32 msgCount;
568 + LIST_ENTRY* anchor;
569 + LIST_ENTRY* curr;
570 + UINT32 nextGpadlHandle;
571 +
572 + DPRINT_ENTER(VMBUS);
573 +
574 + nextGpadlHandle = gVmbusConnection.NextGpadlHandle;
575 + InterlockedIncrement((int*)&gVmbusConnection.NextGpadlHandle);
576 +
577 + VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount);
578 + ASSERT(msgInfo != NULL);
579 + ASSERT(msgCount >0);
580 +
581 + msgInfo->WaitEvent = WaitEventCreate();
582 + gpadlMsg = (VMBUS_CHANNEL_GPADL_HEADER*)msgInfo->Msg;
583 + gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader;
584 + gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId;
585 + gpadlMsg->Gpadl = nextGpadlHandle;
586 +
587 + DumpGpadlHeader(gpadlMsg);
588 +
589 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
590 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
591 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
592 +
593 + DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d", Kbuffer, Size, msgCount);
594 +
595 + DPRINT_DBG(VMBUS, "Sending GPADL Header - len %d", msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
596 +
597 + ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
598 + if (ret != 0)
599 + {
600 + DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
601 + goto Cleanup;
602 + }
603 +
604 + if (msgCount>1)
605 + {
606 + ITERATE_LIST_ENTRIES(anchor, curr, &msgInfo->SubMsgList)
607 + {
608 + subMsgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
609 + gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)subMsgInfo->Msg;
610 +
611 + gpadlBody->Header.MessageType = ChannelMessageGpadlBody;
612 + gpadlBody->Gpadl = nextGpadlHandle;
613 +
614 + DPRINT_DBG(VMBUS, "Sending GPADL Body - len %d", subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
615 +
616 + DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
617 + ret = VmbusPostMessage(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
618 + ASSERT(ret == 0);
619 + }
620 + }
621 + WaitEventWait(msgInfo->WaitEvent);
622 +
623 + // At this point, we received the gpadl created msg
624 + DPRINT_DBG(VMBUS, "Received GPADL created (relid %d, status %d handle %x)",
625 + Channel->OfferMsg.ChildRelId,
626 + msgInfo->Response.GpadlCreated.CreationStatus,
627 + gpadlMsg->Gpadl);
628 +
629 + *GpadlHandle = gpadlMsg->Gpadl;
630 +
631 +Cleanup:
632 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
633 + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
634 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
635 +
636 + WaitEventClose(msgInfo->WaitEvent);
637 + MemFree(msgInfo);
638 +
639 + DPRINT_EXIT(VMBUS);
640 +
641 + return ret;
642 +}
643 +
644 +
645 +
646 +/*++;
647 +
648 +Name:
649 + VmbusChannelTeardownGpadl()
650 +
651 +Description:
652 + Teardown the specified GPADL handle
653 +
654 +--*/
655 +int
656 +VmbusChannelTeardownGpadl(
657 + VMBUS_CHANNEL *Channel,
658 + UINT32 GpadlHandle
659 + )
660 +{
661 + int ret=0;
662 + VMBUS_CHANNEL_GPADL_TEARDOWN *msg;
663 + VMBUS_CHANNEL_MSGINFO* info;
664 +
665 + DPRINT_ENTER(VMBUS);
666 +
667 + ASSERT(GpadlHandle != 0);
668 +
669 + info =
670 + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN));
671 + ASSERT(info != NULL);
672 +
673 + info->WaitEvent = WaitEventCreate();
674 +
675 + msg = (VMBUS_CHANNEL_GPADL_TEARDOWN*)info->Msg;
676 +
677 + msg->Header.MessageType = ChannelMessageGpadlTeardown;
678 + msg->ChildRelId = Channel->OfferMsg.ChildRelId;
679 + msg->Gpadl = GpadlHandle;
680 +
681 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
682 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &info->MsgListEntry);
683 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
684 +
685 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN));
686 + if (ret != 0)
687 + {
688 + // TODO:
689 + }
690 +
691 + WaitEventWait(info->WaitEvent);
692 +
693 + // Received a torndown response
694 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
695 + REMOVE_ENTRY_LIST(&info->MsgListEntry);
696 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
697 +
698 + WaitEventClose(info->WaitEvent);
699 + MemFree(info);
700 +
701 + DPRINT_EXIT(VMBUS);
702 +
703 + return ret;
704 +}
705 +
706 +
707 +/*++
708 +
709 +Name:
710 + VmbusChannelClose()
711 +
712 +Description:
713 + Close the specified channel
714 +
715 +--*/
716 +VOID
717 +VmbusChannelClose(
718 + VMBUS_CHANNEL *Channel
719 + )
720 +{
721 + int ret=0;
722 + VMBUS_CHANNEL_CLOSE_CHANNEL* msg;
723 + VMBUS_CHANNEL_MSGINFO* info;
724 +
725 + DPRINT_ENTER(VMBUS);
726 +
727 + // Stop callback and cancel the timer asap
728 + Channel->OnChannelCallback = NULL;
729 + TimerStop(Channel->PollTimer);
730 +
731 + // Send a closing message
732 + info =
733 + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL));
734 + ASSERT(info != NULL);
735 +
736 + //info->waitEvent = WaitEventCreate();
737 +
738 + msg = (VMBUS_CHANNEL_CLOSE_CHANNEL*)info->Msg;
739 + msg->Header.MessageType = ChannelMessageCloseChannel;
740 + msg->ChildRelId = Channel->OfferMsg.ChildRelId;
741 +
742 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL));
743 + if (ret != 0)
744 + {
745 + // TODO:
746 + }
747 +
748 + // Tear down the gpadl for the channel's ring buffer
749 + if (Channel->RingBufferGpadlHandle)
750 + {
751 + VmbusChannelTeardownGpadl(Channel, Channel->RingBufferGpadlHandle);
752 + }
753 +
754 + // TODO: Send a msg to release the childRelId
755 +
756 + // Cleanup the ring buffers for this channel
757 + RingBufferCleanup(&Channel->Outbound);
758 + RingBufferCleanup(&Channel->Inbound);
759 +
760 + PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount);
761 +
762 + MemFree(info);
763 +
764 + // If we are closing the channel during an error path in opening the channel, don't free the channel
765 + // since the caller will free the channel
766 + if (Channel->State == CHANNEL_OPEN_STATE)
767 + {
768 + SpinlockAcquire(gVmbusConnection.ChannelLock);
769 + REMOVE_ENTRY_LIST(&Channel->ListEntry);
770 + SpinlockRelease(gVmbusConnection.ChannelLock);
771 +
772 + FreeVmbusChannel(Channel);
773 + }
774 +
775 + DPRINT_EXIT(VMBUS);
776 +}
777 +
778 +
779 +/*++
780 +
781 +Name:
782 + VmbusChannelSendPacket()
783 +
784 +Description:
785 + Send the specified buffer on the given channel
786 +
787 +--*/
788 +int
789 +VmbusChannelSendPacket(
790 + VMBUS_CHANNEL *Channel,
791 + const PVOID Buffer,
792 + UINT32 BufferLen,
793 + UINT64 RequestId,
794 + VMBUS_PACKET_TYPE Type,
795 + UINT32 Flags
796 +)
797 +{
798 + int ret=0;
799 + VMPACKET_DESCRIPTOR desc;
800 + UINT32 packetLen = sizeof(VMPACKET_DESCRIPTOR) + BufferLen;
801 + UINT32 packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64));
802 + SG_BUFFER_LIST bufferList[3];
803 + UINT64 alignedData=0;
804 +
805 + DPRINT_ENTER(VMBUS);
806 + DPRINT_DBG(VMBUS, "channel %p buffer %p len %d", Channel, Buffer, BufferLen);
807 +
808 + DumpVmbusChannel(Channel);
809 +
810 + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
811 +
812 + // Setup the descriptor
813 + desc.Type = Type;//VmbusPacketTypeDataInBand;
814 + desc.Flags = Flags;//VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
815 + desc.DataOffset8 = sizeof(VMPACKET_DESCRIPTOR) >> 3; // in 8-bytes granularity
816 + desc.Length8 = (UINT16)(packetLenAligned >> 3);
817 + desc.TransactionId = RequestId;
818 +
819 + bufferList[0].Data = &desc;
820 + bufferList[0].Length = sizeof(VMPACKET_DESCRIPTOR);
821 +
822 + bufferList[1].Data = Buffer;
823 + bufferList[1].Length = BufferLen;
824 +
825 + bufferList[2].Data = &alignedData;
826 + bufferList[2].Length = packetLenAligned - packetLen;
827 +
828 + ret = RingBufferWrite(
829 + &Channel->Outbound,
830 + bufferList,
831 + 3);
832 +
833 + // TODO: We should determine if this is optional
834 + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
835 + {
836 + VmbusChannelSetEvent(Channel);
837 + }
838 +
839 + DPRINT_EXIT(VMBUS);
840 +
841 + return ret;
842 +}
843 +
844 +
845 +/*++
846 +
847 +Name:
848 + VmbusChannelSendPacketPageBuffer()
849 +
850 +Description:
851 + Send a range of single-page buffer packets using a GPADL Direct packet type.
852 +
853 +--*/
854 +int
855 +VmbusChannelSendPacketPageBuffer(
856 + VMBUS_CHANNEL *Channel,
857 + PAGE_BUFFER PageBuffers[],
858 + UINT32 PageCount,
859 + PVOID Buffer,
860 + UINT32 BufferLen,
861 + UINT64 RequestId
862 +)
863 +{
864 + int ret=0;
865 + int i=0;
866 + VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc;
867 + UINT32 descSize;
868 + UINT32 packetLen;
869 + UINT32 packetLenAligned;
870 + SG_BUFFER_LIST bufferList[3];
871 + UINT64 alignedData=0;
872 +
873 + DPRINT_ENTER(VMBUS);
874 +
875 + ASSERT(PageCount <= MAX_PAGE_BUFFER_COUNT);
876 +
877 + DumpVmbusChannel(Channel);
878 +
879 + // Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the largest size we support
880 + descSize = sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER) - ((MAX_PAGE_BUFFER_COUNT - PageCount)*sizeof(PAGE_BUFFER));
881 + packetLen = descSize + BufferLen;
882 + packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64));
883 +
884 + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
885 +
886 + // Setup the descriptor
887 + desc.Type = VmbusPacketTypeDataUsingGpaDirect;
888 + desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
889 + desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity
890 + desc.Length8 = (UINT16)(packetLenAligned >> 3);
891 + desc.TransactionId = RequestId;
892 + desc.RangeCount = PageCount;
893 +
894 + for (i=0; i<PageCount; i++)
895 + {
896 + desc.Range[i].Length = PageBuffers[i].Length;
897 + desc.Range[i].Offset = PageBuffers[i].Offset;
898 + desc.Range[i].Pfn = PageBuffers[i].Pfn;
899 + }
900 +
901 + bufferList[0].Data = &desc;
902 + bufferList[0].Length = descSize;
903 +
904 + bufferList[1].Data = Buffer;
905 + bufferList[1].Length = BufferLen;
906 +
907 + bufferList[2].Data = &alignedData;
908 + bufferList[2].Length = packetLenAligned - packetLen;
909 +
910 + ret = RingBufferWrite(
911 + &Channel->Outbound,
912 + bufferList,
913 + 3);
914 +
915 + // TODO: We should determine if this is optional
916 + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
917 + {
918 + VmbusChannelSetEvent(Channel);
919 + }
920 +
921 + DPRINT_EXIT(VMBUS);
922 +
923 + return ret;
924 +}
925 +
926 +
927 +
928 +/*++
929 +
930 +Name:
931 + VmbusChannelSendPacketMultiPageBuffer()
932 +
933 +Description:
934 + Send a multi-page buffer packet using a GPADL Direct packet type.
935 +
936 +--*/
937 +int
938 +VmbusChannelSendPacketMultiPageBuffer(
939 + VMBUS_CHANNEL *Channel,
940 + MULTIPAGE_BUFFER *MultiPageBuffer,
941 + PVOID Buffer,
942 + UINT32 BufferLen,
943 + UINT64 RequestId
944 +)
945 +{
946 + int ret=0;
947 + VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc;
948 + UINT32 descSize;
949 + UINT32 packetLen;
950 + UINT32 packetLenAligned;
951 + SG_BUFFER_LIST bufferList[3];
952 + UINT64 alignedData=0;
953 + UINT32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset, MultiPageBuffer->Length);
954 +
955 + DPRINT_ENTER(VMBUS);
956 +
957 + DumpVmbusChannel(Channel);
958 +
959 + DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount);
960 +
961 + ASSERT(PfnCount > 0);
962 + ASSERT(PfnCount <= MAX_MULTIPAGE_BUFFER_COUNT);
963 +
964 + // Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is the largest size we support
965 + descSize = sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) - ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount)*sizeof(UINT64));
966 + packetLen = descSize + BufferLen;
967 + packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64));
968 +
969 + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
970 +
971 + // Setup the descriptor
972 + desc.Type = VmbusPacketTypeDataUsingGpaDirect;
973 + desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
974 + desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity
975 + desc.Length8 = (UINT16)(packetLenAligned >> 3);
976 + desc.TransactionId = RequestId;
977 + desc.RangeCount = 1;
978 +
979 + desc.Range.Length = MultiPageBuffer->Length;
980 + desc.Range.Offset = MultiPageBuffer->Offset;
981 +
982 + memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray, PfnCount*sizeof(UINT64));
983 +
984 + bufferList[0].Data = &desc;
985 + bufferList[0].Length = descSize;
986 +
987 + bufferList[1].Data = Buffer;
988 + bufferList[1].Length = BufferLen;
989 +
990 + bufferList[2].Data = &alignedData;
991 + bufferList[2].Length = packetLenAligned - packetLen;
992 +
993 + ret = RingBufferWrite(
994 + &Channel->Outbound,
995 + bufferList,
996 + 3);
997 +
998 + // TODO: We should determine if this is optional
999 + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
1000 + {
1001 + VmbusChannelSetEvent(Channel);
1002 + }
1003 +
1004 + DPRINT_EXIT(VMBUS);
1005 +
1006 + return ret;
1007 +}
1008 +
1009 +
1010 +/*++
1011 +
1012 +Name:
1013 + VmbusChannelRecvPacket()
1014 +
1015 +Description:
1016 + Retrieve the user packet on the specified channel
1017 +
1018 +--*/
1019 +// TODO: Do we ever receive a gpa direct packet other than the ones we send ?
1020 +int
1021 +VmbusChannelRecvPacket(
1022 + VMBUS_CHANNEL *Channel,
1023 + PVOID Buffer,
1024 + UINT32 BufferLen,
1025 + UINT32* BufferActualLen,
1026 + UINT64* RequestId
1027 + )
1028 +{
1029 + VMPACKET_DESCRIPTOR desc;
1030 + UINT32 packetLen;
1031 + UINT32 userLen;
1032 + int ret;
1033 +
1034 + DPRINT_ENTER(VMBUS);
1035 +
1036 + *BufferActualLen = 0;
1037 + *RequestId = 0;
1038 +
1039 + SpinlockAcquire(Channel->InboundLock);
1040 +
1041 + ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR));
1042 + if (ret != 0)
1043 + {
1044 + SpinlockRelease(Channel->InboundLock);
1045 +
1046 + //DPRINT_DBG(VMBUS, "nothing to read!!");
1047 + DPRINT_EXIT(VMBUS);
1048 + return 0;
1049 + }
1050 +
1051 + //VmbusChannelClearEvent(Channel);
1052 +
1053 + packetLen = desc.Length8 << 3;
1054 + userLen = packetLen - (desc.DataOffset8 << 3);
1055 + //ASSERT(userLen > 0);
1056 +
1057 + DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1058 + Channel,
1059 + Channel->OfferMsg.ChildRelId,
1060 + desc.Type,
1061 + desc.Flags,
1062 + desc.TransactionId, packetLen, userLen);
1063 +
1064 + *BufferActualLen = userLen;
1065 +
1066 + if (userLen > BufferLen)
1067 + {
1068 + SpinlockRelease(Channel->InboundLock);
1069 +
1070 + DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d", BufferLen, userLen);
1071 + DPRINT_EXIT(VMBUS);
1072 +
1073 + return -1;
1074 + }
1075 +
1076 + *RequestId = desc.TransactionId;
1077 +
1078 + // Copy over the packet to the user buffer
1079 + ret = RingBufferRead(&Channel->Inbound, Buffer, userLen, (desc.DataOffset8 << 3));
1080 +
1081 + SpinlockRelease(Channel->InboundLock);
1082 +
1083 + DPRINT_EXIT(VMBUS);
1084 +
1085 + return 0;
1086 +}
1087 +
1088 +/*++
1089 +
1090 +Name:
1091 + VmbusChannelRecvPacketRaw()
1092 +
1093 +Description:
1094 + Retrieve the raw packet on the specified channel
1095 +
1096 +--*/
1097 +int
1098 +VmbusChannelRecvPacketRaw(
1099 + VMBUS_CHANNEL *Channel,
1100 + PVOID Buffer,
1101 + UINT32 BufferLen,
1102 + UINT32* BufferActualLen,
1103 + UINT64* RequestId
1104 + )
1105 +{
1106 + VMPACKET_DESCRIPTOR desc;
1107 + UINT32 packetLen;
1108 + UINT32 userLen;
1109 + int ret;
1110 +
1111 + DPRINT_ENTER(VMBUS);
1112 +
1113 + *BufferActualLen = 0;
1114 + *RequestId = 0;
1115 +
1116 + SpinlockAcquire(Channel->InboundLock);
1117 +
1118 + ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR));
1119 + if (ret != 0)
1120 + {
1121 + SpinlockRelease(Channel->InboundLock);
1122 +
1123 + //DPRINT_DBG(VMBUS, "nothing to read!!");
1124 + DPRINT_EXIT(VMBUS);
1125 + return 0;
1126 + }
1127 +
1128 + //VmbusChannelClearEvent(Channel);
1129 +
1130 + packetLen = desc.Length8 << 3;
1131 + userLen = packetLen - (desc.DataOffset8 << 3);
1132 +
1133 + DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1134 + Channel,
1135 + Channel->OfferMsg.ChildRelId,
1136 + desc.Type,
1137 + desc.Flags,
1138 + desc.TransactionId, packetLen, userLen);
1139 +
1140 + *BufferActualLen = packetLen;
1141 +
1142 + if (packetLen > BufferLen)
1143 + {
1144 + SpinlockRelease(Channel->InboundLock);
1145 +
1146 + DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen, BufferLen);
1147 + DPRINT_EXIT(VMBUS);
1148 + return -2;
1149 + }
1150 +
1151 + *RequestId = desc.TransactionId;
1152 +
1153 + // Copy over the entire packet to the user buffer
1154 + ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0);
1155 +
1156 + SpinlockRelease(Channel->InboundLock);
1157 +
1158 + DPRINT_EXIT(VMBUS);
1159 +
1160 + return 0;
1161 +}
1162 +
1163 +
1164 +/*++
1165 +
1166 +Name:
1167 + VmbusChannelOnChannelEvent()
1168 +
1169 +Description:
1170 + Channel event callback
1171 +
1172 +--*/
1173 +void
1174 +VmbusChannelOnChannelEvent(
1175 + VMBUS_CHANNEL *Channel
1176 + )
1177 +{
1178 + DumpVmbusChannel(Channel);
1179 + ASSERT(Channel->OnChannelCallback);
1180 +#ifdef ENABLE_POLLING
1181 + TimerStop(Channel->PollTimer);
1182 + Channel->OnChannelCallback(Channel->ChannelCallbackContext);
1183 + TimerStart(Channel->PollTimer, 100 /* 100us */);
1184 +#else
1185 + Channel->OnChannelCallback(Channel->ChannelCallbackContext);
1186 +#endif
1187 +}
1188 +
1189 +/*++
1190 +
1191 +Name:
1192 + VmbusChannelOnTimer()
1193 +
1194 +Description:
1195 + Timer event callback
1196 +
1197 +--*/
1198 +void
1199 +VmbusChannelOnTimer(
1200 + void *Context
1201 + )
1202 +{
1203 + VMBUS_CHANNEL *channel = (VMBUS_CHANNEL*)Context;
1204 +
1205 + if (channel->OnChannelCallback)
1206 + {
1207 + channel->OnChannelCallback(channel->ChannelCallbackContext);
1208 +#ifdef ENABLE_POLLING
1209 + TimerStart(channel->PollTimer, 100 /* 100us */);
1210 +#endif
1211 + }
1212 +}
1213 +
1214 +
1215 +/*++
1216 +
1217 +Name:
1218 + DumpVmbusChannel()
1219 +
1220 +Description:
1221 + Dump vmbus channel info to the console
1222 +
1223 +--*/
1224 +static void
1225 +DumpVmbusChannel(
1226 + VMBUS_CHANNEL *Channel
1227 + )
1228 +{
1229 + DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId);
1230 + DumpRingInfo(&Channel->Outbound, "Outbound ");
1231 + DumpRingInfo(&Channel->Inbound, "Inbound ");
1232 +}
1233 +
1234 +
1235 +// eof
1236 --- /dev/null
1237 +++ b/drivers/staging/hv/Channel.h
1238 @@ -0,0 +1,157 @@
1239 +/*
1240 + *
1241 + * Copyright (c) 2009, Microsoft Corporation.
1242 + *
1243 + * This program is free software; you can redistribute it and/or modify it
1244 + * under the terms and conditions of the GNU General Public License,
1245 + * version 2, as published by the Free Software Foundation.
1246 + *
1247 + * This program is distributed in the hope it will be useful, but WITHOUT
1248 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1249 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
1250 + * more details.
1251 + *
1252 + * You should have received a copy of the GNU General Public License along with
1253 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1254 + * Place - Suite 330, Boston, MA 02111-1307 USA.
1255 + *
1256 + * Authors:
1257 + * Haiyang Zhang <haiyangz@microsoft.com>
1258 + * Hank Janssen <hjanssen@microsoft.com>
1259 + *
1260 + */
1261 +
1262 +
1263 +#ifndef _CHANNEL_H_
1264 +#define _CHANNEL_H_
1265 +
1266 +#include "osd.h"
1267 +#include "ChannelMgmt.h"
1268 +
1269 +#pragma pack(push,1)
1270 +
1271 +
1272 +// The format must be the same as VMDATA_GPA_DIRECT
1273 +typedef struct _VMBUS_CHANNEL_PACKET_PAGE_BUFFER {
1274 + UINT16 Type;
1275 + UINT16 DataOffset8;
1276 + UINT16 Length8;
1277 + UINT16 Flags;
1278 + UINT64 TransactionId;
1279 + UINT32 Reserved;
1280 + UINT32 RangeCount;
1281 + PAGE_BUFFER Range[MAX_PAGE_BUFFER_COUNT];
1282 +} VMBUS_CHANNEL_PACKET_PAGE_BUFFER;
1283 +
1284 +
1285 +// The format must be the same as VMDATA_GPA_DIRECT
1286 +typedef struct _VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER {
1287 + UINT16 Type;
1288 + UINT16 DataOffset8;
1289 + UINT16 Length8;
1290 + UINT16 Flags;
1291 + UINT64 TransactionId;
1292 + UINT32 Reserved;
1293 + UINT32 RangeCount; // Always 1 in this case
1294 + MULTIPAGE_BUFFER Range;
1295 +} VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER;
1296 +
1297 +#pragma pack(pop)
1298 +
1299 +//
1300 +// Routines
1301 +//
1302 +
1303 +INTERNAL int
1304 +VmbusChannelOpen(
1305 + VMBUS_CHANNEL *Channel,
1306 + UINT32 SendRingBufferSize,
1307 + UINT32 RecvRingBufferSize,
1308 + PVOID UserData,
1309 + UINT32 UserDataLen,
1310 + PFN_CHANNEL_CALLBACK pfnOnChannelCallback,
1311 + PVOID Context
1312 + );
1313 +
1314 +INTERNAL void
1315 +VmbusChannelClose(
1316 + VMBUS_CHANNEL *Channel
1317 + );
1318 +
1319 +INTERNAL int
1320 +VmbusChannelSendPacket(
1321 + VMBUS_CHANNEL *Channel,
1322 + const PVOID Buffer,
1323 + UINT32 BufferLen,
1324 + UINT64 RequestId,
1325 + VMBUS_PACKET_TYPE Type,
1326 + UINT32 Flags
1327 +);
1328 +
1329 +INTERNAL int
1330 +VmbusChannelSendPacketPageBuffer(
1331 + VMBUS_CHANNEL *Channel,
1332 + PAGE_BUFFER PageBuffers[],
1333 + UINT32 PageCount,
1334 + PVOID Buffer,
1335 + UINT32 BufferLen,
1336 + UINT64 RequestId
1337 + );
1338 +
1339 +INTERNAL int
1340 +VmbusChannelSendPacketMultiPageBuffer(
1341 + VMBUS_CHANNEL *Channel,
1342 + MULTIPAGE_BUFFER *MultiPageBuffer,
1343 + PVOID Buffer,
1344 + UINT32 BufferLen,
1345 + UINT64 RequestId
1346 +);
1347 +
1348 +INTERNAL int
1349 +VmbusChannelEstablishGpadl(
1350 + VMBUS_CHANNEL *Channel,
1351 + PVOID Kbuffer, // from kmalloc()
1352 + UINT32 Size, // page-size multiple
1353 + UINT32 *GpadlHandle
1354 + );
1355 +
1356 +INTERNAL int
1357 +VmbusChannelTeardownGpadl(
1358 + VMBUS_CHANNEL *Channel,
1359 + UINT32 GpadlHandle
1360 + );
1361 +
1362 +INTERNAL int
1363 +VmbusChannelRecvPacket(
1364 + VMBUS_CHANNEL *Channel,
1365 + PVOID Buffer,
1366 + UINT32 BufferLen,
1367 + UINT32* BufferActualLen,
1368 + UINT64* RequestId
1369 + );
1370 +
1371 +INTERNAL int
1372 +VmbusChannelRecvPacketRaw(
1373 + VMBUS_CHANNEL *Channel,
1374 + PVOID Buffer,
1375 + UINT32 BufferLen,
1376 + UINT32* BufferActualLen,
1377 + UINT64* RequestId
1378 + );
1379 +
1380 +INTERNAL void
1381 +VmbusChannelOnChannelEvent(
1382 + VMBUS_CHANNEL *Channel
1383 + );
1384 +
1385 +INTERNAL void
1386 +VmbusChannelGetDebugInfo(
1387 + VMBUS_CHANNEL *Channel,
1388 + VMBUS_CHANNEL_DEBUG_INFO *DebugInfo
1389 + );
1390 +
1391 +INTERNAL void
1392 +VmbusChannelOnTimer(
1393 + void *Context
1394 + );
1395 +#endif //_CHANNEL_H_
1396 --- /dev/null
1397 +++ b/drivers/staging/hv/ChannelInterface.c
1398 @@ -0,0 +1,222 @@
1399 +/*
1400 + *
1401 + * Copyright (c) 2009, Microsoft Corporation.
1402 + *
1403 + * This program is free software; you can redistribute it and/or modify it
1404 + * under the terms and conditions of the GNU General Public License,
1405 + * version 2, as published by the Free Software Foundation.
1406 + *
1407 + * This program is distributed in the hope it will be useful, but WITHOUT
1408 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1409 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
1410 + * more details.
1411 + *
1412 + * You should have received a copy of the GNU General Public License along with
1413 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1414 + * Place - Suite 330, Boston, MA 02111-1307 USA.
1415 + *
1416 + * Authors:
1417 + * Haiyang Zhang <haiyangz@microsoft.com>
1418 + * Hank Janssen <hjanssen@microsoft.com>
1419 + *
1420 + */
1421 +
1422 +#include "VmbusPrivate.h"
1423 +
1424 +INTERNAL int
1425 +IVmbusChannelOpen(
1426 + PDEVICE_OBJECT Device,
1427 + UINT32 SendBufferSize,
1428 + UINT32 RecvRingBufferSize,
1429 + PVOID UserData,
1430 + UINT32 UserDataLen,
1431 + VMBUS_CHANNEL_CALLBACK ChannelCallback,
1432 + PVOID Context
1433 + )
1434 +{
1435 + return VmbusChannelOpen( (VMBUS_CHANNEL*)Device->context,
1436 + SendBufferSize,
1437 + RecvRingBufferSize,
1438 + UserData,
1439 + UserDataLen,
1440 + ChannelCallback,
1441 + Context);
1442 +}
1443 +
1444 +
1445 +INTERNAL void
1446 +IVmbusChannelClose(
1447 + PDEVICE_OBJECT Device
1448 + )
1449 +{
1450 + VmbusChannelClose((VMBUS_CHANNEL*)Device->context);
1451 +}
1452 +
1453 +
1454 +INTERNAL int
1455 +IVmbusChannelSendPacket(
1456 + PDEVICE_OBJECT Device,
1457 + const PVOID Buffer,
1458 + UINT32 BufferLen,
1459 + UINT64 RequestId,
1460 + UINT32 Type,
1461 + UINT32 Flags
1462 + )
1463 +{
1464 + return VmbusChannelSendPacket((VMBUS_CHANNEL*)Device->context,
1465 + Buffer,
1466 + BufferLen,
1467 + RequestId,
1468 + Type,
1469 + Flags);
1470 +}
1471 +
1472 +INTERNAL int
1473 +IVmbusChannelSendPacketPageBuffer(
1474 + PDEVICE_OBJECT Device,
1475 + PAGE_BUFFER PageBuffers[],
1476 + UINT32 PageCount,
1477 + PVOID Buffer,
1478 + UINT32 BufferLen,
1479 + UINT64 RequestId
1480 + )
1481 +{
1482 + return VmbusChannelSendPacketPageBuffer((VMBUS_CHANNEL*)Device->context,
1483 + PageBuffers,
1484 + PageCount,
1485 + Buffer,
1486 + BufferLen,
1487 + RequestId);
1488 +}
1489 +
1490 +INTERNAL int
1491 +IVmbusChannelSendPacketMultiPageBuffer(
1492 + PDEVICE_OBJECT Device,
1493 + MULTIPAGE_BUFFER *MultiPageBuffer,
1494 + PVOID Buffer,
1495 + UINT32 BufferLen,
1496 + UINT64 RequestId
1497 + )
1498 +{
1499 + return VmbusChannelSendPacketMultiPageBuffer((VMBUS_CHANNEL*)Device->context,
1500 + MultiPageBuffer,
1501 + Buffer,
1502 + BufferLen,
1503 + RequestId);
1504 +}
1505 +
1506 +INTERNAL int
1507 +IVmbusChannelRecvPacket (
1508 + PDEVICE_OBJECT Device,
1509 + PVOID Buffer,
1510 + UINT32 BufferLen,
1511 + UINT32* BufferActualLen,
1512 + UINT64* RequestId
1513 + )
1514 +{
1515 + return VmbusChannelRecvPacket((VMBUS_CHANNEL*)Device->context,
1516 + Buffer,
1517 + BufferLen,
1518 + BufferActualLen,
1519 + RequestId);
1520 +}
1521 +
1522 +INTERNAL int
1523 +IVmbusChannelRecvPacketRaw(
1524 + PDEVICE_OBJECT Device,
1525 + PVOID Buffer,
1526 + UINT32 BufferLen,
1527 + UINT32* BufferActualLen,
1528 + UINT64* RequestId
1529 + )
1530 +{
1531 + return VmbusChannelRecvPacketRaw((VMBUS_CHANNEL*)Device->context,
1532 + Buffer,
1533 + BufferLen,
1534 + BufferActualLen,
1535 + RequestId);
1536 +}
1537 +
1538 +INTERNAL int
1539 +IVmbusChannelEstablishGpadl(
1540 + PDEVICE_OBJECT Device,
1541 + PVOID Buffer,
1542 + UINT32 BufferLen,
1543 + UINT32* GpadlHandle
1544 + )
1545 +{
1546 + return VmbusChannelEstablishGpadl((VMBUS_CHANNEL*)Device->context,
1547 + Buffer,
1548 + BufferLen,
1549 + GpadlHandle);
1550 +}
1551 +
1552 +INTERNAL int
1553 +IVmbusChannelTeardownGpadl(
1554 + PDEVICE_OBJECT Device,
1555 + UINT32 GpadlHandle
1556 + )
1557 +{
1558 + return VmbusChannelTeardownGpadl((VMBUS_CHANNEL*)Device->context,
1559 + GpadlHandle);
1560 +
1561 +}
1562 +
1563 +INTERNAL void
1564 +GetChannelInterface(
1565 + VMBUS_CHANNEL_INTERFACE *ChannelInterface
1566 + )
1567 +{
1568 + ChannelInterface->Open = IVmbusChannelOpen;
1569 + ChannelInterface->Close = IVmbusChannelClose;
1570 + ChannelInterface->SendPacket = IVmbusChannelSendPacket;
1571 + ChannelInterface->SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer;
1572 + ChannelInterface->SendPacketMultiPageBuffer = IVmbusChannelSendPacketMultiPageBuffer;
1573 + ChannelInterface->RecvPacket = IVmbusChannelRecvPacket;
1574 + ChannelInterface->RecvPacketRaw = IVmbusChannelRecvPacketRaw;
1575 + ChannelInterface->EstablishGpadl = IVmbusChannelEstablishGpadl;
1576 + ChannelInterface->TeardownGpadl = IVmbusChannelTeardownGpadl;
1577 + ChannelInterface->GetInfo = GetChannelInfo;
1578 +}
1579 +
1580 +
1581 +INTERNAL void
1582 +GetChannelInfo(
1583 + PDEVICE_OBJECT Device,
1584 + DEVICE_INFO *DeviceInfo
1585 + )
1586 +{
1587 + VMBUS_CHANNEL_DEBUG_INFO debugInfo;
1588 +
1589 + if (Device->context)
1590 + {
1591 + VmbusChannelGetDebugInfo((VMBUS_CHANNEL*)Device->context, &debugInfo);
1592 +
1593 + DeviceInfo->ChannelId = debugInfo.RelId;
1594 + DeviceInfo->ChannelState = debugInfo.State;
1595 + memcpy(&DeviceInfo->ChannelType, &debugInfo.InterfaceType, sizeof(GUID));
1596 + memcpy(&DeviceInfo->ChannelInstance, &debugInfo.InterfaceInstance, sizeof(GUID));
1597 +
1598 + DeviceInfo->MonitorId = debugInfo.MonitorId;
1599 +
1600 + DeviceInfo->ServerMonitorPending = debugInfo.ServerMonitorPending;
1601 + DeviceInfo->ServerMonitorLatency = debugInfo.ServerMonitorLatency;
1602 + DeviceInfo->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId;
1603 +
1604 + DeviceInfo->ClientMonitorPending = debugInfo.ClientMonitorPending;
1605 + DeviceInfo->ClientMonitorLatency = debugInfo.ClientMonitorLatency;
1606 + DeviceInfo->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId;
1607 +
1608 + DeviceInfo->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask;
1609 + DeviceInfo->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex;
1610 + DeviceInfo->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex;
1611 + DeviceInfo->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead;
1612 + DeviceInfo->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite;
1613 +
1614 + DeviceInfo->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask;
1615 + DeviceInfo->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex;
1616 + DeviceInfo->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex;
1617 + DeviceInfo->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead;
1618 + DeviceInfo->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite;
1619 + }
1620 +}
1621 --- /dev/null
1622 +++ b/drivers/staging/hv/ChannelInterface.h
1623 @@ -0,0 +1,41 @@
1624 +/*
1625 + *
1626 + * Copyright (c) 2009, Microsoft Corporation.
1627 + *
1628 + * This program is free software; you can redistribute it and/or modify it
1629 + * under the terms and conditions of the GNU General Public License,
1630 + * version 2, as published by the Free Software Foundation.
1631 + *
1632 + * This program is distributed in the hope it will be useful, but WITHOUT
1633 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1634 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
1635 + * more details.
1636 + *
1637 + * You should have received a copy of the GNU General Public License along with
1638 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1639 + * Place - Suite 330, Boston, MA 02111-1307 USA.
1640 + *
1641 + * Authors:
1642 + * Haiyang Zhang <haiyangz@microsoft.com>
1643 + * Hank Janssen <hjanssen@microsoft.com>
1644 + *
1645 + */
1646 +
1647 +
1648 +#ifndef _CHANNEL_INTERFACE_H_
1649 +#define _CHANNEL_INTERFACE_H_
1650 +
1651 +#include "VmbusApi.h"
1652 +
1653 +INTERNAL void
1654 +GetChannelInterface(
1655 + VMBUS_CHANNEL_INTERFACE *ChannelInterface
1656 + );
1657 +
1658 +INTERNAL void
1659 +GetChannelInfo(
1660 + PDEVICE_OBJECT Device,
1661 + DEVICE_INFO *DeviceInfo
1662 + );
1663 +
1664 +#endif // _CHANNEL_INTERFACE_H_
1665 --- /dev/null
1666 +++ b/drivers/staging/hv/ChannelMgmt.c
1667 @@ -0,0 +1,826 @@
1668 +/*
1669 + *
1670 + * Copyright (c) 2009, Microsoft Corporation.
1671 + *
1672 + * This program is free software; you can redistribute it and/or modify it
1673 + * under the terms and conditions of the GNU General Public License,
1674 + * version 2, as published by the Free Software Foundation.
1675 + *
1676 + * This program is distributed in the hope it will be useful, but WITHOUT
1677 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1678 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
1679 + * more details.
1680 + *
1681 + * You should have received a copy of the GNU General Public License along with
1682 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1683 + * Place - Suite 330, Boston, MA 02111-1307 USA.
1684 + *
1685 + * Authors:
1686 + * Haiyang Zhang <haiyangz@microsoft.com>
1687 + * Hank Janssen <hjanssen@microsoft.com>
1688 + *
1689 + */
1690 +
1691 +
1692 +#include "osd.h"
1693 +#include "logging.h"
1694 +
1695 +#include "VmbusPrivate.h"
1696 +
1697 +//
1698 +// Defines
1699 +//
1700 +
1701 +//
1702 +// Data types
1703 +//
1704 +
1705 +typedef void (*PFN_CHANNEL_MESSAGE_HANDLER)(VMBUS_CHANNEL_MESSAGE_HEADER* msg);
1706 +
1707 +typedef struct _VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY {
1708 + VMBUS_CHANNEL_MESSAGE_TYPE messageType;
1709 + PFN_CHANNEL_MESSAGE_HANDLER messageHandler;
1710 +} VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY;
1711 +
1712 +//
1713 +// Internal routines
1714 +//
1715 +
1716 +static void
1717 +VmbusChannelOnOffer(
1718 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1719 + );
1720 +static void
1721 +VmbusChannelOnOpenResult(
1722 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1723 + );
1724 +
1725 +static void
1726 +VmbusChannelOnOfferRescind(
1727 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1728 + );
1729 +
1730 +static void
1731 +VmbusChannelOnGpadlCreated(
1732 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1733 + );
1734 +
1735 +static void
1736 +VmbusChannelOnGpadlTorndown(
1737 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1738 + );
1739 +
1740 +static void
1741 +VmbusChannelOnOffersDelivered(
1742 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1743 + );
1744 +
1745 +static void
1746 +VmbusChannelOnVersionResponse(
1747 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1748 + );
1749 +
1750 +static void
1751 +VmbusChannelProcessOffer(
1752 + PVOID context
1753 + );
1754 +
1755 +static void
1756 +VmbusChannelProcessRescindOffer(
1757 + PVOID context
1758 + );
1759 +
1760 +
1761 +//
1762 +// Globals
1763 +//
1764 +
1765 +#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
1766 +
1767 +const GUID gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED]= {
1768 + //{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}
1769 + {.Data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}},// Storage - SCSI
1770 + //{F8615163-DF3E-46c5-913F-F2D2F965ED0E}
1771 + {.Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}}, // Network
1772 + //{CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A}
1773 + {.Data = {0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A}}, // Input
1774 + //{32412632-86cb-44a2-9b5c-50d1417354f5}
1775 + {.Data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}}, // IDE
1776 +
1777 +};
1778 +
1779 +// Channel message dispatch table
1780 +VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY gChannelMessageTable[ChannelMessageCount]= {
1781 + {ChannelMessageInvalid, NULL},
1782 + {ChannelMessageOfferChannel, VmbusChannelOnOffer},
1783 + {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
1784 + {ChannelMessageRequestOffers, NULL},
1785 + {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
1786 + {ChannelMessageOpenChannel, NULL},
1787 + {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
1788 + {ChannelMessageCloseChannel, NULL},
1789 + {ChannelMessageGpadlHeader, NULL},
1790 + {ChannelMessageGpadlBody, NULL},
1791 + {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
1792 + {ChannelMessageGpadlTeardown, NULL},
1793 + {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
1794 + {ChannelMessageRelIdReleased, NULL},
1795 + {ChannelMessageInitiateContact, NULL},
1796 + {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
1797 + {ChannelMessageUnload, NULL},
1798 +};
1799 +
1800 +/*++
1801 +
1802 +Name:
1803 + AllocVmbusChannel()
1804 +
1805 +Description:
1806 + Allocate and initialize a vmbus channel object
1807 +
1808 +--*/
1809 +VMBUS_CHANNEL* AllocVmbusChannel(void)
1810 +{
1811 + VMBUS_CHANNEL* channel;
1812 +
1813 + channel = (VMBUS_CHANNEL*) MemAllocAtomic(sizeof(VMBUS_CHANNEL));
1814 + if (!channel)
1815 + {
1816 + return NULL;
1817 + }
1818 +
1819 + memset(channel, 0,sizeof(VMBUS_CHANNEL));
1820 + channel->InboundLock = SpinlockCreate();
1821 + if (!channel->InboundLock)
1822 + {
1823 + MemFree(channel);
1824 + return NULL;
1825 + }
1826 +
1827 + channel->PollTimer = TimerCreate(VmbusChannelOnTimer, channel);
1828 + if (!channel->PollTimer)
1829 + {
1830 + SpinlockClose(channel->InboundLock);
1831 + MemFree(channel);
1832 + return NULL;
1833 + }
1834 +
1835 + //channel->dataWorkQueue = WorkQueueCreate("data");
1836 + channel->ControlWQ = WorkQueueCreate("control");
1837 + if (!channel->ControlWQ)
1838 + {
1839 + TimerClose(channel->PollTimer);
1840 + SpinlockClose(channel->InboundLock);
1841 + MemFree(channel);
1842 + return NULL;
1843 + }
1844 +
1845 + return channel;
1846 +}
1847 +
1848 +/*++
1849 +
1850 +Name:
1851 + ReleaseVmbusChannel()
1852 +
1853 +Description:
1854 + Release the vmbus channel object itself
1855 +
1856 +--*/
1857 +static inline void ReleaseVmbusChannel(void* Context)
1858 +{
1859 + VMBUS_CHANNEL* channel = (VMBUS_CHANNEL*)Context;
1860 +
1861 + DPRINT_ENTER(VMBUS);
1862 +
1863 + DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
1864 + WorkQueueClose(channel->ControlWQ);
1865 + DPRINT_DBG(VMBUS, "channel released (%p)", channel);
1866 +
1867 + MemFree(channel);
1868 +
1869 + DPRINT_EXIT(VMBUS);
1870 +}
1871 +
1872 +/*++
1873 +
1874 +Name:
1875 + FreeVmbusChannel()
1876 +
1877 +Description:
1878 + Release the resources used by the vmbus channel object
1879 +
1880 +--*/
1881 +void FreeVmbusChannel(VMBUS_CHANNEL* Channel)
1882 +{
1883 + SpinlockClose(Channel->InboundLock);
1884 + TimerClose(Channel->PollTimer);
1885 +
1886 + // We have to release the channel's workqueue/thread in the vmbus's workqueue/thread context
1887 + // ie we can't destroy ourselves.
1888 + WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, ReleaseVmbusChannel, (void*)Channel);
1889 +}
1890 +
1891 +
1892 +/*++
1893 +
1894 +Name:
1895 + VmbusChannelProcessOffer()
1896 +
1897 +Description:
1898 + Process the offer by creating a channel/device associated with this offer
1899 +
1900 +--*/
1901 +static void
1902 +VmbusChannelProcessOffer(
1903 + PVOID context
1904 + )
1905 +{
1906 + int ret=0;
1907 + VMBUS_CHANNEL* newChannel=(VMBUS_CHANNEL*)context;
1908 + LIST_ENTRY* anchor;
1909 + LIST_ENTRY* curr;
1910 + BOOL fNew=TRUE;
1911 + VMBUS_CHANNEL* channel;
1912 +
1913 + DPRINT_ENTER(VMBUS);
1914 +
1915 + // Make sure this is a new offer
1916 + SpinlockAcquire(gVmbusConnection.ChannelLock);
1917 +
1918 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
1919 + {
1920 + channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
1921 +
1922 + if (!memcmp(&channel->OfferMsg.Offer.InterfaceType, &newChannel->OfferMsg.Offer.InterfaceType,sizeof(GUID)) &&
1923 + !memcmp(&channel->OfferMsg.Offer.InterfaceInstance, &newChannel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID)))
1924 + {
1925 + fNew = FALSE;
1926 + break;
1927 + }
1928 + }
1929 +
1930 + if (fNew)
1931 + {
1932 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelList, &newChannel->ListEntry);
1933 + }
1934 + SpinlockRelease(gVmbusConnection.ChannelLock);
1935 +
1936 + if (!fNew)
1937 + {
1938 + DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", newChannel->OfferMsg.ChildRelId);
1939 + FreeVmbusChannel(newChannel);
1940 + DPRINT_EXIT(VMBUS);
1941 + return;
1942 + }
1943 +
1944 + // Start the process of binding this offer to the driver
1945 + // We need to set the DeviceObject field before calling VmbusChildDeviceAdd()
1946 + newChannel->DeviceObject = VmbusChildDeviceCreate(
1947 + newChannel->OfferMsg.Offer.InterfaceType,
1948 + newChannel->OfferMsg.Offer.InterfaceInstance,
1949 + newChannel);
1950 +
1951 + DPRINT_DBG(VMBUS, "child device object allocated - %p", newChannel->DeviceObject);
1952 +
1953 + // Add the new device to the bus. This will kick off device-driver binding
1954 + // which eventually invokes the device driver's AddDevice() method.
1955 + ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
1956 + if (ret != 0)
1957 + {
1958 + DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)",
1959 + newChannel->OfferMsg.ChildRelId);
1960 +
1961 + SpinlockAcquire(gVmbusConnection.ChannelLock);
1962 + REMOVE_ENTRY_LIST(&newChannel->ListEntry);
1963 + SpinlockRelease(gVmbusConnection.ChannelLock);
1964 +
1965 + FreeVmbusChannel(newChannel);
1966 + }
1967 + else
1968 + {
1969 + // This state is used to indicate a successful open so that when we do close the channel normally,
1970 + // we can cleanup properly
1971 + newChannel->State = CHANNEL_OPEN_STATE;
1972 + }
1973 + DPRINT_EXIT(VMBUS);
1974 +}
1975 +
1976 +/*++
1977 +
1978 +Name:
1979 + VmbusChannelProcessRescindOffer()
1980 +
1981 +Description:
1982 + Rescind the offer by initiating a device removal
1983 +
1984 +--*/
1985 +static void
1986 +VmbusChannelProcessRescindOffer(
1987 + PVOID context
1988 + )
1989 +{
1990 + VMBUS_CHANNEL* channel=(VMBUS_CHANNEL*)context;
1991 +
1992 + DPRINT_ENTER(VMBUS);
1993 +
1994 + VmbusChildDeviceRemove(channel->DeviceObject);
1995 +
1996 + DPRINT_EXIT(VMBUS);
1997 +}
1998 +
1999 +
2000 +/*++
2001 +
2002 +Name:
2003 + VmbusChannelOnOffer()
2004 +
2005 +Description:
2006 + Handler for channel offers from vmbus in parent partition. We ignore all offers except
2007 + network and storage offers. For each network and storage offers, we create a channel object
2008 + and queue a work item to the channel object to process the offer synchronously
2009 +
2010 +--*/
2011 +static void
2012 +VmbusChannelOnOffer(
2013 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2014 + )
2015 +{
2016 + VMBUS_CHANNEL_OFFER_CHANNEL* offer = (VMBUS_CHANNEL_OFFER_CHANNEL*)hdr;
2017 + VMBUS_CHANNEL* newChannel;
2018 +
2019 + GUID *guidType;
2020 + GUID *guidInstance;
2021 + int i;
2022 + int fSupported=0;
2023 +
2024 + DPRINT_ENTER(VMBUS);
2025 +
2026 + for (i=0; i<MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++)
2027 + {
2028 + if (memcmp(&offer->Offer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(GUID)) == 0)
2029 + {
2030 + fSupported = 1;
2031 + break;
2032 + }
2033 + }
2034 +
2035 + if (!fSupported)
2036 + {
2037 + DPRINT_DBG(VMBUS, "Ignoring channel offer notification for child relid %d", offer->ChildRelId);
2038 + DPRINT_EXIT(VMBUS);
2039 +
2040 + return;
2041 + }
2042 +
2043 + guidType = &offer->Offer.InterfaceType;
2044 + guidInstance = &offer->Offer.InterfaceInstance;
2045 +
2046 + DPRINT_INFO(VMBUS, "Channel offer notification - child relid %d monitor id %d allocated %d, "
2047 + "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x} "
2048 + "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
2049 + offer->ChildRelId,
2050 + offer->MonitorId,
2051 + offer->MonitorAllocated,
2052 + 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],
2053 + 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]);
2054 +
2055 + // Allocate the channel object and save this offer.
2056 + newChannel = AllocVmbusChannel();
2057 + if (!newChannel)
2058 + {
2059 + DPRINT_ERR(VMBUS, "unable to allocate channel object");
2060 + return;
2061 + }
2062 +
2063 + DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
2064 +
2065 + memcpy(&newChannel->OfferMsg, offer, sizeof(VMBUS_CHANNEL_OFFER_CHANNEL));
2066 + newChannel->MonitorGroup = (UINT8)offer->MonitorId / 32;
2067 + newChannel->MonitorBit = (UINT8)offer->MonitorId % 32;
2068 +
2069 + // TODO: Make sure the offer comes from our parent partition
2070 + WorkQueueQueueWorkItem(newChannel->ControlWQ, VmbusChannelProcessOffer, newChannel);
2071 +
2072 + DPRINT_EXIT(VMBUS);
2073 +}
2074 +
2075 +
2076 +/*++
2077 +
2078 +Name:
2079 + VmbusChannelOnOfferRescind()
2080 +
2081 +Description:
2082 + Rescind offer handler. We queue a work item to process this offer
2083 + synchronously
2084 +
2085 +--*/
2086 +static void
2087 +VmbusChannelOnOfferRescind(
2088 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2089 + )
2090 +{
2091 + VMBUS_CHANNEL_RESCIND_OFFER* rescind = (VMBUS_CHANNEL_RESCIND_OFFER*)hdr;
2092 + VMBUS_CHANNEL* channel;
2093 +
2094 + DPRINT_ENTER(VMBUS);
2095 +
2096 + channel = GetChannelFromRelId(rescind->ChildRelId);
2097 + if (channel == NULL)
2098 + {
2099 + DPRINT_DBG(VMBUS, "channel not found for relId %d", rescind->ChildRelId);
2100 + return;
2101 + }
2102 +
2103 + WorkQueueQueueWorkItem(channel->ControlWQ, VmbusChannelProcessRescindOffer, channel);
2104 +
2105 + DPRINT_EXIT(VMBUS);
2106 +}
2107 +
2108 +
2109 +/*++
2110 +
2111 +Name:
2112 + VmbusChannelOnOffersDelivered()
2113 +
2114 +Description:
2115 + This is invoked when all offers have been delivered.
2116 + Nothing to do here.
2117 +
2118 +--*/
2119 +static void
2120 +VmbusChannelOnOffersDelivered(
2121 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2122 + )
2123 +{
2124 + DPRINT_ENTER(VMBUS);
2125 + DPRINT_EXIT(VMBUS);
2126 +}
2127 +
2128 +
2129 +/*++
2130 +
2131 +Name:
2132 + VmbusChannelOnOpenResult()
2133 +
2134 +Description:
2135 + Open result handler. This is invoked when we received a response
2136 + to our channel open request. Find the matching request, copy the
2137 + response and signal the requesting thread.
2138 +
2139 +--*/
2140 +static void
2141 +VmbusChannelOnOpenResult(
2142 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2143 + )
2144 +{
2145 + VMBUS_CHANNEL_OPEN_RESULT* result = (VMBUS_CHANNEL_OPEN_RESULT*)hdr;
2146 + LIST_ENTRY* anchor;
2147 + LIST_ENTRY* curr;
2148 + VMBUS_CHANNEL_MSGINFO* msgInfo;
2149 + VMBUS_CHANNEL_MESSAGE_HEADER* requestHeader;
2150 + VMBUS_CHANNEL_OPEN_CHANNEL* openMsg;
2151 +
2152 + DPRINT_ENTER(VMBUS);
2153 +
2154 + DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
2155 +
2156 + // Find the open msg, copy the result and signal/unblock the wait event
2157 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2158 +
2159 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
2160 + {
2161 + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
2162 + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2163 +
2164 + if (requestHeader->MessageType == ChannelMessageOpenChannel)
2165 + {
2166 + openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)msgInfo->Msg;
2167 + if (openMsg->ChildRelId == result->ChildRelId &&
2168 + openMsg->OpenId == result->OpenId)
2169 + {
2170 + memcpy(&msgInfo->Response.OpenResult, result, sizeof(VMBUS_CHANNEL_OPEN_RESULT));
2171 + WaitEventSet(msgInfo->WaitEvent);
2172 + break;
2173 + }
2174 + }
2175 + }
2176 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2177 +
2178 + DPRINT_EXIT(VMBUS);
2179 +}
2180 +
2181 +
2182 +/*++
2183 +
2184 +Name:
2185 + VmbusChannelOnGpadlCreated()
2186 +
2187 +Description:
2188 + GPADL created handler. This is invoked when we received a response
2189 + to our gpadl create request. Find the matching request, copy the
2190 + response and signal the requesting thread.
2191 +
2192 +--*/
2193 +static void
2194 +VmbusChannelOnGpadlCreated(
2195 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2196 + )
2197 +{
2198 + VMBUS_CHANNEL_GPADL_CREATED *gpadlCreated = (VMBUS_CHANNEL_GPADL_CREATED*)hdr;
2199 + LIST_ENTRY *anchor;
2200 + LIST_ENTRY *curr;
2201 + VMBUS_CHANNEL_MSGINFO *msgInfo;
2202 + VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
2203 + VMBUS_CHANNEL_GPADL_HEADER *gpadlHeader;
2204 +
2205 + DPRINT_ENTER(VMBUS);
2206 +
2207 + DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", gpadlCreated->CreationStatus);
2208 +
2209 + // Find the establish msg, copy the result and signal/unblock the wait event
2210 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2211 +
2212 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
2213 + {
2214 + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
2215 + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2216 +
2217 + if (requestHeader->MessageType == ChannelMessageGpadlHeader)
2218 + {
2219 + gpadlHeader = (VMBUS_CHANNEL_GPADL_HEADER*)requestHeader;
2220 +
2221 + if ((gpadlCreated->ChildRelId == gpadlHeader->ChildRelId) &&
2222 + (gpadlCreated->Gpadl == gpadlHeader->Gpadl))
2223 + {
2224 + memcpy(&msgInfo->Response.GpadlCreated, gpadlCreated, sizeof(VMBUS_CHANNEL_GPADL_CREATED));
2225 + WaitEventSet(msgInfo->WaitEvent);
2226 + break;
2227 + }
2228 + }
2229 + }
2230 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2231 +
2232 + DPRINT_EXIT(VMBUS);
2233 +}
2234 +
2235 +
2236 +/*++
2237 +
2238 +Name:
2239 + VmbusChannelOnGpadlTorndown()
2240 +
2241 +Description:
2242 + GPADL torndown handler. This is invoked when we received a response
2243 + to our gpadl teardown request. Find the matching request, copy the
2244 + response and signal the requesting thread.
2245 +
2246 +--*/
2247 +static void
2248 +VmbusChannelOnGpadlTorndown(
2249 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2250 + )
2251 +{
2252 + VMBUS_CHANNEL_GPADL_TORNDOWN* gpadlTorndown = (VMBUS_CHANNEL_GPADL_TORNDOWN*)hdr;
2253 + LIST_ENTRY* anchor;
2254 + LIST_ENTRY* curr;
2255 + VMBUS_CHANNEL_MSGINFO* msgInfo;
2256 + VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
2257 + VMBUS_CHANNEL_GPADL_TEARDOWN *gpadlTeardown;
2258 +
2259 + DPRINT_ENTER(VMBUS);
2260 +
2261 + // Find the open msg, copy the result and signal/unblock the wait event
2262 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2263 +
2264 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
2265 + {
2266 + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
2267 + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2268 +
2269 + if (requestHeader->MessageType == ChannelMessageGpadlTeardown)
2270 + {
2271 + gpadlTeardown = (VMBUS_CHANNEL_GPADL_TEARDOWN*)requestHeader;
2272 +
2273 + if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl)
2274 + {
2275 + memcpy(&msgInfo->Response.GpadlTorndown, gpadlTorndown, sizeof(VMBUS_CHANNEL_GPADL_TORNDOWN));
2276 + WaitEventSet(msgInfo->WaitEvent);
2277 + break;
2278 + }
2279 + }
2280 + }
2281 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2282 +
2283 + DPRINT_EXIT(VMBUS);
2284 +}
2285 +
2286 +
2287 +/*++
2288 +
2289 +Name:
2290 + VmbusChannelOnVersionResponse()
2291 +
2292 +Description:
2293 + Version response handler. This is invoked when we received a response
2294 + to our initiate contact request. Find the matching request, copy the
2295 + response and signal the requesting thread.
2296 +
2297 +--*/
2298 +static void
2299 +VmbusChannelOnVersionResponse(
2300 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2301 + )
2302 +{
2303 + LIST_ENTRY* anchor;
2304 + LIST_ENTRY* curr;
2305 + VMBUS_CHANNEL_MSGINFO *msgInfo;
2306 + VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
2307 + VMBUS_CHANNEL_INITIATE_CONTACT *initiate;
2308 + VMBUS_CHANNEL_VERSION_RESPONSE *versionResponse = (VMBUS_CHANNEL_VERSION_RESPONSE*)hdr;
2309 +
2310 + DPRINT_ENTER(VMBUS);
2311 +
2312 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2313 +
2314 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
2315 + {
2316 + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
2317 + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2318 +
2319 + if (requestHeader->MessageType == ChannelMessageInitiateContact)
2320 + {
2321 + initiate = (VMBUS_CHANNEL_INITIATE_CONTACT*)requestHeader;
2322 + memcpy(&msgInfo->Response.VersionResponse, versionResponse, sizeof(VMBUS_CHANNEL_VERSION_RESPONSE));
2323 + WaitEventSet(msgInfo->WaitEvent);
2324 + }
2325 + }
2326 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2327 +
2328 + DPRINT_EXIT(VMBUS);
2329 +}
2330 +
2331 +
2332 +/*++
2333 +
2334 +Name:
2335 + VmbusOnChannelMessage()
2336 +
2337 +Description:
2338 + Handler for channel protocol messages.
2339 + This is invoked in the vmbus worker thread context.
2340 +
2341 +--*/
2342 +VOID
2343 +VmbusOnChannelMessage(
2344 + void *Context
2345 + )
2346 +{
2347 + HV_MESSAGE *msg=(HV_MESSAGE*)Context;
2348 + VMBUS_CHANNEL_MESSAGE_HEADER* hdr;
2349 + int size;
2350 +
2351 + DPRINT_ENTER(VMBUS);
2352 +
2353 + hdr = (VMBUS_CHANNEL_MESSAGE_HEADER*)msg->u.Payload;
2354 + size=msg->Header.PayloadSize;
2355 +
2356 + DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
2357 +
2358 + if (hdr->MessageType >= ChannelMessageCount)
2359 + {
2360 + DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", hdr->MessageType, size);
2361 + PrintBytes((unsigned char *)msg->u.Payload, size);
2362 + MemFree(msg);
2363 + return;
2364 + }
2365 +
2366 + if (gChannelMessageTable[hdr->MessageType].messageHandler)
2367 + {
2368 + gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
2369 + }
2370 + else
2371 + {
2372 + DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->MessageType);
2373 + }
2374 +
2375 + // Free the msg that was allocated in VmbusOnMsgDPC()
2376 + MemFree(msg);
2377 + DPRINT_EXIT(VMBUS);
2378 +}
2379 +
2380 +
2381 +/*++
2382 +
2383 +Name:
2384 + VmbusChannelRequestOffers()
2385 +
2386 +Description:
2387 + Send a request to get all our pending offers.
2388 +
2389 +--*/
2390 +int
2391 +VmbusChannelRequestOffers(
2392 + VOID
2393 + )
2394 +{
2395 + int ret=0;
2396 + VMBUS_CHANNEL_MESSAGE_HEADER* msg;
2397 + VMBUS_CHANNEL_MSGINFO* msgInfo;
2398 +
2399 + DPRINT_ENTER(VMBUS);
2400 +
2401 + msgInfo =
2402 + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_MESSAGE_HEADER));
2403 + ASSERT(msgInfo != NULL);
2404 +
2405 + msgInfo->WaitEvent = WaitEventCreate();
2406 + msg = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2407 +
2408 + msg->MessageType = ChannelMessageRequestOffers;
2409 +
2410 + /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
2411 + INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, &msgInfo->msgListEntry);
2412 + SpinlockRelease(gVmbusConnection.channelMsgLock);*/
2413 +
2414 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_MESSAGE_HEADER));
2415 + if (ret != 0)
2416 + {
2417 + DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
2418 +
2419 + /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
2420 + REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
2421 + SpinlockRelease(gVmbusConnection.channelMsgLock);*/
2422 +
2423 + goto Cleanup;
2424 + }
2425 + //WaitEventWait(msgInfo->waitEvent);
2426 +
2427 + /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
2428 + REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
2429 + SpinlockRelease(gVmbusConnection.channelMsgLock);*/
2430 +
2431 +
2432 +Cleanup:
2433 + if (msgInfo)
2434 + {
2435 + WaitEventClose(msgInfo->WaitEvent);
2436 + MemFree(msgInfo);
2437 + }
2438 +
2439 + DPRINT_EXIT(VMBUS);
2440 +
2441 + return ret;
2442 +}
2443 +
2444 +/*++
2445 +
2446 +Name:
2447 + VmbusChannelReleaseUnattachedChannels()
2448 +
2449 +Description:
2450 + Release channels that are unattached/unconnected ie (no drivers associated)
2451 +
2452 +--*/
2453 +void
2454 +VmbusChannelReleaseUnattachedChannels(
2455 + VOID
2456 + )
2457 +{
2458 + LIST_ENTRY *entry;
2459 + VMBUS_CHANNEL *channel;
2460 + VMBUS_CHANNEL *start=NULL;
2461 +
2462 + SpinlockAcquire(gVmbusConnection.ChannelLock);
2463 +
2464 + while (!IsListEmpty(&gVmbusConnection.ChannelList))
2465 + {
2466 + entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList);
2467 + channel = CONTAINING_RECORD(entry, VMBUS_CHANNEL, ListEntry);
2468 +
2469 + if (channel == start)
2470 + break;
2471 +
2472 + if (!channel->DeviceObject->Driver)
2473 + {
2474 + REMOVE_ENTRY_LIST(&channel->ListEntry);
2475 + DPRINT_INFO(VMBUS, "Releasing unattached device object %p", channel->DeviceObject);
2476 +
2477 + VmbusChildDeviceRemove(channel->DeviceObject);
2478 + FreeVmbusChannel(channel);
2479 + }
2480 + else
2481 + {
2482 + if (!start)
2483 + {
2484 + start = channel;
2485 + }
2486 + }
2487 + }
2488 +
2489 + SpinlockRelease(gVmbusConnection.ChannelLock);
2490 +}
2491 +
2492 +// eof
2493 +
2494 --- /dev/null
2495 +++ b/drivers/staging/hv/ChannelMgmt.h
2496 @@ -0,0 +1,156 @@
2497 +/*
2498 + *
2499 + * Copyright (c) 2009, Microsoft Corporation.
2500 + *
2501 + * This program is free software; you can redistribute it and/or modify it
2502 + * under the terms and conditions of the GNU General Public License,
2503 + * version 2, as published by the Free Software Foundation.
2504 + *
2505 + * This program is distributed in the hope it will be useful, but WITHOUT
2506 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2507 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
2508 + * more details.
2509 + *
2510 + * You should have received a copy of the GNU General Public License along with
2511 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
2512 + * Place - Suite 330, Boston, MA 02111-1307 USA.
2513 + *
2514 + * Authors:
2515 + * Haiyang Zhang <haiyangz@microsoft.com>
2516 + * Hank Janssen <hjanssen@microsoft.com>
2517 + *
2518 + */
2519 +
2520 +
2521 +#ifndef _CHANNEL_MGMT_H_
2522 +#define _CHANNEL_MGMT_H_
2523 +
2524 +#include "osd.h"
2525 +#include "List.h"
2526 +#include "RingBuffer.h"
2527 +
2528 +#include "VmbusChannelInterface.h"
2529 +#include "ChannelMessages.h"
2530 +
2531 +
2532 +
2533 +typedef void (*PFN_CHANNEL_CALLBACK)(PVOID context);
2534 +
2535 +typedef enum {
2536 + CHANNEL_OFFER_STATE,
2537 + CHANNEL_OPENING_STATE,
2538 + CHANNEL_OPEN_STATE,
2539 +} VMBUS_CHANNEL_STATE;
2540 +
2541 +typedef struct _VMBUS_CHANNEL {
2542 + LIST_ENTRY ListEntry;
2543 +
2544 + DEVICE_OBJECT* DeviceObject;
2545 +
2546 + HANDLE PollTimer; // SA-111 workaround
2547 +
2548 + VMBUS_CHANNEL_STATE State;
2549 +
2550 + VMBUS_CHANNEL_OFFER_CHANNEL OfferMsg;
2551 + // These are based on the OfferMsg.MonitorId. Save it here for easy access.
2552 + UINT8 MonitorGroup;
2553 + UINT8 MonitorBit;
2554 +
2555 + UINT32 RingBufferGpadlHandle;
2556 +
2557 + // Allocated memory for ring buffer
2558 + VOID* RingBufferPages;
2559 + UINT32 RingBufferPageCount;
2560 + RING_BUFFER_INFO Outbound; // send to parent
2561 + RING_BUFFER_INFO Inbound; // receive from parent
2562 + HANDLE InboundLock;
2563 + HANDLE ControlWQ;
2564 +
2565 + // Channel callback are invoked in this workqueue context
2566 + //HANDLE dataWorkQueue;
2567 +
2568 + PFN_CHANNEL_CALLBACK OnChannelCallback;
2569 + PVOID ChannelCallbackContext;
2570 +
2571 +} VMBUS_CHANNEL;
2572 +
2573 +
2574 +typedef struct _VMBUS_CHANNEL_DEBUG_INFO {
2575 + UINT32 RelId;
2576 + VMBUS_CHANNEL_STATE State;
2577 + GUID InterfaceType;
2578 + GUID InterfaceInstance;
2579 + UINT32 MonitorId;
2580 + UINT32 ServerMonitorPending;
2581 + UINT32 ServerMonitorLatency;
2582 + UINT32 ServerMonitorConnectionId;
2583 + UINT32 ClientMonitorPending;
2584 + UINT32 ClientMonitorLatency;
2585 + UINT32 ClientMonitorConnectionId;
2586 +
2587 + RING_BUFFER_DEBUG_INFO Inbound;
2588 + RING_BUFFER_DEBUG_INFO Outbound;
2589 +} VMBUS_CHANNEL_DEBUG_INFO;
2590 +
2591 +
2592 +typedef union {
2593 + VMBUS_CHANNEL_VERSION_SUPPORTED VersionSupported;
2594 + VMBUS_CHANNEL_OPEN_RESULT OpenResult;
2595 + VMBUS_CHANNEL_GPADL_TORNDOWN GpadlTorndown;
2596 + VMBUS_CHANNEL_GPADL_CREATED GpadlCreated;
2597 + VMBUS_CHANNEL_VERSION_RESPONSE VersionResponse;
2598 +} VMBUS_CHANNEL_MESSAGE_RESPONSE;
2599 +
2600 +
2601 +// Represents each channel msg on the vmbus connection
2602 +// This is a variable-size data structure depending on
2603 +// the msg type itself
2604 +typedef struct _VMBUS_CHANNEL_MSGINFO {
2605 + // Bookkeeping stuff
2606 + LIST_ENTRY MsgListEntry;
2607 +
2608 + // So far, this is only used to handle gpadl body message
2609 + LIST_ENTRY SubMsgList;
2610 +
2611 + // Synchronize the request/response if needed
2612 + HANDLE WaitEvent;
2613 +
2614 + VMBUS_CHANNEL_MESSAGE_RESPONSE Response;
2615 +
2616 + UINT32 MessageSize;
2617 + // The channel message that goes out on the "wire".
2618 + // It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
2619 + unsigned char Msg[0];
2620 +} VMBUS_CHANNEL_MSGINFO;
2621 +
2622 +
2623 +//
2624 +// Routines
2625 +//
2626 +
2627 +INTERNAL VMBUS_CHANNEL*
2628 +AllocVmbusChannel(
2629 + void
2630 + );
2631 +
2632 +INTERNAL void
2633 +FreeVmbusChannel(
2634 + VMBUS_CHANNEL *Channel
2635 + );
2636 +
2637 +INTERNAL void
2638 +VmbusOnChannelMessage(
2639 + void *Context
2640 + );
2641 +
2642 +INTERNAL int
2643 +VmbusChannelRequestOffers(
2644 + void
2645 + );
2646 +
2647 +INTERNAL void
2648 +VmbusChannelReleaseUnattachedChannels(
2649 + void
2650 + );
2651 +
2652 +#endif //_CHANNEL_MGMT_H_
2653 --- /dev/null
2654 +++ b/drivers/staging/hv/Connection.c
2655 @@ -0,0 +1,432 @@
2656 +/*
2657 + *
2658 + * Copyright (c) 2009, Microsoft Corporation.
2659 + *
2660 + * This program is free software; you can redistribute it and/or modify it
2661 + * under the terms and conditions of the GNU General Public License,
2662 + * version 2, as published by the Free Software Foundation.
2663 + *
2664 + * This program is distributed in the hope it will be useful, but WITHOUT
2665 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2666 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
2667 + * more details.
2668 + *
2669 + * You should have received a copy of the GNU General Public License along with
2670 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
2671 + * Place - Suite 330, Boston, MA 02111-1307 USA.
2672 + *
2673 + * Authors:
2674 + * Haiyang Zhang <haiyangz@microsoft.com>
2675 + * Hank Janssen <hjanssen@microsoft.com>
2676 + *
2677 + */
2678 +
2679 +
2680 +#include "logging.h"
2681 +
2682 +#include "VmbusPrivate.h"
2683 +
2684 +//
2685 +// Globals
2686 +//
2687 +
2688 +
2689 +VMBUS_CONNECTION gVmbusConnection = {
2690 + .ConnectState = Disconnected,
2691 + .NextGpadlHandle = 0xE1E10,
2692 +};
2693 +
2694 +
2695 +/*++
2696 +
2697 +Name:
2698 + VmbusConnect()
2699 +
2700 +Description:
2701 + Sends a connect request on the partition service connection
2702 +
2703 +--*/
2704 +int
2705 +VmbusConnect(
2706 + )
2707 +{
2708 + int ret=0;
2709 + VMBUS_CHANNEL_MSGINFO *msgInfo=NULL;
2710 + VMBUS_CHANNEL_INITIATE_CONTACT *msg;
2711 +
2712 + DPRINT_ENTER(VMBUS);
2713 +
2714 + // Make sure we are not connecting or connected
2715 + if (gVmbusConnection.ConnectState != Disconnected)
2716 + return -1;
2717 +
2718 + // Initialize the vmbus connection
2719 + gVmbusConnection.ConnectState = Connecting;
2720 + gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ");
2721 +
2722 + INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
2723 + gVmbusConnection.ChannelMsgLock = SpinlockCreate();
2724 +
2725 + INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList);
2726 + gVmbusConnection.ChannelLock = SpinlockCreate();
2727 +
2728 + // Setup the vmbus event connection for channel interrupt abstraction stuff
2729 + gVmbusConnection.InterruptPage = PageAlloc(1);
2730 + if (gVmbusConnection.InterruptPage == NULL)
2731 + {
2732 + ret = -1;
2733 + goto Cleanup;
2734 + }
2735 +
2736 + gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
2737 + gVmbusConnection.SendInterruptPage = (void*)((ULONG_PTR)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1));
2738 +
2739 + // Setup the monitor notification facility. The 1st page for parent->child and the 2nd page for child->parent
2740 + gVmbusConnection.MonitorPages = PageAlloc(2);
2741 + if (gVmbusConnection.MonitorPages == NULL)
2742 + {
2743 + ret = -1;
2744 + goto Cleanup;
2745 + }
2746 +
2747 + msgInfo = (VMBUS_CHANNEL_MSGINFO*)MemAllocZeroed(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
2748 + if (msgInfo == NULL)
2749 + {
2750 + ret = -1;
2751 + goto Cleanup;
2752 + }
2753 +
2754 + msgInfo->WaitEvent = WaitEventCreate();
2755 + msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg;
2756 +
2757 + msg->Header.MessageType = ChannelMessageInitiateContact;
2758 + msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
2759 + msg->InterruptPage = GetPhysicalAddress(gVmbusConnection.InterruptPage);
2760 + msg->MonitorPage1 = GetPhysicalAddress(gVmbusConnection.MonitorPages);
2761 + msg->MonitorPage2 = GetPhysicalAddress((PVOID)((ULONG_PTR)gVmbusConnection.MonitorPages + PAGE_SIZE));
2762 +
2763 + // Add to list before we send the request since we may receive the response
2764 + // before returning from this routine
2765 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2766 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
2767 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2768 +
2769 + DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx",
2770 + msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
2771 +
2772 + DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
2773 +
2774 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
2775 + if (ret != 0)
2776 + {
2777 + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
2778 + goto Cleanup;
2779 + }
2780 +
2781 + // Wait for the connection response
2782 + WaitEventWait(msgInfo->WaitEvent);
2783 +
2784 + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
2785 +
2786 + // Check if successful
2787 + if (msgInfo->Response.VersionResponse.VersionSupported)
2788 + {
2789 + DPRINT_INFO(VMBUS, "Vmbus connected!!");
2790 + gVmbusConnection.ConnectState = Connected;
2791 +
2792 + }
2793 + else
2794 + {
2795 + DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER);
2796 + ret = -1;
2797 +
2798 + goto Cleanup;
2799 + }
2800 +
2801 +
2802 + WaitEventClose(msgInfo->WaitEvent);
2803 + MemFree(msgInfo);
2804 + DPRINT_EXIT(VMBUS);
2805 +
2806 + return 0;
2807 +
2808 +Cleanup:
2809 +
2810 + gVmbusConnection.ConnectState = Disconnected;
2811 +
2812 + WorkQueueClose(gVmbusConnection.WorkQueue);
2813 + SpinlockClose(gVmbusConnection.ChannelLock);
2814 + SpinlockClose(gVmbusConnection.ChannelMsgLock);
2815 +
2816 + if (gVmbusConnection.InterruptPage)
2817 + {
2818 + PageFree(gVmbusConnection.InterruptPage, 1);
2819 + gVmbusConnection.InterruptPage = NULL;
2820 + }
2821 +
2822 + if (gVmbusConnection.MonitorPages)
2823 + {
2824 + PageFree(gVmbusConnection.MonitorPages, 2);
2825 + gVmbusConnection.MonitorPages = NULL;
2826 + }
2827 +
2828 + if (msgInfo)
2829 + {
2830 + if (msgInfo->WaitEvent)
2831 + WaitEventClose(msgInfo->WaitEvent);
2832 +
2833 + MemFree(msgInfo);
2834 + }
2835 +
2836 + DPRINT_EXIT(VMBUS);
2837 +
2838 + return ret;
2839 +}
2840 +
2841 +
2842 +/*++
2843 +
2844 +Name:
2845 + VmbusDisconnect()
2846 +
2847 +Description:
2848 + Sends a disconnect request on the partition service connection
2849 +
2850 +--*/
2851 +int
2852 +VmbusDisconnect(
2853 + VOID
2854 + )
2855 +{
2856 + int ret=0;
2857 + VMBUS_CHANNEL_UNLOAD *msg;
2858 +
2859 + DPRINT_ENTER(VMBUS);
2860 +
2861 + // Make sure we are connected
2862 + if (gVmbusConnection.ConnectState != Connected)
2863 + return -1;
2864 +
2865 + msg = MemAllocZeroed(sizeof(VMBUS_CHANNEL_UNLOAD));
2866 +
2867 + msg->MessageType = ChannelMessageUnload;
2868 +
2869 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD));
2870 +
2871 + if (ret != 0)
2872 + {
2873 + goto Cleanup;
2874 + }
2875 +
2876 + PageFree(gVmbusConnection.InterruptPage, 1);
2877 +
2878 + // TODO: iterate thru the msg list and free up
2879 +
2880 + SpinlockClose(gVmbusConnection.ChannelMsgLock);
2881 +
2882 + WorkQueueClose(gVmbusConnection.WorkQueue);
2883 +
2884 + gVmbusConnection.ConnectState = Disconnected;
2885 +
2886 + DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
2887 +
2888 +Cleanup:
2889 + if (msg)
2890 + {
2891 + MemFree(msg);
2892 + }
2893 +
2894 + DPRINT_EXIT(VMBUS);
2895 +
2896 + return ret;
2897 +}
2898 +
2899 +
2900 +/*++
2901 +
2902 +Name:
2903 + GetChannelFromRelId()
2904 +
2905 +Description:
2906 + Get the channel object given its child relative id (ie channel id)
2907 +
2908 +--*/
2909 +VMBUS_CHANNEL*
2910 +GetChannelFromRelId(
2911 + UINT32 relId
2912 + )
2913 +{
2914 + VMBUS_CHANNEL* channel;
2915 + VMBUS_CHANNEL* foundChannel=NULL;
2916 + LIST_ENTRY* anchor;
2917 + LIST_ENTRY* curr;
2918 +
2919 + SpinlockAcquire(gVmbusConnection.ChannelLock);
2920 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
2921 + {
2922 + channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
2923 +
2924 + if (channel->OfferMsg.ChildRelId == relId)
2925 + {
2926 + foundChannel = channel;
2927 + break;
2928 + }
2929 + }
2930 + SpinlockRelease(gVmbusConnection.ChannelLock);
2931 +
2932 + return foundChannel;
2933 +}
2934 +
2935 +
2936 +
2937 +/*++
2938 +
2939 +Name:
2940 + VmbusProcessChannelEvent()
2941 +
2942 +Description:
2943 + Process a channel event notification
2944 +
2945 +--*/
2946 +static void
2947 +VmbusProcessChannelEvent(
2948 + PVOID context
2949 + )
2950 +{
2951 + VMBUS_CHANNEL* channel;
2952 + UINT32 relId = (UINT32)(ULONG_PTR)context;
2953 +
2954 + ASSERT(relId > 0);
2955 +
2956 + // Find the channel based on this relid and invokes
2957 + // the channel callback to process the event
2958 + channel = GetChannelFromRelId(relId);
2959 +
2960 + if (channel)
2961 + {
2962 + VmbusChannelOnChannelEvent(channel);
2963 + //WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel);
2964 + }
2965 + else
2966 + {
2967 + DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
2968 + }
2969 +}
2970 +
2971 +
2972 +/*++
2973 +
2974 +Name:
2975 + VmbusOnEvents()
2976 +
2977 +Description:
2978 + Handler for events
2979 +
2980 +--*/
2981 +VOID
2982 +VmbusOnEvents(
2983 + VOID
2984 + )
2985 +{
2986 + int dword;
2987 + //int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes
2988 + int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
2989 + int bit;
2990 + int relid;
2991 + UINT32* recvInterruptPage = gVmbusConnection.RecvInterruptPage;
2992 + //VMBUS_CHANNEL_MESSAGE* receiveMsg;
2993 +
2994 + DPRINT_ENTER(VMBUS);
2995 +
2996 + // Check events
2997 + if (recvInterruptPage)
2998 + {
2999 + for (dword = 0; dword < maxdword; dword++)
3000 + {
3001 + if (recvInterruptPage[dword])
3002 + {
3003 + for (bit = 0; bit < 32; bit++)
3004 + {
3005 + if (BitTestAndClear(&recvInterruptPage[dword], bit))
3006 + {
3007 + relid = (dword << 5) + bit;
3008 +
3009 + DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
3010 +
3011 + if (relid == 0) // special case - vmbus channel protocol msg
3012 + {
3013 + DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
3014 +
3015 + continue; }
3016 + else
3017 + {
3018 + //QueueWorkItem(VmbusProcessEvent, (void*)relid);
3019 + //ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid);
3020 + VmbusProcessChannelEvent((void*)(ULONG_PTR)relid);
3021 + }
3022 + }
3023 + }
3024 + }
3025 + }
3026 + }
3027 + DPRINT_EXIT(VMBUS);
3028 +
3029 + return;
3030 +}
3031 +
3032 +/*++
3033 +
3034 +Name:
3035 + VmbusPostMessage()
3036 +
3037 +Description:
3038 + Send a msg on the vmbus's message connection
3039 +
3040 +--*/
3041 +int
3042 +VmbusPostMessage(
3043 + PVOID buffer,
3044 + SIZE_T bufferLen
3045 + )
3046 +{
3047 + int ret=0;
3048 + HV_CONNECTION_ID connId;
3049 +
3050 +
3051 + connId.AsUINT32 =0;
3052 + connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
3053 + ret = HvPostMessage(
3054 + connId,
3055 + 1,
3056 + buffer,
3057 + bufferLen);
3058 +
3059 + return ret;
3060 +}
3061 +
3062 +/*++
3063 +
3064 +Name:
3065 + VmbusSetEvent()
3066 +
3067 +Description:
3068 + Send an event notification to the parent
3069 +
3070 +--*/
3071 +int
3072 +VmbusSetEvent(UINT32 childRelId)
3073 +{
3074 + int ret=0;
3075 +
3076 + DPRINT_ENTER(VMBUS);
3077 +
3078 + // Each UINT32 represents 32 channels
3079 + BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31);
3080 + ret = HvSignalEvent();
3081 +
3082 + DPRINT_EXIT(VMBUS);
3083 +
3084 + return ret;
3085 +}
3086 +
3087 +// EOF
3088 --- /dev/null
3089 +++ b/drivers/staging/hv/Hv.c
3090 @@ -0,0 +1,672 @@
3091 +/*
3092 + *
3093 + * Copyright (c) 2009, Microsoft Corporation.
3094 + *
3095 + * This program is free software; you can redistribute it and/or modify it
3096 + * under the terms and conditions of the GNU General Public License,
3097 + * version 2, as published by the Free Software Foundation.
3098 + *
3099 + * This program is distributed in the hope it will be useful, but WITHOUT
3100 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3101 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
3102 + * more details.
3103 + *
3104 + * You should have received a copy of the GNU General Public License along with
3105 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
3106 + * Place - Suite 330, Boston, MA 02111-1307 USA.
3107 + *
3108 + * Authors:
3109 + * Haiyang Zhang <haiyangz@microsoft.com>
3110 + * Hank Janssen <hjanssen@microsoft.com>
3111 + *
3112 + */
3113 +
3114 +
3115 +#include "logging.h"
3116 +#include "VmbusPrivate.h"
3117 +
3118 +//
3119 +// Globals
3120 +//
3121 +
3122 +// The one and only
3123 +HV_CONTEXT gHvContext={
3124 + .SynICInitialized = FALSE,
3125 + .HypercallPage = NULL,
3126 + .SignalEventParam = NULL,
3127 + .SignalEventBuffer = NULL,
3128 +};
3129 +
3130 +
3131 +/*++
3132 +
3133 +Name:
3134 + HvQueryHypervisorPresence()
3135 +
3136 +Description:
3137 + Query the cpuid for presense of windows hypervisor
3138 +
3139 +--*/
3140 +static int
3141 +HvQueryHypervisorPresence (
3142 + void
3143 + )
3144 +{
3145 + unsigned int eax;
3146 + unsigned int ebx;
3147 + unsigned int ecx;
3148 + unsigned int edx;
3149 + unsigned int op;
3150 +
3151 + eax = 0;
3152 + ebx = 0;
3153 + ecx = 0;
3154 + edx = 0;
3155 + op = HvCpuIdFunctionVersionAndFeatures;
3156 + do_cpuid(op, &eax, &ebx, &ecx, &edx);
3157 +
3158 + return (ecx & HV_PRESENT_BIT);
3159 +}
3160 +
3161 +
3162 +/*++
3163 +
3164 +Name:
3165 + HvQueryHypervisorInfo()
3166 +
3167 +Description:
3168 + Get version info of the windows hypervisor
3169 +
3170 +--*/
3171 +static int
3172 +HvQueryHypervisorInfo (
3173 + void
3174 + )
3175 +{
3176 + unsigned int eax;
3177 + unsigned int ebx;
3178 + unsigned int ecx;
3179 + unsigned int edx;
3180 + unsigned int maxLeaf;
3181 + unsigned int op;
3182 +
3183 + //
3184 + // Its assumed that this is called after confirming that Viridian is present.
3185 + // Query id and revision.
3186 + //
3187 +
3188 + eax = 0;
3189 + ebx = 0;
3190 + ecx = 0;
3191 + edx = 0;
3192 + op = HvCpuIdFunctionHvVendorAndMaxFunction;
3193 + do_cpuid(op, &eax, &ebx, &ecx, &edx);
3194 +
3195 + DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
3196 + (ebx & 0xFF),
3197 + ((ebx >> 8) & 0xFF),
3198 + ((ebx >> 16) & 0xFF),
3199 + ((ebx >> 24) & 0xFF),
3200 + (ecx & 0xFF),
3201 + ((ecx >> 8) & 0xFF),
3202 + ((ecx >> 16) & 0xFF),
3203 + ((ecx >> 24) & 0xFF),
3204 + (edx & 0xFF),
3205 + ((edx >> 8) & 0xFF),
3206 + ((edx >> 16) & 0xFF),
3207 + ((edx >> 24) & 0xFF));
3208 +
3209 + maxLeaf = eax;
3210 + eax = 0;
3211 + ebx = 0;
3212 + ecx = 0;
3213 + edx = 0;
3214 + op = HvCpuIdFunctionHvInterface;
3215 + do_cpuid(op, &eax, &ebx, &ecx, &edx);
3216 +
3217 + DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
3218 + (eax & 0xFF),
3219 + ((eax >> 8) & 0xFF),
3220 + ((eax >> 16) & 0xFF),
3221 + ((eax >> 24) & 0xFF));
3222 +
3223 + if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
3224 + eax = 0;
3225 + ebx = 0;
3226 + ecx = 0;
3227 + edx = 0;
3228 + op = HvCpuIdFunctionMsHvVersion;
3229 + do_cpuid(op, &eax, &ebx, &ecx, &edx);
3230 + DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",
3231 + eax,
3232 + ebx >> 16,
3233 + ebx & 0xFFFF,
3234 + ecx,
3235 + edx >> 24,
3236 + edx & 0xFFFFFF);
3237 + }
3238 + return maxLeaf;
3239 +}
3240 +
3241 +
3242 +/*++
3243 +
3244 +Name:
3245 + HvDoHypercall()
3246 +
3247 +Description:
3248 + Invoke the specified hypercall
3249 +
3250 +--*/
3251 +static UINT64
3252 +HvDoHypercall (
3253 + UINT64 Control,
3254 + void* Input,
3255 + void* Output
3256 + )
3257 +{
3258 +#ifdef x86_64
3259 + UINT64 hvStatus=0;
3260 + UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0;
3261 + UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0;
3262 + volatile void* hypercallPage = gHvContext.HypercallPage;
3263 +
3264 + DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>",
3265 + Control,
3266 + inputAddress,
3267 + Input,
3268 + outputAddress,
3269 + Output,
3270 + hypercallPage);
3271 +
3272 + __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8");
3273 + __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage));
3274 +
3275 + DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
3276 +
3277 + return hvStatus;
3278 +
3279 +#else
3280 +
3281 + UINT32 controlHi = Control >> 32;
3282 + UINT32 controlLo = Control & 0xFFFFFFFF;
3283 + UINT32 hvStatusHi = 1;
3284 + UINT32 hvStatusLo = 1;
3285 + UINT64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0;
3286 + UINT32 inputAddressHi = inputAddress >> 32;
3287 + UINT32 inputAddressLo = inputAddress & 0xFFFFFFFF;
3288 + UINT64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0;
3289 + UINT32 outputAddressHi = outputAddress >> 32;
3290 + UINT32 outputAddressLo = outputAddress & 0xFFFFFFFF;
3291 + volatile void* hypercallPage = gHvContext.HypercallPage;
3292 +
3293 + DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
3294 + Control,
3295 + Input,
3296 + Output);
3297 +
3298 + __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage));
3299 +
3300 +
3301 + DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((UINT64)hvStatusHi << 32));
3302 +
3303 + return (hvStatusLo | ((UINT64)hvStatusHi << 32));
3304 +#endif // x86_64
3305 +}
3306 +
3307 +/*++
3308 +
3309 +Name:
3310 + HvInit()
3311 +
3312 +Description:
3313 + Main initialization routine. This routine must be called
3314 + before any other routines in here are called
3315 +
3316 +--*/
3317 +static int
3318 +HvInit (
3319 + void
3320 + )
3321 +{
3322 + int ret=0;
3323 + int maxLeaf;
3324 + HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
3325 + void* virtAddr=0;
3326 + ULONG_PTR physAddr=0;
3327 +
3328 + DPRINT_ENTER(VMBUS);
3329 +
3330 + memset(gHvContext.synICEventPage, 0, sizeof(HANDLE)*MAX_NUM_CPUS);
3331 + memset(gHvContext.synICMessagePage, 0, sizeof(HANDLE)*MAX_NUM_CPUS);
3332 +
3333 + if (!HvQueryHypervisorPresence())
3334 + {
3335 + DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
3336 + goto Cleanup;
3337 + }
3338 +
3339 + DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info...");
3340 +
3341 + maxLeaf = HvQueryHypervisorInfo();
3342 + //HvQueryHypervisorFeatures(maxLeaf);
3343 +
3344 + // Determine if we are running on xenlinux (ie x2v shim) or native linux
3345 + gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
3346 +
3347 + if (gHvContext.GuestId == 0)
3348 + {
3349 + // Write our OS info
3350 + WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
3351 +
3352 + gHvContext.GuestId = HV_LINUX_GUEST_ID;
3353 + }
3354 +
3355 + // See if the hypercall page is already set
3356 + hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
3357 +
3358 + if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
3359 + {
3360 + // Allocate the hypercall page memory
3361 + //virtAddr = PageAlloc(1);
3362 + virtAddr = VirtualAllocExec(PAGE_SIZE);
3363 +
3364 + if (!virtAddr)
3365 + {
3366 + DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!");
3367 + goto Cleanup;
3368 + }
3369 +
3370 + hypercallMsr.Enable = 1;
3371 + //hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT;
3372 + hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT;
3373 + WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
3374 +
3375 + // Confirm that hypercall page did get setup.
3376 + hypercallMsr.AsUINT64 = 0;
3377 + hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
3378 +
3379 + if (!hypercallMsr.Enable)
3380 + {
3381 + DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
3382 + goto Cleanup;
3383 + }
3384 +
3385 + gHvContext.HypercallPage = virtAddr;
3386 + }
3387 + else
3388 + {
3389 + DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId);
3390 + goto Cleanup;
3391 + }
3392 +
3393 + DPRINT_INFO(VMBUS, "Hypercall page VA=0x%08x, PA=0x%08x",
3394 + (unsigned long)gHvContext.HypercallPage,
3395 + (unsigned long)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
3396 +
3397 + // Setup the global signal event param for the signal event hypercall
3398 + gHvContext.SignalEventBuffer = MemAlloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER));
3399 + if (!gHvContext.SignalEventBuffer)
3400 + {
3401 + goto Cleanup;
3402 + }
3403 +
3404 + gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((ULONG_PTR)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN));
3405 + gHvContext.SignalEventParam->ConnectionId.AsUINT32 = 0;
3406 + gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID;
3407 + gHvContext.SignalEventParam->FlagNumber = 0;
3408 + gHvContext.SignalEventParam->RsvdZ = 0;
3409 +
3410 + //DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId());
3411 +
3412 + DPRINT_EXIT(VMBUS);
3413 +
3414 + return ret;
3415 +
3416 +Cleanup:
3417 + if (virtAddr)
3418 + {
3419 + if (hypercallMsr.Enable)
3420 + {
3421 + hypercallMsr.AsUINT64 = 0;
3422 + WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
3423 + }
3424 +
3425 + VirtualFree(virtAddr);
3426 + }
3427 + ret = -1;
3428 + DPRINT_EXIT(VMBUS);
3429 +
3430 + return ret;
3431 +}
3432 +
3433 +
3434 +/*++
3435 +
3436 +Name:
3437 + HvCleanup()
3438 +
3439 +Description:
3440 + Cleanup routine. This routine is called normally during driver unloading or exiting.
3441 +
3442 +--*/
3443 +void
3444 +HvCleanup (
3445 + void
3446 + )
3447 +{
3448 + HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
3449 +
3450 + DPRINT_ENTER(VMBUS);
3451 +
3452 + if (gHvContext.SignalEventBuffer)
3453 + {
3454 + MemFree(gHvContext.SignalEventBuffer);
3455 + gHvContext.SignalEventBuffer = NULL;
3456 + gHvContext.SignalEventParam = NULL;
3457 + }
3458 +
3459 + if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
3460 + {
3461 + if (gHvContext.HypercallPage)
3462 + {
3463 + hypercallMsr.AsUINT64 = 0;
3464 + WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
3465 + VirtualFree(gHvContext.HypercallPage);
3466 + gHvContext.HypercallPage = NULL;
3467 + }
3468 + }
3469 +
3470 + DPRINT_EXIT(VMBUS);
3471 +
3472 +}
3473 +
3474 +
3475 +/*++
3476 +
3477 +Name:
3478 + HvPostMessage()
3479 +
3480 +Description:
3481 + Post a message using the hypervisor message IPC. This
3482 + involves a hypercall.
3483 +
3484 +--*/
3485 +HV_STATUS
3486 +HvPostMessage(
3487 + HV_CONNECTION_ID connectionId,
3488 + HV_MESSAGE_TYPE messageType,
3489 + PVOID payload,
3490 + SIZE_T payloadSize
3491 + )
3492 +{
3493 + struct alignedInput {
3494 + UINT64 alignment8;
3495 + HV_INPUT_POST_MESSAGE msg;
3496 + };
3497 +
3498 + PHV_INPUT_POST_MESSAGE alignedMsg;
3499 + HV_STATUS status;
3500 + ULONG_PTR addr;
3501 +
3502 + if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
3503 + {
3504 + return -1;
3505 + }
3506 +
3507 + addr = (ULONG_PTR)MemAllocAtomic(sizeof(struct alignedInput));
3508 +
3509 + if (!addr)
3510 + {
3511 + return -1;
3512 + }
3513 +
3514 + alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
3515 +
3516 + alignedMsg->ConnectionId = connectionId;
3517 + alignedMsg->MessageType = messageType;
3518 + alignedMsg->PayloadSize = payloadSize;
3519 + memcpy((void*)alignedMsg->Payload, payload, payloadSize);
3520 +
3521 + status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF;
3522 +
3523 + MemFree((void*)addr);
3524 +
3525 + return status;
3526 +}
3527 +
3528 +
3529 +/*++
3530 +
3531 +Name:
3532 + HvSignalEvent()
3533 +
3534 +Description:
3535 + Signal an event on the specified connection using the hypervisor event IPC. This
3536 + involves a hypercall.
3537 +
3538 +--*/
3539 +HV_STATUS
3540 +HvSignalEvent(
3541 + )
3542 +{
3543 + HV_STATUS status;
3544 +
3545 + status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF;
3546 +
3547 + return status;
3548 +}
3549 +
3550 +
3551 +/*++
3552 +
3553 +Name:
3554 + HvSynicInit()
3555 +
3556 +Description:
3557 + Initialize the Synthethic Interrupt Controller. If it is already initialized by
3558 + another entity (ie x2v shim), we need to retrieve the initialized message and event pages.
3559 + Otherwise, we create and initialize the message and event pages.
3560 +
3561 +--*/
3562 +int
3563 +HvSynicInit (
3564 + UINT32 irqVector
3565 + )
3566 +{
3567 + UINT64 version;
3568 + HV_SYNIC_SIMP simp;
3569 + HV_SYNIC_SIEFP siefp;
3570 + HV_SYNIC_SINT sharedSint;
3571 + HV_SYNIC_SCONTROL sctrl;
3572 + UINT64 guestID;
3573 + int ret=0;
3574 +
3575 + DPRINT_ENTER(VMBUS);
3576 +
3577 + if (!gHvContext.HypercallPage)
3578 + {
3579 + DPRINT_EXIT(VMBUS);
3580 + return ret;
3581 + }
3582 +
3583 + // Check the version
3584 + version = ReadMsr(HV_X64_MSR_SVERSION);
3585 +
3586 + DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
3587 +
3588 + // TODO: Handle SMP
3589 + if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID)
3590 + {
3591 + DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set.");
3592 +
3593 + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
3594 + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
3595 +
3596 + DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64);
3597 +
3598 + // Determine if we are running on xenlinux (ie x2v shim) or native linux
3599 + guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
3600 +
3601 + if (guestID == HV_LINUX_GUEST_ID)
3602 + {
3603 + gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT);
3604 + gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT);
3605 + }
3606 + else
3607 + {
3608 + DPRINT_ERR(VMBUS, "unknown guest id!!");
3609 + goto Cleanup;
3610 + }
3611 + DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]);
3612 + }
3613 + else
3614 + {
3615 + gHvContext.synICMessagePage[0] = PageAlloc(1);
3616 + if (gHvContext.synICMessagePage[0] == NULL)
3617 + {
3618 + DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!");
3619 + goto Cleanup;
3620 + }
3621 +
3622 + gHvContext.synICEventPage[0] = PageAlloc(1);
3623 + if (gHvContext.synICEventPage[0] == NULL)
3624 + {
3625 + DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!");
3626 + goto Cleanup;
3627 + }
3628 +
3629 + //
3630 + // Setup the Synic's message page
3631 + //
3632 + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
3633 + simp.SimpEnabled = 1;
3634 + simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT;
3635 +
3636 + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
3637 +
3638 + WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
3639 +
3640 + //
3641 + // Setup the Synic's event page
3642 + //
3643 + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
3644 + siefp.SiefpEnabled = 1;
3645 + siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT;
3646 +
3647 + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
3648 +
3649 + WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
3650 + }
3651 + //
3652 + // Setup the interception SINT.
3653 + //
3654 + //WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX),
3655 + // interceptionSint.AsUINT64);
3656 +
3657 + //
3658 + // Setup the shared SINT.
3659 + //
3660 + sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
3661 +
3662 + sharedSint.AsUINT64 = 0;
3663 + sharedSint.Vector = irqVector; //HV_SHARED_SINT_IDT_VECTOR + 0x20;
3664 + sharedSint.Masked = FALSE;
3665 + sharedSint.AutoEoi = TRUE;
3666 +
3667 + DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64);
3668 +
3669 + WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
3670 +
3671 + // Enable the global synic bit
3672 + sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL);
3673 + sctrl.Enable = 1;
3674 +
3675 + WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
3676 +
3677 + gHvContext.SynICInitialized = TRUE;
3678 +
3679 + DPRINT_EXIT(VMBUS);
3680 +
3681 + return ret;
3682 +
3683 +Cleanup:
3684 + ret = -1;
3685 +
3686 + if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
3687 + {
3688 + if (gHvContext.synICEventPage[0])
3689 + {
3690 + PageFree(gHvContext.synICEventPage[0],1);
3691 + }
3692 +
3693 + if (gHvContext.synICMessagePage[0])
3694 + {
3695 + PageFree(gHvContext.synICMessagePage[0], 1);
3696 + }
3697 + }
3698 +
3699 + DPRINT_EXIT(VMBUS);
3700 +
3701 + return ret;
3702 +
3703 +}
3704 +
3705 +/*++
3706 +
3707 +Name:
3708 + HvSynicCleanup()
3709 +
3710 +Description:
3711 + Cleanup routine for HvSynicInit().
3712 +
3713 +--*/
3714 +VOID
3715 +HvSynicCleanup(
3716 + VOID
3717 + )
3718 +{
3719 + HV_SYNIC_SINT sharedSint;
3720 + HV_SYNIC_SIMP simp;
3721 + HV_SYNIC_SIEFP siefp;
3722 +
3723 + DPRINT_ENTER(VMBUS);
3724 +
3725 + if (!gHvContext.SynICInitialized)
3726 + {
3727 + DPRINT_EXIT(VMBUS);
3728 + return;
3729 + }
3730 +
3731 + sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
3732 +
3733 + sharedSint.Masked = 1;
3734 +
3735 + // Disable the interrupt
3736 + WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
3737 +
3738 + // Disable and free the resources only if we are running as native linux
3739 + // since in xenlinux, we are sharing the resources with the x2v shim
3740 + if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
3741 + {
3742 + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
3743 + simp.SimpEnabled = 0;
3744 + simp.BaseSimpGpa = 0;
3745 +
3746 + WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
3747 +
3748 + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
3749 + siefp.SiefpEnabled = 0;
3750 + siefp.BaseSiefpGpa = 0;
3751 +
3752 + WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
3753 +
3754 + PageFree(gHvContext.synICMessagePage[0], 1);
3755 + PageFree(gHvContext.synICEventPage[0], 1);
3756 + }
3757 +
3758 + DPRINT_EXIT(VMBUS);
3759 +}
3760 +
3761 +
3762 +// eof
3763 --- /dev/null
3764 +++ b/drivers/staging/hv/Hv.h
3765 @@ -0,0 +1,184 @@
3766 +/*
3767 + *
3768 + * Copyright (c) 2009, Microsoft Corporation.
3769 + *
3770 + * This program is free software; you can redistribute it and/or modify it
3771 + * under the terms and conditions of the GNU General Public License,
3772 + * version 2, as published by the Free Software Foundation.
3773 + *
3774 + * This program is distributed in the hope it will be useful, but WITHOUT
3775 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3776 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
3777 + * more details.
3778 + *
3779 + * You should have received a copy of the GNU General Public License along with
3780 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
3781 + * Place - Suite 330, Boston, MA 02111-1307 USA.
3782 + *
3783 + * Authors:
3784 + * Haiyang Zhang <haiyangz@microsoft.com>
3785 + * Hank Janssen <hjanssen@microsoft.com>
3786 + *
3787 + */
3788 +
3789 +
3790 +#ifndef __HV_H__
3791 +#define __HV_H__
3792 +
3793 +#include "osd.h"
3794 +
3795 +#include "HvTypes.h"
3796 +#include "HvStatus.h"
3797 +//#include "HvVmApi.h"
3798 +//#include "HvKeApi.h"
3799 +//#include "HvMmApi.h"
3800 +//#include "HvCpuApi.h"
3801 +#include "HvHalApi.h"
3802 +#include "HvVpApi.h"
3803 +//#include "HvTrApi.h"
3804 +#include "HvSynicApi.h"
3805 +//#include "HvAmApi.h"
3806 +//#include "HvHkApi.h"
3807 +//#include "HvValApi.h"
3808 +#include "HvHcApi.h"
3809 +#include "HvPtApi.h"
3810 +
3811 +enum
3812 +{
3813 + VMBUS_MESSAGE_CONNECTION_ID = 1,
3814 + VMBUS_MESSAGE_PORT_ID = 1,
3815 + VMBUS_EVENT_CONNECTION_ID = 2,
3816 + VMBUS_EVENT_PORT_ID = 2,
3817 + VMBUS_MONITOR_CONNECTION_ID = 3,
3818 + VMBUS_MONITOR_PORT_ID = 3,
3819 + VMBUS_MESSAGE_SINT = 2
3820 +};
3821 +//
3822 +// #defines
3823 +//
3824 +#define HV_PRESENT_BIT 0x80000000
3825 +
3826 +#define HV_XENLINUX_GUEST_ID_LO 0x00000000
3827 +#define HV_XENLINUX_GUEST_ID_HI 0x0B00B135
3828 +#define HV_XENLINUX_GUEST_ID (((UINT64)HV_XENLINUX_GUEST_ID_HI << 32) | HV_XENLINUX_GUEST_ID_LO)
3829 +
3830 +#define HV_LINUX_GUEST_ID_LO 0x00000000
3831 +#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
3832 +#define HV_LINUX_GUEST_ID (((UINT64)HV_LINUX_GUEST_ID_HI << 32) | HV_LINUX_GUEST_ID_LO)
3833 +
3834 +#define HV_CPU_POWER_MANAGEMENT (1 << 0)
3835 +#define HV_RECOMMENDATIONS_MAX 4
3836 +
3837 +#define HV_X64_MAX 5
3838 +#define HV_CAPS_MAX 8
3839 +
3840 +
3841 +#define HV_HYPERCALL_PARAM_ALIGN sizeof(UINT64)
3842 +
3843 +//
3844 +// Service definitions
3845 +//
3846 +#define HV_SERVICE_PARENT_PORT (0)
3847 +#define HV_SERVICE_PARENT_CONNECTION (0)
3848 +
3849 +#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0)
3850 +#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1)
3851 +#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2)
3852 +#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3)
3853 +
3854 +#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1)
3855 +#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2)
3856 +#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3)
3857 +#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4)
3858 +#define HV_SERVICE_MAX_MESSAGE_ID (4)
3859 +
3860 +#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
3861 +#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
3862 +
3863 +//#define VMBUS_REVISION_NUMBER 6
3864 +//#define VMBUS_PORT_ID 11 // Our local vmbus's port and connection id. Anything >0 is fine
3865 +
3866 +// 628180B8-308D-4c5e-B7DB-1BEB62E62EF4
3867 +static const GUID VMBUS_SERVICE_ID = {.Data = {0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c, 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4} };
3868 +
3869 +#define MAX_NUM_CPUS 1
3870 +
3871 +
3872 +typedef struct {
3873 + UINT64 Align8;
3874 + HV_INPUT_SIGNAL_EVENT Event;
3875 +} HV_INPUT_SIGNAL_EVENT_BUFFER;
3876 +
3877 +typedef struct {
3878 + UINT64 GuestId; // XenLinux or native Linux. If XenLinux, the hypercall and synic pages has already been initialized
3879 + void* HypercallPage;
3880 +
3881 + BOOL SynICInitialized;
3882 + // This is used as an input param to HvCallSignalEvent hypercall. The input param is immutable
3883 + // in our usage and must be dynamic mem (vs stack or global).
3884 + HV_INPUT_SIGNAL_EVENT_BUFFER *SignalEventBuffer;
3885 + HV_INPUT_SIGNAL_EVENT *SignalEventParam; // 8-bytes aligned of the buffer above
3886 +
3887 + HANDLE synICMessagePage[MAX_NUM_CPUS];
3888 + HANDLE synICEventPage[MAX_NUM_CPUS];
3889 +} HV_CONTEXT;
3890 +
3891 +extern HV_CONTEXT gHvContext;
3892 +
3893 +
3894 +//
3895 +// Inline routines
3896 +//
3897 +static inline unsigned long long ReadMsr(int msr)
3898 +{
3899 + unsigned long long val;
3900 +
3901 + RDMSR(msr, val);
3902 +
3903 + return val;
3904 +}
3905 +
3906 +static inline void WriteMsr(int msr, UINT64 val)
3907 +{
3908 + WRMSR(msr, val);
3909 +
3910 + return;
3911 +}
3912 +
3913 +//
3914 +// Hv Interface
3915 +//
3916 +INTERNAL int
3917 +HvInit(
3918 + VOID
3919 + );
3920 +
3921 +INTERNAL VOID
3922 +HvCleanup(
3923 + VOID
3924 + );
3925 +
3926 +INTERNAL HV_STATUS
3927 +HvPostMessage(
3928 + HV_CONNECTION_ID connectionId,
3929 + HV_MESSAGE_TYPE messageType,
3930 + PVOID payload,
3931 + SIZE_T payloadSize
3932 + );
3933 +
3934 +INTERNAL HV_STATUS
3935 +HvSignalEvent(
3936 + VOID
3937 + );
3938 +
3939 +INTERNAL int
3940 +HvSynicInit(
3941 + UINT32 irqVector
3942 + );
3943 +
3944 +INTERNAL VOID
3945 +HvSynicCleanup(
3946 + VOID
3947 + );
3948 +
3949 +#endif // __HV_H__
3950 --- /dev/null
3951 +++ b/drivers/staging/hv/osd.c
3952 @@ -0,0 +1,500 @@
3953 +/*
3954 + *
3955 + * Copyright (c) 2009, Microsoft Corporation.
3956 + *
3957 + * This program is free software; you can redistribute it and/or modify it
3958 + * under the terms and conditions of the GNU General Public License,
3959 + * version 2, as published by the Free Software Foundation.
3960 + *
3961 + * This program is distributed in the hope it will be useful, but WITHOUT
3962 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3963 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
3964 + * more details.
3965 + *
3966 + * You should have received a copy of the GNU General Public License along with
3967 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
3968 + * Place - Suite 330, Boston, MA 02111-1307 USA.
3969 + *
3970 + * Authors:
3971 + * Haiyang Zhang <haiyangz@microsoft.com>
3972 + * Hank Janssen <hjanssen@microsoft.com>
3973 + *
3974 + */
3975 +
3976 +
3977 +#include <linux/module.h>
3978 +#include <linux/init.h>
3979 +#include <linux/types.h>
3980 +#include <linux/mm.h>
3981 +#include <linux/highmem.h>
3982 +#include <linux/vmalloc.h>
3983 +//#include <linux/config.h>
3984 +#include <linux/ioport.h>
3985 +#include <linux/irq.h>
3986 +#include <linux/interrupt.h>
3987 +#include <linux/wait.h>
3988 +#include <linux/spinlock.h>
3989 +#include <linux/workqueue.h>
3990 +#include <linux/kernel.h>
3991 +#include <linux/timer.h>
3992 +#include <linux/jiffies.h>
3993 +#include <linux/delay.h>
3994 +#include <linux/time.h>
3995 +
3996 +#include <asm/io.h>
3997 +#include <asm/bitops.h>
3998 +#include <asm/kmap_types.h>
3999 +#include <asm/atomic.h>
4000 +
4001 +#include "osd.h"
4002 +
4003 +//
4004 +// Data types
4005 +//
4006 +typedef struct _TIMER {
4007 + struct timer_list timer;
4008 + PFN_TIMER_CALLBACK callback;
4009 + void* context;
4010 +}TIMER;
4011 +
4012 +
4013 +typedef struct _WAITEVENT {
4014 + int condition;
4015 + wait_queue_head_t event;
4016 +} WAITEVENT;
4017 +
4018 +typedef struct _SPINLOCK {
4019 + spinlock_t lock;
4020 + unsigned long flags;
4021 +} SPINLOCK;
4022 +
4023 +typedef struct _WORKQUEUE {
4024 + struct workqueue_struct *queue;
4025 +} WORKQUEUE;
4026 +
4027 +typedef struct _WORKITEM {
4028 + struct work_struct work;
4029 + PFN_WORKITEM_CALLBACK callback;
4030 + void* context;
4031 +} WORKITEM;
4032 +
4033 +
4034 +//
4035 +// Global
4036 +//
4037 +
4038 +void LogMsg(const char *fmt, ...)
4039 +{
4040 +#ifdef KERNEL_2_6_5
4041 + char buf[1024];
4042 +#endif
4043 + va_list args;
4044 +
4045 + va_start(args, fmt);
4046 +#ifdef KERNEL_2_6_5
4047 + vsnprintf(buf, 1024, fmt, args);
4048 + va_end(args);
4049 + printk(buf);
4050 +#else
4051 + vprintk(fmt, args);
4052 + va_end(args);
4053 +#endif
4054 +}
4055 +
4056 +void BitSet(unsigned int* addr, int bit)
4057 +{
4058 + set_bit(bit, (unsigned long*)addr);
4059 +}
4060 +
4061 +int BitTest(unsigned int* addr, int bit)
4062 +{
4063 + return test_bit(bit, (unsigned long*)addr);
4064 +}
4065 +
4066 +void BitClear(unsigned int* addr, int bit)
4067 +{
4068 + clear_bit(bit, (unsigned long*)addr);
4069 +}
4070 +
4071 +int BitTestAndClear(unsigned int* addr, int bit)
4072 +{
4073 + return test_and_clear_bit(bit, (unsigned long*)addr);
4074 +}
4075 +
4076 +int BitTestAndSet(unsigned int* addr, int bit)
4077 +{
4078 + return test_and_set_bit(bit, (unsigned long*)addr);
4079 +}
4080 +
4081 +
4082 +int InterlockedIncrement(int *val)
4083 +{
4084 +#ifdef KERNEL_2_6_5
4085 + int i;
4086 + local_irq_disable();
4087 + i = atomic_read((atomic_t*)val);
4088 + atomic_set((atomic_t*)val, i+1);
4089 + local_irq_enable();
4090 + return i+1;
4091 +#else
4092 + return atomic_inc_return((atomic_t*)val);
4093 +#endif
4094 +}
4095 +
4096 +int InterlockedDecrement(int *val)
4097 +{
4098 +#ifdef KERNEL_2_6_5
4099 + int i;
4100 + local_irq_disable();
4101 + i = atomic_read((atomic_t*)val);
4102 + atomic_set((atomic_t*)val, i-1);
4103 + local_irq_enable();
4104 + return i-1;
4105 +#else
4106 + return atomic_dec_return((atomic_t*)val);
4107 +#endif
4108 +}
4109 +
4110 +#ifndef atomic_cmpxchg
4111 +#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
4112 +#endif
4113 +int InterlockedCompareExchange(int *val, int new, int curr)
4114 +{
4115 + //return ((int)cmpxchg(((atomic_t*)val), curr, new));
4116 + return atomic_cmpxchg((atomic_t*)val, curr, new);
4117 +
4118 +}
4119 +
4120 +void Sleep(unsigned long usecs)
4121 +{
4122 + udelay(usecs);
4123 +}
4124 +
4125 +void* VirtualAllocExec(unsigned int size)
4126 +{
4127 +#ifdef __x86_64__
4128 + return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC);
4129 +#else
4130 + return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX)));
4131 +#endif
4132 +}
4133 +
4134 +void VirtualFree(void* VirtAddr)
4135 +{
4136 + return vfree(VirtAddr);
4137 +}
4138 +
4139 +void* PageAlloc(unsigned int count)
4140 +{
4141 + void *p;
4142 + p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE));
4143 + if (p) memset(p, 0, count * PAGE_SIZE);
4144 + return p;
4145 +
4146 + //struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO);
4147 + //void *p;
4148 +
4149 + ////BUGBUG: We need to use kmap in case we are in HIMEM region
4150 + //p = page_address(page);
4151 + //if (p) memset(p, 0, PAGE_SIZE);
4152 + //return p;
4153 +}
4154 +
4155 +void PageFree(void* page, unsigned int count)
4156 +{
4157 + free_pages((unsigned long)page, get_order(count * PAGE_SIZE));
4158 + /*struct page* p = virt_to_page(page);
4159 + __free_page(p);*/
4160 +}
4161 +
4162 +
4163 +void* PageMapVirtualAddress(unsigned long Pfn)
4164 +{
4165 + return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0);
4166 +}
4167 +
4168 +void PageUnmapVirtualAddress(void* VirtAddr)
4169 +{
4170 + kunmap_atomic(VirtAddr, KM_IRQ0);
4171 +}
4172 +
4173 +void* MemAlloc(unsigned int size)
4174 +{
4175 + return kmalloc(size, GFP_KERNEL);
4176 +}
4177 +
4178 +void* MemAllocZeroed(unsigned int size)
4179 +{
4180 + void *p = kmalloc(size, GFP_KERNEL);
4181 + if (p) memset(p, 0, size);
4182 + return p;
4183 +}
4184 +
4185 +void* MemAllocAtomic(unsigned int size)
4186 +{
4187 + return kmalloc(size, GFP_ATOMIC);
4188 +}
4189 +
4190 +void MemFree(void* buf)
4191 +{
4192 + kfree(buf);
4193 +}
4194 +
4195 +void *MemMapIO(unsigned long phys, unsigned long size)
4196 +{
4197 +#if X2V_LINUX
4198 +#ifdef __x86_64__
4199 + return (void*)(phys + 0xFFFF83000C000000);
4200 +#else // i386
4201 + return (void*)(phys + 0xfb000000);
4202 +#endif
4203 +#else
4204 + return (void*)GetVirtualAddress(phys); //return ioremap_nocache(phys, size);
4205 +#endif
4206 +}
4207 +
4208 +void MemUnmapIO(void *virt)
4209 +{
4210 + //iounmap(virt);
4211 +}
4212 +
4213 +void MemoryFence()
4214 +{
4215 + mb();
4216 +}
4217 +
4218 +void TimerCallback(unsigned long data)
4219 +{
4220 + TIMER* t = (TIMER*)data;
4221 +
4222 + t->callback(t->context);
4223 +}
4224 +
4225 +HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context)
4226 +{
4227 + TIMER* t = kmalloc(sizeof(TIMER), GFP_KERNEL);
4228 + if (!t)
4229 + {
4230 + return NULL;
4231 + }
4232 +
4233 + t->callback = pfnTimerCB;
4234 + t->context = context;
4235 +
4236 + init_timer(&t->timer);
4237 + t->timer.data = (unsigned long)t;
4238 + t->timer.function = TimerCallback;
4239 +
4240 + return t;
4241 +}
4242 +
4243 +void TimerStart(HANDLE hTimer, UINT32 expirationInUs)
4244 +{
4245 + TIMER* t = (TIMER* )hTimer;
4246 +
4247 + t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs);
4248 + add_timer(&t->timer);
4249 +}
4250 +
4251 +int TimerStop(HANDLE hTimer)
4252 +{
4253 + TIMER* t = (TIMER* )hTimer;
4254 +
4255 + return del_timer(&t->timer);
4256 +}
4257 +
4258 +void TimerClose(HANDLE hTimer)
4259 +{
4260 + TIMER* t = (TIMER* )hTimer;
4261 +
4262 + del_timer(&t->timer);
4263 + kfree(t);
4264 +}
4265 +
4266 +SIZE_T GetTickCount(void)
4267 +{
4268 + return jiffies;
4269 +}
4270 +
4271 +signed long long GetTimestamp(void)
4272 +{
4273 + struct timeval t;
4274 +
4275 + do_gettimeofday(&t);
4276 +
4277 + return timeval_to_ns(&t);
4278 +}
4279 +
4280 +HANDLE WaitEventCreate(void)
4281 +{
4282 + WAITEVENT* wait = kmalloc(sizeof(WAITEVENT), GFP_KERNEL);
4283 + if (!wait)
4284 + {
4285 + return NULL;
4286 + }
4287 +
4288 + wait->condition = 0;
4289 + init_waitqueue_head(&wait->event);
4290 + return wait;
4291 +}
4292 +
4293 +void WaitEventClose(HANDLE hWait)
4294 +{
4295 + WAITEVENT* waitEvent = (WAITEVENT* )hWait;
4296 + kfree(waitEvent);
4297 +}
4298 +
4299 +void WaitEventSet(HANDLE hWait)
4300 +{
4301 + WAITEVENT* waitEvent = (WAITEVENT* )hWait;
4302 + waitEvent->condition = 1;
4303 + wake_up_interruptible(&waitEvent->event);
4304 +}
4305 +
4306 +int WaitEventWait(HANDLE hWait)
4307 +{
4308 + int ret=0;
4309 + WAITEVENT* waitEvent = (WAITEVENT* )hWait;
4310 +
4311 + ret= wait_event_interruptible(waitEvent->event,
4312 + waitEvent->condition);
4313 + waitEvent->condition = 0;
4314 + return ret;
4315 +}
4316 +
4317 +int WaitEventWaitEx(HANDLE hWait, UINT32 TimeoutInMs)
4318 +{
4319 + int ret=0;
4320 + WAITEVENT* waitEvent = (WAITEVENT* )hWait;
4321 +
4322 + ret= wait_event_interruptible_timeout(waitEvent->event,
4323 + waitEvent->condition,
4324 + msecs_to_jiffies(TimeoutInMs));
4325 + waitEvent->condition = 0;
4326 + return ret;
4327 +}
4328 +
4329 +HANDLE SpinlockCreate(VOID)
4330 +{
4331 + SPINLOCK* spin = kmalloc(sizeof(SPINLOCK), GFP_KERNEL);
4332 + if (!spin)
4333 + {
4334 + return NULL;
4335 + }
4336 + spin_lock_init(&spin->lock);
4337 +
4338 + return spin;
4339 +}
4340 +
4341 +VOID SpinlockAcquire(HANDLE hSpin)
4342 +{
4343 + SPINLOCK* spin = (SPINLOCK* )hSpin;
4344 +
4345 + spin_lock_irqsave(&spin->lock, spin->flags);
4346 +}
4347 +
4348 +VOID SpinlockRelease(HANDLE hSpin)
4349 +{
4350 + SPINLOCK* spin = (SPINLOCK* )hSpin;
4351 +
4352 + spin_unlock_irqrestore(&spin->lock, spin->flags);
4353 +}
4354 +
4355 +VOID SpinlockClose(HANDLE hSpin)
4356 +{
4357 + SPINLOCK* spin = (SPINLOCK* )hSpin;
4358 + kfree(spin);
4359 +}
4360 +
4361 +void* Physical2LogicalAddr(ULONG_PTR PhysAddr)
4362 +{
4363 + void* logicalAddr = phys_to_virt(PhysAddr);
4364 + BUG_ON(!virt_addr_valid(logicalAddr));
4365 + return logicalAddr;
4366 +}
4367 +
4368 +ULONG_PTR Logical2PhysicalAddr(PVOID LogicalAddr)
4369 +{
4370 + BUG_ON(!virt_addr_valid(LogicalAddr));
4371 + return virt_to_phys(LogicalAddr);
4372 +}
4373 +
4374 +
4375 +ULONG_PTR Virtual2Physical(PVOID VirtAddr)
4376 +{
4377 + ULONG_PTR pfn = vmalloc_to_pfn(VirtAddr);
4378 +
4379 + return pfn << PAGE_SHIFT;
4380 +}
4381 +
4382 +#ifdef KERNEL_2_6_27
4383 +void WorkItemCallback(struct work_struct *work)
4384 +#else
4385 +void WorkItemCallback(void* work)
4386 +#endif
4387 +{
4388 + WORKITEM* w = (WORKITEM*)work;
4389 +
4390 + w->callback(w->context);
4391 +
4392 + kfree(w);
4393 +}
4394 +
4395 +HANDLE WorkQueueCreate(char* name)
4396 +{
4397 + WORKQUEUE *wq = kmalloc(sizeof(WORKQUEUE), GFP_KERNEL);
4398 + if (!wq)
4399 + {
4400 + return NULL;
4401 + }
4402 + wq->queue = create_workqueue(name);
4403 +
4404 + return wq;
4405 +}
4406 +
4407 +void WorkQueueClose(HANDLE hWorkQueue)
4408 +{
4409 + WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue;
4410 +
4411 + destroy_workqueue(wq->queue);
4412 +
4413 + return;
4414 +}
4415 +
4416 +int WorkQueueQueueWorkItem(HANDLE hWorkQueue, PFN_WORKITEM_CALLBACK workItem, void* context)
4417 +{
4418 + WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue;
4419 +
4420 + WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
4421 + if (!w)
4422 + {
4423 + return -1;
4424 + }
4425 +
4426 + w->callback = workItem,
4427 + w->context = context;
4428 +#ifdef KERNEL_2_6_27
4429 + INIT_WORK(&w->work, WorkItemCallback);
4430 +#else
4431 + INIT_WORK(&w->work, WorkItemCallback, w);
4432 +#endif
4433 + return queue_work(wq->queue, &w->work);
4434 +}
4435 +
4436 +void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context)
4437 +{
4438 + WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
4439 + if (!w)
4440 + {
4441 + return;
4442 + }
4443 +
4444 + w->callback = workItem,
4445 + w->context = context;
4446 +#ifdef KERNEL_2_6_27
4447 + INIT_WORK(&w->work, WorkItemCallback);
4448 +#else
4449 + INIT_WORK(&w->work, WorkItemCallback, w);
4450 +#endif
4451 + schedule_work(&w->work);
4452 +}
4453 --- /dev/null
4454 +++ b/drivers/staging/hv/RingBuffer.c
4455 @@ -0,0 +1,630 @@
4456 +/*
4457 + *
4458 + * Copyright (c) 2009, Microsoft Corporation.
4459 + *
4460 + * This program is free software; you can redistribute it and/or modify it
4461 + * under the terms and conditions of the GNU General Public License,
4462 + * version 2, as published by the Free Software Foundation.
4463 + *
4464 + * This program is distributed in the hope it will be useful, but WITHOUT
4465 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4466 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
4467 + * more details.
4468 + *
4469 + * You should have received a copy of the GNU General Public License along with
4470 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
4471 + * Place - Suite 330, Boston, MA 02111-1307 USA.
4472 + *
4473 + * Authors:
4474 + * Haiyang Zhang <haiyangz@microsoft.com>
4475 + * Hank Janssen <hjanssen@microsoft.com>
4476 + *
4477 + */
4478 +
4479 +
4480 +#include "logging.h"
4481 +#include "RingBuffer.h"
4482 +
4483 +//
4484 +// #defines
4485 +//
4486 +
4487 +// Amount of space to write to
4488 +#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w))
4489 +
4490 +
4491 +/*++
4492 +
4493 +Name:
4494 + GetRingBufferAvailBytes()
4495 +
4496 +Description:
4497 + Get number of bytes available to read and to write to
4498 + for the specified ring buffer
4499 +
4500 +--*/
4501 +static inline void
4502 +GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, UINT32 *read, UINT32 *write)
4503 +{
4504 + UINT32 read_loc,write_loc;
4505 +
4506 + // Capture the read/write indices before they changed
4507 + read_loc = rbi->RingBuffer->ReadIndex;
4508 + write_loc = rbi->RingBuffer->WriteIndex;
4509 +
4510 + *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize);
4511 + *read = rbi->RingDataSize - *write;
4512 +}
4513 +
4514 +/*++
4515 +
4516 +Name:
4517 + GetNextWriteLocation()
4518 +
4519 +Description:
4520 + Get the next write location for the specified ring buffer
4521 +
4522 +--*/
4523 +static inline UINT32
4524 +GetNextWriteLocation(RING_BUFFER_INFO* RingInfo)
4525 +{
4526 + UINT32 next = RingInfo->RingBuffer->WriteIndex;
4527 +
4528 + ASSERT(next < RingInfo->RingDataSize);
4529 +
4530 + return next;
4531 +}
4532 +
4533 +/*++
4534 +
4535 +Name:
4536 + SetNextWriteLocation()
4537 +
4538 +Description:
4539 + Set the next write location for the specified ring buffer
4540 +
4541 +--*/
4542 +static inline void
4543 +SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextWriteLocation)
4544 +{
4545 + RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
4546 +}
4547 +
4548 +/*++
4549 +
4550 +Name:
4551 + GetNextReadLocation()
4552 +
4553 +Description:
4554 + Get the next read location for the specified ring buffer
4555 +
4556 +--*/
4557 +static inline UINT32
4558 +GetNextReadLocation(RING_BUFFER_INFO* RingInfo)
4559 +{
4560 + UINT32 next = RingInfo->RingBuffer->ReadIndex;
4561 +
4562 + ASSERT(next < RingInfo->RingDataSize);
4563 +
4564 + return next;
4565 +}
4566 +
4567 +/*++
4568 +
4569 +Name:
4570 + GetNextReadLocationWithOffset()
4571 +
4572 +Description:
4573 + Get the next read location + offset for the specified ring buffer.
4574 + This allows the caller to skip
4575 +
4576 +--*/
4577 +static inline UINT32
4578 +GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, UINT32 Offset)
4579 +{
4580 + UINT32 next = RingInfo->RingBuffer->ReadIndex;
4581 +
4582 + ASSERT(next < RingInfo->RingDataSize);
4583 + next += Offset;
4584 + next %= RingInfo->RingDataSize;
4585 +
4586 + return next;
4587 +}
4588 +
4589 +/*++
4590 +
4591 +Name:
4592 + SetNextReadLocation()
4593 +
4594 +Description:
4595 + Set the next read location for the specified ring buffer
4596 +
4597 +--*/
4598 +static inline void
4599 +SetNextReadLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextReadLocation)
4600 +{
4601 + RingInfo->RingBuffer->ReadIndex = NextReadLocation;
4602 +}
4603 +
4604 +
4605 +/*++
4606 +
4607 +Name:
4608 + GetRingBuffer()
4609 +
4610 +Description:
4611 + Get the start of the ring buffer
4612 +
4613 +--*/
4614 +static inline PVOID
4615 +GetRingBuffer(RING_BUFFER_INFO* RingInfo)
4616 +{
4617 + return (PVOID)RingInfo->RingBuffer->Buffer;
4618 +}
4619 +
4620 +
4621 +/*++
4622 +
4623 +Name:
4624 + GetRingBufferSize()
4625 +
4626 +Description:
4627 + Get the size of the ring buffer
4628 +
4629 +--*/
4630 +static inline UINT32
4631 +GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
4632 +{
4633 + return RingInfo->RingDataSize;
4634 +}
4635 +
4636 +/*++
4637 +
4638 +Name:
4639 + GetRingBufferIndices()
4640 +
4641 +Description:
4642 + Get the read and write indices as UINT64 of the specified ring buffer
4643 +
4644 +--*/
4645 +static inline UINT64
4646 +GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
4647 +{
4648 + return ((UINT64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
4649 +}
4650 +
4651 +
4652 +/*++
4653 +
4654 +Name:
4655 + DumpRingInfo()
4656 +
4657 +Description:
4658 + Dump out to console the ring buffer info
4659 +
4660 +--*/
4661 +void
4662 +DumpRingInfo(RING_BUFFER_INFO* RingInfo, char *Prefix)
4663 +{
4664 + UINT32 bytesAvailToWrite;
4665 + UINT32 bytesAvailToRead;
4666 +
4667 + GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
4668 +
4669 + DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>",
4670 + Prefix,
4671 + RingInfo,
4672 + RingInfo->RingBuffer->Buffer,
4673 + bytesAvailToWrite,
4674 + bytesAvailToRead,
4675 + RingInfo->RingBuffer->ReadIndex,
4676 + RingInfo->RingBuffer->WriteIndex);
4677 +}
4678 +
4679 +//
4680 +// Internal routines
4681 +//
4682 +static UINT32
4683 +CopyToRingBuffer(
4684 + RING_BUFFER_INFO *RingInfo,
4685 + UINT32 StartWriteOffset,
4686 + PVOID Src,
4687 + UINT32 SrcLen);
4688 +
4689 +static UINT32
4690 +CopyFromRingBuffer(
4691 + RING_BUFFER_INFO *RingInfo,
4692 + PVOID Dest,
4693 + UINT32 DestLen,
4694 + UINT32 StartReadOffset);
4695 +
4696 +
4697 +
4698 +/*++
4699 +
4700 +Name:
4701 + RingBufferGetDebugInfo()
4702 +
4703 +Description:
4704 + Get various debug metrics for the specified ring buffer
4705 +
4706 +--*/
4707 +void
4708 +RingBufferGetDebugInfo(
4709 + RING_BUFFER_INFO *RingInfo,
4710 + RING_BUFFER_DEBUG_INFO *DebugInfo
4711 + )
4712 +{
4713 + UINT32 bytesAvailToWrite;
4714 + UINT32 bytesAvailToRead;
4715 +
4716 + if (RingInfo->RingBuffer)
4717 + {
4718 + GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
4719 +
4720 + DebugInfo->BytesAvailToRead = bytesAvailToRead;
4721 + DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
4722 + DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
4723 + DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
4724 +
4725 + DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
4726 + }
4727 +}
4728 +
4729 +
4730 +/*++
4731 +
4732 +Name:
4733 + GetRingBufferInterruptMask()
4734 +
4735 +Description:
4736 + Get the interrupt mask for the specified ring buffer
4737 +
4738 +--*/
4739 +UINT32
4740 +GetRingBufferInterruptMask(
4741 + RING_BUFFER_INFO *rbi
4742 + )
4743 +{
4744 + return rbi->RingBuffer->InterruptMask;
4745 +}
4746 +
4747 +/*++
4748 +
4749 +Name:
4750 + RingBufferInit()
4751 +
4752 +Description:
4753 + Initialize the ring buffer
4754 +
4755 +--*/
4756 +int
4757 +RingBufferInit(
4758 + RING_BUFFER_INFO *RingInfo,
4759 + VOID *Buffer,
4760 + UINT32 BufferLen
4761 + )
4762 +{
4763 + ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE);
4764 +
4765 + memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
4766 +
4767 + RingInfo->RingBuffer = (RING_BUFFER*)Buffer;
4768 + RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
4769 +
4770 + RingInfo->RingSize = BufferLen;
4771 + RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER);
4772 +
4773 + RingInfo->RingLock = SpinlockCreate();
4774 +
4775 + return 0;
4776 +}
4777 +
4778 +/*++
4779 +
4780 +Name:
4781 + RingBufferCleanup()
4782 +
4783 +Description:
4784 + Cleanup the ring buffer
4785 +
4786 +--*/
4787 +void
4788 +RingBufferCleanup(
4789 + RING_BUFFER_INFO* RingInfo
4790 + )
4791 +{
4792 + SpinlockClose(RingInfo->RingLock);
4793 +}
4794 +
4795 +/*++
4796 +
4797 +Name:
4798 + RingBufferWrite()
4799 +
4800 +Description:
4801 + Write to the ring buffer
4802 +
4803 +--*/
4804 +int
4805 +RingBufferWrite(
4806 + RING_BUFFER_INFO* OutRingInfo,
4807 + SG_BUFFER_LIST SgBuffers[],
4808 + UINT32 SgBufferCount
4809 + )
4810 +{
4811 + int i=0;
4812 + UINT32 byteAvailToWrite;
4813 + UINT32 byteAvailToRead;
4814 + UINT32 totalBytesToWrite=0;
4815 +
4816 + volatile UINT32 nextWriteLocation;
4817 + UINT64 prevIndices=0;
4818 +
4819 + DPRINT_ENTER(VMBUS);
4820 +
4821 + for (i=0; i < SgBufferCount; i++)
4822 + {
4823 + totalBytesToWrite += SgBuffers[i].Length;
4824 + }
4825 +
4826 + totalBytesToWrite += sizeof(UINT64);
4827 +
4828 + SpinlockAcquire(OutRingInfo->RingLock);
4829 +
4830 + GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
4831 +
4832 + DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
4833 +
4834 + //DumpRingInfo(OutRingInfo, "BEFORE ");
4835 +
4836 + // If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer
4837 + // is empty since the read index == write index
4838 + if (byteAvailToWrite <= totalBytesToWrite)
4839 + {
4840 + DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
4841 +
4842 + SpinlockRelease(OutRingInfo->RingLock);
4843 +
4844 + DPRINT_EXIT(VMBUS);
4845 +
4846 + return -1;
4847 + }
4848 +
4849 + // Write to the ring buffer
4850 + nextWriteLocation = GetNextWriteLocation(OutRingInfo);
4851 +
4852 + for (i=0; i < SgBufferCount; i++)
4853 + {
4854 + nextWriteLocation = CopyToRingBuffer(OutRingInfo,
4855 + nextWriteLocation,
4856 + SgBuffers[i].Data,
4857 + SgBuffers[i].Length);
4858 + }
4859 +
4860 + // Set previous packet start
4861 + prevIndices = GetRingBufferIndices(OutRingInfo);
4862 +
4863 + nextWriteLocation = CopyToRingBuffer(OutRingInfo,
4864 + nextWriteLocation,
4865 + &prevIndices,
4866 + sizeof(UINT64));
4867 +
4868 + // Make sure we flush all writes before updating the writeIndex
4869 + MemoryFence();
4870 +
4871 + // Now, update the write location
4872 + SetNextWriteLocation(OutRingInfo, nextWriteLocation);
4873 +
4874 + //DumpRingInfo(OutRingInfo, "AFTER ");
4875 +
4876 + SpinlockRelease(OutRingInfo->RingLock);
4877 +
4878 + DPRINT_EXIT(VMBUS);
4879 +
4880 + return 0;
4881 +}
4882 +
4883 +
4884 +/*++
4885 +
4886 +Name:
4887 + RingBufferPeek()
4888 +
4889 +Description:
4890 + Read without advancing the read index
4891 +
4892 +--*/
4893 +int
4894 +RingBufferPeek(
4895 + RING_BUFFER_INFO* InRingInfo,
4896 + void* Buffer,
4897 + UINT32 BufferLen
4898 + )
4899 +{
4900 + UINT32 bytesAvailToWrite;
4901 + UINT32 bytesAvailToRead;
4902 + UINT32 nextReadLocation=0;
4903 +
4904 + SpinlockAcquire(InRingInfo->RingLock);
4905 +
4906 + GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
4907 +
4908 + // Make sure there is something to read
4909 + if (bytesAvailToRead < BufferLen )
4910 + {
4911 + //DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
4912 +
4913 + SpinlockRelease(InRingInfo->RingLock);
4914 +
4915 + return -1;
4916 + }
4917 +
4918 + // Convert to byte offset
4919 + nextReadLocation = GetNextReadLocation(InRingInfo);
4920 +
4921 + nextReadLocation = CopyFromRingBuffer(InRingInfo,
4922 + Buffer,
4923 + BufferLen,
4924 + nextReadLocation);
4925 +
4926 + SpinlockRelease(InRingInfo->RingLock);
4927 +
4928 + return 0;
4929 +}
4930 +
4931 +
4932 +/*++
4933 +
4934 +Name:
4935 + RingBufferRead()
4936 +
4937 +Description:
4938 + Read and advance the read index
4939 +
4940 +--*/
4941 +int
4942 +RingBufferRead(
4943 + RING_BUFFER_INFO* InRingInfo,
4944 + PVOID Buffer,
4945 + UINT32 BufferLen,
4946 + UINT32 Offset
4947 + )
4948 +{
4949 + UINT32 bytesAvailToWrite;
4950 + UINT32 bytesAvailToRead;
4951 + UINT32 nextReadLocation=0;
4952 + UINT64 prevIndices=0;
4953 +
4954 + ASSERT(BufferLen > 0);
4955 +
4956 + SpinlockAcquire(InRingInfo->RingLock);
4957 +
4958 + GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
4959 +
4960 + DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
4961 +
4962 + //DumpRingInfo(InRingInfo, "BEFORE ");
4963 +
4964 + // Make sure there is something to read
4965 + if (bytesAvailToRead < BufferLen )
4966 + {
4967 + DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
4968 +
4969 + SpinlockRelease(InRingInfo->RingLock);
4970 +
4971 + return -1;
4972 + }
4973 +
4974 + nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
4975 +
4976 + nextReadLocation = CopyFromRingBuffer(InRingInfo,
4977 + Buffer,
4978 + BufferLen,
4979 + nextReadLocation);
4980 +
4981 + nextReadLocation = CopyFromRingBuffer(InRingInfo,
4982 + &prevIndices,
4983 + sizeof(UINT64),
4984 + nextReadLocation);
4985 +
4986 + // Make sure all reads are done before we update the read index since
4987 + // the writer may start writing to the read area once the read index is updated
4988 + MemoryFence();
4989 +
4990 + // Update the read index
4991 + SetNextReadLocation(InRingInfo, nextReadLocation);
4992 +
4993 + //DumpRingInfo(InRingInfo, "AFTER ");
4994 +
4995 + SpinlockRelease(InRingInfo->RingLock);
4996 +
4997 + return 0;
4998 +}
4999 +
5000 +
5001 +/*++
5002 +
5003 +Name:
5004 + CopyToRingBuffer()
5005 +
5006 +Description:
5007 + Helper routine to copy from source to ring buffer.
5008 + Assume there is enough room. Handles wrap-around in dest case only!!
5009 +
5010 +--*/
5011 +UINT32
5012 +CopyToRingBuffer(
5013 + RING_BUFFER_INFO *RingInfo,
5014 + UINT32 StartWriteOffset,
5015 + PVOID Src,
5016 + UINT32 SrcLen)
5017 +{
5018 + PVOID ringBuffer=GetRingBuffer(RingInfo);
5019 + UINT32 ringBufferSize=GetRingBufferSize(RingInfo);
5020 + UINT32 fragLen;
5021 +
5022 + if (SrcLen > ringBufferSize - StartWriteOffset) // wrap-around detected!
5023 + {
5024 + DPRINT_DBG(VMBUS, "wrap-around detected!");
5025 +
5026 + fragLen = ringBufferSize - StartWriteOffset;
5027 + memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
5028 + memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
5029 + }
5030 + else
5031 + {
5032 + memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
5033 + }
5034 +
5035 + StartWriteOffset += SrcLen;
5036 + StartWriteOffset %= ringBufferSize;
5037 +
5038 + return StartWriteOffset;
5039 +}
5040 +
5041 +
5042 +/*++
5043 +
5044 +Name:
5045 + CopyFromRingBuffer()
5046 +
5047 +Description:
5048 + Helper routine to copy to source from ring buffer.
5049 + Assume there is enough room. Handles wrap-around in src case only!!
5050 +
5051 +--*/
5052 +UINT32
5053 +CopyFromRingBuffer(
5054 + RING_BUFFER_INFO *RingInfo,
5055 + PVOID Dest,
5056 + UINT32 DestLen,
5057 + UINT32 StartReadOffset)
5058 +{
5059 + PVOID ringBuffer=GetRingBuffer(RingInfo);
5060 + UINT32 ringBufferSize=GetRingBufferSize(RingInfo);
5061 +
5062 + UINT32 fragLen;
5063 +
5064 + if (DestLen > ringBufferSize - StartReadOffset) // wrap-around detected at the src
5065 + {
5066 + DPRINT_DBG(VMBUS, "src wrap-around detected!");
5067 +
5068 + fragLen = ringBufferSize - StartReadOffset;
5069 +
5070 + memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
5071 + memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
5072 + }
5073 + else
5074 + {
5075 + memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
5076 + }
5077 +
5078 + StartReadOffset += DestLen;
5079 + StartReadOffset %= ringBufferSize;
5080 +
5081 + return StartReadOffset;
5082 +}
5083 +
5084 +
5085 +// eof
5086 --- /dev/null
5087 +++ b/drivers/staging/hv/RingBuffer.h
5088 @@ -0,0 +1,123 @@
5089 +/*
5090 + *
5091 + * Copyright (c) 2009, Microsoft Corporation.
5092 + *
5093 + * This program is free software; you can redistribute it and/or modify it
5094 + * under the terms and conditions of the GNU General Public License,
5095 + * version 2, as published by the Free Software Foundation.
5096 + *
5097 + * This program is distributed in the hope it will be useful, but WITHOUT
5098 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5099 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
5100 + * more details.
5101 + *
5102 + * You should have received a copy of the GNU General Public License along with
5103 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
5104 + * Place - Suite 330, Boston, MA 02111-1307 USA.
5105 + *
5106 + * Authors:
5107 + * Haiyang Zhang <haiyangz@microsoft.com>
5108 + * Hank Janssen <hjanssen@microsoft.com>
5109 + *
5110 + */
5111 +
5112 +
5113 +#ifndef _RING_BUFFER_H_
5114 +#define _RING_BUFFER_H_
5115 +
5116 +#include "osd.h"
5117 +
5118 +typedef struct _SG_BUFFER_LIST {
5119 + PVOID Data;
5120 + UINT32 Length;
5121 +} SG_BUFFER_LIST;
5122 +
5123 +typedef struct _RING_BUFFER {
5124 + volatile UINT32 WriteIndex; // Offset in bytes from the start of ring data below
5125 + volatile UINT32 ReadIndex; // Offset in bytes from the start of ring data below
5126 +
5127 + volatile UINT32 InterruptMask;
5128 + UINT8 Reserved[4084]; // Pad it to PAGE_SIZE so that data starts on page boundary
5129 + // NOTE: The InterruptMask field is used only for channels but since our vmbus connection
5130 + // also uses this data structure and its data starts here, we commented out this field.
5131 + // volatile UINT32 InterruptMask;
5132 + // Ring data starts here + RingDataStartOffset !!! DO NOT place any fields below this !!!
5133 + UINT8 Buffer[0];
5134 +} STRUCT_PACKED RING_BUFFER;
5135 +
5136 +typedef struct _RING_BUFFER_INFO {
5137 + RING_BUFFER* RingBuffer;
5138 + UINT32 RingSize; // Include the shared header
5139 + HANDLE RingLock;
5140 +
5141 + UINT32 RingDataSize; // < ringSize
5142 + UINT32 RingDataStartOffset;
5143 +
5144 +} RING_BUFFER_INFO;
5145 +
5146 +
5147 +typedef struct _RING_BUFFER_DEBUG_INFO {
5148 + UINT32 CurrentInterruptMask;
5149 + UINT32 CurrentReadIndex;
5150 + UINT32 CurrentWriteIndex;
5151 + UINT32 BytesAvailToRead;
5152 + UINT32 BytesAvailToWrite;
5153 +}RING_BUFFER_DEBUG_INFO;
5154 +
5155 +
5156 +//
5157 +// Interface
5158 +//
5159 +
5160 +INTERNAL int
5161 +RingBufferInit(
5162 + RING_BUFFER_INFO *RingInfo,
5163 + PVOID Buffer,
5164 + UINT32 BufferLen
5165 + );
5166 +
5167 +INTERNAL void
5168 +RingBufferCleanup(
5169 + RING_BUFFER_INFO *RingInfo
5170 + );
5171 +
5172 +INTERNAL int
5173 +RingBufferWrite(
5174 + RING_BUFFER_INFO *RingInfo,
5175 + SG_BUFFER_LIST SgBuffers[],
5176 + UINT32 SgBufferCount
5177 + );
5178 +
5179 +INTERNAL int
5180 +RingBufferPeek(
5181 + RING_BUFFER_INFO *RingInfo,
5182 + PVOID Buffer,
5183 + UINT32 BufferLen
5184 + );
5185 +
5186 +INTERNAL int
5187 +RingBufferRead(
5188 + RING_BUFFER_INFO *RingInfo,
5189 + PVOID Buffer,
5190 + UINT32 BufferLen,
5191 + UINT32 Offset
5192 + );
5193 +
5194 +INTERNAL UINT32
5195 +GetRingBufferInterruptMask(
5196 + RING_BUFFER_INFO *RingInfo
5197 + );
5198 +
5199 +INTERNAL void
5200 +DumpRingInfo(
5201 + RING_BUFFER_INFO* RingInfo,
5202 + char *Prefix
5203 + );
5204 +
5205 +INTERNAL void
5206 +RingBufferGetDebugInfo(
5207 + RING_BUFFER_INFO *RingInfo,
5208 + RING_BUFFER_DEBUG_INFO *DebugInfo
5209 + );
5210 +
5211 +#endif // _RING_BUFFER_H_
5212 --- /dev/null
5213 +++ b/drivers/staging/hv/Sources.c
5214 @@ -0,0 +1,31 @@
5215 +/*
5216 + *
5217 + * Copyright (c) 2009, Microsoft Corporation.
5218 + *
5219 + * This program is free software; you can redistribute it and/or modify it
5220 + * under the terms and conditions of the GNU General Public License,
5221 + * version 2, as published by the Free Software Foundation.
5222 + *
5223 + * This program is distributed in the hope it will be useful, but WITHOUT
5224 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5225 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
5226 + * more details.
5227 + *
5228 + * You should have received a copy of the GNU General Public License along with
5229 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
5230 + * Place - Suite 330, Boston, MA 02111-1307 USA.
5231 + *
5232 + * Authors:
5233 + * Haiyang Zhang <haiyangz@microsoft.com>
5234 + * Hank Janssen <hjanssen@microsoft.com>
5235 + *
5236 + */
5237 +
5238 +
5239 +#include "Vmbus.c"
5240 +#include "Hv.c"
5241 +#include "Connection.c"
5242 +#include "Channel.c"
5243 +#include "ChannelMgmt.c"
5244 +#include "ChannelInterface.c"
5245 +#include "RingBuffer.c"
5246 --- /dev/null
5247 +++ b/drivers/staging/hv/VersionInfo.h
5248 @@ -0,0 +1,29 @@
5249 +/*
5250 + *
5251 + * Copyright (c) 2009, Microsoft Corporation.
5252 + *
5253 + * This program is free software; you can redistribute it and/or modify it
5254 + * under the terms and conditions of the GNU General Public License,
5255 + * version 2, as published by the Free Software Foundation.
5256 + *
5257 + * This program is distributed in the hope it will be useful, but WITHOUT
5258 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5259 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
5260 + * more details.
5261 + *
5262 + * You should have received a copy of the GNU General Public License along with
5263 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
5264 + * Place - Suite 330, Boston, MA 02111-1307 USA.
5265 + *
5266 + * Authors:
5267 + * Haiyang Zhang <haiyangz@microsoft.com>
5268 + * Hank Janssen <hjanssen@microsoft.com>
5269 + *
5270 + */
5271 +
5272 +
5273 +#pragma once
5274 +
5275 +const char VersionDate[]=__DATE__;
5276 +const char VersionTime[]=__TIME__;
5277 +const char VersionDesc[]= "Version 2.0";
5278 --- /dev/null
5279 +++ b/drivers/staging/hv/Vmbus.c
5280 @@ -0,0 +1,508 @@
5281 +/*
5282 + *
5283 + * Copyright (c) 2009, Microsoft Corporation.
5284 + *
5285 + * This program is free software; you can redistribute it and/or modify it
5286 + * under the terms and conditions of the GNU General Public License,
5287 + * version 2, as published by the Free Software Foundation.
5288 + *
5289 + * This program is distributed in the hope it will be useful, but WITHOUT
5290 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5291 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
5292 + * more details.
5293 + *
5294 + * You should have received a copy of the GNU General Public License along with
5295 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
5296 + * Place - Suite 330, Boston, MA 02111-1307 USA.
5297 + *
5298 + * Authors:
5299 + * Haiyang Zhang <haiyangz@microsoft.com>
5300 + * Hank Janssen <hjanssen@microsoft.com>
5301 + *
5302 + */
5303 +
5304 +
5305 +#include "logging.h"
5306 +#include "VersionInfo.h"
5307 +#include "VmbusPrivate.h"
5308 +
5309 +//
5310 +// Globals
5311 +//
5312 +static const char* gDriverName="vmbus";
5313 +
5314 +// Windows vmbus does not defined this. We defined this to be consistent with other devices
5315 +//{c5295816-f63a-4d5f-8d1a-4daf999ca185}
5316 +static const GUID gVmbusDeviceType={
5317 + .Data = {0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85}
5318 +};
5319 +
5320 +//{ac3760fc-9adf-40aa-9427-a70ed6de95c5}
5321 +static const GUID gVmbusDeviceId={
5322 + .Data = {0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5}
5323 +};
5324 +
5325 +static DRIVER_OBJECT* gDriver; // vmbus driver object
5326 +static DEVICE_OBJECT* gDevice; // vmbus root device
5327 +
5328 +
5329 +//
5330 +// Internal routines
5331 +//
5332 +
5333 +static void
5334 +VmbusGetChannelInterface(
5335 + VMBUS_CHANNEL_INTERFACE *Interface
5336 + );
5337 +
5338 +static void
5339 +VmbusGetChannelInfo(
5340 + DEVICE_OBJECT *DeviceObject,
5341 + DEVICE_INFO *DeviceInfo
5342 + );
5343 +
5344 +static void
5345 +VmbusGetChannelOffers(
5346 + void
5347 + );
5348 +
5349 +static int
5350 +VmbusOnDeviceAdd(
5351 + DEVICE_OBJECT *Device,
5352 + void *AdditionalInfo
5353 + );
5354 +
5355 +static int
5356 +VmbusOnDeviceRemove(
5357 + DEVICE_OBJECT* dev
5358 + );
5359 +
5360 +static void
5361 +VmbusOnCleanup(
5362 + DRIVER_OBJECT* drv
5363 + );
5364 +
5365 +static int
5366 +VmbusOnISR(
5367 + DRIVER_OBJECT* drv
5368 + );
5369 +
5370 +static void
5371 +VmbusOnMsgDPC(
5372 + DRIVER_OBJECT* drv
5373 + );
5374 +
5375 +static void
5376 +VmbusOnEventDPC(
5377 + DRIVER_OBJECT* drv
5378 + );
5379 +
5380 +/*++;
5381 +
5382 +Name:
5383 + VmbusInitialize()
5384 +
5385 +Description:
5386 + Main entry point
5387 +
5388 +--*/
5389 +int
5390 +VmbusInitialize(
5391 + DRIVER_OBJECT* drv
5392 + )
5393 +{
5394 + VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
5395 + int ret=0;
5396 +
5397 + DPRINT_ENTER(VMBUS);
5398 +
5399 + DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime);
5400 + DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc);
5401 +
5402 + DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER);
5403 + DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT);
5404 +
5405 + DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%d, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%d",
5406 + sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
5407 +
5408 + drv->name = gDriverName;
5409 + memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(GUID));
5410 +
5411 + // Setup dispatch table
5412 + driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
5413 + driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
5414 + driver->Base.OnCleanup = VmbusOnCleanup;
5415 + driver->OnIsr = VmbusOnISR;
5416 + driver->OnMsgDpc = VmbusOnMsgDPC;
5417 + driver->OnEventDpc = VmbusOnEventDPC;
5418 + driver->GetChannelOffers = VmbusGetChannelOffers;
5419 + driver->GetChannelInterface = VmbusGetChannelInterface;
5420 + driver->GetChannelInfo = VmbusGetChannelInfo;
5421 +
5422 + // Hypervisor initialization...setup hypercall page..etc
5423 + ret = HvInit();
5424 + if (ret != 0)
5425 + {
5426 + DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret);
5427 + }
5428 +
5429 + gDriver = drv;
5430 +
5431 + DPRINT_EXIT(VMBUS);
5432 +
5433 + return ret;
5434 +}
5435 +
5436 +
5437 +/*++;
5438 +
5439 +Name:
5440 + VmbusGetChannelOffers()
5441 +
5442 +Description:
5443 + Retrieve the channel offers from the parent partition
5444 +
5445 +--*/
5446 +
5447 +static void
5448 +VmbusGetChannelOffers(void)
5449 +{
5450 + DPRINT_ENTER(VMBUS);
5451 + VmbusChannelRequestOffers();
5452 + DPRINT_EXIT(VMBUS);
5453 +}
5454 +
5455 +
5456 +/*++;
5457 +
5458 +Name:
5459 + VmbusGetChannelInterface()
5460 +
5461 +Description:
5462 + Get the channel interface
5463 +
5464 +--*/
5465 +static void
5466 +VmbusGetChannelInterface(
5467 + VMBUS_CHANNEL_INTERFACE *Interface
5468 + )
5469 +{
5470 + GetChannelInterface(Interface);
5471 +}
5472 +
5473 +
5474 +/*++;
5475 +
5476 +Name:
5477 + VmbusGetChannelInterface()
5478 +
5479 +Description:
5480 + Get the device info for the specified device object
5481 +
5482 +--*/
5483 +static void
5484 +VmbusGetChannelInfo(
5485 + DEVICE_OBJECT *DeviceObject,
5486 + DEVICE_INFO *DeviceInfo
5487 + )
5488 +{
5489 + GetChannelInfo(DeviceObject, DeviceInfo);
5490 +}
5491 +
5492 +
5493 +
5494 +/*++
5495 +
5496 +Name:
5497 + VmbusCreateChildDevice()
5498 +
5499 +Description:
5500 + Creates the child device on the bus that represents the channel offer
5501 +
5502 +--*/
5503 +
5504 +DEVICE_OBJECT*
5505 +VmbusChildDeviceCreate(
5506 + GUID DeviceType,
5507 + GUID DeviceInstance,
5508 + void *Context)
5509 +{
5510 + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
5511 +
5512 + return vmbusDriver->OnChildDeviceCreate(
5513 + DeviceType,
5514 + DeviceInstance,
5515 + Context);
5516 +}
5517 +
5518 +
5519 +/*++
5520 +
5521 +Name:
5522 + VmbusChildDeviceAdd()
5523 +
5524 +Description:
5525 + Registers the child device with the vmbus
5526 +
5527 +--*/
5528 +int
5529 +VmbusChildDeviceAdd(
5530 + DEVICE_OBJECT* ChildDevice)
5531 +{
5532 + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
5533 +
5534 + return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
5535 +}
5536 +
5537 +
5538 +/*++
5539 +
5540 +Name:
5541 + VmbusChildDeviceRemove()
5542 +
5543 +Description:
5544 + Unregisters the child device from the vmbus
5545 +
5546 +--*/
5547 +void
5548 +VmbusChildDeviceRemove(
5549 + DEVICE_OBJECT* ChildDevice)
5550 +{
5551 + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
5552 +
5553 + vmbusDriver->OnChildDeviceRemove(ChildDevice);
5554 +}
5555 +
5556 +/*++
5557 +
5558 +Name:
5559 + VmbusChildDeviceDestroy()
5560 +
5561 +Description:
5562 + Release the child device from the vmbus
5563 +
5564 +--*/
5565 +//void
5566 +//VmbusChildDeviceDestroy(
5567 +// DEVICE_OBJECT* ChildDevice
5568 +// )
5569 +//{
5570 +// VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
5571 +//
5572 +// vmbusDriver->OnChildDeviceDestroy(ChildDevice);
5573 +//}
5574 +
5575 +/*++
5576 +
5577 +Name:
5578 + VmbusOnDeviceAdd()
5579 +
5580 +Description:
5581 + Callback when the root bus device is added
5582 +
5583 +--*/
5584 +static int
5585 +VmbusOnDeviceAdd(
5586 + DEVICE_OBJECT *dev,
5587 + void *AdditionalInfo
5588 + )
5589 +{
5590 + UINT32 *irqvector = (UINT32*) AdditionalInfo;
5591 + int ret=0;
5592 +
5593 + DPRINT_ENTER(VMBUS);
5594 +
5595 + gDevice = dev;
5596 +
5597 + memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(GUID));
5598 + memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(GUID));
5599 +
5600 + //strcpy(dev->name, "vmbus");
5601 + // SynIC setup...
5602 + ret = HvSynicInit(*irqvector);
5603 +
5604 + // Connect to VMBus in the root partition
5605 + ret = VmbusConnect();
5606 +
5607 + //VmbusSendEvent(device->localPortId+1);
5608 + DPRINT_EXIT(VMBUS);
5609 +
5610 + return ret;
5611 +}
5612 +
5613 +
5614 +/*++
5615 +
5616 +Name:
5617 + VmbusOnDeviceRemove()
5618 +
5619 +Description:
5620 + Callback when the root bus device is removed
5621 +
5622 +--*/
5623 +int VmbusOnDeviceRemove(
5624 + DEVICE_OBJECT* dev
5625 + )
5626 +{
5627 + int ret=0;
5628 +
5629 + DPRINT_ENTER(VMBUS);
5630 +
5631 + VmbusChannelReleaseUnattachedChannels();
5632 +
5633 + VmbusDisconnect();
5634 +
5635 + HvSynicCleanup();
5636 +
5637 + DPRINT_EXIT(VMBUS);
5638 +
5639 + return ret;
5640 +}
5641 +
5642 +
5643 +/*++
5644 +
5645 +Name:
5646 + VmbusOnCleanup()
5647 +
5648 +Description:
5649 + Perform any cleanup when the driver is removed
5650 +
5651 +--*/
5652 +void
5653 +VmbusOnCleanup(
5654 + DRIVER_OBJECT* drv
5655 + )
5656 +{
5657 + //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
5658 +
5659 + DPRINT_ENTER(VMBUS);
5660 +
5661 + HvCleanup();
5662 +
5663 + DPRINT_EXIT(VMBUS);
5664 +}
5665 +
5666 +
5667 +/*++
5668 +
5669 +Name:
5670 + VmbusOnMsgDPC()
5671 +
5672 +Description:
5673 + DPC routine to handle messages from the hypervisior
5674 +
5675 +--*/
5676 +void
5677 +VmbusOnMsgDPC(
5678 + DRIVER_OBJECT* drv
5679 + )
5680 +{
5681 + void *page_addr = gHvContext.synICMessagePage[0];
5682 +
5683 + HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
5684 + HV_MESSAGE *copied;
5685 + while (1)
5686 + {
5687 + if (msg->Header.MessageType == HvMessageTypeNone) // no msg
5688 + {
5689 + break;
5690 + }
5691 + else
5692 + {
5693 + copied = MemAllocAtomic(sizeof(HV_MESSAGE));
5694 + if (copied == NULL)
5695 + {
5696 + continue;
5697 + }
5698 +
5699 + memcpy(copied, msg, sizeof(HV_MESSAGE));
5700 + WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, VmbusOnChannelMessage, (void*)copied);
5701 + }
5702 +
5703 + msg->Header.MessageType = HvMessageTypeNone;
5704 +
5705 + // Make sure the write to MessageType (ie set to HvMessageTypeNone) happens
5706 + // before we read the MessagePending and EOMing. Otherwise, the EOMing will not deliver
5707 + // any more messages since there is no empty slot
5708 + MemoryFence();
5709 +
5710 + if (msg->Header.MessageFlags.MessagePending)
5711 + {
5712 + // This will cause message queue rescan to possibly deliver another msg from the hypervisor
5713 + WriteMsr(HV_X64_MSR_EOM, 0);
5714 + }
5715 + }
5716 +}
5717 +
5718 +/*++
5719 +
5720 +Name:
5721 + VmbusOnEventDPC()
5722 +
5723 +Description:
5724 + DPC routine to handle events from the hypervisior
5725 +
5726 +--*/
5727 +void
5728 +VmbusOnEventDPC(
5729 + DRIVER_OBJECT* drv
5730 + )
5731 +{
5732 + // TODO: Process any events
5733 + VmbusOnEvents();
5734 +}
5735 +
5736 +
5737 +/*++
5738 +
5739 +Name:
5740 + VmbusOnISR()
5741 +
5742 +Description:
5743 + ISR routine
5744 +
5745 +--*/
5746 +int
5747 +VmbusOnISR(
5748 + DRIVER_OBJECT* drv
5749 + )
5750 +{
5751 + //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
5752 +
5753 + int ret=0;
5754 + //struct page* page;
5755 + void *page_addr;
5756 + HV_MESSAGE* msg;
5757 + HV_SYNIC_EVENT_FLAGS* event;
5758 +
5759 + //page = SynICMessagePage[0];
5760 + //page_addr = page_address(page);
5761 + page_addr = gHvContext.synICMessagePage[0];
5762 + msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
5763 +
5764 + DPRINT_ENTER(VMBUS);
5765 +
5766 + // Check if there are actual msgs to be process
5767 + if (msg->Header.MessageType != HvMessageTypeNone)
5768 + {
5769 + DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize);
5770 + ret |= 0x1;
5771 + }
5772 +
5773 + // TODO: Check if there are events to be process
5774 + page_addr = gHvContext.synICEventPage[0];
5775 + event = (HV_SYNIC_EVENT_FLAGS*)page_addr + VMBUS_MESSAGE_SINT;
5776 +
5777 + // Since we are a child, we only need to check bit 0
5778 + if (BitTestAndClear(&event->Flags32[0], 0))
5779 + {
5780 + DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
5781 + ret |= 0x2;
5782 + }
5783 +
5784 + DPRINT_EXIT(VMBUS);
5785 + return ret;
5786 +}
5787 +
5788 +// eof
5789 --- /dev/null
5790 +++ b/drivers/staging/hv/vmbus_drv.c
5791 @@ -0,0 +1,1228 @@
5792 +/*
5793 + *
5794 + * Copyright (c) 2009, Microsoft Corporation.
5795 + *
5796 + * This program is free software; you can redistribute it and/or modify it
5797 + * under the terms and conditions of the GNU General Public License,
5798 + * version 2, as published by the Free Software Foundation.
5799 + *
5800 + * This program is distributed in the hope it will be useful, but WITHOUT
5801 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5802 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
5803 + * more details.
5804 + *
5805 + * You should have received a copy of the GNU General Public License along with
5806 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
5807 + * Place - Suite 330, Boston, MA 02111-1307 USA.
5808 + *
5809 + * Authors:
5810 + * Haiyang Zhang <haiyangz@microsoft.com>
5811 + * Hank Janssen <hjanssen@microsoft.com>
5812 + *
5813 + */
5814 +
5815 +
5816 +#include <linux/init.h>
5817 +#include <linux/module.h>
5818 +#include <linux/device.h>
5819 +#include <linux/irq.h>
5820 +#include <linux/interrupt.h>
5821 +#include <linux/sysctl.h>
5822 +
5823 +#include "logging.h"
5824 +#include "vmbus.h"
5825 +
5826 +//
5827 +// Defines
5828 +//
5829 +
5830 +// FIXME! We need to do this dynamically for PIC and APIC system
5831 +#define VMBUS_IRQ 0x5
5832 +#ifdef KERNEL_2_6_27
5833 +#define VMBUS_IRQ_VECTOR IRQ5_VECTOR
5834 +#endif
5835 +//
5836 +// Data types
5837 +//
5838 +
5839 +// Main vmbus driver data structure
5840 +struct vmbus_driver_context {
5841 + // !! These must be the first 2 fields !!
5842 + // The driver field is not used in here. Instead, the bus field is
5843 + // used to represent the driver
5844 + struct driver_context drv_ctx;
5845 + VMBUS_DRIVER_OBJECT drv_obj;
5846 +
5847 + struct bus_type bus;
5848 + struct tasklet_struct msg_dpc;
5849 + struct tasklet_struct event_dpc;
5850 +
5851 + // The bus root device
5852 + struct device_context device_ctx;
5853 +};
5854 +
5855 +//
5856 +// Static decl
5857 +//
5858 +static int vmbus_match(struct device *device, struct device_driver *driver);
5859 +static int vmbus_probe(struct device *device);
5860 +static int vmbus_remove(struct device *device);
5861 +static void vmbus_shutdown(struct device *device);
5862 +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
5863 +#elif defined(KERNEL_2_6_27)
5864 +static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env);
5865 +#else
5866 +static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size);
5867 +#endif
5868 +static void vmbus_msg_dpc(unsigned long data);
5869 +static void vmbus_event_dpc(unsigned long data);
5870 +
5871 +#ifdef KERNEL_2_6_27
5872 +static irqreturn_t vmbus_isr(int irq, void* dev_id);
5873 +#else
5874 +static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs);
5875 +#endif
5876 +
5877 +static void vmbus_device_release(struct device *device);
5878 +static void vmbus_bus_release(struct device *device);
5879 +
5880 +static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context);
5881 +static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj);
5882 +static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj);
5883 +static void vmbus_child_device_unregister(DEVICE_OBJECT* child_device_obj);
5884 +static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info);
5885 +
5886 +//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf);
5887 +//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf);
5888 +
5889 +static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf);
5890 +
5891 +//
5892 +// Global
5893 +//
5894 +
5895 +// Global logging setting
5896 +
5897 +//unsigned int vmbus_loglevel= (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT);
5898 +//unsigned int vmbus_loglevel= (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT);
5899 +unsigned int vmbus_loglevel= (ALL_MODULES << 16 | INFO_LVL);
5900 +EXPORT_SYMBOL(vmbus_loglevel);
5901 +
5902 +static int vmbus_irq = VMBUS_IRQ;
5903 +
5904 +// Setup /proc/sys/bus/vmbus/vmbus_loglevel
5905 +// Allow usage of sysctl cmd to set the logging level
5906 +static struct ctl_table_header *vmbus_ctl_table_hdr;
5907 +
5908 +static ctl_table vmbus_dev_ctl_table[] = {
5909 + { .ctl_name = 8461,
5910 + .procname = "vmbus_loglevel",
5911 + .data = &vmbus_loglevel,
5912 + .maxlen = sizeof(vmbus_loglevel),
5913 + .mode = 0644,
5914 + .proc_handler = &proc_dointvec },
5915 + { }
5916 +};
5917 +
5918 +static ctl_table vmbus_ctl_table[] = {
5919 + { .ctl_name = CTL_DEV,
5920 + .procname = "vmbus",
5921 + .mode = 0555,
5922 + .child = vmbus_dev_ctl_table },
5923 + { }
5924 +};
5925 +
5926 +static ctl_table vmus_root_ctl_table[] = {
5927 + { .ctl_name = CTL_BUS,
5928 + .procname = "bus",
5929 + .mode = 0555,
5930 + .child = vmbus_ctl_table },
5931 + { }
5932 +};
5933 +
5934 +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
5935 +#else
5936 +//
5937 +// Set up per device attributes in /sys/bus/vmbus/devices/<bus device>
5938 +//
5939 +static struct device_attribute vmbus_device_attrs[] = {
5940 + __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL),
5941 + __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL),
5942 + __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL),
5943 + __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL),
5944 + __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL),
5945 +
5946 + __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
5947 + __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
5948 + __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
5949 +
5950 + __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
5951 + __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
5952 + __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
5953 +
5954 + __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
5955 + __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
5956 + __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
5957 + __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
5958 + __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
5959 +
5960 + __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
5961 + __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
5962 + __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
5963 + __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
5964 + __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
5965 + __ATTR_NULL
5966 +};
5967 +#endif
5968 +
5969 +// The one and only one
5970 +static struct vmbus_driver_context g_vmbus_drv={
5971 + .bus.name = "vmbus",
5972 + .bus.match = vmbus_match,
5973 +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
5974 +#else
5975 + .bus.shutdown = vmbus_shutdown,
5976 + .bus.remove = vmbus_remove,
5977 + .bus.probe = vmbus_probe,
5978 + .bus.uevent = vmbus_uevent,
5979 + .bus.dev_attrs = vmbus_device_attrs,
5980 +#endif
5981 +};
5982 +
5983 +//
5984 +// Routines
5985 +//
5986 +
5987 +
5988 +/*++
5989 +
5990 +Name: vmbus_show_device_attr()
5991 +
5992 +Desc: Show the device attribute in sysfs. This is invoked when user does a "cat /sys/bus/vmbus/devices/<bus device>/<attr name>"
5993 +
5994 +--*/
5995 +static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf)
5996 +{
5997 + struct device_context *device_ctx = device_to_device_context(dev);
5998 + DEVICE_INFO device_info;
5999 +
6000 + memset(&device_info, 0, sizeof(DEVICE_INFO));
6001 +
6002 + vmbus_child_device_get_info(&device_ctx->device_obj, &device_info);
6003 +
6004 + if (!strcmp(dev_attr->attr.name, "class_id"))
6005 + {
6006 + return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
6007 + device_info.ChannelType.Data[3], device_info.ChannelType.Data[2], device_info.ChannelType.Data[1], device_info.ChannelType.Data[0],
6008 + device_info.ChannelType.Data[5], device_info.ChannelType.Data[4],
6009 + device_info.ChannelType.Data[7], device_info.ChannelType.Data[6],
6010 + 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]);
6011 +
6012 + }
6013 + else if (!strcmp(dev_attr->attr.name, "device_id"))
6014 + {
6015 + return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
6016 + device_info.ChannelInstance.Data[3], device_info.ChannelInstance.Data[2], device_info.ChannelInstance.Data[1], device_info.ChannelInstance.Data[0],
6017 + device_info.ChannelInstance.Data[5], device_info.ChannelInstance.Data[4],
6018 + device_info.ChannelInstance.Data[7], device_info.ChannelInstance.Data[6],
6019 + 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]);
6020 + }
6021 + else if (!strcmp(dev_attr->attr.name, "state"))
6022 + {
6023 + return sprintf(buf, "%d\n", device_info.ChannelState);
6024 + }
6025 + else if (!strcmp(dev_attr->attr.name, "id"))
6026 + {
6027 + return sprintf(buf, "%d\n", device_info.ChannelId);
6028 + }
6029 + else if (!strcmp(dev_attr->attr.name, "out_intr_mask"))
6030 + {
6031 + return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask);
6032 + }
6033 + else if (!strcmp(dev_attr->attr.name, "out_read_index"))
6034 + {
6035 + return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex);
6036 + }
6037 + else if (!strcmp(dev_attr->attr.name, "out_write_index"))
6038 + {
6039 + return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex);
6040 + }
6041 + else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail"))
6042 + {
6043 + return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToRead);
6044 + }
6045 + else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail"))
6046 + {
6047 + return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToWrite);
6048 + }
6049 + else if (!strcmp(dev_attr->attr.name, "in_intr_mask"))
6050 + {
6051 + return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask);
6052 + }
6053 + else if (!strcmp(dev_attr->attr.name, "in_read_index"))
6054 + {
6055 + return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex);
6056 + }
6057 + else if (!strcmp(dev_attr->attr.name, "in_write_index"))
6058 + {
6059 + return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex);
6060 + }
6061 + else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail"))
6062 + {
6063 + return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToRead);
6064 + }
6065 + else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail"))
6066 + {
6067 + return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToWrite);
6068 + }
6069 + else if (!strcmp(dev_attr->attr.name, "monitor_id"))
6070 + {
6071 + return sprintf(buf, "%d\n", device_info.MonitorId);
6072 + }
6073 + else if (!strcmp(dev_attr->attr.name, "server_monitor_pending"))
6074 + {
6075 + return sprintf(buf, "%d\n", device_info.ServerMonitorPending);
6076 + }
6077 + else if (!strcmp(dev_attr->attr.name, "server_monitor_latency"))
6078 + {
6079 + return sprintf(buf, "%d\n", device_info.ServerMonitorLatency);
6080 + }
6081 + else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id"))
6082 + {
6083 + return sprintf(buf, "%d\n", device_info.ServerMonitorConnectionId);
6084 + }
6085 + else if (!strcmp(dev_attr->attr.name, "client_monitor_pending"))
6086 + {
6087 + return sprintf(buf, "%d\n", device_info.ClientMonitorPending);
6088 + }
6089 + else if (!strcmp(dev_attr->attr.name, "client_monitor_latency"))
6090 + {
6091 + return sprintf(buf, "%d\n", device_info.ClientMonitorLatency);
6092 + }
6093 + else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id"))
6094 + {
6095 + return sprintf(buf, "%d\n", device_info.ClientMonitorConnectionId);
6096 + }
6097 + else
6098 + {
6099 + return 0;
6100 + }
6101 +}
6102 +
6103 +/*++
6104 +
6105 +Name: vmbus_show_class_id()
6106 +
6107 +Desc: Show the device class id in sysfs
6108 +
6109 +--*/
6110 +//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf)
6111 +//{
6112 +// struct device_context *device_ctx = device_to_device_context(dev);
6113 +// return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
6114 +// device_ctx->class_id[3], device_ctx->class_id[2], device_ctx->class_id[1], device_ctx->class_id[0],
6115 +// device_ctx->class_id[5], device_ctx->class_id[4],
6116 +// device_ctx->class_id[7], device_ctx->class_id[6],
6117 +// 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]);
6118 +//}
6119 +
6120 +/*++
6121 +
6122 +Name: vmbus_show_device_id()
6123 +
6124 +Desc: Show the device instance id in sysfs
6125 +
6126 +--*/
6127 +//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf)
6128 +//{
6129 +// struct device_context *device_ctx = device_to_device_context(dev);
6130 +// return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
6131 +// device_ctx->device_id[3], device_ctx->device_id[2], device_ctx->device_id[1], device_ctx->device_id[0],
6132 +// device_ctx->device_id[5], device_ctx->device_id[4],
6133 +// device_ctx->device_id[7], device_ctx->device_id[6],
6134 +// 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]);
6135 +//}
6136 +
6137 +/*++
6138 +
6139 +Name: vmbus_bus_init()
6140 +
6141 +Desc: Main vmbus driver initialization routine. Here, we
6142 + - initialize the vmbus driver context
6143 + - setup various driver entry points
6144 + - invoke the vmbus hv main init routine
6145 + - get the irq resource
6146 + - invoke the vmbus to add the vmbus root device
6147 + - setup the vmbus root device
6148 + - retrieve the channel offers
6149 +--*/
6150 +int vmbus_bus_init(PFN_DRIVERINITIALIZE pfn_drv_init)
6151 +{
6152 + int ret=0;
6153 + unsigned int vector=0;
6154 +
6155 + struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv;
6156 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6157 +
6158 + struct device_context *dev_ctx=&g_vmbus_drv.device_ctx;
6159 +
6160 + DPRINT_ENTER(VMBUS_DRV);
6161 +
6162 + // Set this up to allow lower layer to callback to add/remove child devices on the bus
6163 + vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create;
6164 + vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy;
6165 + vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register;
6166 + vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister;
6167 +
6168 + // Call to bus driver to initialize
6169 + ret = pfn_drv_init(&vmbus_drv_obj->Base);
6170 + if (ret != 0)
6171 + {
6172 + DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret);
6173 + goto cleanup;
6174 + }
6175 +
6176 + // Sanity checks
6177 + if (!vmbus_drv_obj->Base.OnDeviceAdd)
6178 + {
6179 + DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set");
6180 + ret = -1;
6181 + goto cleanup;
6182 + }
6183 +
6184 + vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name;
6185 +
6186 + // Initialize the bus context
6187 + tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, (unsigned long)vmbus_drv_obj);
6188 + tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, (unsigned long)vmbus_drv_obj);
6189 +
6190 + // Now, register the bus driver with LDM
6191 + bus_register(&vmbus_drv_ctx->bus);
6192 +
6193 + // Get the interrupt resource
6194 +#ifdef KERNEL_2_6_27
6195 + ret = request_irq(vmbus_irq,
6196 + vmbus_isr,
6197 + IRQF_SAMPLE_RANDOM,
6198 + vmbus_drv_obj->Base.name,
6199 + NULL);
6200 +#else
6201 + ret = request_irq(vmbus_irq,
6202 + vmbus_isr,
6203 + SA_SAMPLE_RANDOM,
6204 + vmbus_drv_obj->Base.name,
6205 + NULL);
6206 +#endif
6207 +
6208 + if (ret != 0)
6209 + {
6210 + DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", vmbus_irq);
6211 +
6212 + bus_unregister(&vmbus_drv_ctx->bus);
6213 +
6214 + ret = -1;
6215 + goto cleanup;
6216 + }
6217 +#ifdef KERNEL_2_6_27
6218 + vector = VMBUS_IRQ_VECTOR;
6219 +#else
6220 +#if X2V_LINUX
6221 + vector = vmbus_irq + FIRST_DEVICE_VECTOR - 2;
6222 +#else
6223 + vector = vmbus_irq + FIRST_EXTERNAL_VECTOR;
6224 +#endif
6225 +#endif
6226 +
6227 + DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
6228 +
6229 + // Call to bus driver to add the root device
6230 + memset(dev_ctx, 0, sizeof(struct device_context));
6231 +
6232 + ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector);
6233 + if (ret != 0)
6234 + {
6235 + DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to add vmbus root device");
6236 +
6237 + free_irq(vmbus_irq, NULL);
6238 +
6239 + bus_unregister(&vmbus_drv_ctx->bus);
6240 +
6241 + ret = -1;
6242 + goto cleanup;
6243 + }
6244 + //strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name);
6245 + sprintf(dev_ctx->device.bus_id, "vmbus_0_0");
6246 + memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType, sizeof(GUID));
6247 + memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance, sizeof(GUID));
6248 +
6249 + // No need to bind a driver to the root device.
6250 + dev_ctx->device.parent = NULL;
6251 + dev_ctx->device.bus = &vmbus_drv_ctx->bus; //NULL; // vmbus_remove() does not get invoked
6252 +
6253 + // Setup the device dispatch table
6254 + dev_ctx->device.release = vmbus_bus_release;
6255 +
6256 + // Setup the bus as root device
6257 + device_register(&dev_ctx->device);
6258 +
6259 + vmbus_drv_obj->GetChannelOffers();
6260 +
6261 +cleanup:
6262 + DPRINT_EXIT(VMBUS_DRV);
6263 +
6264 + return ret;
6265 +}
6266 +
6267 +
6268 +/*++
6269 +
6270 +Name: vmbus_bus_exit()
6271 +
6272 +Desc: Terminate the vmbus driver. This routine is opposite of vmbus_bus_init()
6273 +
6274 +--*/
6275 +void vmbus_bus_exit(void)
6276 +{
6277 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6278 + struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv;
6279 +
6280 + struct device_context *dev_ctx=&g_vmbus_drv.device_ctx;
6281 +
6282 + DPRINT_ENTER(VMBUS_DRV);
6283 +
6284 + // Remove the root device
6285 + if (vmbus_drv_obj->Base.OnDeviceRemove)
6286 + vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj);
6287 +
6288 + if (vmbus_drv_obj->Base.OnCleanup)
6289 + vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base);
6290 +
6291 + // Unregister the root bus device
6292 + device_unregister(&dev_ctx->device);
6293 +
6294 + bus_unregister(&vmbus_drv_ctx->bus);
6295 +
6296 + free_irq(vmbus_irq, NULL);
6297 +
6298 + tasklet_kill(&vmbus_drv_ctx->msg_dpc);
6299 + tasklet_kill(&vmbus_drv_ctx->event_dpc);
6300 +
6301 + DPRINT_EXIT(VMBUS_DRV);
6302 +
6303 + return;
6304 +}
6305 +
6306 +/*++
6307 +
6308 +Name: vmbus_child_driver_register()
6309 +
6310 +Desc: Register a vmbus's child driver
6311 +
6312 +--*/
6313 +void vmbus_child_driver_register(struct driver_context* driver_ctx)
6314 +{
6315 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6316 +
6317 + DPRINT_ENTER(VMBUS_DRV);
6318 +
6319 + DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", driver_ctx, driver_ctx->driver.name);
6320 +
6321 + // The child driver on this vmbus
6322 + driver_ctx->driver.bus = &g_vmbus_drv.bus;
6323 +
6324 + driver_register(&driver_ctx->driver);
6325 +
6326 + vmbus_drv_obj->GetChannelOffers();
6327 +
6328 + DPRINT_EXIT(VMBUS_DRV);
6329 +}
6330 +
6331 +EXPORT_SYMBOL(vmbus_child_driver_register);
6332 +
6333 +/*++
6334 +
6335 +Name: vmbus_child_driver_unregister()
6336 +
6337 +Desc: Unregister a vmbus's child driver
6338 +
6339 +--*/
6340 +void vmbus_child_driver_unregister(struct driver_context* driver_ctx)
6341 +{
6342 + DPRINT_ENTER(VMBUS_DRV);
6343 +
6344 + DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", driver_ctx, driver_ctx->driver.name);
6345 +
6346 + driver_unregister(&driver_ctx->driver);
6347 +
6348 + driver_ctx->driver.bus = NULL;
6349 +
6350 + DPRINT_EXIT(VMBUS_DRV);
6351 +}
6352 +
6353 +EXPORT_SYMBOL(vmbus_child_driver_unregister);
6354 +
6355 +/*++
6356 +
6357 +Name: vmbus_get_interface()
6358 +
6359 +Desc: Get the vmbus channel interface. This is invoked by child/client driver that sits
6360 + above vmbus
6361 +--*/
6362 +void vmbus_get_interface(VMBUS_CHANNEL_INTERFACE *interface)
6363 +{
6364 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6365 +
6366 + vmbus_drv_obj->GetChannelInterface(interface);
6367 +}
6368 +
6369 +EXPORT_SYMBOL(vmbus_get_interface);
6370 +
6371 +
6372 +/*++
6373 +
6374 +Name: vmbus_child_device_get_info()
6375 +
6376 +Desc: Get the vmbus child device info. This is invoked to display various device attributes in sysfs.
6377 +--*/
6378 +static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info)
6379 +{
6380 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6381 +
6382 + vmbus_drv_obj->GetChannelInfo(device_obj, device_info);
6383 +}
6384 +
6385 +
6386 +/*++
6387 +
6388 +Name: vmbus_child_device_create()
6389 +
6390 +Desc: Creates and registers a new child device on the vmbus.
6391 +
6392 +--*/
6393 +static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context)
6394 +{
6395 + struct device_context *child_device_ctx;
6396 + DEVICE_OBJECT* child_device_obj;
6397 +
6398 + DPRINT_ENTER(VMBUS_DRV);
6399 +
6400 + // Allocate the new child device
6401 + child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL);
6402 + if (!child_device_ctx)
6403 + {
6404 + DPRINT_ERR(VMBUS_DRV, "unable to allocate device_context for child device");
6405 + DPRINT_EXIT(VMBUS_DRV);
6406 +
6407 + return NULL;
6408 + }
6409 +
6410 + DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - "
6411 + "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x},"
6412 + "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
6413 + &child_device_ctx->device,
6414 + 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],
6415 + 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]);
6416 +
6417 + child_device_obj = &child_device_ctx->device_obj;
6418 + child_device_obj->context = context;
6419 + memcpy(&child_device_obj->deviceType, &type, sizeof(GUID));
6420 + memcpy(&child_device_obj->deviceInstance, &instance, sizeof(GUID));
6421 +
6422 + memcpy(&child_device_ctx->class_id, &type, sizeof(GUID));
6423 + memcpy(&child_device_ctx->device_id, &instance, sizeof(GUID));
6424 +
6425 + DPRINT_EXIT(VMBUS_DRV);
6426 +
6427 + return child_device_obj;
6428 +}
6429 +
6430 +/*++
6431 +
6432 +Name: vmbus_child_device_register()
6433 +
6434 +Desc: Register the child device on the specified bus
6435 +
6436 +--*/
6437 +static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj)
6438 +{
6439 + int ret=0;
6440 + struct device_context *root_device_ctx = to_device_context(root_device_obj);
6441 + struct device_context *child_device_ctx = to_device_context(child_device_obj);
6442 + static int device_num=0;
6443 +
6444 + DPRINT_ENTER(VMBUS_DRV);
6445 +
6446 + DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", child_device_ctx);
6447 + //
6448 + // Make sure we are not registered already
6449 + //
6450 + if (child_device_ctx->device.bus_id[0] != '\0')
6451 + {
6452 + DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, child_device_ctx->device.bus_id);
6453 +
6454 + ret = -1;
6455 + goto Cleanup;
6456 + }
6457 +
6458 + // Set the device bus id. Otherwise, device_register()will fail.
6459 + sprintf(child_device_ctx->device.bus_id, "vmbus_0_%d", InterlockedIncrement(&device_num));
6460 +
6461 + // The new device belongs to this bus
6462 + child_device_ctx->device.bus = &g_vmbus_drv.bus; //device->dev.bus;
6463 + child_device_ctx->device.parent = &root_device_ctx->device;
6464 + child_device_ctx->device.release = vmbus_device_release;
6465 +
6466 + // Register with the LDM. This will kick off the driver/device binding...which will
6467 + // eventually call vmbus_match() and vmbus_probe()
6468 + ret = device_register(&child_device_ctx->device);
6469 +
6470 + // vmbus_probe() error does not get propergate to device_register().
6471 + ret = child_device_ctx->probe_error;
6472 +
6473 + if (ret)
6474 + DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p) (%d)", &child_device_ctx->device);
6475 + else
6476 + DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", &child_device_ctx->device);
6477 +
6478 +Cleanup:
6479 + DPRINT_EXIT(VMBUS_DRV);
6480 +
6481 + return ret;
6482 +}
6483 +
6484 +/*++
6485 +
6486 +Name: vmbus_child_device_unregister()
6487 +
6488 +Desc: Remove the specified child device from the vmbus.
6489 +
6490 +--*/
6491 +static void vmbus_child_device_unregister(DEVICE_OBJECT* device_obj)
6492 +{
6493 + struct device_context *device_ctx = to_device_context(device_obj);
6494 +
6495 + DPRINT_ENTER(VMBUS_DRV);
6496 +
6497 + DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", &device_ctx->device);
6498 +
6499 + // Kick off the process of unregistering the device.
6500 + // This will call vmbus_remove() and eventually vmbus_device_release()
6501 + device_unregister(&device_ctx->device);
6502 +
6503 + DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", &device_ctx->device);
6504 +
6505 + DPRINT_EXIT(VMBUS_DRV);
6506 +}
6507 +
6508 +
6509 +/*++
6510 +
6511 +Name: vmbus_child_device_destroy()
6512 +
6513 +Desc: Destroy the specified child device on the vmbus.
6514 +
6515 +--*/
6516 +static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj)
6517 +{
6518 + DPRINT_ENTER(VMBUS_DRV);
6519 +
6520 + DPRINT_EXIT(VMBUS_DRV);
6521 +}
6522 +
6523 +/*++
6524 +
6525 +Name: vmbus_uevent()
6526 +
6527 +Desc: This routine is invoked when a device is added or removed on the vmbus to generate a uevent to udev in the
6528 + userspace. The udev will then look at its rule and the uevent generated here to load the appropriate driver
6529 +
6530 +--*/
6531 +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
6532 +#elif defined(KERNEL_2_6_27)
6533 +static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
6534 +{
6535 + struct device_context *device_ctx = device_to_device_context(device);
6536 + int i=0;
6537 + int len=0;
6538 + int ret;
6539 +
6540 + DPRINT_ENTER(VMBUS_DRV);
6541 +
6542 + 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}",
6543 + device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0],
6544 + device_ctx->class_id.Data[5], device_ctx->class_id.Data[4],
6545 + device_ctx->class_id.Data[7], device_ctx->class_id.Data[6],
6546 + device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11],
6547 + device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]);
6548 +
6549 + env->envp_idx = i;
6550 + env->buflen = len;
6551 + ret = add_uevent_var(env,
6552 + "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
6553 + device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0],
6554 + device_ctx->class_id.Data[5], device_ctx->class_id.Data[4],
6555 + device_ctx->class_id.Data[7], device_ctx->class_id.Data[6],
6556 + device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11],
6557 + device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]);
6558 +
6559 + if (ret)
6560 + {
6561 + return ret;
6562 + }
6563 +
6564 + ret = add_uevent_var(env,
6565 + "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
6566 + device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0],
6567 + device_ctx->device_id.Data[5], device_ctx->device_id.Data[4],
6568 + device_ctx->device_id.Data[7], device_ctx->device_id.Data[6],
6569 + device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11],
6570 + device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]);
6571 +
6572 + if (ret)
6573 + {
6574 + return ret;
6575 + }
6576 +
6577 + env->envp[env->envp_idx] = NULL;
6578 +
6579 + DPRINT_EXIT(VMBUS_DRV);
6580 +
6581 + return 0;
6582 +}
6583 +
6584 +#else
6585 +static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size)
6586 +{
6587 + struct device_context *device_ctx = device_to_device_context(device);
6588 + int i=0;
6589 + int len=0;
6590 + int ret;
6591 +
6592 + DPRINT_ENTER(VMBUS_DRV);
6593 +
6594 + 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}",
6595 + device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0],
6596 + device_ctx->class_id.Data[5], device_ctx->class_id.Data[4],
6597 + device_ctx->class_id.Data[7], device_ctx->class_id.Data[6],
6598 + device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11],
6599 + device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]);
6600 +
6601 + ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
6602 + "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
6603 + device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0],
6604 + device_ctx->class_id.Data[5], device_ctx->class_id.Data[4],
6605 + device_ctx->class_id.Data[7], device_ctx->class_id.Data[6],
6606 + device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11],
6607 + device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]);
6608 +
6609 + if (ret)
6610 + {
6611 + return ret;
6612 + }
6613 +
6614 + ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
6615 + "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
6616 + device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0],
6617 + device_ctx->device_id.Data[5], device_ctx->device_id.Data[4],
6618 + device_ctx->device_id.Data[7], device_ctx->device_id.Data[6],
6619 + device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11],
6620 + device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]);
6621 +
6622 + if (ret)
6623 + {
6624 + return ret;
6625 + }
6626 +
6627 + envp[i] = NULL;
6628 +
6629 + DPRINT_EXIT(VMBUS_DRV);
6630 +
6631 + return 0;
6632 +}
6633 +#endif
6634 +
6635 +/*++
6636 +
6637 +Name: vmbus_match()
6638 +
6639 +Desc: Attempt to match the specified device to the specified driver
6640 +
6641 +--*/
6642 +static int vmbus_match(struct device *device, struct device_driver *driver)
6643 +{
6644 + int match=0;
6645 + struct driver_context *driver_ctx = driver_to_driver_context(driver);
6646 + struct device_context *device_ctx = device_to_device_context(device);
6647 +
6648 + DPRINT_ENTER(VMBUS_DRV);
6649 +
6650 + // We found our driver ?
6651 + if (memcmp(&device_ctx->class_id, &driver_ctx->class_id, sizeof(GUID)) == 0)
6652 + {
6653 + // !! NOTE: The driver_ctx is not a vmbus_drv_ctx. We typecast it here to access the
6654 + // DRIVER_OBJECT field
6655 + struct vmbus_driver_context *vmbus_drv_ctx = (struct vmbus_driver_context*)driver_ctx;
6656 + device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base;
6657 + DPRINT_INFO(VMBUS_DRV, "device object (%p) set to driver object (%p)", &device_ctx->device_obj, device_ctx->device_obj.Driver);
6658 +
6659 + match = 1;
6660 + }
6661 +
6662 + DPRINT_EXIT(VMBUS_DRV);
6663 +
6664 + return match;
6665 +}
6666 +
6667 +
6668 +/*++
6669 +
6670 +Name: vmbus_probe_failed_cb()
6671 +
6672 +Desc: Callback when a driver probe failed in vmbus_probe(). We need a callback because
6673 + we cannot invoked device_unregister() inside vmbus_probe() since vmbus_probe() may be
6674 + invoked inside device_register() i.e. we cannot call device_unregister() inside
6675 + device_register()
6676 +--*/
6677 +#ifdef KERNEL_2_6_27
6678 +static void vmbus_probe_failed_cb(struct work_struct *context)
6679 +#else
6680 +static void vmbus_probe_failed_cb(void* context)
6681 +#endif
6682 +{
6683 + struct device_context *device_ctx = (struct device_context*)context;
6684 +
6685 +
6686 + DPRINT_ENTER(VMBUS_DRV);
6687 +
6688 + // Kick off the process of unregistering the device.
6689 + // This will call vmbus_remove() and eventually vmbus_device_release()
6690 + device_unregister(&device_ctx->device);
6691 +
6692 + //put_device(&device_ctx->device);
6693 + DPRINT_EXIT(VMBUS_DRV);
6694 +}
6695 +
6696 +
6697 +/*++
6698 +
6699 +Name: vmbus_probe()
6700 +
6701 +Desc: Add the new vmbus's child device
6702 +
6703 +--*/
6704 +static int vmbus_probe(struct device *child_device)
6705 +{
6706 + int ret=0;
6707 + struct driver_context *driver_ctx = driver_to_driver_context(child_device->driver);
6708 + struct device_context *device_ctx = device_to_device_context(child_device);
6709 +
6710 + DPRINT_ENTER(VMBUS_DRV);
6711 +
6712 + // Let the specific open-source driver handles the probe if it can
6713 + if (driver_ctx->probe)
6714 + {
6715 + ret = device_ctx->probe_error = driver_ctx->probe(child_device);
6716 + if (ret != 0)
6717 + {
6718 + 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);
6719 +
6720 +#ifdef KERNEL_2_6_27
6721 + INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb);
6722 +#else
6723 + INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb, device_ctx);
6724 +#endif
6725 + schedule_work(&device_ctx->probe_failed_work_item);
6726 + }
6727 + }
6728 + else
6729 + {
6730 + DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", child_device->driver->name);
6731 + ret = -1;
6732 + }
6733 +
6734 + DPRINT_EXIT(VMBUS_DRV);
6735 + return ret;
6736 +}
6737 +
6738 +
6739 +/*++
6740 +
6741 +Name: vmbus_remove()
6742 +
6743 +Desc: Remove a vmbus device
6744 +
6745 +--*/
6746 +static int vmbus_remove(struct device *child_device)
6747 +{
6748 + int ret=0;
6749 + struct driver_context *driver_ctx;
6750 +
6751 + DPRINT_ENTER(VMBUS_DRV);
6752 +
6753 + // Special case root bus device
6754 + if (child_device->parent == NULL)
6755 + {
6756 + // No-op since it is statically defined and handle in vmbus_bus_exit()
6757 + DPRINT_EXIT(VMBUS_DRV);
6758 + return 0;
6759 + }
6760 +
6761 + if (child_device->driver)
6762 + {
6763 + driver_ctx = driver_to_driver_context(child_device->driver);
6764 +
6765 + // Let the specific open-source driver handles the removal if it can
6766 + if (driver_ctx->remove)
6767 + {
6768 + ret = driver_ctx->remove(child_device);
6769 + }
6770 + else
6771 + {
6772 + DPRINT_ERR(VMBUS_DRV, "remove() method not set for driver - %s", child_device->driver->name);
6773 + ret = -1;
6774 + }
6775 + }
6776 + else
6777 + {
6778 +
6779 + }
6780 +
6781 + DPRINT_EXIT(VMBUS_DRV);
6782 +
6783 + return 0;
6784 +}
6785 +
6786 +/*++
6787 +
6788 +Name: vmbus_shutdown()
6789 +
6790 +Desc: Shutdown a vmbus device
6791 +
6792 +--*/
6793 +static void vmbus_shutdown(struct device *child_device)
6794 +{
6795 + struct driver_context *driver_ctx;
6796 +
6797 + DPRINT_ENTER(VMBUS_DRV);
6798 +
6799 + // Special case root bus device
6800 + if (child_device->parent == NULL)
6801 + {
6802 + // No-op since it is statically defined and handle in vmbus_bus_exit()
6803 + DPRINT_EXIT(VMBUS_DRV);
6804 + return;
6805 + }
6806 +
6807 + // The device may not be attached yet
6808 + if (!child_device->driver)
6809 + {
6810 + DPRINT_EXIT(VMBUS_DRV);
6811 + return;
6812 + }
6813 +
6814 + driver_ctx = driver_to_driver_context(child_device->driver);
6815 +
6816 + // Let the specific open-source driver handles the removal if it can
6817 + if (driver_ctx->shutdown)
6818 + {
6819 + driver_ctx->shutdown(child_device);
6820 + }
6821 +
6822 + DPRINT_EXIT(VMBUS_DRV);
6823 +
6824 + return;
6825 +}
6826 +
6827 +/*++
6828 +
6829 +Name: vmbus_bus_release()
6830 +
6831 +Desc: Final callback release of the vmbus root device
6832 +
6833 +--*/
6834 +static void vmbus_bus_release(struct device *device)
6835 +{
6836 + DPRINT_ENTER(VMBUS_DRV);
6837 + DPRINT_EXIT(VMBUS_DRV);
6838 +}
6839 +
6840 +/*++
6841 +
6842 +Name: vmbus_device_release()
6843 +
6844 +Desc: Final callback release of the vmbus child device
6845 +
6846 +--*/
6847 +static void vmbus_device_release(struct device *device)
6848 +{
6849 + struct device_context *device_ctx = device_to_device_context(device);
6850 +
6851 + DPRINT_ENTER(VMBUS_DRV);
6852 +
6853 + //vmbus_child_device_destroy(&device_ctx->device_obj);
6854 + kfree(device_ctx);
6855 +
6856 + // !!DO NOT REFERENCE device_ctx anymore at this point!!
6857 +
6858 + DPRINT_EXIT(VMBUS_DRV);
6859 +
6860 + return;
6861 +}
6862 +
6863 +/*++
6864 +
6865 +Name: vmbus_msg_dpc()
6866 +
6867 +Desc: Tasklet routine to handle hypervisor messages
6868 +
6869 +--*/
6870 +static void vmbus_msg_dpc(unsigned long data)
6871 +{
6872 + VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data;
6873 +
6874 + DPRINT_ENTER(VMBUS_DRV);
6875 +
6876 + ASSERT(vmbus_drv_obj->OnMsgDpc != NULL);
6877 +
6878 + // Call to bus driver to handle interrupt
6879 + vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base);
6880 +
6881 + DPRINT_EXIT(VMBUS_DRV);
6882 +}
6883 +
6884 +/*++
6885 +
6886 +Name: vmbus_msg_dpc()
6887 +
6888 +Desc: Tasklet routine to handle hypervisor events
6889 +
6890 +--*/
6891 +static void vmbus_event_dpc(unsigned long data)
6892 +{
6893 + VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data;
6894 +
6895 + DPRINT_ENTER(VMBUS_DRV);
6896 +
6897 + ASSERT(vmbus_drv_obj->OnEventDpc != NULL);
6898 +
6899 + // Call to bus driver to handle interrupt
6900 + vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base);
6901 +
6902 + DPRINT_EXIT(VMBUS_DRV);
6903 +}
6904 +
6905 +/*++
6906 +
6907 +Name: vmbus_msg_dpc()
6908 +
6909 +Desc: ISR routine
6910 +
6911 +--*/
6912 +#ifdef KERNEL_2_6_27
6913 +static irqreturn_t vmbus_isr(int irq, void* dev_id)
6914 +#else
6915 +static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs)
6916 +#endif
6917 +{
6918 + int ret=0;
6919 + VMBUS_DRIVER_OBJECT* vmbus_driver_obj = &g_vmbus_drv.drv_obj;
6920 +
6921 + DPRINT_ENTER(VMBUS_DRV);
6922 +
6923 + ASSERT(vmbus_driver_obj->OnIsr != NULL);
6924 +
6925 + // Call to bus driver to handle interrupt
6926 + ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base);
6927 +
6928 + // Schedules a dpc if necessary
6929 + if (ret > 0)
6930 + {
6931 + if (test_bit(0, (unsigned long*)&ret))
6932 + {
6933 + tasklet_schedule(&g_vmbus_drv.msg_dpc);
6934 + }
6935 +
6936 + if (test_bit(1, (unsigned long*)&ret))
6937 + {
6938 + tasklet_schedule(&g_vmbus_drv.event_dpc);
6939 + }
6940 +
6941 + DPRINT_EXIT(VMBUS_DRV);
6942 + return IRQ_HANDLED;
6943 + }
6944 + else
6945 + {
6946 + DPRINT_EXIT(VMBUS_DRV);
6947 + return IRQ_NONE;
6948 + }
6949 +}
6950 +
6951 +MODULE_LICENSE("GPL");
6952 +
6953 +
6954 +/*++
6955 +
6956 +Name: vmbus_init()
6957 +
6958 +Desc: Main vmbus driver entry routine
6959 +
6960 +--*/
6961 +static int __init vmbus_init(void)
6962 +{
6963 + int ret=0;
6964 +
6965 + DPRINT_ENTER(VMBUS_DRV);
6966 +
6967 + DPRINT_INFO(VMBUS_DRV,
6968 + "Vmbus initializing.... current log level 0x%x (%x,%x)",
6969 + vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
6970 +#ifdef KERNEL_2_6_27
6971 +//Todo: it is used for loglevel, to be ported to new kernel.
6972 +#else
6973 + vmbus_ctl_table_hdr = register_sysctl_table(vmus_root_ctl_table, 0);
6974 + if (!vmbus_ctl_table_hdr)
6975 + {
6976 + DPRINT_EXIT(VMBUS_DRV);
6977 + return -ENOMEM;
6978 + }
6979 +#endif
6980 +
6981 + ret = vmbus_bus_init(VmbusInitialize);
6982 +
6983 + DPRINT_EXIT(VMBUS_DRV);
6984 + return ret;
6985 +}
6986 +
6987 +
6988 +
6989 +/*++
6990 +
6991 +Name: vmbus_init()
6992 +
6993 +Desc: Main vmbus driver exit routine
6994 +
6995 +--*/
6996 +static void __exit vmbus_exit(void)
6997 +{
6998 + DPRINT_ENTER(VMBUS_DRV);
6999 +
7000 + vmbus_bus_exit();
7001 +#ifdef KERNEL_2_6_27
7002 +//Todo: it is used for loglevel, to be ported to new kernel.
7003 +#else
7004 + unregister_sysctl_table(vmbus_ctl_table_hdr);
7005 +#endif
7006 + DPRINT_EXIT(VMBUS_DRV);
7007 +
7008 + return;
7009 +}
7010 +
7011 +#if defined(KERNEL_2_6_5)
7012 +#else
7013 +module_param(vmbus_irq, int, S_IRUGO);
7014 +module_param(vmbus_loglevel, int, S_IRUGO);
7015 +#endif
7016 +
7017 +module_init(vmbus_init);
7018 +module_exit(vmbus_exit);
7019 +// eof
7020 --- /dev/null
7021 +++ b/drivers/staging/hv/VmbusPrivate.h
7022 @@ -0,0 +1,170 @@
7023 +/*
7024 + *
7025 + * Copyright (c) 2009, Microsoft Corporation.
7026 + *
7027 + * This program is free software; you can redistribute it and/or modify it
7028 + * under the terms and conditions of the GNU General Public License,
7029 + * version 2, as published by the Free Software Foundation.
7030 + *
7031 + * This program is distributed in the hope it will be useful, but WITHOUT
7032 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
7033 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
7034 + * more details.
7035 + *
7036 + * You should have received a copy of the GNU General Public License along with
7037 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
7038 + * Place - Suite 330, Boston, MA 02111-1307 USA.
7039 + *
7040 + * Authors:
7041 + * Haiyang Zhang <haiyangz@microsoft.com>
7042 + * Hank Janssen <hjanssen@microsoft.com>
7043 + *
7044 + */
7045 +
7046 +
7047 +#ifndef _VMBUS_PRIVATE_H_
7048 +#define _VMBUS_PRIVATE_H_
7049 +
7050 +#ifndef INTERNAL
7051 +#define INTERNAL static
7052 +#endif
7053 +
7054 +#include "Hv.h"
7055 +#include "VmbusApi.h"
7056 +#include "Channel.h"
7057 +#include "ChannelMgmt.h"
7058 +#include "ChannelInterface.h"
7059 +//#include "ChannelMessages.h"
7060 +#include "RingBuffer.h"
7061 +//#include "Packet.h"
7062 +#include "List.h"
7063 +
7064 +//
7065 +// Defines
7066 +//
7067 +
7068 +// Maximum channels is determined by the size of the interrupt page which is PAGE_SIZE. 1/2 of PAGE_SIZE is for
7069 +// send endpoint interrupt and the other is receive endpoint interrupt
7070 +#define MAX_NUM_CHANNELS (PAGE_SIZE >> 1) << 3 // 16348 channels
7071 +
7072 +// The value here must be in multiple of 32
7073 +// TODO: Need to make this configurable
7074 +#define MAX_NUM_CHANNELS_SUPPORTED 256
7075 +
7076 +//
7077 +// Data types
7078 +//
7079 +
7080 +typedef enum {
7081 + Disconnected,
7082 + Connecting,
7083 + Connected,
7084 + Disconnecting
7085 +} VMBUS_CONNECT_STATE;
7086 +
7087 +#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
7088 +
7089 +typedef struct _VMBUS_CONNECTION {
7090 +
7091 + VMBUS_CONNECT_STATE ConnectState;
7092 +
7093 + UINT32 NextGpadlHandle;
7094 +
7095 + // Represents channel interrupts. Each bit position
7096 + // represents a channel.
7097 + // When a channel sends an interrupt via VMBUS, it
7098 + // finds its bit in the sendInterruptPage, set it and
7099 + // calls Hv to generate a port event. The other end
7100 + // receives the port event and parse the recvInterruptPage
7101 + // to see which bit is set
7102 + VOID* InterruptPage;
7103 + VOID* SendInterruptPage;
7104 + VOID* RecvInterruptPage;
7105 +
7106 + // 2 pages - 1st page for parent->child notification and 2nd is child->parent notification
7107 + VOID* MonitorPages;
7108 + LIST_ENTRY ChannelMsgList;
7109 + HANDLE ChannelMsgLock;
7110 +
7111 + // List of channels
7112 + LIST_ENTRY ChannelList;
7113 + HANDLE ChannelLock;
7114 +
7115 + HANDLE WorkQueue;
7116 +} VMBUS_CONNECTION;
7117 +
7118 +
7119 +typedef struct _VMBUS_MSGINFO {
7120 + // Bookkeeping stuff
7121 + LIST_ENTRY MsgListEntry;
7122 +
7123 + // Synchronize the request/response if needed
7124 + HANDLE WaitEvent;
7125 +
7126 + // The message itself
7127 + unsigned char Msg[0];
7128 +} VMBUS_MSGINFO;
7129 +
7130 +
7131 +//
7132 +// Externs
7133 +//
7134 +extern VMBUS_CONNECTION gVmbusConnection;
7135 +
7136 +//
7137 +// General vmbus interface
7138 +//
7139 +INTERNAL DEVICE_OBJECT*
7140 +VmbusChildDeviceCreate(
7141 + GUID deviceType,
7142 + GUID deviceInstance,
7143 + void *context);
7144 +
7145 +INTERNAL int
7146 +VmbusChildDeviceAdd(
7147 + DEVICE_OBJECT* Device);
7148 +
7149 +INTERNAL void
7150 +VmbusChildDeviceRemove(
7151 + DEVICE_OBJECT* Device);
7152 +
7153 +//INTERNAL void
7154 +//VmbusChildDeviceDestroy(
7155 +// DEVICE_OBJECT*);
7156 +
7157 +INTERNAL VMBUS_CHANNEL*
7158 +GetChannelFromRelId(
7159 + UINT32 relId
7160 + );
7161 +
7162 +//
7163 +// Connection interface
7164 +//
7165 +INTERNAL int
7166 +VmbusConnect(
7167 + VOID
7168 + );
7169 +
7170 +INTERNAL int
7171 +VmbusDisconnect(
7172 + VOID
7173 + );
7174 +
7175 +INTERNAL int
7176 +VmbusPostMessage(
7177 + PVOID buffer,
7178 + SIZE_T bufSize
7179 + );
7180 +
7181 +INTERNAL int
7182 +VmbusSetEvent(
7183 + UINT32 childRelId
7184 + );
7185 +
7186 +INTERNAL VOID
7187 +VmbusOnEvents(
7188 + VOID
7189 + );
7190 +
7191 +
7192 +#endif // _VMBUS_PRIVATE_H_