]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - 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
CommitLineData
2cb7cef9
BS
1From foo@baz Mon Jul 13 16:02:34 PDT 2009
2Date: Mon, 13 Jul 2009 16:02:34 -0700
3From: Hank Janssen <hjanssen@microsoft.com>
4Subject: Staging: hv: add the Hyper-V virtual bus
5
6From: Hank Janssen <hjanssen@microsoft.com>
7
8This is the virtual bus that all of the Linux Hyper-V drivers use.
9
10Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
11Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
12Signed-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_