3 * Copyright (c) 2009, Microsoft Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
28 #include "VmbusPrivate.h"
34 VmbusChannelCreateGpadlHeader(
35 PVOID Kbuffer
, // must be phys and virt contiguous
36 UINT32 Size
, // page-size multiple
37 VMBUS_CHANNEL_MSGINFO
**msgInfo
,
43 VMBUS_CHANNEL
*Channel
49 VMBUS_CHANNEL
*Channel
56 HV_MONITOR_PAGE
*MonitorPage
62 DPRINT_DBG(VMBUS
, "monitorPage - %p, trigger state - %d", MonitorPage
, MonitorPage
->TriggerState
);
66 DPRINT_DBG(VMBUS
, "trigger group (%d) - %llx", i
, MonitorPage
->TriggerGroup
[i
].AsUINT64
);
73 DPRINT_DBG(VMBUS
, "latency (%d)(%d) - %llx", i
, j
, MonitorPage
->Latency
[i
][j
]);
80 DPRINT_DBG(VMBUS
, "param-conn id (%d)(%d) - %d", i
, j
, MonitorPage
->Parameter
[i
][j
].ConnectionId
.AsUINT32
);
81 DPRINT_DBG(VMBUS
, "param-flag (%d)(%d) - %d", i
, j
, MonitorPage
->Parameter
[i
][j
].FlagNumber
);
91 VmbusChannelSetEvent()
94 Trigger an event notification on the specified channel.
99 VMBUS_CHANNEL
*Channel
102 HV_MONITOR_PAGE
*monitorPage
;
106 if (Channel
->OfferMsg
.MonitorAllocated
)
108 // Each UINT32 represents 32 channels
109 BitSet((UINT32
*)gVmbusConnection
.SendInterruptPage
+ (Channel
->OfferMsg
.ChildRelId
>> 5), Channel
->OfferMsg
.ChildRelId
& 31);
111 monitorPage
= (HV_MONITOR_PAGE
*)gVmbusConnection
.MonitorPages
;
112 monitorPage
++; // Get the child to parent monitor page
114 BitSet((UINT32
*) &monitorPage
->TriggerGroup
[Channel
->MonitorGroup
].Pending
, Channel
->MonitorBit
);
118 VmbusSetEvent(Channel
->OfferMsg
.ChildRelId
);
126 VmbusChannelClearEvent(
127 VMBUS_CHANNEL
*Channel
130 HV_MONITOR_PAGE
*monitorPage
;
134 if (Channel
->OfferMsg
.MonitorAllocated
)
136 // Each UINT32 represents 32 channels
137 BitClear((UINT32
*)gVmbusConnection
.SendInterruptPage
+ (Channel
->OfferMsg
.ChildRelId
>> 5), Channel
->OfferMsg
.ChildRelId
& 31);
139 monitorPage
= (HV_MONITOR_PAGE
*)gVmbusConnection
.MonitorPages
;
140 monitorPage
++; // Get the child to parent monitor page
142 BitClear((UINT32
*) &monitorPage
->TriggerGroup
[Channel
->MonitorGroup
].Pending
, Channel
->MonitorBit
);
152 VmbusChannelGetDebugInfo()
155 Retrieve various channel debug info
159 VmbusChannelGetDebugInfo(
160 VMBUS_CHANNEL
*Channel
,
161 VMBUS_CHANNEL_DEBUG_INFO
*DebugInfo
164 HV_MONITOR_PAGE
*monitorPage
;
165 UINT8 monitorGroup
= (UINT8
)Channel
->OfferMsg
.MonitorId
/ 32;
166 UINT8 monitorOffset
= (UINT8
)Channel
->OfferMsg
.MonitorId
% 32;
167 //UINT32 monitorBit = 1 << monitorOffset;
169 DebugInfo
->RelId
= Channel
->OfferMsg
.ChildRelId
;
170 DebugInfo
->State
= Channel
->State
;
171 memcpy(&DebugInfo
->InterfaceType
, &Channel
->OfferMsg
.Offer
.InterfaceType
, sizeof(GUID
));
172 memcpy(&DebugInfo
->InterfaceInstance
, &Channel
->OfferMsg
.Offer
.InterfaceInstance
, sizeof(GUID
));
174 monitorPage
= (HV_MONITOR_PAGE
*)gVmbusConnection
.MonitorPages
;
176 DebugInfo
->MonitorId
= Channel
->OfferMsg
.MonitorId
;
178 DebugInfo
->ServerMonitorPending
= monitorPage
->TriggerGroup
[monitorGroup
].Pending
;
179 DebugInfo
->ServerMonitorLatency
= monitorPage
->Latency
[monitorGroup
][ monitorOffset
];
180 DebugInfo
->ServerMonitorConnectionId
= monitorPage
->Parameter
[monitorGroup
][ monitorOffset
].ConnectionId
.u
.Id
;
184 DebugInfo
->ClientMonitorPending
= monitorPage
->TriggerGroup
[monitorGroup
].Pending
;
185 DebugInfo
->ClientMonitorLatency
= monitorPage
->Latency
[monitorGroup
][ monitorOffset
];
186 DebugInfo
->ClientMonitorConnectionId
= monitorPage
->Parameter
[monitorGroup
][ monitorOffset
].ConnectionId
.u
.Id
;
188 RingBufferGetDebugInfo(&Channel
->Inbound
, &DebugInfo
->Inbound
);
189 RingBufferGetDebugInfo(&Channel
->Outbound
, &DebugInfo
->Outbound
);
199 Open the specified channel.
204 VMBUS_CHANNEL
*NewChannel
,
205 UINT32 SendRingBufferSize
,
206 UINT32 RecvRingBufferSize
,
209 PFN_CHANNEL_CALLBACK pfnOnChannelCallback
,
214 VMBUS_CHANNEL_OPEN_CHANNEL
* openMsg
;
215 VMBUS_CHANNEL_MSGINFO
* openInfo
;
220 // Aligned to page size
221 ASSERT(!(SendRingBufferSize
& (PAGE_SIZE
-1)));
222 ASSERT(!(RecvRingBufferSize
& (PAGE_SIZE
-1)));
224 NewChannel
->OnChannelCallback
= pfnOnChannelCallback
;
225 NewChannel
->ChannelCallbackContext
= Context
;
227 // Allocate the ring buffer
228 out
= PageAlloc((SendRingBufferSize
+ RecvRingBufferSize
) >> PAGE_SHIFT
);
229 //out = MemAllocZeroed(sendRingBufferSize + recvRingBufferSize);
231 ASSERT(((ULONG_PTR
)out
& (PAGE_SIZE
-1)) == 0);
233 in
= (void*)((ULONG_PTR
)out
+ SendRingBufferSize
);
235 NewChannel
->RingBufferPages
= out
;
236 NewChannel
->RingBufferPageCount
= (SendRingBufferSize
+ RecvRingBufferSize
) >> PAGE_SHIFT
;
238 RingBufferInit(&NewChannel
->Outbound
, out
, SendRingBufferSize
);
240 RingBufferInit(&NewChannel
->Inbound
, in
, RecvRingBufferSize
);
242 // Establish the gpadl for the ring buffer
243 DPRINT_DBG(VMBUS
, "Establishing ring buffer's gpadl for channel %p...", NewChannel
);
245 NewChannel
->RingBufferGpadlHandle
= 0;
247 ret
= VmbusChannelEstablishGpadl(NewChannel
,
248 NewChannel
->Outbound
.RingBuffer
,
249 SendRingBufferSize
+ RecvRingBufferSize
,
250 &NewChannel
->RingBufferGpadlHandle
);
252 DPRINT_DBG(VMBUS
, "channel %p <relid %d gpadl 0x%x send ring %p size %d recv ring %p size %d, downstreamoffset %d>",
254 NewChannel
->OfferMsg
.ChildRelId
,
255 NewChannel
->RingBufferGpadlHandle
,
256 NewChannel
->Outbound
.RingBuffer
,
257 NewChannel
->Outbound
.RingSize
,
258 NewChannel
->Inbound
.RingBuffer
,
259 NewChannel
->Inbound
.RingSize
,
262 // Create and init the channel open message
264 (VMBUS_CHANNEL_MSGINFO
*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL
));
265 ASSERT(openInfo
!= NULL
);
267 openInfo
->WaitEvent
= WaitEventCreate();
269 openMsg
= (VMBUS_CHANNEL_OPEN_CHANNEL
*)openInfo
->Msg
;
270 openMsg
->Header
.MessageType
= ChannelMessageOpenChannel
;
271 openMsg
->OpenId
= NewChannel
->OfferMsg
.ChildRelId
; // FIXME
272 openMsg
->ChildRelId
= NewChannel
->OfferMsg
.ChildRelId
;
273 openMsg
->RingBufferGpadlHandle
= NewChannel
->RingBufferGpadlHandle
;
274 ASSERT(openMsg
->RingBufferGpadlHandle
);
275 openMsg
->DownstreamRingBufferPageOffset
= SendRingBufferSize
>> PAGE_SHIFT
;
276 openMsg
->ServerContextAreaGpadlHandle
= 0; // TODO
278 ASSERT(UserDataLen
<= MAX_USER_DEFINED_BYTES
);
281 memcpy(openMsg
->UserData
, UserData
, UserDataLen
);
284 SpinlockAcquire(gVmbusConnection
.ChannelMsgLock
);
285 INSERT_TAIL_LIST(&gVmbusConnection
.ChannelMsgList
, &openInfo
->MsgListEntry
);
286 SpinlockRelease(gVmbusConnection
.ChannelMsgLock
);
288 DPRINT_DBG(VMBUS
, "Sending channel open msg...");
290 ret
= VmbusPostMessage(openMsg
, sizeof(VMBUS_CHANNEL_OPEN_CHANNEL
));
293 DPRINT_ERR(VMBUS
, "unable to open channel - %d", ret
);
297 // FIXME: Need to time-out here
298 WaitEventWait(openInfo
->WaitEvent
);
300 if (openInfo
->Response
.OpenResult
.Status
== 0)
302 DPRINT_INFO(VMBUS
, "channel <%p> open success!!", NewChannel
);
306 DPRINT_INFO(VMBUS
, "channel <%p> open failed - %d!!", NewChannel
, openInfo
->Response
.OpenResult
.Status
);
310 SpinlockAcquire(gVmbusConnection
.ChannelMsgLock
);
311 REMOVE_ENTRY_LIST(&openInfo
->MsgListEntry
);
312 SpinlockRelease(gVmbusConnection
.ChannelMsgLock
);
314 WaitEventClose(openInfo
->WaitEvent
);
328 Dump the gpadl body message to the console for debugging purposes.
331 static void DumpGpadlBody(
332 VMBUS_CHANNEL_GPADL_BODY
*Gpadl
,
338 pfnCount
= (Len
- sizeof(VMBUS_CHANNEL_GPADL_BODY
))/ sizeof(UINT64
);
339 DPRINT_DBG(VMBUS
, "gpadl body - len %d pfn count %d", Len
, pfnCount
);
341 for (i
=0; i
< pfnCount
; i
++)
343 DPRINT_DBG(VMBUS
, "gpadl body - %d) pfn %llu", i
, Gpadl
->Pfn
[i
]);
354 Dump the gpadl header message to the console for debugging purposes.
357 static void DumpGpadlHeader(
358 VMBUS_CHANNEL_GPADL_HEADER
*Gpadl
365 DPRINT_DBG(VMBUS
, "gpadl header - relid %d, range count %d, range buflen %d",
369 for (i
=0; i
< Gpadl
->RangeCount
; i
++)
371 pageCount
= Gpadl
->Range
[i
].ByteCount
>> PAGE_SHIFT
;
372 pageCount
= (pageCount
> 26)? 26 : pageCount
;
374 DPRINT_DBG(VMBUS
, "gpadl range %d - len %d offset %d page count %d",
375 i
, Gpadl
->Range
[i
].ByteCount
, Gpadl
->Range
[i
].ByteOffset
, pageCount
);
377 for (j
=0; j
< pageCount
; j
++)
379 DPRINT_DBG(VMBUS
, "%d) pfn %llu", j
, Gpadl
->Range
[i
].PfnArray
[j
]);
387 VmbusChannelCreateGpadlHeader()
390 Creates a gpadl for the specified buffer
394 VmbusChannelCreateGpadlHeader(
395 PVOID Kbuffer
, // from kmalloc()
396 UINT32 Size
, // page-size multiple
397 VMBUS_CHANNEL_MSGINFO
**MsgInfo
,
398 UINT32
*MessageCount
)
402 unsigned long long pfn
;
403 VMBUS_CHANNEL_GPADL_HEADER
* gpaHeader
;
404 VMBUS_CHANNEL_GPADL_BODY
* gpadlBody
;
405 VMBUS_CHANNEL_MSGINFO
* msgHeader
;
406 VMBUS_CHANNEL_MSGINFO
* msgBody
;
409 int pfnSum
, pfnCount
, pfnLeft
, pfnCurr
, pfnSize
;
411 //ASSERT( (kbuffer & (PAGE_SIZE-1)) == 0);
412 ASSERT( (Size
& (PAGE_SIZE
-1)) == 0);
414 pageCount
= Size
>> PAGE_SHIFT
;
415 pfn
= GetPhysicalAddress(Kbuffer
) >> PAGE_SHIFT
;
417 // do we need a gpadl body msg
418 pfnSize
= MAX_SIZE_CHANNEL_MESSAGE
- sizeof(VMBUS_CHANNEL_GPADL_HEADER
) - sizeof(GPA_RANGE
);
419 pfnCount
= pfnSize
/ sizeof(UINT64
);
421 if (pageCount
> pfnCount
) // we need a gpadl body
423 // fill in the header
424 msgSize
= sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_GPADL_HEADER
) + sizeof(GPA_RANGE
) + pfnCount
*sizeof(UINT64
);
425 msgHeader
= MemAllocZeroed(msgSize
);
427 INITIALIZE_LIST_HEAD(&msgHeader
->SubMsgList
);
428 msgHeader
->MessageSize
=msgSize
;
430 gpaHeader
= (VMBUS_CHANNEL_GPADL_HEADER
*)msgHeader
->Msg
;
431 gpaHeader
->RangeCount
= 1;
432 gpaHeader
->RangeBufLen
= sizeof(GPA_RANGE
) + pageCount
*sizeof(UINT64
);
433 gpaHeader
->Range
[0].ByteOffset
= 0;
434 gpaHeader
->Range
[0].ByteCount
= Size
;
435 for (i
=0; i
<pfnCount
; i
++)
437 gpaHeader
->Range
[0].PfnArray
[i
] = pfn
+i
;
439 *MsgInfo
= msgHeader
;
443 pfnLeft
= pageCount
- pfnCount
;
445 // how many pfns can we fit
446 pfnSize
= MAX_SIZE_CHANNEL_MESSAGE
- sizeof(VMBUS_CHANNEL_GPADL_BODY
);
447 pfnCount
= pfnSize
/ sizeof(UINT64
);
452 if (pfnLeft
> pfnCount
)
461 msgSize
= sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_GPADL_BODY
) + pfnCurr
*sizeof(UINT64
);
462 msgBody
= MemAllocZeroed(msgSize
);
464 msgBody
->MessageSize
= msgSize
;
466 gpadlBody
= (VMBUS_CHANNEL_GPADL_BODY
*)msgBody
->Msg
;
468 // FIXME: Gpadl is UINT32 and we are using a pointer which could be 64-bit
469 //gpadlBody->Gpadl = kbuffer;
470 for (i
=0; i
<pfnCurr
; i
++)
472 gpadlBody
->Pfn
[i
] = pfn
+ pfnSum
+ i
;
476 INSERT_TAIL_LIST(&msgHeader
->SubMsgList
, &msgBody
->MsgListEntry
);
483 // everything fits in a header
484 msgSize
= sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_GPADL_HEADER
) + sizeof(GPA_RANGE
) + pageCount
*sizeof(UINT64
);
485 msgHeader
= MemAllocZeroed(msgSize
);
486 msgHeader
->MessageSize
=msgSize
;
488 gpaHeader
= (VMBUS_CHANNEL_GPADL_HEADER
*)msgHeader
->Msg
;
489 gpaHeader
->RangeCount
= 1;
490 gpaHeader
->RangeBufLen
= sizeof(GPA_RANGE
) + pageCount
*sizeof(UINT64
);
491 gpaHeader
->Range
[0].ByteOffset
= 0;
492 gpaHeader
->Range
[0].ByteCount
= Size
;
493 for (i
=0; i
<pageCount
; i
++)
495 gpaHeader
->Range
[0].PfnArray
[i
] = pfn
+i
;
498 *MsgInfo
= msgHeader
;
509 VmbusChannelEstablishGpadl()
512 Estabish a GPADL for the specified buffer
516 VmbusChannelEstablishGpadl(
517 VMBUS_CHANNEL
*Channel
,
518 PVOID Kbuffer
, // from kmalloc()
519 UINT32 Size
, // page-size multiple
524 VMBUS_CHANNEL_GPADL_HEADER
* gpadlMsg
;
525 VMBUS_CHANNEL_GPADL_BODY
* gpadlBody
;
526 //VMBUS_CHANNEL_GPADL_CREATED* gpadlCreated;
528 VMBUS_CHANNEL_MSGINFO
*msgInfo
;
529 VMBUS_CHANNEL_MSGINFO
*subMsgInfo
;
534 UINT32 nextGpadlHandle
;
538 nextGpadlHandle
= gVmbusConnection
.NextGpadlHandle
;
539 InterlockedIncrement((int*)&gVmbusConnection
.NextGpadlHandle
);
541 VmbusChannelCreateGpadlHeader(Kbuffer
, Size
, &msgInfo
, &msgCount
);
542 ASSERT(msgInfo
!= NULL
);
545 msgInfo
->WaitEvent
= WaitEventCreate();
546 gpadlMsg
= (VMBUS_CHANNEL_GPADL_HEADER
*)msgInfo
->Msg
;
547 gpadlMsg
->Header
.MessageType
= ChannelMessageGpadlHeader
;
548 gpadlMsg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
549 gpadlMsg
->Gpadl
= nextGpadlHandle
;
551 DumpGpadlHeader(gpadlMsg
);
553 SpinlockAcquire(gVmbusConnection
.ChannelMsgLock
);
554 INSERT_TAIL_LIST(&gVmbusConnection
.ChannelMsgList
, &msgInfo
->MsgListEntry
);
555 SpinlockRelease(gVmbusConnection
.ChannelMsgLock
);
557 DPRINT_DBG(VMBUS
, "buffer %p, size %d msg cnt %d", Kbuffer
, Size
, msgCount
);
559 DPRINT_DBG(VMBUS
, "Sending GPADL Header - len %d", msgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
561 ret
= VmbusPostMessage(gpadlMsg
, msgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
564 DPRINT_ERR(VMBUS
, "Unable to open channel - %d", ret
);
570 ITERATE_LIST_ENTRIES(anchor
, curr
, &msgInfo
->SubMsgList
)
572 subMsgInfo
= (VMBUS_CHANNEL_MSGINFO
*) curr
;
573 gpadlBody
= (VMBUS_CHANNEL_GPADL_BODY
*)subMsgInfo
->Msg
;
575 gpadlBody
->Header
.MessageType
= ChannelMessageGpadlBody
;
576 gpadlBody
->Gpadl
= nextGpadlHandle
;
578 DPRINT_DBG(VMBUS
, "Sending GPADL Body - len %d", subMsgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
580 DumpGpadlBody(gpadlBody
, subMsgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
581 ret
= VmbusPostMessage(gpadlBody
, subMsgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
585 WaitEventWait(msgInfo
->WaitEvent
);
587 // At this point, we received the gpadl created msg
588 DPRINT_DBG(VMBUS
, "Received GPADL created (relid %d, status %d handle %x)",
589 Channel
->OfferMsg
.ChildRelId
,
590 msgInfo
->Response
.GpadlCreated
.CreationStatus
,
593 *GpadlHandle
= gpadlMsg
->Gpadl
;
596 SpinlockAcquire(gVmbusConnection
.ChannelMsgLock
);
597 REMOVE_ENTRY_LIST(&msgInfo
->MsgListEntry
);
598 SpinlockRelease(gVmbusConnection
.ChannelMsgLock
);
600 WaitEventClose(msgInfo
->WaitEvent
);
613 VmbusChannelTeardownGpadl()
616 Teardown the specified GPADL handle
620 VmbusChannelTeardownGpadl(
621 VMBUS_CHANNEL
*Channel
,
626 VMBUS_CHANNEL_GPADL_TEARDOWN
*msg
;
627 VMBUS_CHANNEL_MSGINFO
* info
;
631 ASSERT(GpadlHandle
!= 0);
634 (VMBUS_CHANNEL_MSGINFO
*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN
));
635 ASSERT(info
!= NULL
);
637 info
->WaitEvent
= WaitEventCreate();
639 msg
= (VMBUS_CHANNEL_GPADL_TEARDOWN
*)info
->Msg
;
641 msg
->Header
.MessageType
= ChannelMessageGpadlTeardown
;
642 msg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
643 msg
->Gpadl
= GpadlHandle
;
645 SpinlockAcquire(gVmbusConnection
.ChannelMsgLock
);
646 INSERT_TAIL_LIST(&gVmbusConnection
.ChannelMsgList
, &info
->MsgListEntry
);
647 SpinlockRelease(gVmbusConnection
.ChannelMsgLock
);
649 ret
= VmbusPostMessage(msg
, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN
));
655 WaitEventWait(info
->WaitEvent
);
657 // Received a torndown response
658 SpinlockAcquire(gVmbusConnection
.ChannelMsgLock
);
659 REMOVE_ENTRY_LIST(&info
->MsgListEntry
);
660 SpinlockRelease(gVmbusConnection
.ChannelMsgLock
);
662 WaitEventClose(info
->WaitEvent
);
677 Close the specified channel
682 VMBUS_CHANNEL
*Channel
686 VMBUS_CHANNEL_CLOSE_CHANNEL
* msg
;
687 VMBUS_CHANNEL_MSGINFO
* info
;
691 // Stop callback and cancel the timer asap
692 Channel
->OnChannelCallback
= NULL
;
693 TimerStop(Channel
->PollTimer
);
695 // Send a closing message
697 (VMBUS_CHANNEL_MSGINFO
*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL
));
698 ASSERT(info
!= NULL
);
700 //info->waitEvent = WaitEventCreate();
702 msg
= (VMBUS_CHANNEL_CLOSE_CHANNEL
*)info
->Msg
;
703 msg
->Header
.MessageType
= ChannelMessageCloseChannel
;
704 msg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
706 ret
= VmbusPostMessage(msg
, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL
));
712 // Tear down the gpadl for the channel's ring buffer
713 if (Channel
->RingBufferGpadlHandle
)
715 VmbusChannelTeardownGpadl(Channel
, Channel
->RingBufferGpadlHandle
);
718 // TODO: Send a msg to release the childRelId
720 // Cleanup the ring buffers for this channel
721 RingBufferCleanup(&Channel
->Outbound
);
722 RingBufferCleanup(&Channel
->Inbound
);
724 PageFree(Channel
->RingBufferPages
, Channel
->RingBufferPageCount
);
728 // If we are closing the channel during an error path in opening the channel, don't free the channel
729 // since the caller will free the channel
730 if (Channel
->State
== CHANNEL_OPEN_STATE
)
732 SpinlockAcquire(gVmbusConnection
.ChannelLock
);
733 REMOVE_ENTRY_LIST(&Channel
->ListEntry
);
734 SpinlockRelease(gVmbusConnection
.ChannelLock
);
736 FreeVmbusChannel(Channel
);
746 VmbusChannelSendPacket()
749 Send the specified buffer on the given channel
753 VmbusChannelSendPacket(
754 VMBUS_CHANNEL
*Channel
,
758 VMBUS_PACKET_TYPE Type
,
763 VMPACKET_DESCRIPTOR desc
;
764 UINT32 packetLen
= sizeof(VMPACKET_DESCRIPTOR
) + BufferLen
;
765 UINT32 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(UINT64
));
766 SG_BUFFER_LIST bufferList
[3];
767 UINT64 alignedData
=0;
770 DPRINT_DBG(VMBUS
, "channel %p buffer %p len %d", Channel
, Buffer
, BufferLen
);
772 DumpVmbusChannel(Channel
);
774 ASSERT((packetLenAligned
- packetLen
) < sizeof(UINT64
));
776 // Setup the descriptor
777 desc
.Type
= Type
;//VmbusPacketTypeDataInBand;
778 desc
.Flags
= Flags
;//VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
779 desc
.DataOffset8
= sizeof(VMPACKET_DESCRIPTOR
) >> 3; // in 8-bytes granularity
780 desc
.Length8
= (UINT16
)(packetLenAligned
>> 3);
781 desc
.TransactionId
= RequestId
;
783 bufferList
[0].Data
= &desc
;
784 bufferList
[0].Length
= sizeof(VMPACKET_DESCRIPTOR
);
786 bufferList
[1].Data
= Buffer
;
787 bufferList
[1].Length
= BufferLen
;
789 bufferList
[2].Data
= &alignedData
;
790 bufferList
[2].Length
= packetLenAligned
- packetLen
;
792 ret
= RingBufferWrite(
797 // TODO: We should determine if this is optional
798 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
800 VmbusChannelSetEvent(Channel
);
812 VmbusChannelSendPacketPageBuffer()
815 Send a range of single-page buffer packets using a GPADL Direct packet type.
819 VmbusChannelSendPacketPageBuffer(
820 VMBUS_CHANNEL
*Channel
,
821 PAGE_BUFFER PageBuffers
[],
830 VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc
;
833 UINT32 packetLenAligned
;
834 SG_BUFFER_LIST bufferList
[3];
835 UINT64 alignedData
=0;
839 ASSERT(PageCount
<= MAX_PAGE_BUFFER_COUNT
);
841 DumpVmbusChannel(Channel
);
843 // Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the largest size we support
844 descSize
= sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER
) - ((MAX_PAGE_BUFFER_COUNT
- PageCount
)*sizeof(PAGE_BUFFER
));
845 packetLen
= descSize
+ BufferLen
;
846 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(UINT64
));
848 ASSERT((packetLenAligned
- packetLen
) < sizeof(UINT64
));
850 // Setup the descriptor
851 desc
.Type
= VmbusPacketTypeDataUsingGpaDirect
;
852 desc
.Flags
= VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
;
853 desc
.DataOffset8
= descSize
>> 3; // in 8-bytes grandularity
854 desc
.Length8
= (UINT16
)(packetLenAligned
>> 3);
855 desc
.TransactionId
= RequestId
;
856 desc
.RangeCount
= PageCount
;
858 for (i
=0; i
<PageCount
; i
++)
860 desc
.Range
[i
].Length
= PageBuffers
[i
].Length
;
861 desc
.Range
[i
].Offset
= PageBuffers
[i
].Offset
;
862 desc
.Range
[i
].Pfn
= PageBuffers
[i
].Pfn
;
865 bufferList
[0].Data
= &desc
;
866 bufferList
[0].Length
= descSize
;
868 bufferList
[1].Data
= Buffer
;
869 bufferList
[1].Length
= BufferLen
;
871 bufferList
[2].Data
= &alignedData
;
872 bufferList
[2].Length
= packetLenAligned
- packetLen
;
874 ret
= RingBufferWrite(
879 // TODO: We should determine if this is optional
880 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
882 VmbusChannelSetEvent(Channel
);
895 VmbusChannelSendPacketMultiPageBuffer()
898 Send a multi-page buffer packet using a GPADL Direct packet type.
902 VmbusChannelSendPacketMultiPageBuffer(
903 VMBUS_CHANNEL
*Channel
,
904 MULTIPAGE_BUFFER
*MultiPageBuffer
,
911 VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc
;
914 UINT32 packetLenAligned
;
915 SG_BUFFER_LIST bufferList
[3];
916 UINT64 alignedData
=0;
917 UINT32 PfnCount
= NUM_PAGES_SPANNED(MultiPageBuffer
->Offset
, MultiPageBuffer
->Length
);
921 DumpVmbusChannel(Channel
);
923 DPRINT_DBG(VMBUS
, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer
->Offset
, MultiPageBuffer
->Length
, PfnCount
);
925 ASSERT(PfnCount
> 0);
926 ASSERT(PfnCount
<= MAX_MULTIPAGE_BUFFER_COUNT
);
928 // Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is the largest size we support
929 descSize
= sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER
) - ((MAX_MULTIPAGE_BUFFER_COUNT
- PfnCount
)*sizeof(UINT64
));
930 packetLen
= descSize
+ BufferLen
;
931 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(UINT64
));
933 ASSERT((packetLenAligned
- packetLen
) < sizeof(UINT64
));
935 // Setup the descriptor
936 desc
.Type
= VmbusPacketTypeDataUsingGpaDirect
;
937 desc
.Flags
= VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
;
938 desc
.DataOffset8
= descSize
>> 3; // in 8-bytes grandularity
939 desc
.Length8
= (UINT16
)(packetLenAligned
>> 3);
940 desc
.TransactionId
= RequestId
;
943 desc
.Range
.Length
= MultiPageBuffer
->Length
;
944 desc
.Range
.Offset
= MultiPageBuffer
->Offset
;
946 memcpy(desc
.Range
.PfnArray
, MultiPageBuffer
->PfnArray
, PfnCount
*sizeof(UINT64
));
948 bufferList
[0].Data
= &desc
;
949 bufferList
[0].Length
= descSize
;
951 bufferList
[1].Data
= Buffer
;
952 bufferList
[1].Length
= BufferLen
;
954 bufferList
[2].Data
= &alignedData
;
955 bufferList
[2].Length
= packetLenAligned
- packetLen
;
957 ret
= RingBufferWrite(
962 // TODO: We should determine if this is optional
963 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
965 VmbusChannelSetEvent(Channel
);
977 VmbusChannelRecvPacket()
980 Retrieve the user packet on the specified channel
983 // TODO: Do we ever receive a gpa direct packet other than the ones we send ?
985 VmbusChannelRecvPacket(
986 VMBUS_CHANNEL
*Channel
,
989 UINT32
* BufferActualLen
,
993 VMPACKET_DESCRIPTOR desc
;
1000 *BufferActualLen
= 0;
1003 SpinlockAcquire(Channel
->InboundLock
);
1005 ret
= RingBufferPeek(&Channel
->Inbound
, &desc
, sizeof(VMPACKET_DESCRIPTOR
));
1008 SpinlockRelease(Channel
->InboundLock
);
1010 //DPRINT_DBG(VMBUS, "nothing to read!!");
1015 //VmbusChannelClearEvent(Channel);
1017 packetLen
= desc
.Length8
<< 3;
1018 userLen
= packetLen
- (desc
.DataOffset8
<< 3);
1019 //ASSERT(userLen > 0);
1021 DPRINT_DBG(VMBUS
, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1023 Channel
->OfferMsg
.ChildRelId
,
1026 desc
.TransactionId
, packetLen
, userLen
);
1028 *BufferActualLen
= userLen
;
1030 if (userLen
> BufferLen
)
1032 SpinlockRelease(Channel
->InboundLock
);
1034 DPRINT_ERR(VMBUS
, "buffer too small - got %d needs %d", BufferLen
, userLen
);
1040 *RequestId
= desc
.TransactionId
;
1042 // Copy over the packet to the user buffer
1043 ret
= RingBufferRead(&Channel
->Inbound
, Buffer
, userLen
, (desc
.DataOffset8
<< 3));
1045 SpinlockRelease(Channel
->InboundLock
);
1055 VmbusChannelRecvPacketRaw()
1058 Retrieve the raw packet on the specified channel
1062 VmbusChannelRecvPacketRaw(
1063 VMBUS_CHANNEL
*Channel
,
1066 UINT32
* BufferActualLen
,
1070 VMPACKET_DESCRIPTOR desc
;
1075 DPRINT_ENTER(VMBUS
);
1077 *BufferActualLen
= 0;
1080 SpinlockAcquire(Channel
->InboundLock
);
1082 ret
= RingBufferPeek(&Channel
->Inbound
, &desc
, sizeof(VMPACKET_DESCRIPTOR
));
1085 SpinlockRelease(Channel
->InboundLock
);
1087 //DPRINT_DBG(VMBUS, "nothing to read!!");
1092 //VmbusChannelClearEvent(Channel);
1094 packetLen
= desc
.Length8
<< 3;
1095 userLen
= packetLen
- (desc
.DataOffset8
<< 3);
1097 DPRINT_DBG(VMBUS
, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1099 Channel
->OfferMsg
.ChildRelId
,
1102 desc
.TransactionId
, packetLen
, userLen
);
1104 *BufferActualLen
= packetLen
;
1106 if (packetLen
> BufferLen
)
1108 SpinlockRelease(Channel
->InboundLock
);
1110 DPRINT_ERR(VMBUS
, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen
, BufferLen
);
1115 *RequestId
= desc
.TransactionId
;
1117 // Copy over the entire packet to the user buffer
1118 ret
= RingBufferRead(&Channel
->Inbound
, Buffer
, packetLen
, 0);
1120 SpinlockRelease(Channel
->InboundLock
);
1131 VmbusChannelOnChannelEvent()
1134 Channel event callback
1138 VmbusChannelOnChannelEvent(
1139 VMBUS_CHANNEL
*Channel
1142 DumpVmbusChannel(Channel
);
1143 ASSERT(Channel
->OnChannelCallback
);
1144 #ifdef ENABLE_POLLING
1145 TimerStop(Channel
->PollTimer
);
1146 Channel
->OnChannelCallback(Channel
->ChannelCallbackContext
);
1147 TimerStart(Channel
->PollTimer
, 100 /* 100us */);
1149 Channel
->OnChannelCallback(Channel
->ChannelCallbackContext
);
1156 VmbusChannelOnTimer()
1159 Timer event callback
1163 VmbusChannelOnTimer(
1167 VMBUS_CHANNEL
*channel
= (VMBUS_CHANNEL
*)Context
;
1169 if (channel
->OnChannelCallback
)
1171 channel
->OnChannelCallback(channel
->ChannelCallbackContext
);
1172 #ifdef ENABLE_POLLING
1173 TimerStart(channel
->PollTimer
, 100 /* 100us */);
1185 Dump vmbus channel info to the console
1190 VMBUS_CHANNEL
*Channel
1193 DPRINT_DBG(VMBUS
, "Channel (%d)", Channel
->OfferMsg
.ChildRelId
);
1194 DumpRingInfo(&Channel
->Outbound
, "Outbound ");
1195 DumpRingInfo(&Channel
->Inbound
, "Inbound ");