1 From foo@baz Mon Jul 13 16:02:34 PDT 2009
2 Date: Mon, 13 Jul 2009 16:02:34 -0700
3 From: Hank Janssen <hjanssen@microsoft.com>
4 Subject: Staging: hv: add the Hyper-V virtual bus
6 From: Hank Janssen <hjanssen@microsoft.com>
8 This is the virtual bus that all of the Linux Hyper-V drivers use.
10 Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
11 Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
12 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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(+)
35 +++ b/drivers/staging/hv/Channel.c
39 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
55 + * Haiyang Zhang <haiyangz@microsoft.com>
56 + * Hank Janssen <hjanssen@microsoft.com>
64 +#include "VmbusPrivate.h"
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
79 + VMBUS_CHANNEL *Channel
84 +VmbusChannelSetEvent(
85 + VMBUS_CHANNEL *Channel
92 + HV_MONITOR_PAGE *MonitorPage
98 + DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d", MonitorPage, MonitorPage->TriggerState);
100 + for (i=0; i<4; i++)
102 + DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i, MonitorPage->TriggerGroup[i].AsUINT64);
105 + for (i=0; i<4; i++)
107 + for (j=0; j<32; j++)
109 + DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j, MonitorPage->Latency[i][j]);
112 + for (i=0; i<4; i++)
114 + for (j=0; j<32; j++)
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);
127 + VmbusChannelSetEvent()
130 + Trigger an event notification on the specified channel.
134 +VmbusChannelSetEvent(
135 + VMBUS_CHANNEL *Channel
138 + HV_MONITOR_PAGE *monitorPage;
140 + DPRINT_ENTER(VMBUS);
142 + if (Channel->OfferMsg.MonitorAllocated)
144 + // Each UINT32 represents 32 channels
145 + BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31);
147 + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
148 + monitorPage++; // Get the child to parent monitor page
150 + BitSet((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit);
154 + VmbusSetEvent(Channel->OfferMsg.ChildRelId);
157 + DPRINT_EXIT(VMBUS);
162 +VmbusChannelClearEvent(
163 + VMBUS_CHANNEL *Channel
166 + HV_MONITOR_PAGE *monitorPage;
168 + DPRINT_ENTER(VMBUS);
170 + if (Channel->OfferMsg.MonitorAllocated)
172 + // Each UINT32 represents 32 channels
173 + BitClear((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31);
175 + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
176 + monitorPage++; // Get the child to parent monitor page
178 + BitClear((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit);
181 + DPRINT_EXIT(VMBUS);
188 + VmbusChannelGetDebugInfo()
191 + Retrieve various channel debug info
195 +VmbusChannelGetDebugInfo(
196 + VMBUS_CHANNEL *Channel,
197 + VMBUS_CHANNEL_DEBUG_INFO *DebugInfo
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;
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));
210 + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
212 + DebugInfo->MonitorId = Channel->OfferMsg.MonitorId;
214 + DebugInfo->ServerMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending;
215 + DebugInfo->ServerMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset];
216 + DebugInfo->ServerMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id;
220 + DebugInfo->ClientMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending;
221 + DebugInfo->ClientMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset];
222 + DebugInfo->ClientMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id;
224 + RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound);
225 + RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound);
235 + Open the specified channel.
240 + VMBUS_CHANNEL *NewChannel,
241 + UINT32 SendRingBufferSize,
242 + UINT32 RecvRingBufferSize,
244 + UINT32 UserDataLen,
245 + PFN_CHANNEL_CALLBACK pfnOnChannelCallback,
250 + VMBUS_CHANNEL_OPEN_CHANNEL* openMsg;
251 + VMBUS_CHANNEL_MSGINFO* openInfo;
254 + DPRINT_ENTER(VMBUS);
256 + // Aligned to page size
257 + ASSERT(!(SendRingBufferSize & (PAGE_SIZE -1)));
258 + ASSERT(!(RecvRingBufferSize & (PAGE_SIZE -1)));
260 + NewChannel->OnChannelCallback = pfnOnChannelCallback;
261 + NewChannel->ChannelCallbackContext = Context;
263 + // Allocate the ring buffer
264 + out = PageAlloc((SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT);
265 + //out = MemAllocZeroed(sendRingBufferSize + recvRingBufferSize);
267 + ASSERT(((ULONG_PTR)out & (PAGE_SIZE-1)) == 0);
269 + in = (void*)((ULONG_PTR)out + SendRingBufferSize);
271 + NewChannel->RingBufferPages = out;
272 + NewChannel->RingBufferPageCount = (SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT;
274 + RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize);
276 + RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize);
278 + // Establish the gpadl for the ring buffer
279 + DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...", NewChannel);
281 + NewChannel->RingBufferGpadlHandle = 0;
283 + ret = VmbusChannelEstablishGpadl(NewChannel,
284 + NewChannel->Outbound.RingBuffer,
285 + SendRingBufferSize + RecvRingBufferSize,
286 + &NewChannel->RingBufferGpadlHandle);
288 + DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p size %d recv ring %p size %d, downstreamoffset %d>",
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);
298 + // Create and init the channel open message
300 + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL));
301 + ASSERT(openInfo != NULL);
303 + openInfo->WaitEvent = WaitEventCreate();
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
314 + ASSERT(UserDataLen <= MAX_USER_DEFINED_BYTES);
317 + memcpy(openMsg->UserData, UserData, UserDataLen);
320 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
321 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &openInfo->MsgListEntry);
322 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
324 + DPRINT_DBG(VMBUS, "Sending channel open msg...");
326 + ret = VmbusPostMessage(openMsg, sizeof(VMBUS_CHANNEL_OPEN_CHANNEL));
329 + DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
333 + // FIXME: Need to time-out here
334 + WaitEventWait(openInfo->WaitEvent);
336 + if (openInfo->Response.OpenResult.Status == 0)
338 + DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel);
342 + DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!", NewChannel, openInfo->Response.OpenResult.Status);
346 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
347 + REMOVE_ENTRY_LIST(&openInfo->MsgListEntry);
348 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
350 + WaitEventClose(openInfo->WaitEvent);
353 + DPRINT_EXIT(VMBUS);
364 + Dump the gpadl body message to the console for debugging purposes.
367 +static void DumpGpadlBody(
368 + VMBUS_CHANNEL_GPADL_BODY *Gpadl,
374 + pfnCount = (Len - sizeof(VMBUS_CHANNEL_GPADL_BODY))/ sizeof(UINT64);
375 + DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount);
377 + for (i=0; i< pfnCount; i++)
379 + DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", i, Gpadl->Pfn[i]);
390 + Dump the gpadl header message to the console for debugging purposes.
393 +static void DumpGpadlHeader(
394 + VMBUS_CHANNEL_GPADL_HEADER *Gpadl
401 + DPRINT_DBG(VMBUS, "gpadl header - relid %d, range count %d, range buflen %d",
404 + Gpadl->RangeBufLen);
405 + for (i=0; i< Gpadl->RangeCount; i++)
407 + pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT;
408 + pageCount = (pageCount > 26)? 26 : pageCount;
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);
413 + for (j=0; j< pageCount; j++)
415 + DPRINT_DBG(VMBUS, "%d) pfn %llu", j, Gpadl->Range[i].PfnArray[j]);
423 + VmbusChannelCreateGpadlHeader()
426 + Creates a gpadl for the specified buffer
430 +VmbusChannelCreateGpadlHeader(
431 + PVOID Kbuffer, // from kmalloc()
432 + UINT32 Size, // page-size multiple
433 + VMBUS_CHANNEL_MSGINFO **MsgInfo,
434 + UINT32 *MessageCount)
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;
445 + int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize;
447 + //ASSERT( (kbuffer & (PAGE_SIZE-1)) == 0);
448 + ASSERT( (Size & (PAGE_SIZE-1)) == 0);
450 + pageCount = Size >> PAGE_SHIFT;
451 + pfn = GetPhysicalAddress(Kbuffer) >> PAGE_SHIFT;
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);
457 + if (pageCount > pfnCount) // we need a gpadl body
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);
463 + INITIALIZE_LIST_HEAD(&msgHeader->SubMsgList);
464 + msgHeader->MessageSize=msgSize;
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++)
473 + gpaHeader->Range[0].PfnArray[i] = pfn+i;
475 + *MsgInfo = msgHeader;
479 + pfnLeft = pageCount - pfnCount;
481 + // how many pfns can we fit
482 + pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_BODY);
483 + pfnCount = pfnSize / sizeof(UINT64);
485 + // fill in the body
488 + if (pfnLeft > pfnCount)
490 + pfnCurr = pfnCount;
497 + msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_BODY) + pfnCurr*sizeof(UINT64);
498 + msgBody = MemAllocZeroed(msgSize);
500 + msgBody->MessageSize = msgSize;
502 + gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)msgBody->Msg;
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++)
508 + gpadlBody->Pfn[i] = pfn + pfnSum + i;
511 + // add to msg header
512 + INSERT_TAIL_LIST(&msgHeader->SubMsgList, &msgBody->MsgListEntry);
514 + pfnLeft -= pfnCurr;
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;
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++)
531 + gpaHeader->Range[0].PfnArray[i] = pfn+i;
534 + *MsgInfo = msgHeader;
545 + VmbusChannelEstablishGpadl()
548 + Estabish a GPADL for the specified buffer
552 +VmbusChannelEstablishGpadl(
553 + VMBUS_CHANNEL *Channel,
554 + PVOID Kbuffer, // from kmalloc()
555 + UINT32 Size, // page-size multiple
556 + UINT32 *GpadlHandle
560 + VMBUS_CHANNEL_GPADL_HEADER* gpadlMsg;
561 + VMBUS_CHANNEL_GPADL_BODY* gpadlBody;
562 + //VMBUS_CHANNEL_GPADL_CREATED* gpadlCreated;
564 + VMBUS_CHANNEL_MSGINFO *msgInfo;
565 + VMBUS_CHANNEL_MSGINFO *subMsgInfo;
568 + LIST_ENTRY* anchor;
570 + UINT32 nextGpadlHandle;
572 + DPRINT_ENTER(VMBUS);
574 + nextGpadlHandle = gVmbusConnection.NextGpadlHandle;
575 + InterlockedIncrement((int*)&gVmbusConnection.NextGpadlHandle);
577 + VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount);
578 + ASSERT(msgInfo != NULL);
579 + ASSERT(msgCount >0);
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;
587 + DumpGpadlHeader(gpadlMsg);
589 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
590 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
591 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
593 + DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d", Kbuffer, Size, msgCount);
595 + DPRINT_DBG(VMBUS, "Sending GPADL Header - len %d", msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
597 + ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
600 + DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
606 + ITERATE_LIST_ENTRIES(anchor, curr, &msgInfo->SubMsgList)
608 + subMsgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
609 + gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)subMsgInfo->Msg;
611 + gpadlBody->Header.MessageType = ChannelMessageGpadlBody;
612 + gpadlBody->Gpadl = nextGpadlHandle;
614 + DPRINT_DBG(VMBUS, "Sending GPADL Body - len %d", subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
616 + DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
617 + ret = VmbusPostMessage(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
621 + WaitEventWait(msgInfo->WaitEvent);
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,
629 + *GpadlHandle = gpadlMsg->Gpadl;
632 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
633 + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
634 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
636 + WaitEventClose(msgInfo->WaitEvent);
639 + DPRINT_EXIT(VMBUS);
649 + VmbusChannelTeardownGpadl()
652 + Teardown the specified GPADL handle
656 +VmbusChannelTeardownGpadl(
657 + VMBUS_CHANNEL *Channel,
662 + VMBUS_CHANNEL_GPADL_TEARDOWN *msg;
663 + VMBUS_CHANNEL_MSGINFO* info;
665 + DPRINT_ENTER(VMBUS);
667 + ASSERT(GpadlHandle != 0);
670 + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN));
671 + ASSERT(info != NULL);
673 + info->WaitEvent = WaitEventCreate();
675 + msg = (VMBUS_CHANNEL_GPADL_TEARDOWN*)info->Msg;
677 + msg->Header.MessageType = ChannelMessageGpadlTeardown;
678 + msg->ChildRelId = Channel->OfferMsg.ChildRelId;
679 + msg->Gpadl = GpadlHandle;
681 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
682 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &info->MsgListEntry);
683 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
685 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN));
691 + WaitEventWait(info->WaitEvent);
693 + // Received a torndown response
694 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
695 + REMOVE_ENTRY_LIST(&info->MsgListEntry);
696 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
698 + WaitEventClose(info->WaitEvent);
701 + DPRINT_EXIT(VMBUS);
710 + VmbusChannelClose()
713 + Close the specified channel
718 + VMBUS_CHANNEL *Channel
722 + VMBUS_CHANNEL_CLOSE_CHANNEL* msg;
723 + VMBUS_CHANNEL_MSGINFO* info;
725 + DPRINT_ENTER(VMBUS);
727 + // Stop callback and cancel the timer asap
728 + Channel->OnChannelCallback = NULL;
729 + TimerStop(Channel->PollTimer);
731 + // Send a closing message
733 + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL));
734 + ASSERT(info != NULL);
736 + //info->waitEvent = WaitEventCreate();
738 + msg = (VMBUS_CHANNEL_CLOSE_CHANNEL*)info->Msg;
739 + msg->Header.MessageType = ChannelMessageCloseChannel;
740 + msg->ChildRelId = Channel->OfferMsg.ChildRelId;
742 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL));
748 + // Tear down the gpadl for the channel's ring buffer
749 + if (Channel->RingBufferGpadlHandle)
751 + VmbusChannelTeardownGpadl(Channel, Channel->RingBufferGpadlHandle);
754 + // TODO: Send a msg to release the childRelId
756 + // Cleanup the ring buffers for this channel
757 + RingBufferCleanup(&Channel->Outbound);
758 + RingBufferCleanup(&Channel->Inbound);
760 + PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount);
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)
768 + SpinlockAcquire(gVmbusConnection.ChannelLock);
769 + REMOVE_ENTRY_LIST(&Channel->ListEntry);
770 + SpinlockRelease(gVmbusConnection.ChannelLock);
772 + FreeVmbusChannel(Channel);
775 + DPRINT_EXIT(VMBUS);
782 + VmbusChannelSendPacket()
785 + Send the specified buffer on the given channel
789 +VmbusChannelSendPacket(
790 + VMBUS_CHANNEL *Channel,
791 + const PVOID Buffer,
794 + VMBUS_PACKET_TYPE Type,
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;
805 + DPRINT_ENTER(VMBUS);
806 + DPRINT_DBG(VMBUS, "channel %p buffer %p len %d", Channel, Buffer, BufferLen);
808 + DumpVmbusChannel(Channel);
810 + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
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;
819 + bufferList[0].Data = &desc;
820 + bufferList[0].Length = sizeof(VMPACKET_DESCRIPTOR);
822 + bufferList[1].Data = Buffer;
823 + bufferList[1].Length = BufferLen;
825 + bufferList[2].Data = &alignedData;
826 + bufferList[2].Length = packetLenAligned - packetLen;
828 + ret = RingBufferWrite(
829 + &Channel->Outbound,
833 + // TODO: We should determine if this is optional
834 + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
836 + VmbusChannelSetEvent(Channel);
839 + DPRINT_EXIT(VMBUS);
848 + VmbusChannelSendPacketPageBuffer()
851 + Send a range of single-page buffer packets using a GPADL Direct packet type.
855 +VmbusChannelSendPacketPageBuffer(
856 + VMBUS_CHANNEL *Channel,
857 + PAGE_BUFFER PageBuffers[],
866 + VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc;
869 + UINT32 packetLenAligned;
870 + SG_BUFFER_LIST bufferList[3];
871 + UINT64 alignedData=0;
873 + DPRINT_ENTER(VMBUS);
875 + ASSERT(PageCount <= MAX_PAGE_BUFFER_COUNT);
877 + DumpVmbusChannel(Channel);
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));
884 + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
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;
894 + for (i=0; i<PageCount; i++)
896 + desc.Range[i].Length = PageBuffers[i].Length;
897 + desc.Range[i].Offset = PageBuffers[i].Offset;
898 + desc.Range[i].Pfn = PageBuffers[i].Pfn;
901 + bufferList[0].Data = &desc;
902 + bufferList[0].Length = descSize;
904 + bufferList[1].Data = Buffer;
905 + bufferList[1].Length = BufferLen;
907 + bufferList[2].Data = &alignedData;
908 + bufferList[2].Length = packetLenAligned - packetLen;
910 + ret = RingBufferWrite(
911 + &Channel->Outbound,
915 + // TODO: We should determine if this is optional
916 + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
918 + VmbusChannelSetEvent(Channel);
921 + DPRINT_EXIT(VMBUS);
931 + VmbusChannelSendPacketMultiPageBuffer()
934 + Send a multi-page buffer packet using a GPADL Direct packet type.
938 +VmbusChannelSendPacketMultiPageBuffer(
939 + VMBUS_CHANNEL *Channel,
940 + MULTIPAGE_BUFFER *MultiPageBuffer,
947 + VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc;
950 + UINT32 packetLenAligned;
951 + SG_BUFFER_LIST bufferList[3];
952 + UINT64 alignedData=0;
953 + UINT32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset, MultiPageBuffer->Length);
955 + DPRINT_ENTER(VMBUS);
957 + DumpVmbusChannel(Channel);
959 + DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount);
961 + ASSERT(PfnCount > 0);
962 + ASSERT(PfnCount <= MAX_MULTIPAGE_BUFFER_COUNT);
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));
969 + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
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;
979 + desc.Range.Length = MultiPageBuffer->Length;
980 + desc.Range.Offset = MultiPageBuffer->Offset;
982 + memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray, PfnCount*sizeof(UINT64));
984 + bufferList[0].Data = &desc;
985 + bufferList[0].Length = descSize;
987 + bufferList[1].Data = Buffer;
988 + bufferList[1].Length = BufferLen;
990 + bufferList[2].Data = &alignedData;
991 + bufferList[2].Length = packetLenAligned - packetLen;
993 + ret = RingBufferWrite(
994 + &Channel->Outbound,
998 + // TODO: We should determine if this is optional
999 + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
1001 + VmbusChannelSetEvent(Channel);
1004 + DPRINT_EXIT(VMBUS);
1013 + VmbusChannelRecvPacket()
1016 + Retrieve the user packet on the specified channel
1019 +// TODO: Do we ever receive a gpa direct packet other than the ones we send ?
1021 +VmbusChannelRecvPacket(
1022 + VMBUS_CHANNEL *Channel,
1025 + UINT32* BufferActualLen,
1029 + VMPACKET_DESCRIPTOR desc;
1034 + DPRINT_ENTER(VMBUS);
1036 + *BufferActualLen = 0;
1039 + SpinlockAcquire(Channel->InboundLock);
1041 + ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR));
1044 + SpinlockRelease(Channel->InboundLock);
1046 + //DPRINT_DBG(VMBUS, "nothing to read!!");
1047 + DPRINT_EXIT(VMBUS);
1051 + //VmbusChannelClearEvent(Channel);
1053 + packetLen = desc.Length8 << 3;
1054 + userLen = packetLen - (desc.DataOffset8 << 3);
1055 + //ASSERT(userLen > 0);
1057 + DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1059 + Channel->OfferMsg.ChildRelId,
1062 + desc.TransactionId, packetLen, userLen);
1064 + *BufferActualLen = userLen;
1066 + if (userLen > BufferLen)
1068 + SpinlockRelease(Channel->InboundLock);
1070 + DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d", BufferLen, userLen);
1071 + DPRINT_EXIT(VMBUS);
1076 + *RequestId = desc.TransactionId;
1078 + // Copy over the packet to the user buffer
1079 + ret = RingBufferRead(&Channel->Inbound, Buffer, userLen, (desc.DataOffset8 << 3));
1081 + SpinlockRelease(Channel->InboundLock);
1083 + DPRINT_EXIT(VMBUS);
1091 + VmbusChannelRecvPacketRaw()
1094 + Retrieve the raw packet on the specified channel
1098 +VmbusChannelRecvPacketRaw(
1099 + VMBUS_CHANNEL *Channel,
1102 + UINT32* BufferActualLen,
1106 + VMPACKET_DESCRIPTOR desc;
1111 + DPRINT_ENTER(VMBUS);
1113 + *BufferActualLen = 0;
1116 + SpinlockAcquire(Channel->InboundLock);
1118 + ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR));
1121 + SpinlockRelease(Channel->InboundLock);
1123 + //DPRINT_DBG(VMBUS, "nothing to read!!");
1124 + DPRINT_EXIT(VMBUS);
1128 + //VmbusChannelClearEvent(Channel);
1130 + packetLen = desc.Length8 << 3;
1131 + userLen = packetLen - (desc.DataOffset8 << 3);
1133 + DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1135 + Channel->OfferMsg.ChildRelId,
1138 + desc.TransactionId, packetLen, userLen);
1140 + *BufferActualLen = packetLen;
1142 + if (packetLen > BufferLen)
1144 + SpinlockRelease(Channel->InboundLock);
1146 + DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen, BufferLen);
1147 + DPRINT_EXIT(VMBUS);
1151 + *RequestId = desc.TransactionId;
1153 + // Copy over the entire packet to the user buffer
1154 + ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0);
1156 + SpinlockRelease(Channel->InboundLock);
1158 + DPRINT_EXIT(VMBUS);
1167 + VmbusChannelOnChannelEvent()
1170 + Channel event callback
1174 +VmbusChannelOnChannelEvent(
1175 + VMBUS_CHANNEL *Channel
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 */);
1185 + Channel->OnChannelCallback(Channel->ChannelCallbackContext);
1192 + VmbusChannelOnTimer()
1195 + Timer event callback
1199 +VmbusChannelOnTimer(
1203 + VMBUS_CHANNEL *channel = (VMBUS_CHANNEL*)Context;
1205 + if (channel->OnChannelCallback)
1207 + channel->OnChannelCallback(channel->ChannelCallbackContext);
1208 +#ifdef ENABLE_POLLING
1209 + TimerStart(channel->PollTimer, 100 /* 100us */);
1218 + DumpVmbusChannel()
1221 + Dump vmbus channel info to the console
1226 + VMBUS_CHANNEL *Channel
1229 + DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId);
1230 + DumpRingInfo(&Channel->Outbound, "Outbound ");
1231 + DumpRingInfo(&Channel->Inbound, "Inbound ");
1237 +++ b/drivers/staging/hv/Channel.h
1241 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
1257 + * Haiyang Zhang <haiyangz@microsoft.com>
1258 + * Hank Janssen <hjanssen@microsoft.com>
1263 +#ifndef _CHANNEL_H_
1264 +#define _CHANNEL_H_
1267 +#include "ChannelMgmt.h"
1269 +#pragma pack(push,1)
1272 +// The format must be the same as VMDATA_GPA_DIRECT
1273 +typedef struct _VMBUS_CHANNEL_PACKET_PAGE_BUFFER {
1275 + UINT16 DataOffset8;
1278 + UINT64 TransactionId;
1280 + UINT32 RangeCount;
1281 + PAGE_BUFFER Range[MAX_PAGE_BUFFER_COUNT];
1282 +} VMBUS_CHANNEL_PACKET_PAGE_BUFFER;
1285 +// The format must be the same as VMDATA_GPA_DIRECT
1286 +typedef struct _VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER {
1288 + UINT16 DataOffset8;
1291 + UINT64 TransactionId;
1293 + UINT32 RangeCount; // Always 1 in this case
1294 + MULTIPAGE_BUFFER Range;
1295 +} VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER;
1305 + VMBUS_CHANNEL *Channel,
1306 + UINT32 SendRingBufferSize,
1307 + UINT32 RecvRingBufferSize,
1309 + UINT32 UserDataLen,
1310 + PFN_CHANNEL_CALLBACK pfnOnChannelCallback,
1316 + VMBUS_CHANNEL *Channel
1320 +VmbusChannelSendPacket(
1321 + VMBUS_CHANNEL *Channel,
1322 + const PVOID Buffer,
1325 + VMBUS_PACKET_TYPE Type,
1330 +VmbusChannelSendPacketPageBuffer(
1331 + VMBUS_CHANNEL *Channel,
1332 + PAGE_BUFFER PageBuffers[],
1340 +VmbusChannelSendPacketMultiPageBuffer(
1341 + VMBUS_CHANNEL *Channel,
1342 + MULTIPAGE_BUFFER *MultiPageBuffer,
1349 +VmbusChannelEstablishGpadl(
1350 + VMBUS_CHANNEL *Channel,
1351 + PVOID Kbuffer, // from kmalloc()
1352 + UINT32 Size, // page-size multiple
1353 + UINT32 *GpadlHandle
1357 +VmbusChannelTeardownGpadl(
1358 + VMBUS_CHANNEL *Channel,
1359 + UINT32 GpadlHandle
1363 +VmbusChannelRecvPacket(
1364 + VMBUS_CHANNEL *Channel,
1367 + UINT32* BufferActualLen,
1372 +VmbusChannelRecvPacketRaw(
1373 + VMBUS_CHANNEL *Channel,
1376 + UINT32* BufferActualLen,
1381 +VmbusChannelOnChannelEvent(
1382 + VMBUS_CHANNEL *Channel
1386 +VmbusChannelGetDebugInfo(
1387 + VMBUS_CHANNEL *Channel,
1388 + VMBUS_CHANNEL_DEBUG_INFO *DebugInfo
1392 +VmbusChannelOnTimer(
1395 +#endif //_CHANNEL_H_
1397 +++ b/drivers/staging/hv/ChannelInterface.c
1401 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
1417 + * Haiyang Zhang <haiyangz@microsoft.com>
1418 + * Hank Janssen <hjanssen@microsoft.com>
1422 +#include "VmbusPrivate.h"
1426 + PDEVICE_OBJECT Device,
1427 + UINT32 SendBufferSize,
1428 + UINT32 RecvRingBufferSize,
1430 + UINT32 UserDataLen,
1431 + VMBUS_CHANNEL_CALLBACK ChannelCallback,
1435 + return VmbusChannelOpen( (VMBUS_CHANNEL*)Device->context,
1437 + RecvRingBufferSize,
1446 +IVmbusChannelClose(
1447 + PDEVICE_OBJECT Device
1450 + VmbusChannelClose((VMBUS_CHANNEL*)Device->context);
1455 +IVmbusChannelSendPacket(
1456 + PDEVICE_OBJECT Device,
1457 + const PVOID Buffer,
1464 + return VmbusChannelSendPacket((VMBUS_CHANNEL*)Device->context,
1473 +IVmbusChannelSendPacketPageBuffer(
1474 + PDEVICE_OBJECT Device,
1475 + PAGE_BUFFER PageBuffers[],
1482 + return VmbusChannelSendPacketPageBuffer((VMBUS_CHANNEL*)Device->context,
1491 +IVmbusChannelSendPacketMultiPageBuffer(
1492 + PDEVICE_OBJECT Device,
1493 + MULTIPAGE_BUFFER *MultiPageBuffer,
1499 + return VmbusChannelSendPacketMultiPageBuffer((VMBUS_CHANNEL*)Device->context,
1507 +IVmbusChannelRecvPacket (
1508 + PDEVICE_OBJECT Device,
1511 + UINT32* BufferActualLen,
1515 + return VmbusChannelRecvPacket((VMBUS_CHANNEL*)Device->context,
1523 +IVmbusChannelRecvPacketRaw(
1524 + PDEVICE_OBJECT Device,
1527 + UINT32* BufferActualLen,
1531 + return VmbusChannelRecvPacketRaw((VMBUS_CHANNEL*)Device->context,
1539 +IVmbusChannelEstablishGpadl(
1540 + PDEVICE_OBJECT Device,
1543 + UINT32* GpadlHandle
1546 + return VmbusChannelEstablishGpadl((VMBUS_CHANNEL*)Device->context,
1553 +IVmbusChannelTeardownGpadl(
1554 + PDEVICE_OBJECT Device,
1555 + UINT32 GpadlHandle
1558 + return VmbusChannelTeardownGpadl((VMBUS_CHANNEL*)Device->context,
1564 +GetChannelInterface(
1565 + VMBUS_CHANNEL_INTERFACE *ChannelInterface
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;
1583 + PDEVICE_OBJECT Device,
1584 + DEVICE_INFO *DeviceInfo
1587 + VMBUS_CHANNEL_DEBUG_INFO debugInfo;
1589 + if (Device->context)
1591 + VmbusChannelGetDebugInfo((VMBUS_CHANNEL*)Device->context, &debugInfo);
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));
1598 + DeviceInfo->MonitorId = debugInfo.MonitorId;
1600 + DeviceInfo->ServerMonitorPending = debugInfo.ServerMonitorPending;
1601 + DeviceInfo->ServerMonitorLatency = debugInfo.ServerMonitorLatency;
1602 + DeviceInfo->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId;
1604 + DeviceInfo->ClientMonitorPending = debugInfo.ClientMonitorPending;
1605 + DeviceInfo->ClientMonitorLatency = debugInfo.ClientMonitorLatency;
1606 + DeviceInfo->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId;
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;
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;
1622 +++ b/drivers/staging/hv/ChannelInterface.h
1626 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
1642 + * Haiyang Zhang <haiyangz@microsoft.com>
1643 + * Hank Janssen <hjanssen@microsoft.com>
1648 +#ifndef _CHANNEL_INTERFACE_H_
1649 +#define _CHANNEL_INTERFACE_H_
1651 +#include "VmbusApi.h"
1654 +GetChannelInterface(
1655 + VMBUS_CHANNEL_INTERFACE *ChannelInterface
1660 + PDEVICE_OBJECT Device,
1661 + DEVICE_INFO *DeviceInfo
1664 +#endif // _CHANNEL_INTERFACE_H_
1666 +++ b/drivers/staging/hv/ChannelMgmt.c
1670 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
1686 + * Haiyang Zhang <haiyangz@microsoft.com>
1687 + * Hank Janssen <hjanssen@microsoft.com>
1693 +#include "logging.h"
1695 +#include "VmbusPrivate.h"
1705 +typedef void (*PFN_CHANNEL_MESSAGE_HANDLER)(VMBUS_CHANNEL_MESSAGE_HEADER* msg);
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;
1713 +// Internal routines
1717 +VmbusChannelOnOffer(
1718 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1721 +VmbusChannelOnOpenResult(
1722 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1726 +VmbusChannelOnOfferRescind(
1727 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1731 +VmbusChannelOnGpadlCreated(
1732 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1736 +VmbusChannelOnGpadlTorndown(
1737 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1741 +VmbusChannelOnOffersDelivered(
1742 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1746 +VmbusChannelOnVersionResponse(
1747 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
1751 +VmbusChannelProcessOffer(
1756 +VmbusChannelProcessRescindOffer(
1765 +#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
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
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},
1803 + AllocVmbusChannel()
1806 + Allocate and initialize a vmbus channel object
1809 +VMBUS_CHANNEL* AllocVmbusChannel(void)
1811 + VMBUS_CHANNEL* channel;
1813 + channel = (VMBUS_CHANNEL*) MemAllocAtomic(sizeof(VMBUS_CHANNEL));
1819 + memset(channel, 0,sizeof(VMBUS_CHANNEL));
1820 + channel->InboundLock = SpinlockCreate();
1821 + if (!channel->InboundLock)
1827 + channel->PollTimer = TimerCreate(VmbusChannelOnTimer, channel);
1828 + if (!channel->PollTimer)
1830 + SpinlockClose(channel->InboundLock);
1835 + //channel->dataWorkQueue = WorkQueueCreate("data");
1836 + channel->ControlWQ = WorkQueueCreate("control");
1837 + if (!channel->ControlWQ)
1839 + TimerClose(channel->PollTimer);
1840 + SpinlockClose(channel->InboundLock);
1851 + ReleaseVmbusChannel()
1854 + Release the vmbus channel object itself
1857 +static inline void ReleaseVmbusChannel(void* Context)
1859 + VMBUS_CHANNEL* channel = (VMBUS_CHANNEL*)Context;
1861 + DPRINT_ENTER(VMBUS);
1863 + DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
1864 + WorkQueueClose(channel->ControlWQ);
1865 + DPRINT_DBG(VMBUS, "channel released (%p)", channel);
1869 + DPRINT_EXIT(VMBUS);
1875 + FreeVmbusChannel()
1878 + Release the resources used by the vmbus channel object
1881 +void FreeVmbusChannel(VMBUS_CHANNEL* Channel)
1883 + SpinlockClose(Channel->InboundLock);
1884 + TimerClose(Channel->PollTimer);
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);
1895 + VmbusChannelProcessOffer()
1898 + Process the offer by creating a channel/device associated with this offer
1902 +VmbusChannelProcessOffer(
1907 + VMBUS_CHANNEL* newChannel=(VMBUS_CHANNEL*)context;
1908 + LIST_ENTRY* anchor;
1911 + VMBUS_CHANNEL* channel;
1913 + DPRINT_ENTER(VMBUS);
1915 + // Make sure this is a new offer
1916 + SpinlockAcquire(gVmbusConnection.ChannelLock);
1918 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
1920 + channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
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)))
1932 + INSERT_TAIL_LIST(&gVmbusConnection.ChannelList, &newChannel->ListEntry);
1934 + SpinlockRelease(gVmbusConnection.ChannelLock);
1938 + DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", newChannel->OfferMsg.ChildRelId);
1939 + FreeVmbusChannel(newChannel);
1940 + DPRINT_EXIT(VMBUS);
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,
1951 + DPRINT_DBG(VMBUS, "child device object allocated - %p", newChannel->DeviceObject);
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);
1958 + DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)",
1959 + newChannel->OfferMsg.ChildRelId);
1961 + SpinlockAcquire(gVmbusConnection.ChannelLock);
1962 + REMOVE_ENTRY_LIST(&newChannel->ListEntry);
1963 + SpinlockRelease(gVmbusConnection.ChannelLock);
1965 + FreeVmbusChannel(newChannel);
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;
1973 + DPRINT_EXIT(VMBUS);
1979 + VmbusChannelProcessRescindOffer()
1982 + Rescind the offer by initiating a device removal
1986 +VmbusChannelProcessRescindOffer(
1990 + VMBUS_CHANNEL* channel=(VMBUS_CHANNEL*)context;
1992 + DPRINT_ENTER(VMBUS);
1994 + VmbusChildDeviceRemove(channel->DeviceObject);
1996 + DPRINT_EXIT(VMBUS);
2003 + VmbusChannelOnOffer()
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
2012 +VmbusChannelOnOffer(
2013 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2016 + VMBUS_CHANNEL_OFFER_CHANNEL* offer = (VMBUS_CHANNEL_OFFER_CHANNEL*)hdr;
2017 + VMBUS_CHANNEL* newChannel;
2020 + GUID *guidInstance;
2024 + DPRINT_ENTER(VMBUS);
2026 + for (i=0; i<MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++)
2028 + if (memcmp(&offer->Offer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(GUID)) == 0)
2037 + DPRINT_DBG(VMBUS, "Ignoring channel offer notification for child relid %d", offer->ChildRelId);
2038 + DPRINT_EXIT(VMBUS);
2043 + guidType = &offer->Offer.InterfaceType;
2044 + guidInstance = &offer->Offer.InterfaceInstance;
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,
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]);
2055 + // Allocate the channel object and save this offer.
2056 + newChannel = AllocVmbusChannel();
2059 + DPRINT_ERR(VMBUS, "unable to allocate channel object");
2063 + DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
2065 + memcpy(&newChannel->OfferMsg, offer, sizeof(VMBUS_CHANNEL_OFFER_CHANNEL));
2066 + newChannel->MonitorGroup = (UINT8)offer->MonitorId / 32;
2067 + newChannel->MonitorBit = (UINT8)offer->MonitorId % 32;
2069 + // TODO: Make sure the offer comes from our parent partition
2070 + WorkQueueQueueWorkItem(newChannel->ControlWQ, VmbusChannelProcessOffer, newChannel);
2072 + DPRINT_EXIT(VMBUS);
2079 + VmbusChannelOnOfferRescind()
2082 + Rescind offer handler. We queue a work item to process this offer
2087 +VmbusChannelOnOfferRescind(
2088 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2091 + VMBUS_CHANNEL_RESCIND_OFFER* rescind = (VMBUS_CHANNEL_RESCIND_OFFER*)hdr;
2092 + VMBUS_CHANNEL* channel;
2094 + DPRINT_ENTER(VMBUS);
2096 + channel = GetChannelFromRelId(rescind->ChildRelId);
2097 + if (channel == NULL)
2099 + DPRINT_DBG(VMBUS, "channel not found for relId %d", rescind->ChildRelId);
2103 + WorkQueueQueueWorkItem(channel->ControlWQ, VmbusChannelProcessRescindOffer, channel);
2105 + DPRINT_EXIT(VMBUS);
2112 + VmbusChannelOnOffersDelivered()
2115 + This is invoked when all offers have been delivered.
2116 + Nothing to do here.
2120 +VmbusChannelOnOffersDelivered(
2121 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2124 + DPRINT_ENTER(VMBUS);
2125 + DPRINT_EXIT(VMBUS);
2132 + VmbusChannelOnOpenResult()
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.
2141 +VmbusChannelOnOpenResult(
2142 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2145 + VMBUS_CHANNEL_OPEN_RESULT* result = (VMBUS_CHANNEL_OPEN_RESULT*)hdr;
2146 + LIST_ENTRY* anchor;
2148 + VMBUS_CHANNEL_MSGINFO* msgInfo;
2149 + VMBUS_CHANNEL_MESSAGE_HEADER* requestHeader;
2150 + VMBUS_CHANNEL_OPEN_CHANNEL* openMsg;
2152 + DPRINT_ENTER(VMBUS);
2154 + DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
2156 + // Find the open msg, copy the result and signal/unblock the wait event
2157 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2159 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
2161 + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
2162 + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2164 + if (requestHeader->MessageType == ChannelMessageOpenChannel)
2166 + openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)msgInfo->Msg;
2167 + if (openMsg->ChildRelId == result->ChildRelId &&
2168 + openMsg->OpenId == result->OpenId)
2170 + memcpy(&msgInfo->Response.OpenResult, result, sizeof(VMBUS_CHANNEL_OPEN_RESULT));
2171 + WaitEventSet(msgInfo->WaitEvent);
2176 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2178 + DPRINT_EXIT(VMBUS);
2185 + VmbusChannelOnGpadlCreated()
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.
2194 +VmbusChannelOnGpadlCreated(
2195 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2198 + VMBUS_CHANNEL_GPADL_CREATED *gpadlCreated = (VMBUS_CHANNEL_GPADL_CREATED*)hdr;
2199 + LIST_ENTRY *anchor;
2201 + VMBUS_CHANNEL_MSGINFO *msgInfo;
2202 + VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
2203 + VMBUS_CHANNEL_GPADL_HEADER *gpadlHeader;
2205 + DPRINT_ENTER(VMBUS);
2207 + DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", gpadlCreated->CreationStatus);
2209 + // Find the establish msg, copy the result and signal/unblock the wait event
2210 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2212 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
2214 + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
2215 + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2217 + if (requestHeader->MessageType == ChannelMessageGpadlHeader)
2219 + gpadlHeader = (VMBUS_CHANNEL_GPADL_HEADER*)requestHeader;
2221 + if ((gpadlCreated->ChildRelId == gpadlHeader->ChildRelId) &&
2222 + (gpadlCreated->Gpadl == gpadlHeader->Gpadl))
2224 + memcpy(&msgInfo->Response.GpadlCreated, gpadlCreated, sizeof(VMBUS_CHANNEL_GPADL_CREATED));
2225 + WaitEventSet(msgInfo->WaitEvent);
2230 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2232 + DPRINT_EXIT(VMBUS);
2239 + VmbusChannelOnGpadlTorndown()
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.
2248 +VmbusChannelOnGpadlTorndown(
2249 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2252 + VMBUS_CHANNEL_GPADL_TORNDOWN* gpadlTorndown = (VMBUS_CHANNEL_GPADL_TORNDOWN*)hdr;
2253 + LIST_ENTRY* anchor;
2255 + VMBUS_CHANNEL_MSGINFO* msgInfo;
2256 + VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
2257 + VMBUS_CHANNEL_GPADL_TEARDOWN *gpadlTeardown;
2259 + DPRINT_ENTER(VMBUS);
2261 + // Find the open msg, copy the result and signal/unblock the wait event
2262 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2264 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
2266 + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
2267 + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2269 + if (requestHeader->MessageType == ChannelMessageGpadlTeardown)
2271 + gpadlTeardown = (VMBUS_CHANNEL_GPADL_TEARDOWN*)requestHeader;
2273 + if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl)
2275 + memcpy(&msgInfo->Response.GpadlTorndown, gpadlTorndown, sizeof(VMBUS_CHANNEL_GPADL_TORNDOWN));
2276 + WaitEventSet(msgInfo->WaitEvent);
2281 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2283 + DPRINT_EXIT(VMBUS);
2290 + VmbusChannelOnVersionResponse()
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.
2299 +VmbusChannelOnVersionResponse(
2300 + PVMBUS_CHANNEL_MESSAGE_HEADER hdr
2303 + LIST_ENTRY* anchor;
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;
2310 + DPRINT_ENTER(VMBUS);
2312 + SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
2314 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
2316 + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
2317 + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2319 + if (requestHeader->MessageType == ChannelMessageInitiateContact)
2321 + initiate = (VMBUS_CHANNEL_INITIATE_CONTACT*)requestHeader;
2322 + memcpy(&msgInfo->Response.VersionResponse, versionResponse, sizeof(VMBUS_CHANNEL_VERSION_RESPONSE));
2323 + WaitEventSet(msgInfo->WaitEvent);
2326 + SpinlockRelease(gVmbusConnection.ChannelMsgLock);
2328 + DPRINT_EXIT(VMBUS);
2335 + VmbusOnChannelMessage()
2338 + Handler for channel protocol messages.
2339 + This is invoked in the vmbus worker thread context.
2343 +VmbusOnChannelMessage(
2347 + HV_MESSAGE *msg=(HV_MESSAGE*)Context;
2348 + VMBUS_CHANNEL_MESSAGE_HEADER* hdr;
2351 + DPRINT_ENTER(VMBUS);
2353 + hdr = (VMBUS_CHANNEL_MESSAGE_HEADER*)msg->u.Payload;
2354 + size=msg->Header.PayloadSize;
2356 + DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
2358 + if (hdr->MessageType >= ChannelMessageCount)
2360 + DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", hdr->MessageType, size);
2361 + PrintBytes((unsigned char *)msg->u.Payload, size);
2366 + if (gChannelMessageTable[hdr->MessageType].messageHandler)
2368 + gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
2372 + DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->MessageType);
2375 + // Free the msg that was allocated in VmbusOnMsgDPC()
2377 + DPRINT_EXIT(VMBUS);
2384 + VmbusChannelRequestOffers()
2387 + Send a request to get all our pending offers.
2391 +VmbusChannelRequestOffers(
2396 + VMBUS_CHANNEL_MESSAGE_HEADER* msg;
2397 + VMBUS_CHANNEL_MSGINFO* msgInfo;
2399 + DPRINT_ENTER(VMBUS);
2402 + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_MESSAGE_HEADER));
2403 + ASSERT(msgInfo != NULL);
2405 + msgInfo->WaitEvent = WaitEventCreate();
2406 + msg = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
2408 + msg->MessageType = ChannelMessageRequestOffers;
2410 + /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
2411 + INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, &msgInfo->msgListEntry);
2412 + SpinlockRelease(gVmbusConnection.channelMsgLock);*/
2414 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_MESSAGE_HEADER));
2417 + DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
2419 + /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
2420 + REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
2421 + SpinlockRelease(gVmbusConnection.channelMsgLock);*/
2425 + //WaitEventWait(msgInfo->waitEvent);
2427 + /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
2428 + REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
2429 + SpinlockRelease(gVmbusConnection.channelMsgLock);*/
2435 + WaitEventClose(msgInfo->WaitEvent);
2439 + DPRINT_EXIT(VMBUS);
2447 + VmbusChannelReleaseUnattachedChannels()
2450 + Release channels that are unattached/unconnected ie (no drivers associated)
2454 +VmbusChannelReleaseUnattachedChannels(
2458 + LIST_ENTRY *entry;
2459 + VMBUS_CHANNEL *channel;
2460 + VMBUS_CHANNEL *start=NULL;
2462 + SpinlockAcquire(gVmbusConnection.ChannelLock);
2464 + while (!IsListEmpty(&gVmbusConnection.ChannelList))
2466 + entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList);
2467 + channel = CONTAINING_RECORD(entry, VMBUS_CHANNEL, ListEntry);
2469 + if (channel == start)
2472 + if (!channel->DeviceObject->Driver)
2474 + REMOVE_ENTRY_LIST(&channel->ListEntry);
2475 + DPRINT_INFO(VMBUS, "Releasing unattached device object %p", channel->DeviceObject);
2477 + VmbusChildDeviceRemove(channel->DeviceObject);
2478 + FreeVmbusChannel(channel);
2489 + SpinlockRelease(gVmbusConnection.ChannelLock);
2495 +++ b/drivers/staging/hv/ChannelMgmt.h
2499 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
2515 + * Haiyang Zhang <haiyangz@microsoft.com>
2516 + * Hank Janssen <hjanssen@microsoft.com>
2521 +#ifndef _CHANNEL_MGMT_H_
2522 +#define _CHANNEL_MGMT_H_
2526 +#include "RingBuffer.h"
2528 +#include "VmbusChannelInterface.h"
2529 +#include "ChannelMessages.h"
2533 +typedef void (*PFN_CHANNEL_CALLBACK)(PVOID context);
2536 + CHANNEL_OFFER_STATE,
2537 + CHANNEL_OPENING_STATE,
2538 + CHANNEL_OPEN_STATE,
2539 +} VMBUS_CHANNEL_STATE;
2541 +typedef struct _VMBUS_CHANNEL {
2542 + LIST_ENTRY ListEntry;
2544 + DEVICE_OBJECT* DeviceObject;
2546 + HANDLE PollTimer; // SA-111 workaround
2548 + VMBUS_CHANNEL_STATE State;
2550 + VMBUS_CHANNEL_OFFER_CHANNEL OfferMsg;
2551 + // These are based on the OfferMsg.MonitorId. Save it here for easy access.
2552 + UINT8 MonitorGroup;
2555 + UINT32 RingBufferGpadlHandle;
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;
2565 + // Channel callback are invoked in this workqueue context
2566 + //HANDLE dataWorkQueue;
2568 + PFN_CHANNEL_CALLBACK OnChannelCallback;
2569 + PVOID ChannelCallbackContext;
2574 +typedef struct _VMBUS_CHANNEL_DEBUG_INFO {
2576 + VMBUS_CHANNEL_STATE State;
2577 + GUID InterfaceType;
2578 + GUID InterfaceInstance;
2580 + UINT32 ServerMonitorPending;
2581 + UINT32 ServerMonitorLatency;
2582 + UINT32 ServerMonitorConnectionId;
2583 + UINT32 ClientMonitorPending;
2584 + UINT32 ClientMonitorLatency;
2585 + UINT32 ClientMonitorConnectionId;
2587 + RING_BUFFER_DEBUG_INFO Inbound;
2588 + RING_BUFFER_DEBUG_INFO Outbound;
2589 +} VMBUS_CHANNEL_DEBUG_INFO;
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;
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;
2608 + // So far, this is only used to handle gpadl body message
2609 + LIST_ENTRY SubMsgList;
2611 + // Synchronize the request/response if needed
2614 + VMBUS_CHANNEL_MESSAGE_RESPONSE Response;
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;
2627 +INTERNAL VMBUS_CHANNEL*
2634 + VMBUS_CHANNEL *Channel
2638 +VmbusOnChannelMessage(
2643 +VmbusChannelRequestOffers(
2648 +VmbusChannelReleaseUnattachedChannels(
2652 +#endif //_CHANNEL_MGMT_H_
2654 +++ b/drivers/staging/hv/Connection.c
2658 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
2674 + * Haiyang Zhang <haiyangz@microsoft.com>
2675 + * Hank Janssen <hjanssen@microsoft.com>
2680 +#include "logging.h"
2682 +#include "VmbusPrivate.h"
2689 +VMBUS_CONNECTION gVmbusConnection = {
2690 + .ConnectState = Disconnected,
2691 + .NextGpadlHandle = 0xE1E10,
2701 + Sends a connect request on the partition service connection
2709 + VMBUS_CHANNEL_MSGINFO *msgInfo=NULL;
2710 + VMBUS_CHANNEL_INITIATE_CONTACT *msg;
2712 + DPRINT_ENTER(VMBUS);
2714 + // Make sure we are not connecting or connected
2715 + if (gVmbusConnection.ConnectState != Disconnected)
2718 + // Initialize the vmbus connection
2719 + gVmbusConnection.ConnectState = Connecting;
2720 + gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ");
2722 + INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
2723 + gVmbusConnection.ChannelMsgLock = SpinlockCreate();
2725 + INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList);
2726 + gVmbusConnection.ChannelLock = SpinlockCreate();
2728 + // Setup the vmbus event connection for channel interrupt abstraction stuff
2729 + gVmbusConnection.InterruptPage = PageAlloc(1);
2730 + if (gVmbusConnection.InterruptPage == NULL)
2736 + gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
2737 + gVmbusConnection.SendInterruptPage = (void*)((ULONG_PTR)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1));
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)
2747 + msgInfo = (VMBUS_CHANNEL_MSGINFO*)MemAllocZeroed(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
2748 + if (msgInfo == NULL)
2754 + msgInfo->WaitEvent = WaitEventCreate();
2755 + msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg;
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));
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);
2769 + DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx",
2770 + msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
2772 + DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
2774 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
2777 + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
2781 + // Wait for the connection response
2782 + WaitEventWait(msgInfo->WaitEvent);
2784 + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
2786 + // Check if successful
2787 + if (msgInfo->Response.VersionResponse.VersionSupported)
2789 + DPRINT_INFO(VMBUS, "Vmbus connected!!");
2790 + gVmbusConnection.ConnectState = Connected;
2795 + DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER);
2802 + WaitEventClose(msgInfo->WaitEvent);
2804 + DPRINT_EXIT(VMBUS);
2810 + gVmbusConnection.ConnectState = Disconnected;
2812 + WorkQueueClose(gVmbusConnection.WorkQueue);
2813 + SpinlockClose(gVmbusConnection.ChannelLock);
2814 + SpinlockClose(gVmbusConnection.ChannelMsgLock);
2816 + if (gVmbusConnection.InterruptPage)
2818 + PageFree(gVmbusConnection.InterruptPage, 1);
2819 + gVmbusConnection.InterruptPage = NULL;
2822 + if (gVmbusConnection.MonitorPages)
2824 + PageFree(gVmbusConnection.MonitorPages, 2);
2825 + gVmbusConnection.MonitorPages = NULL;
2830 + if (msgInfo->WaitEvent)
2831 + WaitEventClose(msgInfo->WaitEvent);
2836 + DPRINT_EXIT(VMBUS);
2848 + Sends a disconnect request on the partition service connection
2857 + VMBUS_CHANNEL_UNLOAD *msg;
2859 + DPRINT_ENTER(VMBUS);
2861 + // Make sure we are connected
2862 + if (gVmbusConnection.ConnectState != Connected)
2865 + msg = MemAllocZeroed(sizeof(VMBUS_CHANNEL_UNLOAD));
2867 + msg->MessageType = ChannelMessageUnload;
2869 + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD));
2876 + PageFree(gVmbusConnection.InterruptPage, 1);
2878 + // TODO: iterate thru the msg list and free up
2880 + SpinlockClose(gVmbusConnection.ChannelMsgLock);
2882 + WorkQueueClose(gVmbusConnection.WorkQueue);
2884 + gVmbusConnection.ConnectState = Disconnected;
2886 + DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
2894 + DPRINT_EXIT(VMBUS);
2903 + GetChannelFromRelId()
2906 + Get the channel object given its child relative id (ie channel id)
2910 +GetChannelFromRelId(
2914 + VMBUS_CHANNEL* channel;
2915 + VMBUS_CHANNEL* foundChannel=NULL;
2916 + LIST_ENTRY* anchor;
2919 + SpinlockAcquire(gVmbusConnection.ChannelLock);
2920 + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
2922 + channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
2924 + if (channel->OfferMsg.ChildRelId == relId)
2926 + foundChannel = channel;
2930 + SpinlockRelease(gVmbusConnection.ChannelLock);
2932 + return foundChannel;
2940 + VmbusProcessChannelEvent()
2943 + Process a channel event notification
2947 +VmbusProcessChannelEvent(
2951 + VMBUS_CHANNEL* channel;
2952 + UINT32 relId = (UINT32)(ULONG_PTR)context;
2954 + ASSERT(relId > 0);
2956 + // Find the channel based on this relid and invokes
2957 + // the channel callback to process the event
2958 + channel = GetChannelFromRelId(relId);
2962 + VmbusChannelOnChannelEvent(channel);
2963 + //WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel);
2967 + DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
2978 + Handler for events
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;
2991 + UINT32* recvInterruptPage = gVmbusConnection.RecvInterruptPage;
2992 + //VMBUS_CHANNEL_MESSAGE* receiveMsg;
2994 + DPRINT_ENTER(VMBUS);
2997 + if (recvInterruptPage)
2999 + for (dword = 0; dword < maxdword; dword++)
3001 + if (recvInterruptPage[dword])
3003 + for (bit = 0; bit < 32; bit++)
3005 + if (BitTestAndClear(&recvInterruptPage[dword], bit))
3007 + relid = (dword << 5) + bit;
3009 + DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
3011 + if (relid == 0) // special case - vmbus channel protocol msg
3013 + DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
3018 + //QueueWorkItem(VmbusProcessEvent, (void*)relid);
3019 + //ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid);
3020 + VmbusProcessChannelEvent((void*)(ULONG_PTR)relid);
3027 + DPRINT_EXIT(VMBUS);
3035 + VmbusPostMessage()
3038 + Send a msg on the vmbus's message connection
3048 + HV_CONNECTION_ID connId;
3051 + connId.AsUINT32 =0;
3052 + connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
3053 + ret = HvPostMessage(
3068 + Send an event notification to the parent
3072 +VmbusSetEvent(UINT32 childRelId)
3076 + DPRINT_ENTER(VMBUS);
3078 + // Each UINT32 represents 32 channels
3079 + BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31);
3080 + ret = HvSignalEvent();
3082 + DPRINT_EXIT(VMBUS);
3089 +++ b/drivers/staging/hv/Hv.c
3093 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
3109 + * Haiyang Zhang <haiyangz@microsoft.com>
3110 + * Hank Janssen <hjanssen@microsoft.com>
3115 +#include "logging.h"
3116 +#include "VmbusPrivate.h"
3122 +// The one and only
3123 +HV_CONTEXT gHvContext={
3124 + .SynICInitialized = FALSE,
3125 + .HypercallPage = NULL,
3126 + .SignalEventParam = NULL,
3127 + .SignalEventBuffer = NULL,
3134 + HvQueryHypervisorPresence()
3137 + Query the cpuid for presense of windows hypervisor
3141 +HvQueryHypervisorPresence (
3155 + op = HvCpuIdFunctionVersionAndFeatures;
3156 + do_cpuid(op, &eax, &ebx, &ecx, &edx);
3158 + return (ecx & HV_PRESENT_BIT);
3165 + HvQueryHypervisorInfo()
3168 + Get version info of the windows hypervisor
3172 +HvQueryHypervisorInfo (
3180 + unsigned int maxLeaf;
3184 + // Its assumed that this is called after confirming that Viridian is present.
3185 + // Query id and revision.
3192 + op = HvCpuIdFunctionHvVendorAndMaxFunction;
3193 + do_cpuid(op, &eax, &ebx, &ecx, &edx);
3195 + DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
3197 + ((ebx >> 8) & 0xFF),
3198 + ((ebx >> 16) & 0xFF),
3199 + ((ebx >> 24) & 0xFF),
3201 + ((ecx >> 8) & 0xFF),
3202 + ((ecx >> 16) & 0xFF),
3203 + ((ecx >> 24) & 0xFF),
3205 + ((edx >> 8) & 0xFF),
3206 + ((edx >> 16) & 0xFF),
3207 + ((edx >> 24) & 0xFF));
3214 + op = HvCpuIdFunctionHvInterface;
3215 + do_cpuid(op, &eax, &ebx, &ecx, &edx);
3217 + DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
3219 + ((eax >> 8) & 0xFF),
3220 + ((eax >> 16) & 0xFF),
3221 + ((eax >> 24) & 0xFF));
3223 + if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
3228 + op = HvCpuIdFunctionMsHvVersion;
3229 + do_cpuid(op, &eax, &ebx, &ecx, &edx);
3230 + DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",
3248 + Invoke the specified hypercall
3259 + UINT64 hvStatus=0;
3260 + UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0;
3261 + UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0;
3262 + volatile void* hypercallPage = gHvContext.HypercallPage;
3264 + DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>",
3272 + __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8");
3273 + __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage));
3275 + DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
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;
3293 + DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
3298 + __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage));
3301 + DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((UINT64)hvStatusHi << 32));
3303 + return (hvStatusLo | ((UINT64)hvStatusHi << 32));
3313 + Main initialization routine. This routine must be called
3314 + before any other routines in here are called
3324 + HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
3326 + ULONG_PTR physAddr=0;
3328 + DPRINT_ENTER(VMBUS);
3330 + memset(gHvContext.synICEventPage, 0, sizeof(HANDLE)*MAX_NUM_CPUS);
3331 + memset(gHvContext.synICMessagePage, 0, sizeof(HANDLE)*MAX_NUM_CPUS);
3333 + if (!HvQueryHypervisorPresence())
3335 + DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
3339 + DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info...");
3341 + maxLeaf = HvQueryHypervisorInfo();
3342 + //HvQueryHypervisorFeatures(maxLeaf);
3344 + // Determine if we are running on xenlinux (ie x2v shim) or native linux
3345 + gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
3347 + if (gHvContext.GuestId == 0)
3349 + // Write our OS info
3350 + WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
3352 + gHvContext.GuestId = HV_LINUX_GUEST_ID;
3355 + // See if the hypercall page is already set
3356 + hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
3358 + if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
3360 + // Allocate the hypercall page memory
3361 + //virtAddr = PageAlloc(1);
3362 + virtAddr = VirtualAllocExec(PAGE_SIZE);
3366 + DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!");
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);
3375 + // Confirm that hypercall page did get setup.
3376 + hypercallMsr.AsUINT64 = 0;
3377 + hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
3379 + if (!hypercallMsr.Enable)
3381 + DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
3385 + gHvContext.HypercallPage = virtAddr;
3389 + DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId);
3393 + DPRINT_INFO(VMBUS, "Hypercall page VA=0x%08x, PA=0x%08x",
3394 + (unsigned long)gHvContext.HypercallPage,
3395 + (unsigned long)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
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)
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;
3410 + //DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId());
3412 + DPRINT_EXIT(VMBUS);
3419 + if (hypercallMsr.Enable)
3421 + hypercallMsr.AsUINT64 = 0;
3422 + WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
3425 + VirtualFree(virtAddr);
3428 + DPRINT_EXIT(VMBUS);
3440 + Cleanup routine. This routine is called normally during driver unloading or exiting.
3448 + HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
3450 + DPRINT_ENTER(VMBUS);
3452 + if (gHvContext.SignalEventBuffer)
3454 + MemFree(gHvContext.SignalEventBuffer);
3455 + gHvContext.SignalEventBuffer = NULL;
3456 + gHvContext.SignalEventParam = NULL;
3459 + if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
3461 + if (gHvContext.HypercallPage)
3463 + hypercallMsr.AsUINT64 = 0;
3464 + WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
3465 + VirtualFree(gHvContext.HypercallPage);
3466 + gHvContext.HypercallPage = NULL;
3470 + DPRINT_EXIT(VMBUS);
3481 + Post a message using the hypervisor message IPC. This
3482 + involves a hypercall.
3487 + HV_CONNECTION_ID connectionId,
3488 + HV_MESSAGE_TYPE messageType,
3490 + SIZE_T payloadSize
3493 + struct alignedInput {
3494 + UINT64 alignment8;
3495 + HV_INPUT_POST_MESSAGE msg;
3498 + PHV_INPUT_POST_MESSAGE alignedMsg;
3502 + if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
3507 + addr = (ULONG_PTR)MemAllocAtomic(sizeof(struct alignedInput));
3514 + alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
3516 + alignedMsg->ConnectionId = connectionId;
3517 + alignedMsg->MessageType = messageType;
3518 + alignedMsg->PayloadSize = payloadSize;
3519 + memcpy((void*)alignedMsg->Payload, payload, payloadSize);
3521 + status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF;
3523 + MemFree((void*)addr);
3535 + Signal an event on the specified connection using the hypervisor event IPC. This
3536 + involves a hypercall.
3545 + status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF;
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.
3568 + HV_SYNIC_SIMP simp;
3569 + HV_SYNIC_SIEFP siefp;
3570 + HV_SYNIC_SINT sharedSint;
3571 + HV_SYNIC_SCONTROL sctrl;
3575 + DPRINT_ENTER(VMBUS);
3577 + if (!gHvContext.HypercallPage)
3579 + DPRINT_EXIT(VMBUS);
3583 + // Check the version
3584 + version = ReadMsr(HV_X64_MSR_SVERSION);
3586 + DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
3588 + // TODO: Handle SMP
3589 + if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID)
3591 + DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set.");
3593 + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
3594 + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
3596 + DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64);
3598 + // Determine if we are running on xenlinux (ie x2v shim) or native linux
3599 + guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
3601 + if (guestID == HV_LINUX_GUEST_ID)
3603 + gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT);
3604 + gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT);
3608 + DPRINT_ERR(VMBUS, "unknown guest id!!");
3611 + DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]);
3615 + gHvContext.synICMessagePage[0] = PageAlloc(1);
3616 + if (gHvContext.synICMessagePage[0] == NULL)
3618 + DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!");
3622 + gHvContext.synICEventPage[0] = PageAlloc(1);
3623 + if (gHvContext.synICEventPage[0] == NULL)
3625 + DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!");
3630 + // Setup the Synic's message page
3632 + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
3633 + simp.SimpEnabled = 1;
3634 + simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT;
3636 + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
3638 + WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
3641 + // Setup the Synic's event page
3643 + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
3644 + siefp.SiefpEnabled = 1;
3645 + siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT;
3647 + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
3649 + WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
3652 + // Setup the interception SINT.
3654 + //WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX),
3655 + // interceptionSint.AsUINT64);
3658 + // Setup the shared SINT.
3660 + sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
3662 + sharedSint.AsUINT64 = 0;
3663 + sharedSint.Vector = irqVector; //HV_SHARED_SINT_IDT_VECTOR + 0x20;
3664 + sharedSint.Masked = FALSE;
3665 + sharedSint.AutoEoi = TRUE;
3667 + DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64);
3669 + WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
3671 + // Enable the global synic bit
3672 + sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL);
3675 + WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
3677 + gHvContext.SynICInitialized = TRUE;
3679 + DPRINT_EXIT(VMBUS);
3686 + if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
3688 + if (gHvContext.synICEventPage[0])
3690 + PageFree(gHvContext.synICEventPage[0],1);
3693 + if (gHvContext.synICMessagePage[0])
3695 + PageFree(gHvContext.synICMessagePage[0], 1);
3699 + DPRINT_EXIT(VMBUS);
3711 + Cleanup routine for HvSynicInit().
3719 + HV_SYNIC_SINT sharedSint;
3720 + HV_SYNIC_SIMP simp;
3721 + HV_SYNIC_SIEFP siefp;
3723 + DPRINT_ENTER(VMBUS);
3725 + if (!gHvContext.SynICInitialized)
3727 + DPRINT_EXIT(VMBUS);
3731 + sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
3733 + sharedSint.Masked = 1;
3735 + // Disable the interrupt
3736 + WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
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)
3742 + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
3743 + simp.SimpEnabled = 0;
3744 + simp.BaseSimpGpa = 0;
3746 + WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
3748 + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
3749 + siefp.SiefpEnabled = 0;
3750 + siefp.BaseSiefpGpa = 0;
3752 + WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
3754 + PageFree(gHvContext.synICMessagePage[0], 1);
3755 + PageFree(gHvContext.synICEventPage[0], 1);
3758 + DPRINT_EXIT(VMBUS);
3764 +++ b/drivers/staging/hv/Hv.h
3768 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
3784 + * Haiyang Zhang <haiyangz@microsoft.com>
3785 + * Hank Janssen <hjanssen@microsoft.com>
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"
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
3824 +#define HV_PRESENT_BIT 0x80000000
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)
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)
3834 +#define HV_CPU_POWER_MANAGEMENT (1 << 0)
3835 +#define HV_RECOMMENDATIONS_MAX 4
3837 +#define HV_X64_MAX 5
3838 +#define HV_CAPS_MAX 8
3841 +#define HV_HYPERCALL_PARAM_ALIGN sizeof(UINT64)
3844 +// Service definitions
3846 +#define HV_SERVICE_PARENT_PORT (0)
3847 +#define HV_SERVICE_PARENT_CONNECTION (0)
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)
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)
3860 +#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
3861 +#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
3863 +//#define VMBUS_REVISION_NUMBER 6
3864 +//#define VMBUS_PORT_ID 11 // Our local vmbus's port and connection id. Anything >0 is fine
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} };
3869 +#define MAX_NUM_CPUS 1
3874 + HV_INPUT_SIGNAL_EVENT Event;
3875 +} HV_INPUT_SIGNAL_EVENT_BUFFER;
3878 + UINT64 GuestId; // XenLinux or native Linux. If XenLinux, the hypercall and synic pages has already been initialized
3879 + void* HypercallPage;
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
3887 + HANDLE synICMessagePage[MAX_NUM_CPUS];
3888 + HANDLE synICEventPage[MAX_NUM_CPUS];
3891 +extern HV_CONTEXT gHvContext;
3897 +static inline unsigned long long ReadMsr(int msr)
3899 + unsigned long long val;
3906 +static inline void WriteMsr(int msr, UINT64 val)
3928 + HV_CONNECTION_ID connectionId,
3929 + HV_MESSAGE_TYPE messageType,
3931 + SIZE_T payloadSize
3951 +++ b/drivers/staging/hv/osd.c
3955 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
3971 + * Haiyang Zhang <haiyangz@microsoft.com>
3972 + * Hank Janssen <hjanssen@microsoft.com>
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>
3996 +#include <asm/io.h>
3997 +#include <asm/bitops.h>
3998 +#include <asm/kmap_types.h>
3999 +#include <asm/atomic.h>
4006 +typedef struct _TIMER {
4007 + struct timer_list timer;
4008 + PFN_TIMER_CALLBACK callback;
4013 +typedef struct _WAITEVENT {
4015 + wait_queue_head_t event;
4018 +typedef struct _SPINLOCK {
4020 + unsigned long flags;
4023 +typedef struct _WORKQUEUE {
4024 + struct workqueue_struct *queue;
4027 +typedef struct _WORKITEM {
4028 + struct work_struct work;
4029 + PFN_WORKITEM_CALLBACK callback;
4038 +void LogMsg(const char *fmt, ...)
4040 +#ifdef KERNEL_2_6_5
4045 + va_start(args, fmt);
4046 +#ifdef KERNEL_2_6_5
4047 + vsnprintf(buf, 1024, fmt, args);
4051 + vprintk(fmt, args);
4056 +void BitSet(unsigned int* addr, int bit)
4058 + set_bit(bit, (unsigned long*)addr);
4061 +int BitTest(unsigned int* addr, int bit)
4063 + return test_bit(bit, (unsigned long*)addr);
4066 +void BitClear(unsigned int* addr, int bit)
4068 + clear_bit(bit, (unsigned long*)addr);
4071 +int BitTestAndClear(unsigned int* addr, int bit)
4073 + return test_and_clear_bit(bit, (unsigned long*)addr);
4076 +int BitTestAndSet(unsigned int* addr, int bit)
4078 + return test_and_set_bit(bit, (unsigned long*)addr);
4082 +int InterlockedIncrement(int *val)
4084 +#ifdef KERNEL_2_6_5
4086 + local_irq_disable();
4087 + i = atomic_read((atomic_t*)val);
4088 + atomic_set((atomic_t*)val, i+1);
4089 + local_irq_enable();
4092 + return atomic_inc_return((atomic_t*)val);
4096 +int InterlockedDecrement(int *val)
4098 +#ifdef KERNEL_2_6_5
4100 + local_irq_disable();
4101 + i = atomic_read((atomic_t*)val);
4102 + atomic_set((atomic_t*)val, i-1);
4103 + local_irq_enable();
4106 + return atomic_dec_return((atomic_t*)val);
4110 +#ifndef atomic_cmpxchg
4111 +#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
4113 +int InterlockedCompareExchange(int *val, int new, int curr)
4115 + //return ((int)cmpxchg(((atomic_t*)val), curr, new));
4116 + return atomic_cmpxchg((atomic_t*)val, curr, new);
4120 +void Sleep(unsigned long usecs)
4125 +void* VirtualAllocExec(unsigned int size)
4128 + return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC);
4130 + return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX)));
4134 +void VirtualFree(void* VirtAddr)
4136 + return vfree(VirtAddr);
4139 +void* PageAlloc(unsigned int count)
4142 + p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE));
4143 + if (p) memset(p, 0, count * PAGE_SIZE);
4146 + //struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO);
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);
4155 +void PageFree(void* page, unsigned int count)
4157 + free_pages((unsigned long)page, get_order(count * PAGE_SIZE));
4158 + /*struct page* p = virt_to_page(page);
4163 +void* PageMapVirtualAddress(unsigned long Pfn)
4165 + return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0);
4168 +void PageUnmapVirtualAddress(void* VirtAddr)
4170 + kunmap_atomic(VirtAddr, KM_IRQ0);
4173 +void* MemAlloc(unsigned int size)
4175 + return kmalloc(size, GFP_KERNEL);
4178 +void* MemAllocZeroed(unsigned int size)
4180 + void *p = kmalloc(size, GFP_KERNEL);
4181 + if (p) memset(p, 0, size);
4185 +void* MemAllocAtomic(unsigned int size)
4187 + return kmalloc(size, GFP_ATOMIC);
4190 +void MemFree(void* buf)
4195 +void *MemMapIO(unsigned long phys, unsigned long size)
4199 + return (void*)(phys + 0xFFFF83000C000000);
4201 + return (void*)(phys + 0xfb000000);
4204 + return (void*)GetVirtualAddress(phys); //return ioremap_nocache(phys, size);
4208 +void MemUnmapIO(void *virt)
4218 +void TimerCallback(unsigned long data)
4220 + TIMER* t = (TIMER*)data;
4222 + t->callback(t->context);
4225 +HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context)
4227 + TIMER* t = kmalloc(sizeof(TIMER), GFP_KERNEL);
4233 + t->callback = pfnTimerCB;
4234 + t->context = context;
4236 + init_timer(&t->timer);
4237 + t->timer.data = (unsigned long)t;
4238 + t->timer.function = TimerCallback;
4243 +void TimerStart(HANDLE hTimer, UINT32 expirationInUs)
4245 + TIMER* t = (TIMER* )hTimer;
4247 + t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs);
4248 + add_timer(&t->timer);
4251 +int TimerStop(HANDLE hTimer)
4253 + TIMER* t = (TIMER* )hTimer;
4255 + return del_timer(&t->timer);
4258 +void TimerClose(HANDLE hTimer)
4260 + TIMER* t = (TIMER* )hTimer;
4262 + del_timer(&t->timer);
4266 +SIZE_T GetTickCount(void)
4271 +signed long long GetTimestamp(void)
4275 + do_gettimeofday(&t);
4277 + return timeval_to_ns(&t);
4280 +HANDLE WaitEventCreate(void)
4282 + WAITEVENT* wait = kmalloc(sizeof(WAITEVENT), GFP_KERNEL);
4288 + wait->condition = 0;
4289 + init_waitqueue_head(&wait->event);
4293 +void WaitEventClose(HANDLE hWait)
4295 + WAITEVENT* waitEvent = (WAITEVENT* )hWait;
4299 +void WaitEventSet(HANDLE hWait)
4301 + WAITEVENT* waitEvent = (WAITEVENT* )hWait;
4302 + waitEvent->condition = 1;
4303 + wake_up_interruptible(&waitEvent->event);
4306 +int WaitEventWait(HANDLE hWait)
4309 + WAITEVENT* waitEvent = (WAITEVENT* )hWait;
4311 + ret= wait_event_interruptible(waitEvent->event,
4312 + waitEvent->condition);
4313 + waitEvent->condition = 0;
4317 +int WaitEventWaitEx(HANDLE hWait, UINT32 TimeoutInMs)
4320 + WAITEVENT* waitEvent = (WAITEVENT* )hWait;
4322 + ret= wait_event_interruptible_timeout(waitEvent->event,
4323 + waitEvent->condition,
4324 + msecs_to_jiffies(TimeoutInMs));
4325 + waitEvent->condition = 0;
4329 +HANDLE SpinlockCreate(VOID)
4331 + SPINLOCK* spin = kmalloc(sizeof(SPINLOCK), GFP_KERNEL);
4336 + spin_lock_init(&spin->lock);
4341 +VOID SpinlockAcquire(HANDLE hSpin)
4343 + SPINLOCK* spin = (SPINLOCK* )hSpin;
4345 + spin_lock_irqsave(&spin->lock, spin->flags);
4348 +VOID SpinlockRelease(HANDLE hSpin)
4350 + SPINLOCK* spin = (SPINLOCK* )hSpin;
4352 + spin_unlock_irqrestore(&spin->lock, spin->flags);
4355 +VOID SpinlockClose(HANDLE hSpin)
4357 + SPINLOCK* spin = (SPINLOCK* )hSpin;
4361 +void* Physical2LogicalAddr(ULONG_PTR PhysAddr)
4363 + void* logicalAddr = phys_to_virt(PhysAddr);
4364 + BUG_ON(!virt_addr_valid(logicalAddr));
4365 + return logicalAddr;
4368 +ULONG_PTR Logical2PhysicalAddr(PVOID LogicalAddr)
4370 + BUG_ON(!virt_addr_valid(LogicalAddr));
4371 + return virt_to_phys(LogicalAddr);
4375 +ULONG_PTR Virtual2Physical(PVOID VirtAddr)
4377 + ULONG_PTR pfn = vmalloc_to_pfn(VirtAddr);
4379 + return pfn << PAGE_SHIFT;
4382 +#ifdef KERNEL_2_6_27
4383 +void WorkItemCallback(struct work_struct *work)
4385 +void WorkItemCallback(void* work)
4388 + WORKITEM* w = (WORKITEM*)work;
4390 + w->callback(w->context);
4395 +HANDLE WorkQueueCreate(char* name)
4397 + WORKQUEUE *wq = kmalloc(sizeof(WORKQUEUE), GFP_KERNEL);
4402 + wq->queue = create_workqueue(name);
4407 +void WorkQueueClose(HANDLE hWorkQueue)
4409 + WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue;
4411 + destroy_workqueue(wq->queue);
4416 +int WorkQueueQueueWorkItem(HANDLE hWorkQueue, PFN_WORKITEM_CALLBACK workItem, void* context)
4418 + WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue;
4420 + WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
4426 + w->callback = workItem,
4427 + w->context = context;
4428 +#ifdef KERNEL_2_6_27
4429 + INIT_WORK(&w->work, WorkItemCallback);
4431 + INIT_WORK(&w->work, WorkItemCallback, w);
4433 + return queue_work(wq->queue, &w->work);
4436 +void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context)
4438 + WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
4444 + w->callback = workItem,
4445 + w->context = context;
4446 +#ifdef KERNEL_2_6_27
4447 + INIT_WORK(&w->work, WorkItemCallback);
4449 + INIT_WORK(&w->work, WorkItemCallback, w);
4451 + schedule_work(&w->work);
4454 +++ b/drivers/staging/hv/RingBuffer.c
4458 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
4474 + * Haiyang Zhang <haiyangz@microsoft.com>
4475 + * Hank Janssen <hjanssen@microsoft.com>
4480 +#include "logging.h"
4481 +#include "RingBuffer.h"
4487 +// Amount of space to write to
4488 +#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w))
4494 + GetRingBufferAvailBytes()
4497 + Get number of bytes available to read and to write to
4498 + for the specified ring buffer
4502 +GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, UINT32 *read, UINT32 *write)
4504 + UINT32 read_loc,write_loc;
4506 + // Capture the read/write indices before they changed
4507 + read_loc = rbi->RingBuffer->ReadIndex;
4508 + write_loc = rbi->RingBuffer->WriteIndex;
4510 + *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize);
4511 + *read = rbi->RingDataSize - *write;
4517 + GetNextWriteLocation()
4520 + Get the next write location for the specified ring buffer
4523 +static inline UINT32
4524 +GetNextWriteLocation(RING_BUFFER_INFO* RingInfo)
4526 + UINT32 next = RingInfo->RingBuffer->WriteIndex;
4528 + ASSERT(next < RingInfo->RingDataSize);
4536 + SetNextWriteLocation()
4539 + Set the next write location for the specified ring buffer
4543 +SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextWriteLocation)
4545 + RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
4551 + GetNextReadLocation()
4554 + Get the next read location for the specified ring buffer
4557 +static inline UINT32
4558 +GetNextReadLocation(RING_BUFFER_INFO* RingInfo)
4560 + UINT32 next = RingInfo->RingBuffer->ReadIndex;
4562 + ASSERT(next < RingInfo->RingDataSize);
4570 + GetNextReadLocationWithOffset()
4573 + Get the next read location + offset for the specified ring buffer.
4574 + This allows the caller to skip
4577 +static inline UINT32
4578 +GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, UINT32 Offset)
4580 + UINT32 next = RingInfo->RingBuffer->ReadIndex;
4582 + ASSERT(next < RingInfo->RingDataSize);
4584 + next %= RingInfo->RingDataSize;
4592 + SetNextReadLocation()
4595 + Set the next read location for the specified ring buffer
4599 +SetNextReadLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextReadLocation)
4601 + RingInfo->RingBuffer->ReadIndex = NextReadLocation;
4611 + Get the start of the ring buffer
4614 +static inline PVOID
4615 +GetRingBuffer(RING_BUFFER_INFO* RingInfo)
4617 + return (PVOID)RingInfo->RingBuffer->Buffer;
4624 + GetRingBufferSize()
4627 + Get the size of the ring buffer
4630 +static inline UINT32
4631 +GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
4633 + return RingInfo->RingDataSize;
4639 + GetRingBufferIndices()
4642 + Get the read and write indices as UINT64 of the specified ring buffer
4645 +static inline UINT64
4646 +GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
4648 + return ((UINT64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
4658 + Dump out to console the ring buffer info
4662 +DumpRingInfo(RING_BUFFER_INFO* RingInfo, char *Prefix)
4664 + UINT32 bytesAvailToWrite;
4665 + UINT32 bytesAvailToRead;
4667 + GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
4669 + DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>",
4672 + RingInfo->RingBuffer->Buffer,
4673 + bytesAvailToWrite,
4675 + RingInfo->RingBuffer->ReadIndex,
4676 + RingInfo->RingBuffer->WriteIndex);
4680 +// Internal routines
4684 + RING_BUFFER_INFO *RingInfo,
4685 + UINT32 StartWriteOffset,
4690 +CopyFromRingBuffer(
4691 + RING_BUFFER_INFO *RingInfo,
4694 + UINT32 StartReadOffset);
4701 + RingBufferGetDebugInfo()
4704 + Get various debug metrics for the specified ring buffer
4708 +RingBufferGetDebugInfo(
4709 + RING_BUFFER_INFO *RingInfo,
4710 + RING_BUFFER_DEBUG_INFO *DebugInfo
4713 + UINT32 bytesAvailToWrite;
4714 + UINT32 bytesAvailToRead;
4716 + if (RingInfo->RingBuffer)
4718 + GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
4720 + DebugInfo->BytesAvailToRead = bytesAvailToRead;
4721 + DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
4722 + DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
4723 + DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
4725 + DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
4733 + GetRingBufferInterruptMask()
4736 + Get the interrupt mask for the specified ring buffer
4740 +GetRingBufferInterruptMask(
4741 + RING_BUFFER_INFO *rbi
4744 + return rbi->RingBuffer->InterruptMask;
4753 + Initialize the ring buffer
4758 + RING_BUFFER_INFO *RingInfo,
4763 + ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE);
4765 + memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
4767 + RingInfo->RingBuffer = (RING_BUFFER*)Buffer;
4768 + RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
4770 + RingInfo->RingSize = BufferLen;
4771 + RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER);
4773 + RingInfo->RingLock = SpinlockCreate();
4781 + RingBufferCleanup()
4784 + Cleanup the ring buffer
4789 + RING_BUFFER_INFO* RingInfo
4792 + SpinlockClose(RingInfo->RingLock);
4801 + Write to the ring buffer
4806 + RING_BUFFER_INFO* OutRingInfo,
4807 + SG_BUFFER_LIST SgBuffers[],
4808 + UINT32 SgBufferCount
4812 + UINT32 byteAvailToWrite;
4813 + UINT32 byteAvailToRead;
4814 + UINT32 totalBytesToWrite=0;
4816 + volatile UINT32 nextWriteLocation;
4817 + UINT64 prevIndices=0;
4819 + DPRINT_ENTER(VMBUS);
4821 + for (i=0; i < SgBufferCount; i++)
4823 + totalBytesToWrite += SgBuffers[i].Length;
4826 + totalBytesToWrite += sizeof(UINT64);
4828 + SpinlockAcquire(OutRingInfo->RingLock);
4830 + GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
4832 + DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
4834 + //DumpRingInfo(OutRingInfo, "BEFORE ");
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)
4840 + DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
4842 + SpinlockRelease(OutRingInfo->RingLock);
4844 + DPRINT_EXIT(VMBUS);
4849 + // Write to the ring buffer
4850 + nextWriteLocation = GetNextWriteLocation(OutRingInfo);
4852 + for (i=0; i < SgBufferCount; i++)
4854 + nextWriteLocation = CopyToRingBuffer(OutRingInfo,
4855 + nextWriteLocation,
4856 + SgBuffers[i].Data,
4857 + SgBuffers[i].Length);
4860 + // Set previous packet start
4861 + prevIndices = GetRingBufferIndices(OutRingInfo);
4863 + nextWriteLocation = CopyToRingBuffer(OutRingInfo,
4864 + nextWriteLocation,
4868 + // Make sure we flush all writes before updating the writeIndex
4871 + // Now, update the write location
4872 + SetNextWriteLocation(OutRingInfo, nextWriteLocation);
4874 + //DumpRingInfo(OutRingInfo, "AFTER ");
4876 + SpinlockRelease(OutRingInfo->RingLock);
4878 + DPRINT_EXIT(VMBUS);
4890 + Read without advancing the read index
4895 + RING_BUFFER_INFO* InRingInfo,
4900 + UINT32 bytesAvailToWrite;
4901 + UINT32 bytesAvailToRead;
4902 + UINT32 nextReadLocation=0;
4904 + SpinlockAcquire(InRingInfo->RingLock);
4906 + GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
4908 + // Make sure there is something to read
4909 + if (bytesAvailToRead < BufferLen )
4911 + //DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
4913 + SpinlockRelease(InRingInfo->RingLock);
4918 + // Convert to byte offset
4919 + nextReadLocation = GetNextReadLocation(InRingInfo);
4921 + nextReadLocation = CopyFromRingBuffer(InRingInfo,
4924 + nextReadLocation);
4926 + SpinlockRelease(InRingInfo->RingLock);
4938 + Read and advance the read index
4943 + RING_BUFFER_INFO* InRingInfo,
4949 + UINT32 bytesAvailToWrite;
4950 + UINT32 bytesAvailToRead;
4951 + UINT32 nextReadLocation=0;
4952 + UINT64 prevIndices=0;
4954 + ASSERT(BufferLen > 0);
4956 + SpinlockAcquire(InRingInfo->RingLock);
4958 + GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
4960 + DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
4962 + //DumpRingInfo(InRingInfo, "BEFORE ");
4964 + // Make sure there is something to read
4965 + if (bytesAvailToRead < BufferLen )
4967 + DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
4969 + SpinlockRelease(InRingInfo->RingLock);
4974 + nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
4976 + nextReadLocation = CopyFromRingBuffer(InRingInfo,
4979 + nextReadLocation);
4981 + nextReadLocation = CopyFromRingBuffer(InRingInfo,
4984 + nextReadLocation);
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
4990 + // Update the read index
4991 + SetNextReadLocation(InRingInfo, nextReadLocation);
4993 + //DumpRingInfo(InRingInfo, "AFTER ");
4995 + SpinlockRelease(InRingInfo->RingLock);
5004 + CopyToRingBuffer()
5007 + Helper routine to copy from source to ring buffer.
5008 + Assume there is enough room. Handles wrap-around in dest case only!!
5013 + RING_BUFFER_INFO *RingInfo,
5014 + UINT32 StartWriteOffset,
5018 + PVOID ringBuffer=GetRingBuffer(RingInfo);
5019 + UINT32 ringBufferSize=GetRingBufferSize(RingInfo);
5022 + if (SrcLen > ringBufferSize - StartWriteOffset) // wrap-around detected!
5024 + DPRINT_DBG(VMBUS, "wrap-around detected!");
5026 + fragLen = ringBufferSize - StartWriteOffset;
5027 + memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
5028 + memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
5032 + memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
5035 + StartWriteOffset += SrcLen;
5036 + StartWriteOffset %= ringBufferSize;
5038 + return StartWriteOffset;
5045 + CopyFromRingBuffer()
5048 + Helper routine to copy to source from ring buffer.
5049 + Assume there is enough room. Handles wrap-around in src case only!!
5053 +CopyFromRingBuffer(
5054 + RING_BUFFER_INFO *RingInfo,
5057 + UINT32 StartReadOffset)
5059 + PVOID ringBuffer=GetRingBuffer(RingInfo);
5060 + UINT32 ringBufferSize=GetRingBufferSize(RingInfo);
5064 + if (DestLen > ringBufferSize - StartReadOffset) // wrap-around detected at the src
5066 + DPRINT_DBG(VMBUS, "src wrap-around detected!");
5068 + fragLen = ringBufferSize - StartReadOffset;
5070 + memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
5071 + memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
5075 + memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
5078 + StartReadOffset += DestLen;
5079 + StartReadOffset %= ringBufferSize;
5081 + return StartReadOffset;
5087 +++ b/drivers/staging/hv/RingBuffer.h
5091 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
5107 + * Haiyang Zhang <haiyangz@microsoft.com>
5108 + * Hank Janssen <hjanssen@microsoft.com>
5113 +#ifndef _RING_BUFFER_H_
5114 +#define _RING_BUFFER_H_
5118 +typedef struct _SG_BUFFER_LIST {
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
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 !!!
5134 +} STRUCT_PACKED RING_BUFFER;
5136 +typedef struct _RING_BUFFER_INFO {
5137 + RING_BUFFER* RingBuffer;
5138 + UINT32 RingSize; // Include the shared header
5141 + UINT32 RingDataSize; // < ringSize
5142 + UINT32 RingDataStartOffset;
5144 +} RING_BUFFER_INFO;
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;
5162 + RING_BUFFER_INFO *RingInfo,
5169 + RING_BUFFER_INFO *RingInfo
5174 + RING_BUFFER_INFO *RingInfo,
5175 + SG_BUFFER_LIST SgBuffers[],
5176 + UINT32 SgBufferCount
5181 + RING_BUFFER_INFO *RingInfo,
5188 + RING_BUFFER_INFO *RingInfo,
5195 +GetRingBufferInterruptMask(
5196 + RING_BUFFER_INFO *RingInfo
5201 + RING_BUFFER_INFO* RingInfo,
5206 +RingBufferGetDebugInfo(
5207 + RING_BUFFER_INFO *RingInfo,
5208 + RING_BUFFER_DEBUG_INFO *DebugInfo
5211 +#endif // _RING_BUFFER_H_
5213 +++ b/drivers/staging/hv/Sources.c
5217 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
5233 + * Haiyang Zhang <haiyangz@microsoft.com>
5234 + * Hank Janssen <hjanssen@microsoft.com>
5241 +#include "Connection.c"
5242 +#include "Channel.c"
5243 +#include "ChannelMgmt.c"
5244 +#include "ChannelInterface.c"
5245 +#include "RingBuffer.c"
5247 +++ b/drivers/staging/hv/VersionInfo.h
5251 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
5267 + * Haiyang Zhang <haiyangz@microsoft.com>
5268 + * Hank Janssen <hjanssen@microsoft.com>
5275 +const char VersionDate[]=__DATE__;
5276 +const char VersionTime[]=__TIME__;
5277 +const char VersionDesc[]= "Version 2.0";
5279 +++ b/drivers/staging/hv/Vmbus.c
5283 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
5299 + * Haiyang Zhang <haiyangz@microsoft.com>
5300 + * Hank Janssen <hjanssen@microsoft.com>
5305 +#include "logging.h"
5306 +#include "VersionInfo.h"
5307 +#include "VmbusPrivate.h"
5312 +static const char* gDriverName="vmbus";
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}
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}
5325 +static DRIVER_OBJECT* gDriver; // vmbus driver object
5326 +static DEVICE_OBJECT* gDevice; // vmbus root device
5330 +// Internal routines
5334 +VmbusGetChannelInterface(
5335 + VMBUS_CHANNEL_INTERFACE *Interface
5339 +VmbusGetChannelInfo(
5340 + DEVICE_OBJECT *DeviceObject,
5341 + DEVICE_INFO *DeviceInfo
5345 +VmbusGetChannelOffers(
5351 + DEVICE_OBJECT *Device,
5352 + void *AdditionalInfo
5356 +VmbusOnDeviceRemove(
5357 + DEVICE_OBJECT* dev
5362 + DRIVER_OBJECT* drv
5367 + DRIVER_OBJECT* drv
5372 + DRIVER_OBJECT* drv
5377 + DRIVER_OBJECT* drv
5391 + DRIVER_OBJECT* drv
5394 + VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
5397 + DPRINT_ENTER(VMBUS);
5399 + DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime);
5400 + DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc);
5402 + DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER);
5403 + DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT);
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));
5408 + drv->name = gDriverName;
5409 + memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(GUID));
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;
5422 + // Hypervisor initialization...setup hypercall page..etc
5426 + DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret);
5431 + DPRINT_EXIT(VMBUS);
5440 + VmbusGetChannelOffers()
5443 + Retrieve the channel offers from the parent partition
5448 +VmbusGetChannelOffers(void)
5450 + DPRINT_ENTER(VMBUS);
5451 + VmbusChannelRequestOffers();
5452 + DPRINT_EXIT(VMBUS);
5459 + VmbusGetChannelInterface()
5462 + Get the channel interface
5466 +VmbusGetChannelInterface(
5467 + VMBUS_CHANNEL_INTERFACE *Interface
5470 + GetChannelInterface(Interface);
5477 + VmbusGetChannelInterface()
5480 + Get the device info for the specified device object
5484 +VmbusGetChannelInfo(
5485 + DEVICE_OBJECT *DeviceObject,
5486 + DEVICE_INFO *DeviceInfo
5489 + GetChannelInfo(DeviceObject, DeviceInfo);
5497 + VmbusCreateChildDevice()
5500 + Creates the child device on the bus that represents the channel offer
5505 +VmbusChildDeviceCreate(
5507 + GUID DeviceInstance,
5510 + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
5512 + return vmbusDriver->OnChildDeviceCreate(
5522 + VmbusChildDeviceAdd()
5525 + Registers the child device with the vmbus
5529 +VmbusChildDeviceAdd(
5530 + DEVICE_OBJECT* ChildDevice)
5532 + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
5534 + return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
5541 + VmbusChildDeviceRemove()
5544 + Unregisters the child device from the vmbus
5548 +VmbusChildDeviceRemove(
5549 + DEVICE_OBJECT* ChildDevice)
5551 + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
5553 + vmbusDriver->OnChildDeviceRemove(ChildDevice);
5559 + VmbusChildDeviceDestroy()
5562 + Release the child device from the vmbus
5566 +//VmbusChildDeviceDestroy(
5567 +// DEVICE_OBJECT* ChildDevice
5570 +// VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
5572 +// vmbusDriver->OnChildDeviceDestroy(ChildDevice);
5578 + VmbusOnDeviceAdd()
5581 + Callback when the root bus device is added
5586 + DEVICE_OBJECT *dev,
5587 + void *AdditionalInfo
5590 + UINT32 *irqvector = (UINT32*) AdditionalInfo;
5593 + DPRINT_ENTER(VMBUS);
5597 + memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(GUID));
5598 + memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(GUID));
5600 + //strcpy(dev->name, "vmbus");
5602 + ret = HvSynicInit(*irqvector);
5604 + // Connect to VMBus in the root partition
5605 + ret = VmbusConnect();
5607 + //VmbusSendEvent(device->localPortId+1);
5608 + DPRINT_EXIT(VMBUS);
5617 + VmbusOnDeviceRemove()
5620 + Callback when the root bus device is removed
5623 +int VmbusOnDeviceRemove(
5624 + DEVICE_OBJECT* dev
5629 + DPRINT_ENTER(VMBUS);
5631 + VmbusChannelReleaseUnattachedChannels();
5633 + VmbusDisconnect();
5637 + DPRINT_EXIT(VMBUS);
5649 + Perform any cleanup when the driver is removed
5654 + DRIVER_OBJECT* drv
5657 + //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
5659 + DPRINT_ENTER(VMBUS);
5663 + DPRINT_EXIT(VMBUS);
5673 + DPC routine to handle messages from the hypervisior
5678 + DRIVER_OBJECT* drv
5681 + void *page_addr = gHvContext.synICMessagePage[0];
5683 + HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
5684 + HV_MESSAGE *copied;
5687 + if (msg->Header.MessageType == HvMessageTypeNone) // no msg
5693 + copied = MemAllocAtomic(sizeof(HV_MESSAGE));
5694 + if (copied == NULL)
5699 + memcpy(copied, msg, sizeof(HV_MESSAGE));
5700 + WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, VmbusOnChannelMessage, (void*)copied);
5703 + msg->Header.MessageType = HvMessageTypeNone;
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
5710 + if (msg->Header.MessageFlags.MessagePending)
5712 + // This will cause message queue rescan to possibly deliver another msg from the hypervisor
5713 + WriteMsr(HV_X64_MSR_EOM, 0);
5724 + DPC routine to handle events from the hypervisior
5729 + DRIVER_OBJECT* drv
5732 + // TODO: Process any events
5748 + DRIVER_OBJECT* drv
5751 + //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
5754 + //struct page* page;
5757 + HV_SYNIC_EVENT_FLAGS* event;
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;
5764 + DPRINT_ENTER(VMBUS);
5766 + // Check if there are actual msgs to be process
5767 + if (msg->Header.MessageType != HvMessageTypeNone)
5769 + DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize);
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;
5777 + // Since we are a child, we only need to check bit 0
5778 + if (BitTestAndClear(&event->Flags32[0], 0))
5780 + DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
5784 + DPRINT_EXIT(VMBUS);
5790 +++ b/drivers/staging/hv/vmbus_drv.c
5794 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
5810 + * Haiyang Zhang <haiyangz@microsoft.com>
5811 + * Hank Janssen <hjanssen@microsoft.com>
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>
5823 +#include "logging.h"
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
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;
5847 + struct bus_type bus;
5848 + struct tasklet_struct msg_dpc;
5849 + struct tasklet_struct event_dpc;
5851 + // The bus root device
5852 + struct device_context device_ctx;
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);
5866 +static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size);
5868 +static void vmbus_msg_dpc(unsigned long data);
5869 +static void vmbus_event_dpc(unsigned long data);
5871 +#ifdef KERNEL_2_6_27
5872 +static irqreturn_t vmbus_isr(int irq, void* dev_id);
5874 +static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs);
5877 +static void vmbus_device_release(struct device *device);
5878 +static void vmbus_bus_release(struct device *device);
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);
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);
5889 +static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf);
5895 +// Global logging setting
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);
5902 +static int vmbus_irq = VMBUS_IRQ;
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;
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),
5914 + .proc_handler = &proc_dointvec },
5918 +static ctl_table vmbus_ctl_table[] = {
5919 + { .ctl_name = CTL_DEV,
5920 + .procname = "vmbus",
5922 + .child = vmbus_dev_ctl_table },
5926 +static ctl_table vmus_root_ctl_table[] = {
5927 + { .ctl_name = CTL_BUS,
5928 + .procname = "bus",
5930 + .child = vmbus_ctl_table },
5934 +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
5937 +// Set up per device attributes in /sys/bus/vmbus/devices/<bus device>
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),
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),
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),
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),
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),
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)
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,
5990 +Name: vmbus_show_device_attr()
5992 +Desc: Show the device attribute in sysfs. This is invoked when user does a "cat /sys/bus/vmbus/devices/<bus device>/<attr name>"
5995 +static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf)
5997 + struct device_context *device_ctx = device_to_device_context(dev);
5998 + DEVICE_INFO device_info;
6000 + memset(&device_info, 0, sizeof(DEVICE_INFO));
6002 + vmbus_child_device_get_info(&device_ctx->device_obj, &device_info);
6004 + if (!strcmp(dev_attr->attr.name, "class_id"))
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]);
6013 + else if (!strcmp(dev_attr->attr.name, "device_id"))
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]);
6021 + else if (!strcmp(dev_attr->attr.name, "state"))
6023 + return sprintf(buf, "%d\n", device_info.ChannelState);
6025 + else if (!strcmp(dev_attr->attr.name, "id"))
6027 + return sprintf(buf, "%d\n", device_info.ChannelId);
6029 + else if (!strcmp(dev_attr->attr.name, "out_intr_mask"))
6031 + return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask);
6033 + else if (!strcmp(dev_attr->attr.name, "out_read_index"))
6035 + return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex);
6037 + else if (!strcmp(dev_attr->attr.name, "out_write_index"))
6039 + return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex);
6041 + else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail"))
6043 + return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToRead);
6045 + else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail"))
6047 + return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToWrite);
6049 + else if (!strcmp(dev_attr->attr.name, "in_intr_mask"))
6051 + return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask);
6053 + else if (!strcmp(dev_attr->attr.name, "in_read_index"))
6055 + return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex);
6057 + else if (!strcmp(dev_attr->attr.name, "in_write_index"))
6059 + return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex);
6061 + else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail"))
6063 + return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToRead);
6065 + else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail"))
6067 + return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToWrite);
6069 + else if (!strcmp(dev_attr->attr.name, "monitor_id"))
6071 + return sprintf(buf, "%d\n", device_info.MonitorId);
6073 + else if (!strcmp(dev_attr->attr.name, "server_monitor_pending"))
6075 + return sprintf(buf, "%d\n", device_info.ServerMonitorPending);
6077 + else if (!strcmp(dev_attr->attr.name, "server_monitor_latency"))
6079 + return sprintf(buf, "%d\n", device_info.ServerMonitorLatency);
6081 + else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id"))
6083 + return sprintf(buf, "%d\n", device_info.ServerMonitorConnectionId);
6085 + else if (!strcmp(dev_attr->attr.name, "client_monitor_pending"))
6087 + return sprintf(buf, "%d\n", device_info.ClientMonitorPending);
6089 + else if (!strcmp(dev_attr->attr.name, "client_monitor_latency"))
6091 + return sprintf(buf, "%d\n", device_info.ClientMonitorLatency);
6093 + else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id"))
6095 + return sprintf(buf, "%d\n", device_info.ClientMonitorConnectionId);
6105 +Name: vmbus_show_class_id()
6107 +Desc: Show the device class id in sysfs
6110 +//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf)
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]);
6122 +Name: vmbus_show_device_id()
6124 +Desc: Show the device instance id in sysfs
6127 +//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf)
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]);
6139 +Name: vmbus_bus_init()
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
6150 +int vmbus_bus_init(PFN_DRIVERINITIALIZE pfn_drv_init)
6153 + unsigned int vector=0;
6155 + struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv;
6156 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6158 + struct device_context *dev_ctx=&g_vmbus_drv.device_ctx;
6160 + DPRINT_ENTER(VMBUS_DRV);
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;
6168 + // Call to bus driver to initialize
6169 + ret = pfn_drv_init(&vmbus_drv_obj->Base);
6172 + DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret);
6177 + if (!vmbus_drv_obj->Base.OnDeviceAdd)
6179 + DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set");
6184 + vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name;
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);
6190 + // Now, register the bus driver with LDM
6191 + bus_register(&vmbus_drv_ctx->bus);
6193 + // Get the interrupt resource
6194 +#ifdef KERNEL_2_6_27
6195 + ret = request_irq(vmbus_irq,
6197 + IRQF_SAMPLE_RANDOM,
6198 + vmbus_drv_obj->Base.name,
6201 + ret = request_irq(vmbus_irq,
6204 + vmbus_drv_obj->Base.name,
6210 + DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", vmbus_irq);
6212 + bus_unregister(&vmbus_drv_ctx->bus);
6217 +#ifdef KERNEL_2_6_27
6218 + vector = VMBUS_IRQ_VECTOR;
6221 + vector = vmbus_irq + FIRST_DEVICE_VECTOR - 2;
6223 + vector = vmbus_irq + FIRST_EXTERNAL_VECTOR;
6227 + DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
6229 + // Call to bus driver to add the root device
6230 + memset(dev_ctx, 0, sizeof(struct device_context));
6232 + ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector);
6235 + DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to add vmbus root device");
6237 + free_irq(vmbus_irq, NULL);
6239 + bus_unregister(&vmbus_drv_ctx->bus);
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));
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
6253 + // Setup the device dispatch table
6254 + dev_ctx->device.release = vmbus_bus_release;
6256 + // Setup the bus as root device
6257 + device_register(&dev_ctx->device);
6259 + vmbus_drv_obj->GetChannelOffers();
6262 + DPRINT_EXIT(VMBUS_DRV);
6270 +Name: vmbus_bus_exit()
6272 +Desc: Terminate the vmbus driver. This routine is opposite of vmbus_bus_init()
6275 +void vmbus_bus_exit(void)
6277 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6278 + struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv;
6280 + struct device_context *dev_ctx=&g_vmbus_drv.device_ctx;
6282 + DPRINT_ENTER(VMBUS_DRV);
6284 + // Remove the root device
6285 + if (vmbus_drv_obj->Base.OnDeviceRemove)
6286 + vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj);
6288 + if (vmbus_drv_obj->Base.OnCleanup)
6289 + vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base);
6291 + // Unregister the root bus device
6292 + device_unregister(&dev_ctx->device);
6294 + bus_unregister(&vmbus_drv_ctx->bus);
6296 + free_irq(vmbus_irq, NULL);
6298 + tasklet_kill(&vmbus_drv_ctx->msg_dpc);
6299 + tasklet_kill(&vmbus_drv_ctx->event_dpc);
6301 + DPRINT_EXIT(VMBUS_DRV);
6308 +Name: vmbus_child_driver_register()
6310 +Desc: Register a vmbus's child driver
6313 +void vmbus_child_driver_register(struct driver_context* driver_ctx)
6315 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6317 + DPRINT_ENTER(VMBUS_DRV);
6319 + DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", driver_ctx, driver_ctx->driver.name);
6321 + // The child driver on this vmbus
6322 + driver_ctx->driver.bus = &g_vmbus_drv.bus;
6324 + driver_register(&driver_ctx->driver);
6326 + vmbus_drv_obj->GetChannelOffers();
6328 + DPRINT_EXIT(VMBUS_DRV);
6331 +EXPORT_SYMBOL(vmbus_child_driver_register);
6335 +Name: vmbus_child_driver_unregister()
6337 +Desc: Unregister a vmbus's child driver
6340 +void vmbus_child_driver_unregister(struct driver_context* driver_ctx)
6342 + DPRINT_ENTER(VMBUS_DRV);
6344 + DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", driver_ctx, driver_ctx->driver.name);
6346 + driver_unregister(&driver_ctx->driver);
6348 + driver_ctx->driver.bus = NULL;
6350 + DPRINT_EXIT(VMBUS_DRV);
6353 +EXPORT_SYMBOL(vmbus_child_driver_unregister);
6357 +Name: vmbus_get_interface()
6359 +Desc: Get the vmbus channel interface. This is invoked by child/client driver that sits
6362 +void vmbus_get_interface(VMBUS_CHANNEL_INTERFACE *interface)
6364 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6366 + vmbus_drv_obj->GetChannelInterface(interface);
6369 +EXPORT_SYMBOL(vmbus_get_interface);
6374 +Name: vmbus_child_device_get_info()
6376 +Desc: Get the vmbus child device info. This is invoked to display various device attributes in sysfs.
6378 +static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info)
6380 + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
6382 + vmbus_drv_obj->GetChannelInfo(device_obj, device_info);
6388 +Name: vmbus_child_device_create()
6390 +Desc: Creates and registers a new child device on the vmbus.
6393 +static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context)
6395 + struct device_context *child_device_ctx;
6396 + DEVICE_OBJECT* child_device_obj;
6398 + DPRINT_ENTER(VMBUS_DRV);
6400 + // Allocate the new child device
6401 + child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL);
6402 + if (!child_device_ctx)
6404 + DPRINT_ERR(VMBUS_DRV, "unable to allocate device_context for child device");
6405 + DPRINT_EXIT(VMBUS_DRV);
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]);
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));
6422 + memcpy(&child_device_ctx->class_id, &type, sizeof(GUID));
6423 + memcpy(&child_device_ctx->device_id, &instance, sizeof(GUID));
6425 + DPRINT_EXIT(VMBUS_DRV);
6427 + return child_device_obj;
6432 +Name: vmbus_child_device_register()
6434 +Desc: Register the child device on the specified bus
6437 +static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj)
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;
6444 + DPRINT_ENTER(VMBUS_DRV);
6446 + DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", child_device_ctx);
6448 + // Make sure we are not registered already
6450 + if (child_device_ctx->device.bus_id[0] != '\0')
6452 + DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, child_device_ctx->device.bus_id);
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));
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;
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);
6470 + // vmbus_probe() error does not get propergate to device_register().
6471 + ret = child_device_ctx->probe_error;
6474 + DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p) (%d)", &child_device_ctx->device);
6476 + DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", &child_device_ctx->device);
6479 + DPRINT_EXIT(VMBUS_DRV);
6486 +Name: vmbus_child_device_unregister()
6488 +Desc: Remove the specified child device from the vmbus.
6491 +static void vmbus_child_device_unregister(DEVICE_OBJECT* device_obj)
6493 + struct device_context *device_ctx = to_device_context(device_obj);
6495 + DPRINT_ENTER(VMBUS_DRV);
6497 + DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", &device_ctx->device);
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);
6503 + DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", &device_ctx->device);
6505 + DPRINT_EXIT(VMBUS_DRV);
6511 +Name: vmbus_child_device_destroy()
6513 +Desc: Destroy the specified child device on the vmbus.
6516 +static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj)
6518 + DPRINT_ENTER(VMBUS_DRV);
6520 + DPRINT_EXIT(VMBUS_DRV);
6525 +Name: vmbus_uevent()
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
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)
6535 + struct device_context *device_ctx = device_to_device_context(device);
6540 + DPRINT_ENTER(VMBUS_DRV);
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]);
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]);
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]);
6577 + env->envp[env->envp_idx] = NULL;
6579 + DPRINT_EXIT(VMBUS_DRV);
6585 +static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size)
6587 + struct device_context *device_ctx = device_to_device_context(device);
6592 + DPRINT_ENTER(VMBUS_DRV);
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]);
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]);
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]);
6629 + DPRINT_EXIT(VMBUS_DRV);
6637 +Name: vmbus_match()
6639 +Desc: Attempt to match the specified device to the specified driver
6642 +static int vmbus_match(struct device *device, struct device_driver *driver)
6645 + struct driver_context *driver_ctx = driver_to_driver_context(driver);
6646 + struct device_context *device_ctx = device_to_device_context(device);
6648 + DPRINT_ENTER(VMBUS_DRV);
6650 + // We found our driver ?
6651 + if (memcmp(&device_ctx->class_id, &driver_ctx->class_id, sizeof(GUID)) == 0)
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);
6662 + DPRINT_EXIT(VMBUS_DRV);
6670 +Name: vmbus_probe_failed_cb()
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
6677 +#ifdef KERNEL_2_6_27
6678 +static void vmbus_probe_failed_cb(struct work_struct *context)
6680 +static void vmbus_probe_failed_cb(void* context)
6683 + struct device_context *device_ctx = (struct device_context*)context;
6686 + DPRINT_ENTER(VMBUS_DRV);
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);
6692 + //put_device(&device_ctx->device);
6693 + DPRINT_EXIT(VMBUS_DRV);
6699 +Name: vmbus_probe()
6701 +Desc: Add the new vmbus's child device
6704 +static int vmbus_probe(struct device *child_device)
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);
6710 + DPRINT_ENTER(VMBUS_DRV);
6712 + // Let the specific open-source driver handles the probe if it can
6713 + if (driver_ctx->probe)
6715 + ret = device_ctx->probe_error = driver_ctx->probe(child_device);
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);
6720 +#ifdef KERNEL_2_6_27
6721 + INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb);
6723 + INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb, device_ctx);
6725 + schedule_work(&device_ctx->probe_failed_work_item);
6730 + DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", child_device->driver->name);
6734 + DPRINT_EXIT(VMBUS_DRV);
6741 +Name: vmbus_remove()
6743 +Desc: Remove a vmbus device
6746 +static int vmbus_remove(struct device *child_device)
6749 + struct driver_context *driver_ctx;
6751 + DPRINT_ENTER(VMBUS_DRV);
6753 + // Special case root bus device
6754 + if (child_device->parent == NULL)
6756 + // No-op since it is statically defined and handle in vmbus_bus_exit()
6757 + DPRINT_EXIT(VMBUS_DRV);
6761 + if (child_device->driver)
6763 + driver_ctx = driver_to_driver_context(child_device->driver);
6765 + // Let the specific open-source driver handles the removal if it can
6766 + if (driver_ctx->remove)
6768 + ret = driver_ctx->remove(child_device);
6772 + DPRINT_ERR(VMBUS_DRV, "remove() method not set for driver - %s", child_device->driver->name);
6781 + DPRINT_EXIT(VMBUS_DRV);
6788 +Name: vmbus_shutdown()
6790 +Desc: Shutdown a vmbus device
6793 +static void vmbus_shutdown(struct device *child_device)
6795 + struct driver_context *driver_ctx;
6797 + DPRINT_ENTER(VMBUS_DRV);
6799 + // Special case root bus device
6800 + if (child_device->parent == NULL)
6802 + // No-op since it is statically defined and handle in vmbus_bus_exit()
6803 + DPRINT_EXIT(VMBUS_DRV);
6807 + // The device may not be attached yet
6808 + if (!child_device->driver)
6810 + DPRINT_EXIT(VMBUS_DRV);
6814 + driver_ctx = driver_to_driver_context(child_device->driver);
6816 + // Let the specific open-source driver handles the removal if it can
6817 + if (driver_ctx->shutdown)
6819 + driver_ctx->shutdown(child_device);
6822 + DPRINT_EXIT(VMBUS_DRV);
6829 +Name: vmbus_bus_release()
6831 +Desc: Final callback release of the vmbus root device
6834 +static void vmbus_bus_release(struct device *device)
6836 + DPRINT_ENTER(VMBUS_DRV);
6837 + DPRINT_EXIT(VMBUS_DRV);
6842 +Name: vmbus_device_release()
6844 +Desc: Final callback release of the vmbus child device
6847 +static void vmbus_device_release(struct device *device)
6849 + struct device_context *device_ctx = device_to_device_context(device);
6851 + DPRINT_ENTER(VMBUS_DRV);
6853 + //vmbus_child_device_destroy(&device_ctx->device_obj);
6854 + kfree(device_ctx);
6856 + // !!DO NOT REFERENCE device_ctx anymore at this point!!
6858 + DPRINT_EXIT(VMBUS_DRV);
6865 +Name: vmbus_msg_dpc()
6867 +Desc: Tasklet routine to handle hypervisor messages
6870 +static void vmbus_msg_dpc(unsigned long data)
6872 + VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data;
6874 + DPRINT_ENTER(VMBUS_DRV);
6876 + ASSERT(vmbus_drv_obj->OnMsgDpc != NULL);
6878 + // Call to bus driver to handle interrupt
6879 + vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base);
6881 + DPRINT_EXIT(VMBUS_DRV);
6886 +Name: vmbus_msg_dpc()
6888 +Desc: Tasklet routine to handle hypervisor events
6891 +static void vmbus_event_dpc(unsigned long data)
6893 + VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data;
6895 + DPRINT_ENTER(VMBUS_DRV);
6897 + ASSERT(vmbus_drv_obj->OnEventDpc != NULL);
6899 + // Call to bus driver to handle interrupt
6900 + vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base);
6902 + DPRINT_EXIT(VMBUS_DRV);
6907 +Name: vmbus_msg_dpc()
6912 +#ifdef KERNEL_2_6_27
6913 +static irqreturn_t vmbus_isr(int irq, void* dev_id)
6915 +static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs)
6919 + VMBUS_DRIVER_OBJECT* vmbus_driver_obj = &g_vmbus_drv.drv_obj;
6921 + DPRINT_ENTER(VMBUS_DRV);
6923 + ASSERT(vmbus_driver_obj->OnIsr != NULL);
6925 + // Call to bus driver to handle interrupt
6926 + ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base);
6928 + // Schedules a dpc if necessary
6931 + if (test_bit(0, (unsigned long*)&ret))
6933 + tasklet_schedule(&g_vmbus_drv.msg_dpc);
6936 + if (test_bit(1, (unsigned long*)&ret))
6938 + tasklet_schedule(&g_vmbus_drv.event_dpc);
6941 + DPRINT_EXIT(VMBUS_DRV);
6942 + return IRQ_HANDLED;
6946 + DPRINT_EXIT(VMBUS_DRV);
6951 +MODULE_LICENSE("GPL");
6958 +Desc: Main vmbus driver entry routine
6961 +static int __init vmbus_init(void)
6965 + DPRINT_ENTER(VMBUS_DRV);
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.
6973 + vmbus_ctl_table_hdr = register_sysctl_table(vmus_root_ctl_table, 0);
6974 + if (!vmbus_ctl_table_hdr)
6976 + DPRINT_EXIT(VMBUS_DRV);
6981 + ret = vmbus_bus_init(VmbusInitialize);
6983 + DPRINT_EXIT(VMBUS_DRV);
6993 +Desc: Main vmbus driver exit routine
6996 +static void __exit vmbus_exit(void)
6998 + DPRINT_ENTER(VMBUS_DRV);
7001 +#ifdef KERNEL_2_6_27
7002 +//Todo: it is used for loglevel, to be ported to new kernel.
7004 + unregister_sysctl_table(vmbus_ctl_table_hdr);
7006 + DPRINT_EXIT(VMBUS_DRV);
7011 +#if defined(KERNEL_2_6_5)
7013 +module_param(vmbus_irq, int, S_IRUGO);
7014 +module_param(vmbus_loglevel, int, S_IRUGO);
7017 +module_init(vmbus_init);
7018 +module_exit(vmbus_exit);
7021 +++ b/drivers/staging/hv/VmbusPrivate.h
7025 + * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
7041 + * Haiyang Zhang <haiyangz@microsoft.com>
7042 + * Hank Janssen <hjanssen@microsoft.com>
7047 +#ifndef _VMBUS_PRIVATE_H_
7048 +#define _VMBUS_PRIVATE_H_
7051 +#define INTERNAL static
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"
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
7072 +// The value here must be in multiple of 32
7073 +// TODO: Need to make this configurable
7074 +#define MAX_NUM_CHANNELS_SUPPORTED 256
7085 +} VMBUS_CONNECT_STATE;
7087 +#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
7089 +typedef struct _VMBUS_CONNECTION {
7091 + VMBUS_CONNECT_STATE ConnectState;
7093 + UINT32 NextGpadlHandle;
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;
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;
7111 + // List of channels
7112 + LIST_ENTRY ChannelList;
7113 + HANDLE ChannelLock;
7116 +} VMBUS_CONNECTION;
7119 +typedef struct _VMBUS_MSGINFO {
7120 + // Bookkeeping stuff
7121 + LIST_ENTRY MsgListEntry;
7123 + // Synchronize the request/response if needed
7126 + // The message itself
7127 + unsigned char Msg[0];
7134 +extern VMBUS_CONNECTION gVmbusConnection;
7137 +// General vmbus interface
7139 +INTERNAL DEVICE_OBJECT*
7140 +VmbusChildDeviceCreate(
7142 + GUID deviceInstance,
7146 +VmbusChildDeviceAdd(
7147 + DEVICE_OBJECT* Device);
7150 +VmbusChildDeviceRemove(
7151 + DEVICE_OBJECT* Device);
7154 +//VmbusChildDeviceDestroy(
7155 +// DEVICE_OBJECT*);
7157 +INTERNAL VMBUS_CHANNEL*
7158 +GetChannelFromRelId(
7163 +// Connection interface
7192 +#endif // _VMBUS_PRIVATE_H_