2 * Copyright (c) 2009, Microsoft Corporation.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 * Haiyang Zhang <haiyangz@microsoft.com>
19 * Hank Janssen <hjanssen@microsoft.com>
21 #include <linux/kernel.h>
23 #include <linux/slab.h>
26 #include "VmbusPrivate.h"
28 /* Internal routines */
29 static int VmbusChannelCreateGpadlHeader(
30 void *Kbuffer
, /* must be phys and virt contiguous */
31 u32 Size
, /* page-size multiple */
32 struct vmbus_channel_msginfo
**msgInfo
,
34 static void DumpVmbusChannel(struct vmbus_channel
*channel
);
35 static void VmbusChannelSetEvent(struct vmbus_channel
*channel
);
39 static void DumpMonitorPage(struct hv_monitor_page
*MonitorPage
)
44 DPRINT_DBG(VMBUS
, "monitorPage - %p, trigger state - %d",
45 MonitorPage
, MonitorPage
->TriggerState
);
47 for (i
= 0; i
< 4; i
++)
48 DPRINT_DBG(VMBUS
, "trigger group (%d) - %llx", i
,
49 MonitorPage
->TriggerGroup
[i
].AsUINT64
);
51 for (i
= 0; i
< 4; i
++) {
52 for (j
= 0; j
< 32; j
++) {
53 DPRINT_DBG(VMBUS
, "latency (%d)(%d) - %llx", i
, j
,
54 MonitorPage
->Latency
[i
][j
]);
57 for (i
= 0; i
< 4; i
++) {
58 for (j
= 0; j
< 32; j
++) {
59 DPRINT_DBG(VMBUS
, "param-conn id (%d)(%d) - %d", i
, j
,
60 MonitorPage
->Parameter
[i
][j
].ConnectionId
.Asu32
);
61 DPRINT_DBG(VMBUS
, "param-flag (%d)(%d) - %d", i
, j
,
62 MonitorPage
->Parameter
[i
][j
].FlagNumber
);
69 * VmbusChannelSetEvent - Trigger an event notification on the specified
72 static void VmbusChannelSetEvent(struct vmbus_channel
*Channel
)
74 struct hv_monitor_page
*monitorPage
;
78 if (Channel
->OfferMsg
.MonitorAllocated
) {
79 /* Each u32 represents 32 channels */
80 set_bit(Channel
->OfferMsg
.ChildRelId
& 31,
81 (unsigned long *) gVmbusConnection
.SendInterruptPage
+
82 (Channel
->OfferMsg
.ChildRelId
>> 5));
84 monitorPage
= gVmbusConnection
.MonitorPages
;
85 monitorPage
++; /* Get the child to parent monitor page */
87 set_bit(Channel
->MonitorBit
,
88 (unsigned long *)&monitorPage
->TriggerGroup
89 [Channel
->MonitorGroup
].Pending
);
92 VmbusSetEvent(Channel
->OfferMsg
.ChildRelId
);
99 static void VmbusChannelClearEvent(struct vmbus_channel
*channel
)
101 struct hv_monitor_page
*monitorPage
;
105 if (Channel
->OfferMsg
.MonitorAllocated
) {
106 /* Each u32 represents 32 channels */
107 clear_bit(Channel
->OfferMsg
.ChildRelId
& 31,
108 (unsigned long *)gVmbusConnection
.SendInterruptPage
+
109 (Channel
->OfferMsg
.ChildRelId
>> 5));
112 (struct hv_monitor_page
*)gVmbusConnection
.MonitorPages
;
113 monitorPage
++; /* Get the child to parent monitor page */
115 clear_bit(Channel
->MonitorBit
,
116 (unsigned long *)&monitorPage
->TriggerGroup
117 [Channel
->MonitorGroup
].Pending
);
125 * VmbusChannelGetDebugInfo -Retrieve various channel debug info
127 void VmbusChannelGetDebugInfo(struct vmbus_channel
*Channel
,
128 struct vmbus_channel_debug_info
*DebugInfo
)
130 struct hv_monitor_page
*monitorPage
;
131 u8 monitorGroup
= (u8
)Channel
->OfferMsg
.MonitorId
/ 32;
132 u8 monitorOffset
= (u8
)Channel
->OfferMsg
.MonitorId
% 32;
133 /* u32 monitorBit = 1 << monitorOffset; */
135 DebugInfo
->RelId
= Channel
->OfferMsg
.ChildRelId
;
136 DebugInfo
->State
= Channel
->State
;
137 memcpy(&DebugInfo
->InterfaceType
,
138 &Channel
->OfferMsg
.Offer
.InterfaceType
, sizeof(struct hv_guid
));
139 memcpy(&DebugInfo
->InterfaceInstance
,
140 &Channel
->OfferMsg
.Offer
.InterfaceInstance
,
141 sizeof(struct hv_guid
));
143 monitorPage
= (struct hv_monitor_page
*)gVmbusConnection
.MonitorPages
;
145 DebugInfo
->MonitorId
= Channel
->OfferMsg
.MonitorId
;
147 DebugInfo
->ServerMonitorPending
=
148 monitorPage
->TriggerGroup
[monitorGroup
].Pending
;
149 DebugInfo
->ServerMonitorLatency
=
150 monitorPage
->Latency
[monitorGroup
][monitorOffset
];
151 DebugInfo
->ServerMonitorConnectionId
=
152 monitorPage
->Parameter
[monitorGroup
]
153 [monitorOffset
].ConnectionId
.u
.Id
;
157 DebugInfo
->ClientMonitorPending
=
158 monitorPage
->TriggerGroup
[monitorGroup
].Pending
;
159 DebugInfo
->ClientMonitorLatency
=
160 monitorPage
->Latency
[monitorGroup
][monitorOffset
];
161 DebugInfo
->ClientMonitorConnectionId
=
162 monitorPage
->Parameter
[monitorGroup
]
163 [monitorOffset
].ConnectionId
.u
.Id
;
165 RingBufferGetDebugInfo(&Channel
->Inbound
, &DebugInfo
->Inbound
);
166 RingBufferGetDebugInfo(&Channel
->Outbound
, &DebugInfo
->Outbound
);
170 * VmbusChannelOpen - Open the specified channel.
172 int VmbusChannelOpen(struct vmbus_channel
*NewChannel
, u32 SendRingBufferSize
,
173 u32 RecvRingBufferSize
, void *UserData
, u32 UserDataLen
,
174 void (*OnChannelCallback
)(void *context
), void *Context
)
176 struct vmbus_channel_open_channel
*openMsg
;
177 struct vmbus_channel_msginfo
*openInfo
;
184 /* Aligned to page size */
185 ASSERT(!(SendRingBufferSize
& (PAGE_SIZE
- 1)));
186 ASSERT(!(RecvRingBufferSize
& (PAGE_SIZE
- 1)));
188 NewChannel
->OnChannelCallback
= OnChannelCallback
;
189 NewChannel
->ChannelCallbackContext
= Context
;
191 /* Allocate the ring buffer */
192 out
= osd_PageAlloc((SendRingBufferSize
+ RecvRingBufferSize
)
195 ASSERT(((unsigned long)out
& (PAGE_SIZE
-1)) == 0);
197 in
= (void *)((unsigned long)out
+ SendRingBufferSize
);
199 NewChannel
->RingBufferPages
= out
;
200 NewChannel
->RingBufferPageCount
= (SendRingBufferSize
+
201 RecvRingBufferSize
) >> PAGE_SHIFT
;
203 RingBufferInit(&NewChannel
->Outbound
, out
, SendRingBufferSize
);
205 RingBufferInit(&NewChannel
->Inbound
, in
, RecvRingBufferSize
);
207 /* Establish the gpadl for the ring buffer */
208 DPRINT_DBG(VMBUS
, "Establishing ring buffer's gpadl for channel %p...",
211 NewChannel
->RingBufferGpadlHandle
= 0;
213 ret
= VmbusChannelEstablishGpadl(NewChannel
,
214 NewChannel
->Outbound
.RingBuffer
,
217 &NewChannel
->RingBufferGpadlHandle
);
219 DPRINT_DBG(VMBUS
, "channel %p <relid %d gpadl 0x%x send ring %p "
220 "size %d recv ring %p size %d, downstreamoffset %d>",
221 NewChannel
, NewChannel
->OfferMsg
.ChildRelId
,
222 NewChannel
->RingBufferGpadlHandle
,
223 NewChannel
->Outbound
.RingBuffer
,
224 NewChannel
->Outbound
.RingSize
,
225 NewChannel
->Inbound
.RingBuffer
,
226 NewChannel
->Inbound
.RingSize
,
229 /* Create and init the channel open message */
230 openInfo
= kmalloc(sizeof(*openInfo
) +
231 sizeof(struct vmbus_channel_open_channel
),
233 ASSERT(openInfo
!= NULL
);
235 openInfo
->WaitEvent
= osd_WaitEventCreate();
237 openMsg
= (struct vmbus_channel_open_channel
*)openInfo
->Msg
;
238 openMsg
->Header
.MessageType
= ChannelMessageOpenChannel
;
239 openMsg
->OpenId
= NewChannel
->OfferMsg
.ChildRelId
; /* FIXME */
240 openMsg
->ChildRelId
= NewChannel
->OfferMsg
.ChildRelId
;
241 openMsg
->RingBufferGpadlHandle
= NewChannel
->RingBufferGpadlHandle
;
242 ASSERT(openMsg
->RingBufferGpadlHandle
);
243 openMsg
->DownstreamRingBufferPageOffset
= SendRingBufferSize
>>
245 openMsg
->ServerContextAreaGpadlHandle
= 0; /* TODO */
247 ASSERT(UserDataLen
<= MAX_USER_DEFINED_BYTES
);
249 memcpy(openMsg
->UserData
, UserData
, UserDataLen
);
251 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
252 list_add_tail(&openInfo
->MsgListEntry
,
253 &gVmbusConnection
.ChannelMsgList
);
254 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
256 DPRINT_DBG(VMBUS
, "Sending channel open msg...");
258 ret
= VmbusPostMessage(openMsg
,
259 sizeof(struct vmbus_channel_open_channel
));
261 DPRINT_ERR(VMBUS
, "unable to open channel - %d", ret
);
265 /* FIXME: Need to time-out here */
266 osd_WaitEventWait(openInfo
->WaitEvent
);
268 if (openInfo
->Response
.OpenResult
.Status
== 0)
269 DPRINT_INFO(VMBUS
, "channel <%p> open success!!", NewChannel
);
271 DPRINT_INFO(VMBUS
, "channel <%p> open failed - %d!!",
272 NewChannel
, openInfo
->Response
.OpenResult
.Status
);
275 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
276 list_del(&openInfo
->MsgListEntry
);
277 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
279 kfree(openInfo
->WaitEvent
);
288 * DumpGpadlBody - Dump the gpadl body message to the console for
289 * debugging purposes.
291 static void DumpGpadlBody(struct vmbus_channel_gpadl_body
*Gpadl
, u32 Len
)
296 pfnCount
= (Len
- sizeof(struct vmbus_channel_gpadl_body
)) /
298 DPRINT_DBG(VMBUS
, "gpadl body - len %d pfn count %d", Len
, pfnCount
);
300 for (i
= 0; i
< pfnCount
; i
++)
301 DPRINT_DBG(VMBUS
, "gpadl body - %d) pfn %llu",
306 * DumpGpadlHeader - Dump the gpadl header message to the console for
307 * debugging purposes.
309 static void DumpGpadlHeader(struct vmbus_channel_gpadl_header
*Gpadl
)
315 "gpadl header - relid %d, range count %d, range buflen %d",
316 Gpadl
->ChildRelId
, Gpadl
->RangeCount
, Gpadl
->RangeBufLen
);
317 for (i
= 0; i
< Gpadl
->RangeCount
; i
++) {
318 pageCount
= Gpadl
->Range
[i
].ByteCount
>> PAGE_SHIFT
;
319 pageCount
= (pageCount
> 26) ? 26 : pageCount
;
321 DPRINT_DBG(VMBUS
, "gpadl range %d - len %d offset %d "
322 "page count %d", i
, Gpadl
->Range
[i
].ByteCount
,
323 Gpadl
->Range
[i
].ByteOffset
, pageCount
);
325 for (j
= 0; j
< pageCount
; j
++)
326 DPRINT_DBG(VMBUS
, "%d) pfn %llu", j
,
327 Gpadl
->Range
[i
].PfnArray
[j
]);
332 * VmbusChannelCreateGpadlHeader - Creates a gpadl for the specified buffer
334 static int VmbusChannelCreateGpadlHeader(void *Kbuffer
, u32 Size
,
335 struct vmbus_channel_msginfo
**MsgInfo
,
340 unsigned long long pfn
;
341 struct vmbus_channel_gpadl_header
*gpaHeader
;
342 struct vmbus_channel_gpadl_body
*gpadlBody
;
343 struct vmbus_channel_msginfo
*msgHeader
;
344 struct vmbus_channel_msginfo
*msgBody
;
347 int pfnSum
, pfnCount
, pfnLeft
, pfnCurr
, pfnSize
;
349 /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
350 ASSERT((Size
& (PAGE_SIZE
-1)) == 0);
352 pageCount
= Size
>> PAGE_SHIFT
;
353 pfn
= virt_to_phys(Kbuffer
) >> PAGE_SHIFT
;
355 /* do we need a gpadl body msg */
356 pfnSize
= MAX_SIZE_CHANNEL_MESSAGE
-
357 sizeof(struct vmbus_channel_gpadl_header
) -
358 sizeof(struct gpa_range
);
359 pfnCount
= pfnSize
/ sizeof(u64
);
361 if (pageCount
> pfnCount
) {
362 /* we need a gpadl body */
363 /* fill in the header */
364 msgSize
= sizeof(struct vmbus_channel_msginfo
) +
365 sizeof(struct vmbus_channel_gpadl_header
) +
366 sizeof(struct gpa_range
) + pfnCount
* sizeof(u64
);
367 msgHeader
= kzalloc(msgSize
, GFP_KERNEL
);
369 INIT_LIST_HEAD(&msgHeader
->SubMsgList
);
370 msgHeader
->MessageSize
= msgSize
;
372 gpaHeader
= (struct vmbus_channel_gpadl_header
*)msgHeader
->Msg
;
373 gpaHeader
->RangeCount
= 1;
374 gpaHeader
->RangeBufLen
= sizeof(struct gpa_range
) +
375 pageCount
* sizeof(u64
);
376 gpaHeader
->Range
[0].ByteOffset
= 0;
377 gpaHeader
->Range
[0].ByteCount
= Size
;
378 for (i
= 0; i
< pfnCount
; i
++)
379 gpaHeader
->Range
[0].PfnArray
[i
] = pfn
+i
;
380 *MsgInfo
= msgHeader
;
384 pfnLeft
= pageCount
- pfnCount
;
386 /* how many pfns can we fit */
387 pfnSize
= MAX_SIZE_CHANNEL_MESSAGE
-
388 sizeof(struct vmbus_channel_gpadl_body
);
389 pfnCount
= pfnSize
/ sizeof(u64
);
391 /* fill in the body */
393 if (pfnLeft
> pfnCount
)
398 msgSize
= sizeof(struct vmbus_channel_msginfo
) +
399 sizeof(struct vmbus_channel_gpadl_body
) +
400 pfnCurr
* sizeof(u64
);
401 msgBody
= kzalloc(msgSize
, GFP_KERNEL
);
403 msgBody
->MessageSize
= msgSize
;
406 (struct vmbus_channel_gpadl_body
*)msgBody
->Msg
;
410 * Gpadl is u32 and we are using a pointer which could
413 /* gpadlBody->Gpadl = kbuffer; */
414 for (i
= 0; i
< pfnCurr
; i
++)
415 gpadlBody
->Pfn
[i
] = pfn
+ pfnSum
+ i
;
417 /* add to msg header */
418 list_add_tail(&msgBody
->MsgListEntry
,
419 &msgHeader
->SubMsgList
);
424 /* everything fits in a header */
425 msgSize
= sizeof(struct vmbus_channel_msginfo
) +
426 sizeof(struct vmbus_channel_gpadl_header
) +
427 sizeof(struct gpa_range
) + pageCount
* sizeof(u64
);
428 msgHeader
= kzalloc(msgSize
, GFP_KERNEL
);
429 msgHeader
->MessageSize
= msgSize
;
431 gpaHeader
= (struct vmbus_channel_gpadl_header
*)msgHeader
->Msg
;
432 gpaHeader
->RangeCount
= 1;
433 gpaHeader
->RangeBufLen
= sizeof(struct gpa_range
) +
434 pageCount
* sizeof(u64
);
435 gpaHeader
->Range
[0].ByteOffset
= 0;
436 gpaHeader
->Range
[0].ByteCount
= Size
;
437 for (i
= 0; i
< pageCount
; i
++)
438 gpaHeader
->Range
[0].PfnArray
[i
] = pfn
+i
;
440 *MsgInfo
= msgHeader
;
448 * VmbusChannelEstablishGpadl - Estabish a GPADL for the specified buffer
450 * @Channel: a channel
451 * @Kbuffer: from kmalloc
452 * @Size: page-size multiple
453 * @GpadlHandle: some funky thing
455 int VmbusChannelEstablishGpadl(struct vmbus_channel
*Channel
, void *Kbuffer
,
456 u32 Size
, u32
*GpadlHandle
)
458 struct vmbus_channel_gpadl_header
*gpadlMsg
;
459 struct vmbus_channel_gpadl_body
*gpadlBody
;
460 /* struct vmbus_channel_gpadl_created *gpadlCreated; */
461 struct vmbus_channel_msginfo
*msgInfo
;
462 struct vmbus_channel_msginfo
*subMsgInfo
;
464 struct list_head
*curr
;
471 nextGpadlHandle
= atomic_read(&gVmbusConnection
.NextGpadlHandle
);
472 atomic_inc(&gVmbusConnection
.NextGpadlHandle
);
474 VmbusChannelCreateGpadlHeader(Kbuffer
, Size
, &msgInfo
, &msgCount
);
475 ASSERT(msgInfo
!= NULL
);
476 ASSERT(msgCount
> 0);
478 msgInfo
->WaitEvent
= osd_WaitEventCreate();
479 gpadlMsg
= (struct vmbus_channel_gpadl_header
*)msgInfo
->Msg
;
480 gpadlMsg
->Header
.MessageType
= ChannelMessageGpadlHeader
;
481 gpadlMsg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
482 gpadlMsg
->Gpadl
= nextGpadlHandle
;
484 DumpGpadlHeader(gpadlMsg
);
486 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
487 list_add_tail(&msgInfo
->MsgListEntry
,
488 &gVmbusConnection
.ChannelMsgList
);
490 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
491 DPRINT_DBG(VMBUS
, "buffer %p, size %d msg cnt %d",
492 Kbuffer
, Size
, msgCount
);
494 DPRINT_DBG(VMBUS
, "Sending GPADL Header - len %zd",
495 msgInfo
->MessageSize
- sizeof(*msgInfo
));
497 ret
= VmbusPostMessage(gpadlMsg
, msgInfo
->MessageSize
-
500 DPRINT_ERR(VMBUS
, "Unable to open channel - %d", ret
);
505 list_for_each(curr
, &msgInfo
->SubMsgList
) {
507 /* FIXME: should this use list_entry() instead ? */
508 subMsgInfo
= (struct vmbus_channel_msginfo
*)curr
;
510 (struct vmbus_channel_gpadl_body
*)subMsgInfo
->Msg
;
512 gpadlBody
->Header
.MessageType
= ChannelMessageGpadlBody
;
513 gpadlBody
->Gpadl
= nextGpadlHandle
;
515 DPRINT_DBG(VMBUS
, "Sending GPADL Body - len %zd",
516 subMsgInfo
->MessageSize
-
517 sizeof(*subMsgInfo
));
519 DumpGpadlBody(gpadlBody
, subMsgInfo
->MessageSize
-
520 sizeof(*subMsgInfo
));
521 ret
= VmbusPostMessage(gpadlBody
,
522 subMsgInfo
->MessageSize
-
523 sizeof(*subMsgInfo
));
527 osd_WaitEventWait(msgInfo
->WaitEvent
);
529 /* At this point, we received the gpadl created msg */
530 DPRINT_DBG(VMBUS
, "Received GPADL created "
531 "(relid %d, status %d handle %x)",
532 Channel
->OfferMsg
.ChildRelId
,
533 msgInfo
->Response
.GpadlCreated
.CreationStatus
,
536 *GpadlHandle
= gpadlMsg
->Gpadl
;
539 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
540 list_del(&msgInfo
->MsgListEntry
);
541 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
543 kfree(msgInfo
->WaitEvent
);
552 * VmbusChannelTeardownGpadl -Teardown the specified GPADL handle
554 int VmbusChannelTeardownGpadl(struct vmbus_channel
*Channel
, u32 GpadlHandle
)
556 struct vmbus_channel_gpadl_teardown
*msg
;
557 struct vmbus_channel_msginfo
*info
;
563 ASSERT(GpadlHandle
!= 0);
565 info
= kmalloc(sizeof(*info
) +
566 sizeof(struct vmbus_channel_gpadl_teardown
), GFP_KERNEL
);
567 ASSERT(info
!= NULL
);
569 info
->WaitEvent
= osd_WaitEventCreate();
571 msg
= (struct vmbus_channel_gpadl_teardown
*)info
->Msg
;
573 msg
->Header
.MessageType
= ChannelMessageGpadlTeardown
;
574 msg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
575 msg
->Gpadl
= GpadlHandle
;
577 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
578 list_add_tail(&info
->MsgListEntry
,
579 &gVmbusConnection
.ChannelMsgList
);
580 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
582 ret
= VmbusPostMessage(msg
,
583 sizeof(struct vmbus_channel_gpadl_teardown
));
589 osd_WaitEventWait(info
->WaitEvent
);
591 /* Received a torndown response */
592 spin_lock_irqsave(&gVmbusConnection
.channelmsg_lock
, flags
);
593 list_del(&info
->MsgListEntry
);
594 spin_unlock_irqrestore(&gVmbusConnection
.channelmsg_lock
, flags
);
596 kfree(info
->WaitEvent
);
605 * VmbusChannelClose - Close the specified channel
607 void VmbusChannelClose(struct vmbus_channel
*Channel
)
609 struct vmbus_channel_close_channel
*msg
;
610 struct vmbus_channel_msginfo
*info
;
616 /* Stop callback and cancel the timer asap */
617 Channel
->OnChannelCallback
= NULL
;
618 del_timer_sync(&Channel
->poll_timer
);
620 /* Send a closing message */
621 info
= kmalloc(sizeof(*info
) +
622 sizeof(struct vmbus_channel_close_channel
), GFP_KERNEL
);
623 ASSERT(info
!= NULL
);
625 /* info->waitEvent = osd_WaitEventCreate(); */
627 msg
= (struct vmbus_channel_close_channel
*)info
->Msg
;
628 msg
->Header
.MessageType
= ChannelMessageCloseChannel
;
629 msg
->ChildRelId
= Channel
->OfferMsg
.ChildRelId
;
631 ret
= VmbusPostMessage(msg
, sizeof(struct vmbus_channel_close_channel
));
637 /* Tear down the gpadl for the channel's ring buffer */
638 if (Channel
->RingBufferGpadlHandle
)
639 VmbusChannelTeardownGpadl(Channel
,
640 Channel
->RingBufferGpadlHandle
);
642 /* TODO: Send a msg to release the childRelId */
644 /* Cleanup the ring buffers for this channel */
645 RingBufferCleanup(&Channel
->Outbound
);
646 RingBufferCleanup(&Channel
->Inbound
);
648 osd_PageFree(Channel
->RingBufferPages
, Channel
->RingBufferPageCount
);
653 * If we are closing the channel during an error path in
654 * opening the channel, don't free the channel since the
655 * caller will free the channel
658 if (Channel
->State
== CHANNEL_OPEN_STATE
) {
659 spin_lock_irqsave(&gVmbusConnection
.channel_lock
, flags
);
660 list_del(&Channel
->ListEntry
);
661 spin_unlock_irqrestore(&gVmbusConnection
.channel_lock
, flags
);
663 FreeVmbusChannel(Channel
);
670 * VmbusChannelSendPacket - Send the specified buffer on the given channel
672 int VmbusChannelSendPacket(struct vmbus_channel
*Channel
, const void *Buffer
,
673 u32 BufferLen
, u64 RequestId
,
674 enum vmbus_packet_type Type
, u32 Flags
)
676 struct vmpacket_descriptor desc
;
677 u32 packetLen
= sizeof(struct vmpacket_descriptor
) + BufferLen
;
678 u32 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(u64
));
679 struct scatterlist bufferList
[3];
684 DPRINT_DBG(VMBUS
, "channel %p buffer %p len %d",
685 Channel
, Buffer
, BufferLen
);
687 DumpVmbusChannel(Channel
);
689 ASSERT((packetLenAligned
- packetLen
) < sizeof(u64
));
691 /* Setup the descriptor */
692 desc
.Type
= Type
; /* VmbusPacketTypeDataInBand; */
693 desc
.Flags
= Flags
; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
694 /* in 8-bytes granularity */
695 desc
.DataOffset8
= sizeof(struct vmpacket_descriptor
) >> 3;
696 desc
.Length8
= (u16
)(packetLenAligned
>> 3);
697 desc
.TransactionId
= RequestId
;
699 sg_init_table(bufferList
, 3);
700 sg_set_buf(&bufferList
[0], &desc
, sizeof(struct vmpacket_descriptor
));
701 sg_set_buf(&bufferList
[1], Buffer
, BufferLen
);
702 sg_set_buf(&bufferList
[2], &alignedData
, packetLenAligned
- packetLen
);
704 ret
= RingBufferWrite(&Channel
->Outbound
, bufferList
, 3);
706 /* TODO: We should determine if this is optional */
707 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
708 VmbusChannelSetEvent(Channel
);
716 * VmbusChannelSendPacketPageBuffer - Send a range of single-page buffer
717 * packets using a GPADL Direct packet type.
719 int VmbusChannelSendPacketPageBuffer(struct vmbus_channel
*Channel
,
720 struct hv_page_buffer PageBuffers
[],
721 u32 PageCount
, void *Buffer
, u32 BufferLen
,
726 struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc
;
729 u32 packetLenAligned
;
730 struct scatterlist bufferList
[3];
735 ASSERT(PageCount
<= MAX_PAGE_BUFFER_COUNT
);
737 DumpVmbusChannel(Channel
);
740 * Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the
741 * largest size we support
743 descSize
= sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER
) -
744 ((MAX_PAGE_BUFFER_COUNT
- PageCount
) *
745 sizeof(struct hv_page_buffer
));
746 packetLen
= descSize
+ BufferLen
;
747 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(u64
));
749 ASSERT((packetLenAligned
- packetLen
) < sizeof(u64
));
751 /* Setup the descriptor */
752 desc
.Type
= VmbusPacketTypeDataUsingGpaDirect
;
753 desc
.Flags
= VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
;
754 desc
.DataOffset8
= descSize
>> 3; /* in 8-bytes grandularity */
755 desc
.Length8
= (u16
)(packetLenAligned
>> 3);
756 desc
.TransactionId
= RequestId
;
757 desc
.RangeCount
= PageCount
;
759 for (i
= 0; i
< PageCount
; i
++) {
760 desc
.Range
[i
].Length
= PageBuffers
[i
].Length
;
761 desc
.Range
[i
].Offset
= PageBuffers
[i
].Offset
;
762 desc
.Range
[i
].Pfn
= PageBuffers
[i
].Pfn
;
765 sg_init_table(bufferList
, 3);
766 sg_set_buf(&bufferList
[0], &desc
, descSize
);
767 sg_set_buf(&bufferList
[1], Buffer
, BufferLen
);
768 sg_set_buf(&bufferList
[2], &alignedData
, packetLenAligned
- packetLen
);
770 ret
= RingBufferWrite(&Channel
->Outbound
, bufferList
, 3);
772 /* TODO: We should determine if this is optional */
773 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
774 VmbusChannelSetEvent(Channel
);
782 * VmbusChannelSendPacketMultiPageBuffer - Send a multi-page buffer packet
783 * using a GPADL Direct packet type.
785 int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel
*Channel
,
786 struct hv_multipage_buffer
*MultiPageBuffer
,
787 void *Buffer
, u32 BufferLen
, u64 RequestId
)
790 struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc
;
793 u32 packetLenAligned
;
794 struct scatterlist bufferList
[3];
796 u32 PfnCount
= NUM_PAGES_SPANNED(MultiPageBuffer
->Offset
,
797 MultiPageBuffer
->Length
);
801 DumpVmbusChannel(Channel
);
803 DPRINT_DBG(VMBUS
, "data buffer - offset %u len %u pfn count %u",
804 MultiPageBuffer
->Offset
, MultiPageBuffer
->Length
, PfnCount
);
806 ASSERT(PfnCount
> 0);
807 ASSERT(PfnCount
<= MAX_MULTIPAGE_BUFFER_COUNT
);
810 * Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is
811 * the largest size we support
813 descSize
= sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER
) -
814 ((MAX_MULTIPAGE_BUFFER_COUNT
- PfnCount
) *
816 packetLen
= descSize
+ BufferLen
;
817 packetLenAligned
= ALIGN_UP(packetLen
, sizeof(u64
));
819 ASSERT((packetLenAligned
- packetLen
) < sizeof(u64
));
821 /* Setup the descriptor */
822 desc
.Type
= VmbusPacketTypeDataUsingGpaDirect
;
823 desc
.Flags
= VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
;
824 desc
.DataOffset8
= descSize
>> 3; /* in 8-bytes grandularity */
825 desc
.Length8
= (u16
)(packetLenAligned
>> 3);
826 desc
.TransactionId
= RequestId
;
829 desc
.Range
.Length
= MultiPageBuffer
->Length
;
830 desc
.Range
.Offset
= MultiPageBuffer
->Offset
;
832 memcpy(desc
.Range
.PfnArray
, MultiPageBuffer
->PfnArray
,
833 PfnCount
* sizeof(u64
));
835 sg_init_table(bufferList
, 3);
836 sg_set_buf(&bufferList
[0], &desc
, descSize
);
837 sg_set_buf(&bufferList
[1], Buffer
, BufferLen
);
838 sg_set_buf(&bufferList
[2], &alignedData
, packetLenAligned
- packetLen
);
840 ret
= RingBufferWrite(&Channel
->Outbound
, bufferList
, 3);
842 /* TODO: We should determine if this is optional */
843 if (ret
== 0 && !GetRingBufferInterruptMask(&Channel
->Outbound
))
844 VmbusChannelSetEvent(Channel
);
852 * VmbusChannelRecvPacket - Retrieve the user packet on the specified channel
854 /* TODO: Do we ever receive a gpa direct packet other than the ones we send ? */
855 int VmbusChannelRecvPacket(struct vmbus_channel
*Channel
, void *Buffer
,
856 u32 BufferLen
, u32
*BufferActualLen
, u64
*RequestId
)
858 struct vmpacket_descriptor desc
;
866 *BufferActualLen
= 0;
869 spin_lock_irqsave(&Channel
->inbound_lock
, flags
);
871 ret
= RingBufferPeek(&Channel
->Inbound
, &desc
,
872 sizeof(struct vmpacket_descriptor
));
874 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
876 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
881 /* VmbusChannelClearEvent(Channel); */
883 packetLen
= desc
.Length8
<< 3;
884 userLen
= packetLen
- (desc
.DataOffset8
<< 3);
885 /* ASSERT(userLen > 0); */
887 DPRINT_DBG(VMBUS
, "packet received on channel %p relid %d <type %d "
888 "flag %d tid %llx pktlen %d datalen %d> ",
889 Channel
, Channel
->OfferMsg
.ChildRelId
, desc
.Type
,
890 desc
.Flags
, desc
.TransactionId
, packetLen
, userLen
);
892 *BufferActualLen
= userLen
;
894 if (userLen
> BufferLen
) {
895 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
897 DPRINT_ERR(VMBUS
, "buffer too small - got %d needs %d",
904 *RequestId
= desc
.TransactionId
;
906 /* Copy over the packet to the user buffer */
907 ret
= RingBufferRead(&Channel
->Inbound
, Buffer
, userLen
,
908 (desc
.DataOffset8
<< 3));
910 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
918 * VmbusChannelRecvPacketRaw - Retrieve the raw packet on the specified channel
920 int VmbusChannelRecvPacketRaw(struct vmbus_channel
*Channel
, void *Buffer
,
921 u32 BufferLen
, u32
*BufferActualLen
,
924 struct vmpacket_descriptor desc
;
932 *BufferActualLen
= 0;
935 spin_lock_irqsave(&Channel
->inbound_lock
, flags
);
937 ret
= RingBufferPeek(&Channel
->Inbound
, &desc
,
938 sizeof(struct vmpacket_descriptor
));
940 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
942 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
947 /* VmbusChannelClearEvent(Channel); */
949 packetLen
= desc
.Length8
<< 3;
950 userLen
= packetLen
- (desc
.DataOffset8
<< 3);
952 DPRINT_DBG(VMBUS
, "packet received on channel %p relid %d <type %d "
953 "flag %d tid %llx pktlen %d datalen %d> ",
954 Channel
, Channel
->OfferMsg
.ChildRelId
, desc
.Type
,
955 desc
.Flags
, desc
.TransactionId
, packetLen
, userLen
);
957 *BufferActualLen
= packetLen
;
959 if (packetLen
> BufferLen
) {
960 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
962 DPRINT_ERR(VMBUS
, "buffer too small - needed %d bytes but "
963 "got space for only %d bytes", packetLen
, BufferLen
);
968 *RequestId
= desc
.TransactionId
;
970 /* Copy over the entire packet to the user buffer */
971 ret
= RingBufferRead(&Channel
->Inbound
, Buffer
, packetLen
, 0);
973 spin_unlock_irqrestore(&Channel
->inbound_lock
, flags
);
981 * VmbusChannelOnChannelEvent - Channel event callback
983 void VmbusChannelOnChannelEvent(struct vmbus_channel
*Channel
)
985 DumpVmbusChannel(Channel
);
986 ASSERT(Channel
->OnChannelCallback
);
988 Channel
->OnChannelCallback(Channel
->ChannelCallbackContext
);
990 mod_timer(&Channel
->poll_timer
, jiffies
+ usecs_to_jiffies(100));
994 * VmbusChannelOnTimer - Timer event callback
996 void VmbusChannelOnTimer(unsigned long data
)
998 struct vmbus_channel
*channel
= (struct vmbus_channel
*)data
;
1000 if (channel
->OnChannelCallback
)
1001 channel
->OnChannelCallback(channel
->ChannelCallbackContext
);
1005 * DumpVmbusChannel - Dump vmbus channel info to the console
1007 static void DumpVmbusChannel(struct vmbus_channel
*Channel
)
1009 DPRINT_DBG(VMBUS
, "Channel (%d)", Channel
->OfferMsg
.ChildRelId
);
1010 DumpRingInfo(&Channel
->Outbound
, "Outbound ");
1011 DumpRingInfo(&Channel
->Inbound
, "Inbound ");