1
/*********************************************************
2
* Copyright (C) 2011 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation version 2 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
*********************************************************/
22
* Implementation of vPageChannel for guest kernels.
25
#include "vmci_kernel_if.h"
26
#include "vm_assert.h"
27
#include "vmci_defs.h"
28
#include "vmci_page_channel.h"
29
#include "vmciDriver.h"
30
#include "vmciKernelAPI.h"
32
#if !defined(linux) || defined(VMKERNEL)
33
#error "Wrong platform."
34
#endif // !linux || VMKERNEL
36
#define LGPFX "vPageChannel: "
39
* This threshold is to account for packets being in-flight. We can't keep
40
* an accurate count of receive buffers, it's just an estimate, so we allow
44
#define VMCI_PACKET_RECV_THRESHOLD 150
48
* Page channel. This is opaque to clients.
53
VPageChannelRecvCB recvCB;
56
VPageChannelAllocElemFn elemAllocFn;
57
void *allocClientData;
58
VPageChannelFreeElemFn elemFreeFn;
72
VMCIMutex qpRecvMutex;
73
VMCIMutex qpSendMutex;
79
VMCIHandle doorbellHandle;
80
VMCIHandle peerDoorbellHandle;
92
VMCIHandle peerDgHandle;
98
static int VPageChannelSendControl(VPageChannel *channel,
101
VPageChannelPacketType type,
103
VPageChannelElem *elems);
106
*-----------------------------------------------------------------------------
108
* VPageChannelAcquireSendLock
110
* Acquire the channel's send lock.
118
*-----------------------------------------------------------------------------
122
VPageChannelAcquireSendLock(VPageChannel *channel) // IN
125
VMCIMutex_Acquire(&channel->qpSendMutex);
130
*-----------------------------------------------------------------------------
132
* VPageChannelReleaseSendLock
134
* Release the channel's send lock.
142
*-----------------------------------------------------------------------------
146
VPageChannelReleaseSendLock(VPageChannel *channel) // IN
149
VMCIMutex_Release(&channel->qpSendMutex);
154
*-----------------------------------------------------------------------------
156
* VPageChannelAcquireRecvLock
158
* Acquire the channel's receive lock.
166
*-----------------------------------------------------------------------------
170
VPageChannelAcquireRecvLock(VPageChannel *channel) // IN
173
VMCIMutex_Acquire(&channel->qpRecvMutex);
178
*-----------------------------------------------------------------------------
180
* VPageChannelReleaseRecvLock
182
* Release the channel's receive lock.
190
*-----------------------------------------------------------------------------
194
VPageChannelReleaseRecvLock(VPageChannel *channel) // IN
197
VMCIMutex_Release(&channel->qpRecvMutex);
202
*-----------------------------------------------------------------------------
204
* VPageChannelSetRecvBuffers --
206
* Set the receiving buffers for the channel.
209
* VMCI_SUCCESS if set, negative error code otherwise.
214
*-----------------------------------------------------------------------------
218
VPageChannelSetRecvBuffers(VPageChannel *channel, // IN
220
Bool byControl) // IN
224
size_t size = sizeof(VPageChannelPacket) +
225
numElems * sizeof(VPageChannelElem);
226
VPageChannelElem *elems;
227
VPageChannelPacket *packet;
231
packet = (VPageChannelPacket *)VMCI_AllocKernelMem(size, VMCI_MEMORY_ATOMIC);
232
if (packet == NULL) {
233
VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
234
"(size=%"FMTSZ"u).\n",
237
return VMCI_ERROR_NO_MEM;
240
packet->type = VPCPacket_SetRecvBuffer;
242
packet->numElems = numElems;
244
elems = VPAGECHANNEL_PACKET_ELEMS(packet);
245
allocNum = channel->elemAllocFn(channel->allocClientData, elems, numElems);
246
if (allocNum != numElems) {
247
VMCI_WARNING((LGPFX"Failed to allocate receive buffer (channel=%p) "
248
"(expected=%d) (actual=%d).\n",
252
retval = VMCI_ERROR_NO_MEM;
256
if (byControl || !channel->qpConnected) {
257
retval = VPageChannelSendControl(channel, NULL, 0,
258
VPCPacket_SetRecvBuffer,
261
retval = VPageChannel_SendPacket(channel, packet);
263
if (retval < VMCI_SUCCESS) {
264
VMCI_WARNING((LGPFX"Failed to set receive buffers (channel=%p) "
271
channel->curRecvBufs += numElems;
273
VMCI_FreeKernelMem(packet, size);
278
if (packet != NULL) {
280
channel->elemFreeFn(channel->freeClientData, elems, allocNum);
282
VMCI_FreeKernelMem(packet, size);
290
*-----------------------------------------------------------------------------
292
* VPageChannelRecvPacket --
294
* Process a VMCI packet.
297
* Always VMCI_SUCCESS.
302
*-----------------------------------------------------------------------------
306
VPageChannelRecvPacket(VPageChannel *channel, // IN
307
VPageChannelPacket *packet) // IN
314
if (packet->type != VPCPacket_Data &&
315
packet->type != VPCPacket_Completion_Notify &&
316
packet->type != VPCPacket_RequestBuffer &&
317
packet->type != VPCPacket_HyperConnect) {
318
VMCI_WARNING((LGPFX"Received invalid packet (channel=%p) "
322
return VMCI_ERROR_INVALID_ARGS;
326
(LGPFX"Received packet (channel=%p) (type=%d) "
332
if (packet->type == VPCPacket_HyperConnect) {
333
VPageChannelHyperConnectMessage *message;
335
if (packet->msgLen < sizeof *message) {
336
VMCI_WARNING((LGPFX"Received invalid hypervisor connection message "
337
"(channel=%p) (size=%u).\n",
340
return VMCI_ERROR_INVALID_ARGS;
343
message = (VPageChannelHyperConnectMessage *)
344
VPAGECHANNEL_PACKET_MESSAGE(packet);
345
channel->peerDoorbellHandle = message->doorbellHandle;
348
(LGPFX"Connected to peer (channel=%p) "
349
"(db handle=0x%x:0x%x).\n",
351
channel->peerDoorbellHandle.context,
352
channel->peerDoorbellHandle.resource));
357
recvBufsTarget = channel->recvBufsTarget;
359
switch (packet->type) {
360
case VPCPacket_RequestBuffer:
362
* Increase the number of receive buffers by channel->defaultRecvBufs
363
* if the hypervisor requests it.
367
(LGPFX"Requested more buffers (channel=%p) "
368
"(cur=%d) (target=%d) (max=%d).\n",
370
channel->curRecvBufs,
371
channel->recvBufsTarget,
372
channel->maxRecvBufs));
374
if (channel->recvBufsTarget < channel->maxRecvBufs) {
375
recvBufsTarget = channel->recvBufsTarget + channel->defaultRecvBufs;
380
channel->recvCB(channel->clientRecvData, packet);
381
channel->curRecvBufs -= packet->numElems;
384
case VPCPacket_Completion_Notify:
385
channel->recvCB(channel->clientRecvData, packet);
389
ASSERT_NOT_IMPLEMENTED(FALSE);
394
* Set more receive buffers if it is below the threshold. We bump it up
395
* here even when not requested to do so. This is to account for buffers
396
* being in-flight, i.e., in packets that have not yet been processed by
397
* the other side. When we increase here, we also tack on extra threshold,
398
* in the hope that we won't hit this again.
401
if (channel->curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) {
402
int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD -
403
channel->curRecvBufs;
405
if (VPageChannelSetRecvBuffers(channel, numElems, FALSE) ==
407
channel->recvBufsTarget = recvBufsTarget;
416
*-----------------------------------------------------------------------------
418
* VPageChannelDgRecvFunc --
420
* Callback function to receive a VMCI packet. This is only used until
421
* the connection is made; after that, packets are received over the
425
* VMCI_SUCCESS on success, negative values on failure.
430
*-----------------------------------------------------------------------------
434
VPageChannelDgRecvFunc(void *clientData, // IN
435
VMCIDatagram *dg) // IN
437
VPageChannel *channel = (VPageChannel *)clientData;
442
if (dg->src.context != VMCI_HOST_CONTEXT_ID ||
443
dg->src.resource != channel->peerDgHandle.resource) {
444
VMCI_WARNING((LGPFX"Received a packet from an unknown source "
445
"(channel=%p) (handle=0x%x:0x%x).\n",
449
return VMCI_ERROR_NO_ACCESS;
452
if (dg->payloadSize < sizeof (VPageChannelPacket)) {
453
VMCI_WARNING((LGPFX"Received invalid packet (channel=%p) "
454
"(size=%"FMT64"u).\n",
457
return VMCI_ERROR_INVALID_ARGS;
460
return VPageChannelRecvPacket(channel, VMCI_DG_PAYLOAD(dg));
465
*----------------------------------------------------------------------------
467
* VMCIPacketDoDoorbellCallback --
469
* Process a doorbell notification. Will read packets from the queuepair
472
* XXX, this function is now identical to the one with the same name in
473
* modules/vmkernel/vmci/vmciPacketVMK.c. We should share this code.
481
*----------------------------------------------------------------------------
485
VMCIPacketDoDoorbellCallback(VPageChannel *channel) // IN/OUT
488
VPageChannelPacket packetHeader;
492
if (!channel->qpConnected) {
493
VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
498
VPageChannelAcquireRecvLock(channel);
499
inUse = channel->inPoll;
500
channel->inPoll = TRUE;
501
VPageChannelReleaseRecvLock(channel);
508
while (VMCIQPair_ConsumeBufReady(channel->qpair) >= sizeof packetHeader) {
509
ssize_t retSize, totalSize;
510
VPageChannelPacket *packet;
512
retSize = VMCIQPair_Peek(channel->qpair, &packetHeader,
514
/* XXX, UTIL_VMKERNEL_BUFFER for VMKernel. */
516
if (retSize < sizeof packetHeader) {
518
* XXX, deal with partial read.
521
VMCI_WARNING((LGPFX"Failed to peek (channel=%p) "
522
"(required=%"FMTSZ"d) (err=%"FMTSZ"d).\n",
529
totalSize = sizeof packetHeader + packetHeader.msgLen +
530
packetHeader.numElems * sizeof(VPageChannelElem);
532
retSize = VMCIQPair_ConsumeBufReady(channel->qpair);
533
if (retSize < totalSize) {
535
* XXX, deal with partial read.
538
VMCI_WARNING((LGPFX"Received partial packet (channel=%p) "
539
"(type=%d) (len=%d) (num elems=%d) (avail=%"FMTSZ"d) "
540
"(requested=%"FMTSZ"d).\n",
544
packetHeader.numElems,
550
packet = (VPageChannelPacket *)
551
VMCI_AllocKernelMem(totalSize, VMCI_MEMORY_ATOMIC);
553
VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
554
"(size=%"FMTSZ"d).\n",
560
retSize = VMCIQPair_Dequeue(channel->qpair, packet,
562
/* XXX, UTIL_VMKERNEL_BUFFER for VMKernel. */
564
if (retSize < totalSize) {
566
* XXX, deal with partial read.
569
VMCI_WARNING((LGPFX"Failed to dequeue (channel=%p) "
570
"(required=%"FMTSZ"d) (err=%"FMTSZ"d).\n",
574
VMCI_FreeKernelMem(packet, totalSize);
578
VPageChannelRecvPacket(channel, packet);
579
VMCI_FreeKernelMem(packet, totalSize);
582
VPageChannelAcquireRecvLock(channel);
585
* The doorbell may have been notified between when we we finished reading
586
* data and when we grabbed the lock. If that happens, then there may be
587
* data, but we bailed out of that second notification because inPoll was
588
* already set. So that we don't miss anything, do a final check here under
589
* the lock for any data that might have arrived.
592
if (VMCIQPair_ConsumeBufReady(channel->qpair) >= sizeof packetHeader) {
593
VPageChannelReleaseRecvLock(channel);
597
channel->inPoll = FALSE;
598
VPageChannelReleaseRecvLock(channel);
603
*----------------------------------------------------------------------------
605
* VMCIPacketDoorbellCallback --
607
* Callback for doorbell notification. Will invoke the channel's receive
608
* function directly or process the packets in the queuepair.
616
*----------------------------------------------------------------------------
620
VMCIPacketDoorbellCallback(void *clientData) // IN/OUT
622
VPageChannel *channel = (VPageChannel *)clientData;
626
if (channel->notifyOnly) {
627
channel->recvCB(channel->clientRecvData, NULL);
629
VMCIPacketDoDoorbellCallback(channel);
635
*----------------------------------------------------------------------------
637
* VPageChannelSendConnectionMessage --
639
* Send a connection control message to the hypervisor.
642
* VMCI_SUCCESS if sent, negative values on failure.
647
*----------------------------------------------------------------------------
651
VPageChannelSendConnectionMessage(VPageChannel *channel) // IN
653
VPageChannelGuestConnectMessage message;
657
memset(&message, 0, sizeof message);
658
message.dgHandle = channel->dgHandle;
659
message.qpHandle = channel->qpHandle;
660
message.produceQSize = channel->produceQSize;
661
message.consumeQSize = channel->consumeQSize;
662
message.doorbellHandle = channel->doorbellHandle;
665
(LGPFX"Sending guest connect (channel=%p) "
666
"(qp handle=0x%x:0x%x).\n",
668
channel->qpHandle.context,
669
channel->qpHandle.resource));
671
return VPageChannelSendControl(channel,
672
(char *)&message, sizeof message,
673
VPCPacket_GuestConnect, 0, NULL);
678
*----------------------------------------------------------------------------
680
* VMCIPacketPeerAttachCB --
682
* Invoked when a peer attaches to a queue pair.
688
* May modify page channel state.
690
*----------------------------------------------------------------------------
694
VPageChannelPeerAttachCB(VMCIId subId, // IN
695
VMCI_EventData *eData, // IN
696
void *clientData) // IN
698
VPageChannel *channel;
699
VMCIEventPayload_QP *ePayload;
704
channel = (VPageChannel *)clientData;
705
ePayload = VMCIEventDataPayload(eData);
707
if (VMCI_HANDLE_EQUAL(channel->qpHandle, ePayload->handle)) {
709
(LGPFX"Peer attached (channel=%p) "
710
"(qp handle=0x%x:0x%x).\n",
712
ePayload->handle.context,
713
ePayload->handle.resource));
714
channel->qpConnected = TRUE;
720
*----------------------------------------------------------------------------
722
* VMCIPacketPeerDetachCB --
724
* Invoked when a peer detaches from a queue pair.
730
* May modify page channel state.
732
*----------------------------------------------------------------------------
736
VPageChannelPeerDetachCB(VMCIId subId, // IN
737
VMCI_EventData *eData, // IN
738
void *clientData) // IN
740
VPageChannel *channel;
741
VMCIEventPayload_QP *ePayload;
746
channel = (VPageChannel *)clientData;
747
ePayload = VMCIEventDataPayload(eData);
749
if (VMCI_HANDLE_EQUAL(channel->qpHandle, ePayload->handle)) {
751
(LGPFX"Peer detached (channel=%p) "
752
"(qp handle=0x%x:0x%x).\n",
754
ePayload->handle.context,
755
ePayload->handle.resource));
756
channel->qpConnected = FALSE;
762
*----------------------------------------------------------------------------
764
* VPageChannelDestroyQueuePair --
766
* Destroy the channel's queuepair, along with the event subscriptions.
772
* May modify page channel state.
774
*----------------------------------------------------------------------------
778
VPageChannelDestroyQueuePair(VPageChannel *channel) // IN/OUT
782
if (channel->attachSubId != VMCI_INVALID_ID) {
783
VMCIEvent_Unsubscribe(channel->attachSubId);
784
channel->attachSubId = VMCI_INVALID_ID;
787
if (channel->detachSubId != VMCI_INVALID_ID) {
788
VMCIEvent_Unsubscribe(channel->detachSubId);
789
channel->detachSubId = VMCI_INVALID_ID;
792
if (!VMCI_HANDLE_INVALID(channel->qpHandle)) {
793
ASSERT(channel->qpair);
794
VMCIQPair_Detach(&channel->qpair);
795
channel->qpHandle = VMCI_INVALID_HANDLE;
796
channel->qpair = NULL;
799
VMCIMutex_Destroy(&channel->qpRecvMutex);
800
VMCIMutex_Destroy(&channel->qpSendMutex);
802
channel->qpConnected = FALSE;
807
*----------------------------------------------------------------------------
809
* VPageChannelCreateQueuePair --
811
* Create queuepair for data communication.
814
* VMCI_SUCCESS if the queuepair is created, negative values on failure.
817
* May modify page channel state.
819
*----------------------------------------------------------------------------
823
VPageChannelCreateQueuePair(VPageChannel *channel) // IN/OUT
829
ASSERT(VMCI_HANDLE_INVALID(channel->qpHandle));
830
ASSERT(NULL == channel->qpair);
831
ASSERT(VMCI_INVALID_ID == channel->detachSubId);
832
ASSERT(VMCI_INVALID_ID == channel->attachSubId);
834
err = VMCIMutex_Init(&channel->qpSendMutex, "VMCIPacketSendMutex",
835
VMCI_SEMA_RANK_PACKET_QP);
836
if (err < VMCI_SUCCESS) {
837
VMCI_WARNING((LGPFX"Failed to initialize send mutex (channel=%p).\n",
842
err = VMCIMutex_Init(&channel->qpRecvMutex, "VMCIPacketRecvMutex",
843
VMCI_SEMA_RANK_PACKET_QP);
844
if (err < VMCI_SUCCESS) {
845
VMCI_WARNING((LGPFX"Failed to initialize revc mutex (channel=%p).\n",
847
VMCIMutex_Destroy(&channel->qpSendMutex);
851
err = VMCIEvent_Subscribe(VMCI_EVENT_QP_PEER_ATTACH,
852
VMCI_FLAG_EVENT_NONE,
853
VPageChannelPeerAttachCB,
854
channel, &channel->attachSubId);
855
if (err < VMCI_SUCCESS) {
856
VMCI_WARNING((LGPFX"Failed to subscribe to attach event "
857
"(channel=%p) (err=%d).\n",
863
err = VMCIEvent_Subscribe(VMCI_EVENT_QP_PEER_DETACH,
864
VMCI_FLAG_EVENT_NONE,
865
VPageChannelPeerDetachCB,
866
channel, &channel->detachSubId);
867
if (err < VMCI_SUCCESS) {
868
VMCI_WARNING((LGPFX"Failed to subscribe to detach event "
869
"(channel=%p) (err=%d).\n",
876
err = VMCIQPair_Alloc(&channel->qpair, &channel->qpHandle,
877
channel->produceQSize, channel->consumeQSize,
878
VMCI_HOST_CONTEXT_ID, flags, VMCI_NO_PRIVILEGE_FLAGS);
880
VMCI_WARNING((LGPFX"Could not create queue pair (err=%d).\n",
886
(LGPFX"Allocated queuepair (channel=%p) "
887
"(qp handle=0x%x:0x%x) "
888
"(produce=%"FMT64"u) (consume=%"FMT64"u).\n",
890
channel->qpHandle.context,
891
channel->qpHandle.resource,
892
channel->produceQSize,
893
channel->consumeQSize));
898
VPageChannelDestroyQueuePair(channel);
904
*-----------------------------------------------------------------------------
906
* VPageChannel_CreateInVM --
908
* Create a page channel in the guest kernel.
911
* VMCI_SUCCESS if created, negative errno value otherwise.
914
* May set the receive buffers if a default size is given.
916
*-----------------------------------------------------------------------------
920
VPageChannel_CreateInVM(VPageChannel **channel, // IN/OUT
921
VMCIId resourceId, // IN
922
VMCIId peerResourceId, // IN
923
uint64 produceQSize, // IN
924
uint64 consumeQSize, // IN
925
VPageChannelRecvCB recvCB, // IN
926
void *clientRecvData, // IN
927
Bool notifyOnly, // IN
928
VPageChannelAllocElemFn elemAllocFn, // IN
929
void *allocClientData, // IN
930
VPageChannelFreeElemFn elemFreeFn, // IN
931
void *freeClientData, // IN
932
int defaultRecvBuffers, // IN
933
int maxRecvBuffers) // IN
937
VPageChannel *pageChannel;
940
ASSERT(VMCI_INVALID_ID != resourceId);
941
ASSERT(VMCI_INVALID_ID != peerResourceId);
945
VMCI_AllocKernelMem(sizeof *pageChannel, VMCI_MEMORY_NONPAGED);
947
return VMCI_ERROR_NO_MEM;
951
* XXX, we should support a default internal allocation function.
954
memset(pageChannel, 0, sizeof *pageChannel);
955
pageChannel->dgHandle = VMCI_INVALID_HANDLE;
956
pageChannel->attachSubId = VMCI_INVALID_ID;
957
pageChannel->detachSubId = VMCI_INVALID_ID;
958
pageChannel->qpHandle = VMCI_INVALID_HANDLE;
959
pageChannel->qpair = NULL;
960
pageChannel->doorbellHandle = VMCI_INVALID_HANDLE;
961
pageChannel->peerDoorbellHandle = VMCI_INVALID_HANDLE;
962
pageChannel->qpConnected = FALSE;
963
pageChannel->recvCB = recvCB;
964
pageChannel->clientRecvData = clientRecvData;
965
pageChannel->notifyOnly = notifyOnly;
966
pageChannel->elemAllocFn = elemAllocFn;
967
pageChannel->allocClientData = allocClientData;
968
pageChannel->elemFreeFn = elemFreeFn;
969
pageChannel->freeClientData = freeClientData;
970
pageChannel->resourceId = resourceId;
971
pageChannel->peerDgHandle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID,
973
pageChannel->curRecvBufs = 0;
974
pageChannel->recvBufsTarget = defaultRecvBuffers;
975
pageChannel->defaultRecvBufs = defaultRecvBuffers;
976
pageChannel->maxRecvBufs = maxRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
977
pageChannel->produceQSize = produceQSize;
978
pageChannel->consumeQSize = consumeQSize;
981
* Create a datagram handle over which we will connection handshake packets
982
* (once the queuepair is created we can send packets over that instead).
985
flags = VMCI_FLAG_DG_DELAYED_CB;
986
retval = VMCIDatagram_CreateHnd(resourceId, flags,
987
VPageChannelDgRecvFunc, pageChannel,
988
&pageChannel->dgHandle);
989
if (retval < VMCI_SUCCESS) {
990
VMCI_WARNING((LGPFX"Failed to create datagram handle "
991
"(channel=%p) (err=%d).\n",
998
(LGPFX"Created datagram (channel=%p) "
999
"(handle=0x%x:0x%x).\n",
1001
pageChannel->dgHandle.context,
1002
pageChannel->dgHandle.resource));
1005
* Create a doorbell handle. This is used by the peer to signal the
1006
* arrival of packets in the queuepair.
1009
retval = VMCIDoorbell_Create(&pageChannel->doorbellHandle,
1010
VMCI_FLAG_DELAYED_CB,
1011
VMCI_PRIVILEGE_FLAG_RESTRICTED,
1012
VMCIPacketDoorbellCallback, pageChannel);
1013
if (retval < VMCI_SUCCESS) {
1014
VMCI_WARNING((LGPFX"Failed to create doorbell "
1015
"(channel=%p) (err=%d).\n",
1022
(LGPFX"Created doorbell (channel=%p) "
1023
"(handle=0x%x:0x%x).\n",
1025
pageChannel->doorbellHandle.context,
1026
pageChannel->doorbellHandle.resource));
1029
* Now create the queuepair, over which we can pass data packets.
1032
retval = VPageChannelCreateQueuePair(pageChannel);
1033
if (retval < VMCI_SUCCESS) {
1038
* Set the receiving buffers before sending the connection message to
1039
* avoid a race when the connection is made, but there is no receiving
1043
if (defaultRecvBuffers) {
1044
int numElems = defaultRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
1045
retval = VPageChannelSetRecvBuffers(pageChannel, numElems, TRUE);
1046
if (retval < VMCI_SUCCESS) {
1051
retval = VPageChannelSendConnectionMessage(pageChannel);
1052
if (retval < VMCI_SUCCESS) {
1057
(LGPFX"Created (channel=%p) (handle=0x%x:0x%x).\n",
1059
pageChannel->dgHandle.context,
1060
pageChannel->dgHandle.resource));
1062
*channel = pageChannel;
1067
VPageChannel_Destroy(pageChannel);
1070
EXPORT_SYMBOL(VPageChannel_CreateInVM);
1074
*-----------------------------------------------------------------------------
1076
* VPageChannel_Destroy --
1078
* Destroy the page channel.
1086
*-----------------------------------------------------------------------------
1090
VPageChannel_Destroy(VPageChannel *channel) // IN/OUT
1094
VPageChannelDestroyQueuePair(channel);
1096
if (!VMCI_HANDLE_INVALID(channel->doorbellHandle)) {
1097
VMCIDoorbell_Destroy(channel->doorbellHandle);
1100
if (!VMCI_HANDLE_INVALID(channel->dgHandle)) {
1101
VMCIDatagram_DestroyHnd(channel->dgHandle);
1104
VMCI_FreeKernelMem(channel, sizeof *channel);
1107
(LGPFX"Destroyed (channel=%p).\n",
1110
EXPORT_SYMBOL(VPageChannel_Destroy);
1114
*-----------------------------------------------------------------------------
1116
* VMCIPacketAllocDatagram --
1118
* Allocate a datagram for the packet. This is only used until the
1119
* connection is made; after that, packets are passed over the queuepair.
1121
* XXX, this function is now identical to the one of the same name in
1122
* modules/vmkernel/vmci/vmciPacketVMK.c. We should share this code.
1125
* VMCI_SUCCESS and a datagram if successfully allocated, negative error
1131
*-----------------------------------------------------------------------------
1135
VPageChannelAllocDatagram(VPageChannel *channel, // IN
1136
size_t messageLen, // IN
1138
VMCIDatagram **outDg) // OUT
1148
size = VMCI_DG_HEADERSIZE + sizeof(VPageChannelPacket) + messageLen +
1149
numElems * sizeof (VPageChannelElem);
1151
if (size > VMCI_MAX_DG_SIZE) {
1152
VMCI_WARNING((LGPFX"Requested datagram size too large (channel=%p) "
1153
"(size=%"FMTSZ"u).",
1156
return VMCI_ERROR_PAYLOAD_TOO_LARGE;
1159
dg = VMCI_AllocKernelMem(size, VMCI_MEMORY_ATOMIC);
1161
VMCI_WARNING((LGPFX"Failed to allocate datagram (channel=%p).",
1163
return VMCI_ERROR_NO_MEM;
1166
memset(dg, 0, size);
1167
dg->dst = channel->peerDgHandle;
1168
dg->src = channel->dgHandle;
1169
dg->payloadSize = size - VMCI_DG_HEADERSIZE;
1172
// VMCI_DEBUG_LOG(10,
1173
// (LGPFX"Allocated datagram (payload=%"FMT64"u).\n",
1174
// dg->payloadSize));
1178
return VMCI_SUCCESS;
1183
*-----------------------------------------------------------------------------
1185
* VPageChannelSendControl --
1187
* A packet is constructed to send the message and buffer to the guest
1188
* via the control channel (datagram). This is only necessary until the
1189
* queuepair is connected.
1192
* VMCI_SUCCESS if the packet is sent successfully, negative error number
1198
*-----------------------------------------------------------------------------
1202
VPageChannelSendControl(VPageChannel *channel, // IN
1203
char *message, // IN
1205
VPageChannelPacketType type, // IN
1207
VPageChannelElem *elems) // IN
1210
VPageChannelPacket *packet;
1214
ASSERT(type == VPCPacket_Data ||
1215
type == VPCPacket_GuestConnect ||
1216
type == VPCPacket_SetRecvBuffer);
1219
retval = VPageChannelAllocDatagram(channel, len, numElems, &dg);
1220
if (retval < VMCI_SUCCESS) {
1224
packet = (VPageChannelPacket *)VMCI_DG_PAYLOAD(dg);
1225
packet->type = type;
1226
packet->msgLen = len;
1227
packet->numElems = numElems;
1231
memcpy(VPAGECHANNEL_PACKET_MESSAGE(packet), message, len);
1236
memcpy(VPAGECHANNEL_PACKET_ELEMS(packet), elems,
1237
numElems * sizeof (VPageChannelElem));
1240
retval = VMCIDatagram_Send(dg);
1241
if (retval < VMCI_SUCCESS) {
1242
VMCI_WARNING((LGPFX"Failed to send packet (channel=%p) to "
1243
"(handle=0x%x:0x%x) (err=%d).\n",
1250
* We don't care about how many bytes were sent, and callers may not
1251
* expect > 0 to mean success, so just convert to exactly success.
1254
retval = VMCI_SUCCESS;
1257
VMCI_FreeKernelMem(dg, VMCI_DG_SIZE(dg));
1264
*-----------------------------------------------------------------------------
1266
* VPageChannel_SendPacket --
1268
* Send a VMCI packet to the hypervisor.
1270
* XXX, this is now identical to the function of the same name in
1271
* modules/vmkernel/vmci/vmciPacketVMK.c. We should share this code.
1274
* VMCI_SUCCESS if sent, negative error number otherwise.
1279
*-----------------------------------------------------------------------------
1283
VPageChannel_SendPacket(VPageChannel *channel, // IN
1284
VPageChannelPacket *packet) // IN
1287
ssize_t totalSize, sentSize, curSize;
1292
if (!channel->qpConnected) {
1293
VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
1295
retval = VMCI_ERROR_DST_UNREACHABLE;
1301
totalSize = sizeof(VPageChannelPacket) + packet->msgLen +
1302
packet->numElems * sizeof(VPageChannelElem);
1304
VPageChannelAcquireSendLock(channel);
1306
freeSpace = VMCIQPair_ProduceFreeSpace(channel->qpair);
1307
if (freeSpace < totalSize) {
1308
VMCI_WARNING((LGPFX"No free space in queuepair (channel=%p) "
1309
"(required=%"FMTSZ"d) (actual=%"FMTSZ"d).\n",
1313
retval = VMCI_ERROR_NO_MEM;
1317
sentSize = VMCIQPair_Enqueue(channel->qpair, packet, totalSize, 0);
1318
curSize = VMCIQPair_ProduceBufReady(channel->qpair);
1320
if (curSize == sentSize) {
1321
retval = VMCIDoorbell_Notify(channel->peerDoorbellHandle,
1322
/* XXX, TRUSTED for VMKernel. */
1323
VMCI_PRIVILEGE_FLAG_RESTRICTED);
1324
if (retval < VMCI_SUCCESS) {
1325
VMCI_WARNING((LGPFX"Failed to notify doorbell (channel=%p) "
1326
"(handle=0x%x:0x%x) (err=%d).\n",
1328
channel->peerDoorbellHandle.context,
1329
channel->peerDoorbellHandle.resource,
1335
VPageChannelReleaseSendLock(channel);
1337
if (sentSize < totalSize) {
1339
* XXX, deal with partial sending.
1342
VMCI_WARNING((LGPFX"No free space in queuepair (channel=%p) "
1343
"(required=%"FMTSZ"d) (actual=%"FMTSZ"d).\n",
1347
retval = VMCI_ERROR_NO_MEM;
1352
(LGPFX"Sent packet (channel=%p) (size=%"FMTSZ"d).\n",
1356
return VMCI_SUCCESS;
1359
VPageChannelReleaseSendLock(channel);
1363
EXPORT_SYMBOL(VPageChannel_SendPacket);
1367
*-----------------------------------------------------------------------------
1369
* VPageChannel_Send --
1371
* A packet is constructed to send the message and buffer to the guest.
1373
* XXX, this is now identical to the function of the same name in
1374
* modules/vmkernel/vmci/vmciPacketVMK.c. We should share this code.
1377
* VMCI_SUCCESS if the packet is sent successfully, negative error number
1383
*-----------------------------------------------------------------------------
1387
VPageChannel_Send(VPageChannel *channel, // IN/OUT
1388
VPageChannelPacketType type, // IN
1389
char *message, // IN
1391
VPageChannelBuffer *buffer) // IN
1396
VPageChannelPacket *packet;
1400
if (!channel->qpConnected) {
1401
VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
1403
return VMCI_ERROR_DST_UNREACHABLE;
1407
numElems = buffer->numElems;
1412
totalSize = sizeof(VPageChannelPacket) + len +
1413
numElems * sizeof(VPageChannelElem);
1414
packet = (VPageChannelPacket *)
1415
VMCI_AllocKernelMem(totalSize, VMCI_MEMORY_NORMAL);
1417
VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
1418
"(size=%"FMTSZ"d).",
1421
return VMCI_ERROR_NO_MEM;
1424
packet->type = type;
1425
packet->msgLen = len;
1426
packet->numElems = numElems;
1430
memcpy(VPAGECHANNEL_PACKET_MESSAGE(packet), message, len);
1435
ASSERT(buffer->elems);
1436
memcpy(VPAGECHANNEL_PACKET_ELEMS(packet), buffer->elems,
1437
numElems * sizeof (VPageChannelElem));
1440
retval = VPageChannel_SendPacket(channel, packet);
1442
VMCI_FreeKernelMem(packet, totalSize);
1446
EXPORT_SYMBOL(VPageChannel_Send);
1450
*-----------------------------------------------------------------------------
1452
* VPageChannel_PollTx --
1454
* The caller does its own coalescing and notifies us that it starts tx.
1460
* We do not do our own coalescing.
1462
*-----------------------------------------------------------------------------
1466
VPageChannel_PollRecvQ(VPageChannel *channel) // IN
1468
if (channel->qpConnected) {
1469
VMCIPacketDoDoorbellCallback(channel);
1472
EXPORT_SYMBOL(VPageChannel_PollRecvQ);