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>
24 #include <linux/kernel.h>
25 #include "include/osd.h"
26 #include "include/logging.h"
28 #include "VmbusPrivate.h"
34 VmbusChannelCreateGpadlHeader(
35 void * Kbuffer
, // must be phys and virt contiguous
36 u32 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
.Asu32
);
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 u32 represents 32 channels
109 BitSet((u32
*)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((u32
*) &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 u32 represents 32 channels
137 BitClear((u32
*)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((u32
*) &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 u8 monitorGroup
= (u8
)Channel
->OfferMsg
.MonitorId
/ 32;
166 u8 monitorOffset
= (u8
)Channel
->OfferMsg
.MonitorId
% 32;
167 //u32 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 u32 SendRingBufferSize
,
206 u32 RecvRingBufferSize
,
209 PFN_CHANNEL_CALLBACK pfnOnChannelCallback
,
214 VMBUS_CHANNEL_OPEN_CHANNEL
* openMsg
;
215 VMBUS_CHANNEL_MSGINFO
* openInfo
;
221 // Aligned to page size
222 ASSERT(!(SendRingBufferSize
& (PAGE_SIZE
-1)));
223 ASSERT(!(RecvRingBufferSize
& (PAGE_SIZE
-1)));
225 NewChannel
->OnChannelCallback
= pfnOnChannelCallback
;
226 NewChannel
->ChannelCallbackContext
= Context
;
228 // Allocate the ring buffer
229 out
= PageAlloc((SendRingBufferSize
+ RecvRingBufferSize
) >> PAGE_SHIFT
);
230 //out = kzalloc(sendRingBufferSize + recvRingBufferSize, GFP_KERNEL);
232 ASSERT(((unsigned long)out
& (PAGE_SIZE
-1)) == 0);
234 in
= (void*)((unsigned long)out
+ SendRingBufferSize
);
236 NewChannel
->RingBufferPages
= out
;
237 NewChannel
->RingBufferPageCount
= (SendRingBufferSize
+ RecvRingBufferSize
) >> PAGE_SHIFT
;
239 RingBufferInit(&NewChannel
->Outbound
, out
, SendRingBufferSize
);
241 RingBufferInit(&NewChannel
->Inbound
, in
, RecvRingBufferSize
);
243 // Establish the gpadl for the ring buffer
244 DPRINT_DBG(VMBUS
, "Establishing ring buffer's gpadl for channel %p...", NewChannel
);
246 NewChannel
->RingBufferGpadlHandle
= 0;
248 ret
= VmbusChannelEstablishGpadl(NewChannel
,
249 NewChannel
->Outbound
.RingBuffer
,
250 SendRingBufferSize
+ RecvRingBufferSize
,
251 &NewChannel
->RingBufferGpadlHandle
);
253 DPRINT_DBG(VMBUS
, "channel %p <relid %d gpadl 0x%x send ring %p size %d recv ring %p size %d, downstreamoffset %d>",
255 NewChannel
->OfferMsg
.ChildRelId
,
256 NewChannel
->RingBufferGpadlHandle
,
257 NewChannel
->Outbound
.RingBuffer
,
258 NewChannel
->Outbound
.RingSize
,
259 NewChannel
->Inbound
.RingBuffer
,
260 NewChannel
->Inbound
.RingSize
,
263 // Create and init the channel open message
264 openInfo
= kmalloc(sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL
), GFP_KERNEL
);
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 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
285 INSERT_TAIL_LIST(&gVmbusConnection
.ChannelMsgList
, &openInfo
->MsgListEntry
);
286 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
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 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
311 REMOVE_ENTRY_LIST(&openInfo
->MsgListEntry
);
312 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
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(u64
);
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 void * Kbuffer
, // from kmalloc()
396 u32 Size
, // page-size multiple
397 VMBUS_CHANNEL_MSGINFO
**MsgInfo
,
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(u64
);
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(u64
);
425 msgHeader
= kzalloc(msgSize
, GFP_KERNEL
);
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(u64
);
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(u64
);
452 if (pfnLeft
> pfnCount
)
461 msgSize
= sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_GPADL_BODY
) + pfnCurr
*sizeof(u64
);
462 msgBody
= kzalloc(msgSize
, GFP_KERNEL
);
464 msgBody
->MessageSize
= msgSize
;
466 gpadlBody
= (VMBUS_CHANNEL_GPADL_BODY
*)msgBody
->Msg
;
468 // FIXME: Gpadl is u32 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(u64
);
485 msgHeader
= kzalloc(msgSize
, GFP_KERNEL
);
486 msgHeader
->MessageSize
=msgSize
;
488 gpaHeader
= (VMBUS_CHANNEL_GPADL_HEADER
*)msgHeader
->Msg
;
489 gpaHeader
->RangeCount
= 1;
490 gpaHeader
->RangeBufLen
= sizeof(GPA_RANGE
) + pageCount
*sizeof(u64
);
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 void * Kbuffer
, // from kmalloc()
519 u32 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
;
539 nextGpadlHandle
= gVmbusConnection
.NextGpadlHandle
;
540 InterlockedIncrement((int*)&gVmbusConnection
.NextGpadlHandle
);
542 VmbusChannelCreateGpadlHeader(Kbuffer
, Size
, &msgInfo
, &msgCount
);
543 ASSERT(msgInfo
!= NULL
);
546 msgInfo
->WaitEvent
= WaitEventCreate();
547 gpadlMsg
= (VMBUS_CHANNEL_GPADL_HEADER
*)msgInfo
->Msg
;
548 gpadlMsg
->Header
.MessageType
= ChannelMessageGpadlHeader
;
549 gpadlMsg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
550 gpadlMsg
->Gpadl
= nextGpadlHandle
;
552 DumpGpadlHeader(gpadlMsg
);
554 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
555 INSERT_TAIL_LIST(&gVmbusConnection
.ChannelMsgList
, &msgInfo
->MsgListEntry
);
556 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
558 DPRINT_DBG(VMBUS
, "buffer %p, size %d msg cnt %d", Kbuffer
, Size
, msgCount
);
560 DPRINT_DBG(VMBUS
, "Sending GPADL Header - len %ld", msgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
562 ret
= VmbusPostMessage(gpadlMsg
, msgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
565 DPRINT_ERR(VMBUS
, "Unable to open channel - %d", ret
);
571 ITERATE_LIST_ENTRIES(anchor
, curr
, &msgInfo
->SubMsgList
)
573 subMsgInfo
= (VMBUS_CHANNEL_MSGINFO
*) curr
;
574 gpadlBody
= (VMBUS_CHANNEL_GPADL_BODY
*)subMsgInfo
->Msg
;
576 gpadlBody
->Header
.MessageType
= ChannelMessageGpadlBody
;
577 gpadlBody
->Gpadl
= nextGpadlHandle
;
579 DPRINT_DBG(VMBUS
, "Sending GPADL Body - len %ld", subMsgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
581 DumpGpadlBody(gpadlBody
, subMsgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
582 ret
= VmbusPostMessage(gpadlBody
, subMsgInfo
->MessageSize
- sizeof(VMBUS_CHANNEL_MSGINFO
));
586 WaitEventWait(msgInfo
->WaitEvent
);
588 // At this point, we received the gpadl created msg
589 DPRINT_DBG(VMBUS
, "Received GPADL created (relid %d, status %d handle %x)",
590 Channel
->OfferMsg
.ChildRelId
,
591 msgInfo
->Response
.GpadlCreated
.CreationStatus
,
594 *GpadlHandle
= gpadlMsg
->Gpadl
;
597 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
598 REMOVE_ENTRY_LIST(&msgInfo
->MsgListEntry
);
599 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
601 WaitEventClose(msgInfo
->WaitEvent
);
614 VmbusChannelTeardownGpadl()
617 Teardown the specified GPADL handle
621 VmbusChannelTeardownGpadl(
622 VMBUS_CHANNEL
*Channel
,
627 VMBUS_CHANNEL_GPADL_TEARDOWN
*msg
;
628 VMBUS_CHANNEL_MSGINFO
* info
;
633 ASSERT(GpadlHandle
!= 0);
635 info
= kmalloc(sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN
), GFP_KERNEL
);
636 ASSERT(info
!= NULL
);
638 info
->WaitEvent
= WaitEventCreate();
640 msg
= (VMBUS_CHANNEL_GPADL_TEARDOWN
*)info
->Msg
;
642 msg
->Header
.MessageType
= ChannelMessageGpadlTeardown
;
643 msg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
644 msg
->Gpadl
= GpadlHandle
;
646 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
647 INSERT_TAIL_LIST(&gVmbusConnection
.ChannelMsgList
, &info
->MsgListEntry
);
648 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
650 ret
= VmbusPostMessage(msg
, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN
));
656 WaitEventWait(info
->WaitEvent
);
658 // Received a torndown response
659 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
660 REMOVE_ENTRY_LIST(&info
->MsgListEntry
);
661 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
663 WaitEventClose(info
->WaitEvent
);
678 Close the specified channel
683 VMBUS_CHANNEL
*Channel
687 VMBUS_CHANNEL_CLOSE_CHANNEL
* msg
;
688 VMBUS_CHANNEL_MSGINFO
* info
;
693 // Stop callback and cancel the timer asap
694 Channel
->OnChannelCallback
= NULL
;
695 TimerStop(Channel
->PollTimer
);
697 // Send a closing message
698 info
= kmalloc(sizeof(VMBUS_CHANNEL_MSGINFO
) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL
), GFP_KERNEL
);
699 ASSERT(info
!= NULL
);
701 //info->waitEvent = WaitEventCreate();
703 msg
= (VMBUS_CHANNEL_CLOSE_CHANNEL
*)info
->Msg
;
704 msg
->Header
.MessageType
= ChannelMessageCloseChannel
;
705 msg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
707 ret
= VmbusPostMessage(msg
, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL
));
713 // Tear down the gpadl for the channel's ring buffer
714 if (Channel
->RingBufferGpadlHandle
)
716 VmbusChannelTeardownGpadl(Channel
, Channel
->RingBufferGpadlHandle
);
719 // TODO: Send a msg to release the childRelId
721 // Cleanup the ring buffers for this channel
722 RingBufferCleanup(&Channel
->Outbound
);
723 RingBufferCleanup(&Channel
->Inbound
);
725 PageFree(Channel
->RingBufferPages
, Channel
->RingBufferPageCount
);
729 // If we are closing the channel during an error path in opening the channel, don't free the channel
730 // since the caller will free the channel
731 if (Channel
->State
== CHANNEL_OPEN_STATE
)
733 spin_lock_irqsave(&gVmbusConnection
.channel_lock
, flags
);
734 REMOVE_ENTRY_LIST(&Channel
->ListEntry
);
735 spin_unlock_irqrestore(&gVmbusConnection
.channel_lock
, flags
);
737 FreeVmbusChannel(Channel
);
747 VmbusChannelSendPacket()
750 Send the specified buffer on the given channel
754 VmbusChannelSendPacket(
755 VMBUS_CHANNEL
*Channel
,
759 VMBUS_PACKET_TYPE Type
,
764 VMPACKET_DESCRIPTOR desc
;
765 u32 packetLen
= sizeof(VMPACKET_DESCRIPTOR
) + BufferLen
;
766 u32 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(u64
));
767 SG_BUFFER_LIST bufferList
[3];
771 DPRINT_DBG(VMBUS
, "channel %p buffer %p len %d", Channel
, Buffer
, BufferLen
);
773 DumpVmbusChannel(Channel
);
775 ASSERT((packetLenAligned
- packetLen
) < sizeof(u64
));
777 // Setup the descriptor
778 desc
.Type
= Type
;//VmbusPacketTypeDataInBand;
779 desc
.Flags
= Flags
;//VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
780 desc
.DataOffset8
= sizeof(VMPACKET_DESCRIPTOR
) >> 3; // in 8-bytes granularity
781 desc
.Length8
= (u16
)(packetLenAligned
>> 3);
782 desc
.TransactionId
= RequestId
;
784 bufferList
[0].Data
= &desc
;
785 bufferList
[0].Length
= sizeof(VMPACKET_DESCRIPTOR
);
787 bufferList
[1].Data
= Buffer
;
788 bufferList
[1].Length
= BufferLen
;
790 bufferList
[2].Data
= &alignedData
;
791 bufferList
[2].Length
= packetLenAligned
- packetLen
;
793 ret
= RingBufferWrite(
798 // TODO: We should determine if this is optional
799 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
801 VmbusChannelSetEvent(Channel
);
813 VmbusChannelSendPacketPageBuffer()
816 Send a range of single-page buffer packets using a GPADL Direct packet type.
820 VmbusChannelSendPacketPageBuffer(
821 VMBUS_CHANNEL
*Channel
,
822 PAGE_BUFFER PageBuffers
[],
831 VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc
;
834 u32 packetLenAligned
;
835 SG_BUFFER_LIST bufferList
[3];
840 ASSERT(PageCount
<= MAX_PAGE_BUFFER_COUNT
);
842 DumpVmbusChannel(Channel
);
844 // Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the largest size we support
845 descSize
= sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER
) - ((MAX_PAGE_BUFFER_COUNT
- PageCount
)*sizeof(PAGE_BUFFER
));
846 packetLen
= descSize
+ BufferLen
;
847 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(u64
));
849 ASSERT((packetLenAligned
- packetLen
) < sizeof(u64
));
851 // Setup the descriptor
852 desc
.Type
= VmbusPacketTypeDataUsingGpaDirect
;
853 desc
.Flags
= VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
;
854 desc
.DataOffset8
= descSize
>> 3; // in 8-bytes grandularity
855 desc
.Length8
= (u16
)(packetLenAligned
>> 3);
856 desc
.TransactionId
= RequestId
;
857 desc
.RangeCount
= PageCount
;
859 for (i
=0; i
<PageCount
; i
++)
861 desc
.Range
[i
].Length
= PageBuffers
[i
].Length
;
862 desc
.Range
[i
].Offset
= PageBuffers
[i
].Offset
;
863 desc
.Range
[i
].Pfn
= PageBuffers
[i
].Pfn
;
866 bufferList
[0].Data
= &desc
;
867 bufferList
[0].Length
= descSize
;
869 bufferList
[1].Data
= Buffer
;
870 bufferList
[1].Length
= BufferLen
;
872 bufferList
[2].Data
= &alignedData
;
873 bufferList
[2].Length
= packetLenAligned
- packetLen
;
875 ret
= RingBufferWrite(
880 // TODO: We should determine if this is optional
881 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
883 VmbusChannelSetEvent(Channel
);
896 VmbusChannelSendPacketMultiPageBuffer()
899 Send a multi-page buffer packet using a GPADL Direct packet type.
903 VmbusChannelSendPacketMultiPageBuffer(
904 VMBUS_CHANNEL
*Channel
,
905 MULTIPAGE_BUFFER
*MultiPageBuffer
,
912 VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc
;
915 u32 packetLenAligned
;
916 SG_BUFFER_LIST bufferList
[3];
918 u32 PfnCount
= NUM_PAGES_SPANNED(MultiPageBuffer
->Offset
, MultiPageBuffer
->Length
);
922 DumpVmbusChannel(Channel
);
924 DPRINT_DBG(VMBUS
, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer
->Offset
, MultiPageBuffer
->Length
, PfnCount
);
926 ASSERT(PfnCount
> 0);
927 ASSERT(PfnCount
<= MAX_MULTIPAGE_BUFFER_COUNT
);
929 // Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is the largest size we support
930 descSize
= sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER
) - ((MAX_MULTIPAGE_BUFFER_COUNT
- PfnCount
)*sizeof(u64
));
931 packetLen
= descSize
+ BufferLen
;
932 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(u64
));
934 ASSERT((packetLenAligned
- packetLen
) < sizeof(u64
));
936 // Setup the descriptor
937 desc
.Type
= VmbusPacketTypeDataUsingGpaDirect
;
938 desc
.Flags
= VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
;
939 desc
.DataOffset8
= descSize
>> 3; // in 8-bytes grandularity
940 desc
.Length8
= (u16
)(packetLenAligned
>> 3);
941 desc
.TransactionId
= RequestId
;
944 desc
.Range
.Length
= MultiPageBuffer
->Length
;
945 desc
.Range
.Offset
= MultiPageBuffer
->Offset
;
947 memcpy(desc
.Range
.PfnArray
, MultiPageBuffer
->PfnArray
, PfnCount
*sizeof(u64
));
949 bufferList
[0].Data
= &desc
;
950 bufferList
[0].Length
= descSize
;
952 bufferList
[1].Data
= Buffer
;
953 bufferList
[1].Length
= BufferLen
;
955 bufferList
[2].Data
= &alignedData
;
956 bufferList
[2].Length
= packetLenAligned
- packetLen
;
958 ret
= RingBufferWrite(
963 // TODO: We should determine if this is optional
964 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
966 VmbusChannelSetEvent(Channel
);
978 VmbusChannelRecvPacket()
981 Retrieve the user packet on the specified channel
984 // TODO: Do we ever receive a gpa direct packet other than the ones we send ?
986 VmbusChannelRecvPacket(
987 VMBUS_CHANNEL
*Channel
,
990 u32
* BufferActualLen
,
994 VMPACKET_DESCRIPTOR desc
;
1000 DPRINT_ENTER(VMBUS
);
1002 *BufferActualLen
= 0;
1005 spin_lock_irqsave(&Channel
->inbound_lock
, flags
);
1007 ret
= RingBufferPeek(&Channel
->Inbound
, &desc
, sizeof(VMPACKET_DESCRIPTOR
));
1010 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
1012 //DPRINT_DBG(VMBUS, "nothing to read!!");
1017 //VmbusChannelClearEvent(Channel);
1019 packetLen
= desc
.Length8
<< 3;
1020 userLen
= packetLen
- (desc
.DataOffset8
<< 3);
1021 //ASSERT(userLen > 0);
1023 DPRINT_DBG(VMBUS
, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1025 Channel
->OfferMsg
.ChildRelId
,
1028 desc
.TransactionId
, packetLen
, userLen
);
1030 *BufferActualLen
= userLen
;
1032 if (userLen
> BufferLen
)
1034 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
1036 DPRINT_ERR(VMBUS
, "buffer too small - got %d needs %d", BufferLen
, userLen
);
1042 *RequestId
= desc
.TransactionId
;
1044 // Copy over the packet to the user buffer
1045 ret
= RingBufferRead(&Channel
->Inbound
, Buffer
, userLen
, (desc
.DataOffset8
<< 3));
1047 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
1057 VmbusChannelRecvPacketRaw()
1060 Retrieve the raw packet on the specified channel
1064 VmbusChannelRecvPacketRaw(
1065 VMBUS_CHANNEL
*Channel
,
1068 u32
* BufferActualLen
,
1072 VMPACKET_DESCRIPTOR desc
;
1076 unsigned long flags
;
1078 DPRINT_ENTER(VMBUS
);
1080 *BufferActualLen
= 0;
1083 spin_lock_irqsave(&Channel
->inbound_lock
, flags
);
1085 ret
= RingBufferPeek(&Channel
->Inbound
, &desc
, sizeof(VMPACKET_DESCRIPTOR
));
1088 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
1090 //DPRINT_DBG(VMBUS, "nothing to read!!");
1095 //VmbusChannelClearEvent(Channel);
1097 packetLen
= desc
.Length8
<< 3;
1098 userLen
= packetLen
- (desc
.DataOffset8
<< 3);
1100 DPRINT_DBG(VMBUS
, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1102 Channel
->OfferMsg
.ChildRelId
,
1105 desc
.TransactionId
, packetLen
, userLen
);
1107 *BufferActualLen
= packetLen
;
1109 if (packetLen
> BufferLen
)
1111 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
1113 DPRINT_ERR(VMBUS
, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen
, BufferLen
);
1118 *RequestId
= desc
.TransactionId
;
1120 // Copy over the entire packet to the user buffer
1121 ret
= RingBufferRead(&Channel
->Inbound
, Buffer
, packetLen
, 0);
1123 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
1134 VmbusChannelOnChannelEvent()
1137 Channel event callback
1141 VmbusChannelOnChannelEvent(
1142 VMBUS_CHANNEL
*Channel
1145 DumpVmbusChannel(Channel
);
1146 ASSERT(Channel
->OnChannelCallback
);
1147 #ifdef ENABLE_POLLING
1148 TimerStop(Channel
->PollTimer
);
1149 Channel
->OnChannelCallback(Channel
->ChannelCallbackContext
);
1150 TimerStart(Channel
->PollTimer
, 100 /* 100us */);
1152 Channel
->OnChannelCallback(Channel
->ChannelCallbackContext
);
1159 VmbusChannelOnTimer()
1162 Timer event callback
1166 VmbusChannelOnTimer(
1170 VMBUS_CHANNEL
*channel
= (VMBUS_CHANNEL
*)Context
;
1172 if (channel
->OnChannelCallback
)
1174 channel
->OnChannelCallback(channel
->ChannelCallbackContext
);
1175 #ifdef ENABLE_POLLING
1176 TimerStart(channel
->PollTimer
, 100 /* 100us */);
1188 Dump vmbus channel info to the console
1193 VMBUS_CHANNEL
*Channel
1196 DPRINT_DBG(VMBUS
, "Channel (%d)", Channel
->OfferMsg
.ChildRelId
);
1197 DumpRingInfo(&Channel
->Outbound
, "Outbound ");
1198 DumpRingInfo(&Channel
->Inbound
, "Inbound ");