~n-muench/ubuntu/precise/open-vm-tools/open-vm-tools.raring-precise.backport

« back to all changes in this revision

Viewing changes to modules/linux/vmci/common/vmciPageChannel.c

  • Committer: Package Import Robot
  • Author(s): Nate Muench
  • Date: 2012-01-23 16:09:45 UTC
  • mfrom: (1.4.6) (2.4.26 sid)
  • Revision ID: package-import@ubuntu.com-20120123160945-b6s0r1vkcovucpf3
Tags: 2011.12.20-562307-0ubuntu1
* Merge latest upstream git tag. Fixes building on Precise
  (LP: #898289, LP: #905612)

* Items merged from Debian unstable:
  - debian/control:
    + open-vm-tools recommends open-vm-dkms. (LP: #598933)
    + open-vm-tools now suggests open-vm-toolbox. (LP: #604998)
  (From 2011.08.21-471295-1 release)
  - Updating maintainer and uploaders fields.
  - Removing vcs fields.
  - Removing references to Daniel's old email address.
  - Updating years in copyright file.
  - Updating to standards version 3.9.2.
  - Updating to debhelper version 8.
  - Switching to source format 3.0 (quilt).
  - Removing manual chrpath setting.
  - Removing exclusion from plugins from debhelper shlibs.
  - Rediffing kvers.patch.
  (From 2011.09.23-491607-1 release)
  - Marking binary architecture-dependend packages as linux and kfreebsd
  only.
  - Removing liburiparser-dev from build-depends as upstream dropped
  unity support.
  - Building with libproc-dev on amd64 again.
  - Dropping disabling of dnet support.
  (From 2011.09.23-491607-2 release)
  - Adding doxygen to build-depends for api documentation.
  - Adding libcunit1-dev to build-depends for test suites.
  - Minimizing rules file.
  - Adding open-vm-tools-dev package, containing only the api
    documentation for now.
  (From 2011.09.23-491607-3 release)
  - Sorting overrides in rules alphabetically.
  - Compacting copyright file.
  - Adding udev rule to set timeout for vmware scsi devices
  (From 2011.12.20-562307-1 release)
  - Adding patch to correct typo in upstreams dkms configuration

* Remaining Changes:
  - Remove Stable part of version numbering.
  - debian folder:
    + Re-added open-vm-dkms.postinst & open-vm-dkms.prerm.
      * Allows dkms modules to compile upon installation.
  - debian/control:
    + Re-add open-vm-source and make into a transitional package
      for open-vm-toolbox.
    + Return dependancies that were moved to open-vm-tools back to
      open-vm-toolbox.
  - debian/rules and debian/open-vm-toolbox.lintian-overrides:
    + Make vmware-user-suid-wrapper suid-root
  - debian/rules:
    + Added CFLAGS field with -Wno-deprecated-declarations
      * Will suppress issues with glib 2.31 or later.
    + Add line to copy vmware-xdg-detect-de into place.
    + Install vmware-user.desktop through toolbox package.
  - debian/open-vm-tools.init:
    + Re-add 'modprobe [-r] vmblock'.
    + Add 'modprobe [-r] vmxnet'.
      * Incase it's not loaded during boot.
    + Remove and re-add pcnet32 module
      * Will be done before (remove) and after (readd) vmxnet module
        is added.
      * If vmxnet doesn't exist (aka modules fail to build), pcnet32 can be
        still used for network connectivity.
      * Workaround until a better fix can be done.
  - Re-add gnome-session to debian/local/xautostart.conf
  - Manpages removed (from debian/manpages):
    + vmmemctl.9
    + vmxnet3.9
    + Remove references to manpages that have been removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2011 VMware, Inc. All rights reserved.
 
3
 *
 
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.
 
7
 *
 
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
 
11
 * for more details.
 
12
 *
 
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
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/*
 
20
 * vmciPacket.c --
 
21
 *
 
22
 *     Implementation of vPageChannel for guest kernels.
 
23
 */
 
24
 
 
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"
 
31
 
 
32
#if !defined(linux) || defined(VMKERNEL)
 
33
#error "Wrong platform."
 
34
#endif // !linux || VMKERNEL
 
35
 
 
36
#define LGPFX "vPageChannel: "
 
37
 
 
38
/*
 
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
 
41
 * some slack.
 
42
 */
 
43
 
 
44
#define VMCI_PACKET_RECV_THRESHOLD 150
 
45
 
 
46
 
 
47
/*
 
48
 * Page channel.  This is opaque to clients.
 
49
 */
 
50
 
 
51
struct VPageChannel {
 
52
   VMCIHandle dgHandle;
 
53
   VPageChannelRecvCB recvCB;
 
54
   void *clientRecvData;
 
55
   Bool notifyOnly;
 
56
   VPageChannelAllocElemFn elemAllocFn;
 
57
   void *allocClientData;
 
58
   VPageChannelFreeElemFn elemFreeFn;
 
59
   void *freeClientData;
 
60
 
 
61
   /*
 
62
    * QueuePair info.
 
63
    */
 
64
 
 
65
   VMCIQPair *qpair;
 
66
   VMCIHandle qpHandle;
 
67
   uint64 produceQSize;
 
68
   uint64 consumeQSize;
 
69
   VMCIId attachSubId;
 
70
   VMCIId detachSubId;
 
71
   Bool qpConnected;
 
72
   VMCIMutex qpRecvMutex;
 
73
   VMCIMutex qpSendMutex;
 
74
 
 
75
   /*
 
76
    * Doorbell info.
 
77
    */
 
78
 
 
79
   VMCIHandle doorbellHandle;
 
80
   VMCIHandle peerDoorbellHandle;
 
81
 
 
82
   /*
 
83
    * Receiving buffer.
 
84
    */
 
85
 
 
86
   int curRecvBufs;
 
87
   int recvBufsTarget;
 
88
   int defaultRecvBufs;
 
89
   int maxRecvBufs;
 
90
 
 
91
   VMCIId resourceId;
 
92
   VMCIHandle peerDgHandle;
 
93
 
 
94
   Bool inPoll;
 
95
};
 
96
 
 
97
 
 
98
static int VPageChannelSendControl(VPageChannel *channel,
 
99
                                   char *message,
 
100
                                   int len,
 
101
                                   VPageChannelPacketType type,
 
102
                                   int numElems,
 
103
                                   VPageChannelElem *elems);
 
104
 
 
105
/*
 
106
 *-----------------------------------------------------------------------------
 
107
 *
 
108
 * VPageChannelAcquireSendLock
 
109
 *
 
110
 *      Acquire the channel's send lock.
 
111
 *
 
112
 * Results:
 
113
 *      None.
 
114
 *
 
115
 * Side effects:
 
116
 *      None.
 
117
 *
 
118
 *-----------------------------------------------------------------------------
 
119
 */
 
120
 
 
121
static void
 
122
VPageChannelAcquireSendLock(VPageChannel *channel) // IN
 
123
{
 
124
   ASSERT(channel);
 
125
   VMCIMutex_Acquire(&channel->qpSendMutex);
 
126
}
 
127
 
 
128
 
 
129
/*
 
130
 *-----------------------------------------------------------------------------
 
131
 *
 
132
 * VPageChannelReleaseSendLock
 
133
 *
 
134
 *      Release the channel's send lock.
 
135
 *
 
136
 * Results:
 
137
 *      None.
 
138
 *
 
139
 * Side effects:
 
140
 *      None.
 
141
 *
 
142
 *-----------------------------------------------------------------------------
 
143
 */
 
144
 
 
145
static void
 
146
VPageChannelReleaseSendLock(VPageChannel *channel) // IN
 
147
{
 
148
   ASSERT(channel);
 
149
   VMCIMutex_Release(&channel->qpSendMutex);
 
150
}
 
151
 
 
152
 
 
153
/*
 
154
 *-----------------------------------------------------------------------------
 
155
 *
 
156
 * VPageChannelAcquireRecvLock
 
157
 *
 
158
 *      Acquire the channel's receive lock.
 
159
 *
 
160
 * Results:
 
161
 *      None.
 
162
 *
 
163
 * Side effects:
 
164
 *      None.
 
165
 *
 
166
 *-----------------------------------------------------------------------------
 
167
 */
 
168
 
 
169
static void
 
170
VPageChannelAcquireRecvLock(VPageChannel *channel) // IN
 
171
{
 
172
   ASSERT(channel);
 
173
   VMCIMutex_Acquire(&channel->qpRecvMutex);
 
174
}
 
175
 
 
176
 
 
177
/*
 
178
 *-----------------------------------------------------------------------------
 
179
 *
 
180
 * VPageChannelReleaseRecvLock
 
181
 *
 
182
 *      Release the channel's receive lock.
 
183
 *
 
184
 * Results:
 
185
 *      None.
 
186
 *
 
187
 * Side effects:
 
188
 *      None.
 
189
 *
 
190
 *-----------------------------------------------------------------------------
 
191
 */
 
192
 
 
193
static void
 
194
VPageChannelReleaseRecvLock(VPageChannel *channel) // IN
 
195
{
 
196
   ASSERT(channel);
 
197
   VMCIMutex_Release(&channel->qpRecvMutex);
 
198
}
 
199
 
 
200
 
 
201
/*
 
202
 *-----------------------------------------------------------------------------
 
203
 *
 
204
 * VPageChannelSetRecvBuffers --
 
205
 *
 
206
 *      Set the receiving buffers for the channel.
 
207
 *
 
208
 * Results:
 
209
 *      VMCI_SUCCESS if set, negative error code otherwise.
 
210
 *
 
211
 * Side effects:
 
212
 *      None.
 
213
 *
 
214
 *-----------------------------------------------------------------------------
 
215
 */
 
216
 
 
217
static int
 
218
VPageChannelSetRecvBuffers(VPageChannel *channel,     // IN
 
219
                           int numElems,              // IN
 
220
                           Bool byControl)            // IN
 
221
{
 
222
   int retval;
 
223
   int allocNum;
 
224
   size_t size = sizeof(VPageChannelPacket) +
 
225
      numElems * sizeof(VPageChannelElem);
 
226
   VPageChannelElem *elems;
 
227
   VPageChannelPacket *packet;
 
228
 
 
229
   ASSERT(channel);
 
230
 
 
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",
 
235
                    channel,
 
236
                    size));
 
237
      return VMCI_ERROR_NO_MEM;
 
238
   }
 
239
 
 
240
   packet->type = VPCPacket_SetRecvBuffer;
 
241
   packet->msgLen = 0;
 
242
   packet->numElems = numElems;
 
243
 
 
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",
 
249
                    channel,
 
250
                    numElems,
 
251
                    allocNum));
 
252
      retval = VMCI_ERROR_NO_MEM;
 
253
      goto error;
 
254
   }
 
255
 
 
256
   if (byControl || !channel->qpConnected) {
 
257
      retval = VPageChannelSendControl(channel, NULL, 0,
 
258
                                            VPCPacket_SetRecvBuffer,
 
259
                                            numElems, elems);
 
260
   } else {
 
261
      retval = VPageChannel_SendPacket(channel, packet);
 
262
   }
 
263
   if (retval < VMCI_SUCCESS) {
 
264
      VMCI_WARNING((LGPFX"Failed to set receive buffers (channel=%p) "
 
265
                    "(err=%d).\n",
 
266
                    channel,
 
267
                    retval));
 
268
      goto error;
 
269
   }
 
270
 
 
271
   channel->curRecvBufs += numElems;
 
272
 
 
273
   VMCI_FreeKernelMem(packet, size);
 
274
 
 
275
   return VMCI_SUCCESS;
 
276
 
 
277
 error:
 
278
   if (packet != NULL) {
 
279
      if (allocNum) {
 
280
         channel->elemFreeFn(channel->freeClientData, elems, allocNum);
 
281
      }
 
282
      VMCI_FreeKernelMem(packet, size);
 
283
   }
 
284
 
 
285
   return retval;
 
286
}
 
287
 
 
288
 
 
289
/*
 
290
 *-----------------------------------------------------------------------------
 
291
 *
 
292
 * VPageChannelRecvPacket --
 
293
 *
 
294
 *      Process a VMCI packet.
 
295
 *
 
296
 * Results:
 
297
 *      Always VMCI_SUCCESS.
 
298
 *
 
299
 * Side effects:
 
300
 *      None.
 
301
 *
 
302
 *-----------------------------------------------------------------------------
 
303
 */
 
304
 
 
305
static int
 
306
VPageChannelRecvPacket(VPageChannel *channel,         // IN
 
307
                       VPageChannelPacket *packet)    // IN
 
308
{
 
309
   int recvBufsTarget;
 
310
 
 
311
   ASSERT(channel);
 
312
   ASSERT(packet);
 
313
 
 
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) "
 
319
                    "(type=%d).\n",
 
320
                    channel,
 
321
                    packet->type));
 
322
      return VMCI_ERROR_INVALID_ARGS;
 
323
   }
 
324
 
 
325
   VMCI_DEBUG_LOG(10,
 
326
                  (LGPFX"Received packet (channel=%p) (type=%d) "
 
327
                   "(elems=%d).\n",
 
328
                   channel,
 
329
                   packet->type,
 
330
                   packet->numElems));
 
331
 
 
332
   if (packet->type == VPCPacket_HyperConnect) {
 
333
      VPageChannelHyperConnectMessage *message;
 
334
 
 
335
      if (packet->msgLen < sizeof *message) {
 
336
         VMCI_WARNING((LGPFX"Received invalid hypervisor connection message "
 
337
                       "(channel=%p) (size=%u).\n",
 
338
                       channel,
 
339
                       packet->msgLen));
 
340
         return VMCI_ERROR_INVALID_ARGS;
 
341
      }
 
342
 
 
343
      message = (VPageChannelHyperConnectMessage *)
 
344
         VPAGECHANNEL_PACKET_MESSAGE(packet);
 
345
      channel->peerDoorbellHandle = message->doorbellHandle;
 
346
 
 
347
      VMCI_DEBUG_LOG(10,
 
348
                     (LGPFX"Connected to peer (channel=%p) "
 
349
                      "(db handle=0x%x:0x%x).\n",
 
350
                      channel,
 
351
                      channel->peerDoorbellHandle.context,
 
352
                      channel->peerDoorbellHandle.resource));
 
353
 
 
354
      return VMCI_SUCCESS;
 
355
   }
 
356
 
 
357
   recvBufsTarget = channel->recvBufsTarget;
 
358
 
 
359
   switch (packet->type) {
 
360
   case VPCPacket_RequestBuffer:
 
361
      /*
 
362
       * Increase the number of receive buffers by channel->defaultRecvBufs
 
363
       * if the hypervisor requests it.
 
364
       */
 
365
 
 
366
      VMCI_DEBUG_LOG(10,
 
367
                     (LGPFX"Requested more buffers (channel=%p) "
 
368
                      "(cur=%d) (target=%d) (max=%d).\n",
 
369
                      channel,
 
370
                      channel->curRecvBufs,
 
371
                      channel->recvBufsTarget,
 
372
                      channel->maxRecvBufs));
 
373
 
 
374
      if (channel->recvBufsTarget < channel->maxRecvBufs) {
 
375
         recvBufsTarget = channel->recvBufsTarget + channel->defaultRecvBufs;
 
376
      }
 
377
      break;
 
378
 
 
379
   case VPCPacket_Data:
 
380
      channel->recvCB(channel->clientRecvData, packet);
 
381
      channel->curRecvBufs -= packet->numElems;
 
382
      break;
 
383
 
 
384
   case VPCPacket_Completion_Notify:
 
385
      channel->recvCB(channel->clientRecvData, packet);
 
386
      break;
 
387
 
 
388
   default:
 
389
      ASSERT_NOT_IMPLEMENTED(FALSE);
 
390
      break;
 
391
   }
 
392
 
 
393
   /*
 
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.
 
399
    */
 
400
 
 
401
   if (channel->curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) {
 
402
      int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD -
 
403
         channel->curRecvBufs;
 
404
 
 
405
      if (VPageChannelSetRecvBuffers(channel, numElems, FALSE) ==
 
406
          VMCI_SUCCESS) {
 
407
         channel->recvBufsTarget = recvBufsTarget;
 
408
      }
 
409
   }
 
410
 
 
411
   return VMCI_SUCCESS;
 
412
}
 
413
 
 
414
 
 
415
/*
 
416
 *-----------------------------------------------------------------------------
 
417
 *
 
418
 * VPageChannelDgRecvFunc --
 
419
 *
 
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
 
422
 *      queuepair.
 
423
 *
 
424
 * Results:
 
425
 *      VMCI_SUCCESS on success, negative values on failure.
 
426
 *
 
427
 * Side effects:
 
428
 *      None.
 
429
 *
 
430
 *-----------------------------------------------------------------------------
 
431
 */
 
432
 
 
433
static int
 
434
VPageChannelDgRecvFunc(void *clientData,         // IN
 
435
                       VMCIDatagram *dg)         // IN
 
436
{
 
437
   VPageChannel *channel = (VPageChannel *)clientData;
 
438
 
 
439
   ASSERT(channel);
 
440
   ASSERT(dg);
 
441
 
 
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",
 
446
                     channel,
 
447
                     dg->src.context,
 
448
                     dg->src.resource));
 
449
       return VMCI_ERROR_NO_ACCESS;
 
450
   }
 
451
 
 
452
   if (dg->payloadSize < sizeof (VPageChannelPacket)) {
 
453
      VMCI_WARNING((LGPFX"Received invalid packet (channel=%p) "
 
454
                    "(size=%"FMT64"u).\n",
 
455
                    channel,
 
456
                    dg->payloadSize));
 
457
      return VMCI_ERROR_INVALID_ARGS;
 
458
   }
 
459
 
 
460
   return VPageChannelRecvPacket(channel, VMCI_DG_PAYLOAD(dg));
 
461
}
 
462
 
 
463
 
 
464
/*
 
465
 *----------------------------------------------------------------------------
 
466
 *
 
467
 * VMCIPacketDoDoorbellCallback --
 
468
 *
 
469
 *    Process a doorbell notification.  Will read packets from the queuepair
 
470
 *    until empty.
 
471
 *
 
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.
 
474
 *
 
475
 * Results:
 
476
 *    None.
 
477
 *
 
478
 * Side effects:
 
479
 *    None.
 
480
 *
 
481
 *----------------------------------------------------------------------------
 
482
 */
 
483
 
 
484
static void
 
485
VMCIPacketDoDoorbellCallback(VPageChannel *channel) // IN/OUT
 
486
{
 
487
   Bool inUse;
 
488
   VPageChannelPacket packetHeader;
 
489
 
 
490
   ASSERT(channel);
 
491
 
 
492
   if (!channel->qpConnected) {
 
493
      VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
 
494
                    channel));
 
495
      return;
 
496
   }
 
497
 
 
498
   VPageChannelAcquireRecvLock(channel);
 
499
   inUse = channel->inPoll;
 
500
   channel->inPoll = TRUE;
 
501
   VPageChannelReleaseRecvLock(channel);
 
502
 
 
503
   if (inUse) {
 
504
      return;
 
505
   }
 
506
 
 
507
retry:
 
508
   while (VMCIQPair_ConsumeBufReady(channel->qpair) >= sizeof packetHeader) {
 
509
      ssize_t retSize, totalSize;
 
510
      VPageChannelPacket *packet;
 
511
 
 
512
      retSize = VMCIQPair_Peek(channel->qpair, &packetHeader,
 
513
                               sizeof packetHeader,
 
514
                               /* XXX, UTIL_VMKERNEL_BUFFER for VMKernel. */
 
515
                               0);
 
516
      if (retSize < sizeof packetHeader) {
 
517
         /*
 
518
          * XXX, deal with partial read.
 
519
          */
 
520
 
 
521
         VMCI_WARNING((LGPFX"Failed to peek (channel=%p) "
 
522
                       "(required=%"FMTSZ"d) (err=%"FMTSZ"d).\n",
 
523
                       channel,
 
524
                       sizeof packetHeader,
 
525
                       retSize));
 
526
         break;
 
527
      }
 
528
 
 
529
      totalSize = sizeof packetHeader + packetHeader.msgLen +
 
530
         packetHeader.numElems * sizeof(VPageChannelElem);
 
531
 
 
532
      retSize = VMCIQPair_ConsumeBufReady(channel->qpair);
 
533
      if (retSize < totalSize) {
 
534
         /*
 
535
          * XXX, deal with partial read.
 
536
          */
 
537
 
 
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",
 
541
                       channel,
 
542
                       packetHeader.type,
 
543
                       packetHeader.msgLen,
 
544
                       packetHeader.numElems,
 
545
                       retSize,
 
546
                       totalSize));
 
547
         break;
 
548
      }
 
549
 
 
550
      packet = (VPageChannelPacket *)
 
551
         VMCI_AllocKernelMem(totalSize, VMCI_MEMORY_ATOMIC);
 
552
      if (!packet) {
 
553
         VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
 
554
                       "(size=%"FMTSZ"d).\n",
 
555
                       channel,
 
556
                       totalSize));
 
557
         break;
 
558
      }
 
559
 
 
560
      retSize = VMCIQPair_Dequeue(channel->qpair, packet,
 
561
                                  totalSize,
 
562
                                  /* XXX, UTIL_VMKERNEL_BUFFER for VMKernel. */
 
563
                                  0);
 
564
      if (retSize < totalSize) {
 
565
         /*
 
566
          * XXX, deal with partial read.
 
567
          */
 
568
 
 
569
         VMCI_WARNING((LGPFX"Failed to dequeue (channel=%p) "
 
570
                       "(required=%"FMTSZ"d) (err=%"FMTSZ"d).\n",
 
571
                       channel,
 
572
                       totalSize,
 
573
                       retSize));
 
574
         VMCI_FreeKernelMem(packet, totalSize);
 
575
         break;
 
576
      }
 
577
 
 
578
      VPageChannelRecvPacket(channel, packet);
 
579
      VMCI_FreeKernelMem(packet, totalSize);
 
580
   }
 
581
 
 
582
   VPageChannelAcquireRecvLock(channel);
 
583
 
 
584
   /*
 
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.
 
590
    */
 
591
 
 
592
   if (VMCIQPair_ConsumeBufReady(channel->qpair) >= sizeof packetHeader) {
 
593
      VPageChannelReleaseRecvLock(channel);
 
594
      goto retry;
 
595
   }
 
596
 
 
597
   channel->inPoll = FALSE;
 
598
   VPageChannelReleaseRecvLock(channel);
 
599
}
 
600
 
 
601
 
 
602
/*
 
603
 *----------------------------------------------------------------------------
 
604
 *
 
605
 * VMCIPacketDoorbellCallback --
 
606
 *
 
607
 *    Callback for doorbell notification.  Will invoke the channel's receive
 
608
 *    function directly or process the packets in the queuepair.
 
609
 *
 
610
 * Results:
 
611
 *    None.
 
612
 *
 
613
 * Side effects:
 
614
 *    None.
 
615
 *
 
616
 *----------------------------------------------------------------------------
 
617
 */
 
618
 
 
619
static void
 
620
VMCIPacketDoorbellCallback(void *clientData) // IN/OUT
 
621
{
 
622
   VPageChannel *channel = (VPageChannel *)clientData;
 
623
 
 
624
   ASSERT(channel);
 
625
 
 
626
   if (channel->notifyOnly) {
 
627
      channel->recvCB(channel->clientRecvData, NULL);
 
628
   } else {
 
629
      VMCIPacketDoDoorbellCallback(channel);
 
630
   }
 
631
}
 
632
 
 
633
 
 
634
/*
 
635
 *----------------------------------------------------------------------------
 
636
 *
 
637
 * VPageChannelSendConnectionMessage --
 
638
 *
 
639
 *    Send a connection control message to the hypervisor.
 
640
 *
 
641
 * Results:
 
642
 *    VMCI_SUCCESS if sent, negative values on failure.
 
643
 *
 
644
 * Side effects:
 
645
 *    None.
 
646
 *
 
647
 *----------------------------------------------------------------------------
 
648
 */
 
649
 
 
650
static int
 
651
VPageChannelSendConnectionMessage(VPageChannel *channel) // IN
 
652
{
 
653
   VPageChannelGuestConnectMessage message;
 
654
 
 
655
   ASSERT(channel);
 
656
 
 
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;
 
663
 
 
664
   VMCI_DEBUG_LOG(10,
 
665
                  (LGPFX"Sending guest connect (channel=%p) "
 
666
                   "(qp handle=0x%x:0x%x).\n",
 
667
                   channel,
 
668
                   channel->qpHandle.context,
 
669
                   channel->qpHandle.resource));
 
670
 
 
671
   return VPageChannelSendControl(channel,
 
672
                                  (char *)&message, sizeof message,
 
673
                                  VPCPacket_GuestConnect, 0, NULL);
 
674
}
 
675
 
 
676
 
 
677
/*
 
678
 *----------------------------------------------------------------------------
 
679
 *
 
680
 * VMCIPacketPeerAttachCB --
 
681
 *
 
682
 *    Invoked when a peer attaches to a queue pair.
 
683
 *
 
684
 * Results:
 
685
 *    None.
 
686
 *
 
687
 * Side effects:
 
688
 *    May modify page channel state.
 
689
 *
 
690
 *----------------------------------------------------------------------------
 
691
 */
 
692
 
 
693
static void
 
694
VPageChannelPeerAttachCB(VMCIId subId,             // IN
 
695
                         VMCI_EventData *eData,    // IN
 
696
                         void *clientData)         // IN
 
697
{
 
698
   VPageChannel *channel;
 
699
   VMCIEventPayload_QP *ePayload;
 
700
 
 
701
   ASSERT(eData);
 
702
   ASSERT(clientData);
 
703
 
 
704
   channel = (VPageChannel *)clientData;
 
705
   ePayload = VMCIEventDataPayload(eData);
 
706
 
 
707
   if (VMCI_HANDLE_EQUAL(channel->qpHandle, ePayload->handle)) {
 
708
      VMCI_DEBUG_LOG(10,
 
709
                     (LGPFX"Peer attached (channel=%p) "
 
710
                      "(qp handle=0x%x:0x%x).\n",
 
711
                      channel,
 
712
                      ePayload->handle.context,
 
713
                      ePayload->handle.resource));
 
714
      channel->qpConnected = TRUE;
 
715
   }
 
716
}
 
717
 
 
718
 
 
719
/*
 
720
 *----------------------------------------------------------------------------
 
721
 *
 
722
 * VMCIPacketPeerDetachCB --
 
723
 *
 
724
 *    Invoked when a peer detaches from a queue pair.
 
725
 *
 
726
 * Results:
 
727
 *    None.
 
728
 *
 
729
 * Side effects:
 
730
 *    May modify page channel state.
 
731
 *
 
732
 *----------------------------------------------------------------------------
 
733
 */
 
734
 
 
735
static void
 
736
VPageChannelPeerDetachCB(VMCIId subId,             // IN
 
737
                         VMCI_EventData *eData,    // IN
 
738
                         void *clientData)         // IN
 
739
{
 
740
   VPageChannel *channel;
 
741
   VMCIEventPayload_QP *ePayload;
 
742
 
 
743
   ASSERT(eData);
 
744
   ASSERT(clientData);
 
745
 
 
746
   channel = (VPageChannel *)clientData;
 
747
   ePayload = VMCIEventDataPayload(eData);
 
748
 
 
749
   if (VMCI_HANDLE_EQUAL(channel->qpHandle, ePayload->handle)) {
 
750
      VMCI_DEBUG_LOG(10,
 
751
                     (LGPFX"Peer detached (channel=%p) "
 
752
                      "(qp handle=0x%x:0x%x).\n",
 
753
                      channel,
 
754
                      ePayload->handle.context,
 
755
                      ePayload->handle.resource));
 
756
      channel->qpConnected = FALSE;
 
757
   }
 
758
}
 
759
 
 
760
 
 
761
/*
 
762
 *----------------------------------------------------------------------------
 
763
 *
 
764
 * VPageChannelDestroyQueuePair --
 
765
 *
 
766
 *    Destroy the channel's queuepair, along with the event subscriptions.
 
767
 *
 
768
 * Results:
 
769
 *    None.
 
770
 *
 
771
 * Side effects:
 
772
 *    May modify page channel state.
 
773
 *
 
774
 *----------------------------------------------------------------------------
 
775
 */
 
776
 
 
777
static void
 
778
VPageChannelDestroyQueuePair(VPageChannel *channel) // IN/OUT
 
779
{
 
780
   ASSERT(channel);
 
781
 
 
782
   if (channel->attachSubId != VMCI_INVALID_ID) {
 
783
      VMCIEvent_Unsubscribe(channel->attachSubId);
 
784
      channel->attachSubId = VMCI_INVALID_ID;
 
785
   }
 
786
 
 
787
   if (channel->detachSubId != VMCI_INVALID_ID) {
 
788
      VMCIEvent_Unsubscribe(channel->detachSubId);
 
789
      channel->detachSubId = VMCI_INVALID_ID;
 
790
   }
 
791
 
 
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;
 
797
   }
 
798
 
 
799
   VMCIMutex_Destroy(&channel->qpRecvMutex);
 
800
   VMCIMutex_Destroy(&channel->qpSendMutex);
 
801
 
 
802
   channel->qpConnected = FALSE;
 
803
}
 
804
 
 
805
 
 
806
/*
 
807
 *----------------------------------------------------------------------------
 
808
 *
 
809
 * VPageChannelCreateQueuePair --
 
810
 *
 
811
 *    Create queuepair for data communication.
 
812
 *
 
813
 * Results:
 
814
 *    VMCI_SUCCESS if the queuepair is created, negative values on failure.
 
815
 *
 
816
 * Side effects:
 
817
 *    May modify page channel state.
 
818
 *
 
819
 *----------------------------------------------------------------------------
 
820
 */
 
821
 
 
822
static int
 
823
VPageChannelCreateQueuePair(VPageChannel *channel) // IN/OUT
 
824
{
 
825
   int err;
 
826
   uint32 flags;
 
827
 
 
828
   ASSERT(channel);
 
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);
 
833
 
 
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",
 
838
                    channel));
 
839
      return err;
 
840
   }
 
841
 
 
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",
 
846
                    channel));
 
847
      VMCIMutex_Destroy(&channel->qpSendMutex);
 
848
      return err;
 
849
   }
 
850
 
 
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",
 
858
                    channel,
 
859
                    err));
 
860
      goto error;
 
861
   }
 
862
 
 
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",
 
870
                    channel,
 
871
                    err));
 
872
      goto error;
 
873
   }
 
874
 
 
875
   flags = 0;
 
876
   err = VMCIQPair_Alloc(&channel->qpair, &channel->qpHandle,
 
877
                         channel->produceQSize, channel->consumeQSize,
 
878
                         VMCI_HOST_CONTEXT_ID, flags, VMCI_NO_PRIVILEGE_FLAGS);
 
879
   if (err < 0) {
 
880
      VMCI_WARNING((LGPFX"Could not create queue pair (err=%d).\n",
 
881
                    err));
 
882
      goto error;
 
883
   }
 
884
 
 
885
   VMCI_DEBUG_LOG(10,
 
886
                  (LGPFX"Allocated queuepair (channel=%p) "
 
887
                   "(qp handle=0x%x:0x%x) "
 
888
                   "(produce=%"FMT64"u) (consume=%"FMT64"u).\n",
 
889
                   channel,
 
890
                   channel->qpHandle.context,
 
891
                   channel->qpHandle.resource,
 
892
                   channel->produceQSize,
 
893
                   channel->consumeQSize));
 
894
 
 
895
   return VMCI_SUCCESS;
 
896
 
 
897
error:
 
898
   VPageChannelDestroyQueuePair(channel);
 
899
   return err;
 
900
}
 
901
 
 
902
 
 
903
/*
 
904
 *-----------------------------------------------------------------------------
 
905
 *
 
906
 * VPageChannel_CreateInVM --
 
907
 *
 
908
 *     Create a page channel in the guest kernel.
 
909
 *
 
910
 * Results:
 
911
 *     VMCI_SUCCESS if created, negative errno value otherwise.
 
912
 *
 
913
 * Side effects:
 
914
 *     May set the receive buffers if a default size is given.
 
915
 *
 
916
 *-----------------------------------------------------------------------------
 
917
 */
 
918
 
 
919
int
 
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
 
934
{
 
935
   int retval;
 
936
   int flags;
 
937
   VPageChannel *pageChannel;
 
938
 
 
939
   ASSERT(channel);
 
940
   ASSERT(VMCI_INVALID_ID != resourceId);
 
941
   ASSERT(VMCI_INVALID_ID != peerResourceId);
 
942
   ASSERT(recvCB);
 
943
 
 
944
   pageChannel =
 
945
      VMCI_AllocKernelMem(sizeof *pageChannel, VMCI_MEMORY_NONPAGED);
 
946
   if (!pageChannel) {
 
947
      return VMCI_ERROR_NO_MEM;
 
948
   }
 
949
 
 
950
   /*
 
951
    * XXX, we should support a default internal allocation function.
 
952
    */
 
953
 
 
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,
 
972
                                                  peerResourceId);
 
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;
 
979
 
 
980
   /*
 
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).
 
983
    */
 
984
 
 
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",
 
992
                    channel,
 
993
                    retval));
 
994
      goto error;
 
995
   }
 
996
 
 
997
   VMCI_DEBUG_LOG(10,
 
998
                  (LGPFX"Created datagram (channel=%p) "
 
999
                   "(handle=0x%x:0x%x).\n",
 
1000
                   channel,
 
1001
                   pageChannel->dgHandle.context,
 
1002
                   pageChannel->dgHandle.resource));
 
1003
 
 
1004
   /*
 
1005
    * Create a doorbell handle.  This is used by the peer to signal the
 
1006
    * arrival of packets in the queuepair.
 
1007
    */
 
1008
 
 
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",
 
1016
                    channel,
 
1017
                    retval));
 
1018
      goto error;
 
1019
   }
 
1020
 
 
1021
   VMCI_DEBUG_LOG(10,
 
1022
                  (LGPFX"Created doorbell (channel=%p) "
 
1023
                   "(handle=0x%x:0x%x).\n",
 
1024
                   channel,
 
1025
                   pageChannel->doorbellHandle.context,
 
1026
                   pageChannel->doorbellHandle.resource));
 
1027
 
 
1028
   /*
 
1029
    * Now create the queuepair, over which we can pass data packets.
 
1030
    */
 
1031
 
 
1032
   retval = VPageChannelCreateQueuePair(pageChannel);
 
1033
   if (retval < VMCI_SUCCESS) {
 
1034
      goto error;
 
1035
   }
 
1036
 
 
1037
   /*
 
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
 
1040
    * buffer yet.
 
1041
    */
 
1042
 
 
1043
   if (defaultRecvBuffers) {
 
1044
      int numElems = defaultRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
 
1045
      retval = VPageChannelSetRecvBuffers(pageChannel, numElems, TRUE);
 
1046
      if (retval < VMCI_SUCCESS) {
 
1047
         goto error;
 
1048
      }
 
1049
   }
 
1050
 
 
1051
   retval = VPageChannelSendConnectionMessage(pageChannel);
 
1052
   if (retval < VMCI_SUCCESS) {
 
1053
      goto error;
 
1054
   }
 
1055
 
 
1056
   VMCI_DEBUG_LOG(10,
 
1057
                  (LGPFX"Created (channel=%p) (handle=0x%x:0x%x).\n",
 
1058
                   pageChannel,
 
1059
                   pageChannel->dgHandle.context,
 
1060
                   pageChannel->dgHandle.resource));
 
1061
 
 
1062
   *channel = pageChannel;
 
1063
 
 
1064
   return retval;
 
1065
 
 
1066
 error:
 
1067
   VPageChannel_Destroy(pageChannel);
 
1068
   return retval;
 
1069
}
 
1070
EXPORT_SYMBOL(VPageChannel_CreateInVM);
 
1071
 
 
1072
 
 
1073
/*
 
1074
 *-----------------------------------------------------------------------------
 
1075
 *
 
1076
 * VPageChannel_Destroy --
 
1077
 *
 
1078
 *      Destroy the page channel.
 
1079
 *
 
1080
 * Results:
 
1081
 *      None.
 
1082
 *
 
1083
 * Side effects:
 
1084
 *      None.
 
1085
 *
 
1086
 *-----------------------------------------------------------------------------
 
1087
 */
 
1088
 
 
1089
void
 
1090
VPageChannel_Destroy(VPageChannel *channel) // IN/OUT
 
1091
{
 
1092
   ASSERT(channel);
 
1093
 
 
1094
   VPageChannelDestroyQueuePair(channel);
 
1095
 
 
1096
   if (!VMCI_HANDLE_INVALID(channel->doorbellHandle)) {
 
1097
      VMCIDoorbell_Destroy(channel->doorbellHandle);
 
1098
   }
 
1099
 
 
1100
   if (!VMCI_HANDLE_INVALID(channel->dgHandle)) {
 
1101
      VMCIDatagram_DestroyHnd(channel->dgHandle);
 
1102
   }
 
1103
 
 
1104
   VMCI_FreeKernelMem(channel, sizeof *channel);
 
1105
 
 
1106
   VMCI_DEBUG_LOG(10,
 
1107
                  (LGPFX"Destroyed (channel=%p).\n",
 
1108
                   channel));
 
1109
}
 
1110
EXPORT_SYMBOL(VPageChannel_Destroy);
 
1111
 
 
1112
 
 
1113
/*
 
1114
 *-----------------------------------------------------------------------------
 
1115
 *
 
1116
 * VMCIPacketAllocDatagram --
 
1117
 *
 
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.
 
1120
 *
 
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.
 
1123
 *
 
1124
 * Results:
 
1125
 *      VMCI_SUCCESS and a datagram if successfully allocated, negative error
 
1126
 *      value on failure.
 
1127
 *
 
1128
 * Side effects:
 
1129
 *      None.
 
1130
 *
 
1131
 *-----------------------------------------------------------------------------
 
1132
 */
 
1133
 
 
1134
static int
 
1135
VPageChannelAllocDatagram(VPageChannel *channel,       // IN
 
1136
                          size_t messageLen,           // IN
 
1137
                          int numElems,                // IN
 
1138
                          VMCIDatagram **outDg)        // OUT
 
1139
{
 
1140
   size_t size;
 
1141
   VMCIDatagram *dg;
 
1142
 
 
1143
   ASSERT(channel);
 
1144
   ASSERT(outDg);
 
1145
 
 
1146
   *outDg = NULL;
 
1147
 
 
1148
   size = VMCI_DG_HEADERSIZE + sizeof(VPageChannelPacket) + messageLen +
 
1149
      numElems * sizeof (VPageChannelElem);
 
1150
 
 
1151
   if (size > VMCI_MAX_DG_SIZE) {
 
1152
      VMCI_WARNING((LGPFX"Requested datagram size too large (channel=%p) "
 
1153
                   "(size=%"FMTSZ"u).",
 
1154
                   channel,
 
1155
                   size));
 
1156
      return VMCI_ERROR_PAYLOAD_TOO_LARGE;
 
1157
   }
 
1158
 
 
1159
   dg = VMCI_AllocKernelMem(size, VMCI_MEMORY_ATOMIC);
 
1160
   if (!dg) {
 
1161
      VMCI_WARNING((LGPFX"Failed to allocate datagram (channel=%p).",
 
1162
                    channel));
 
1163
      return VMCI_ERROR_NO_MEM;
 
1164
   }
 
1165
 
 
1166
   memset(dg, 0, size);
 
1167
   dg->dst = channel->peerDgHandle;
 
1168
   dg->src = channel->dgHandle;
 
1169
   dg->payloadSize = size - VMCI_DG_HEADERSIZE;
 
1170
 
 
1171
   /* Chatty. */
 
1172
   // VMCI_DEBUG_LOG(10,
 
1173
   //                (LGPFX"Allocated datagram (payload=%"FMT64"u).\n",
 
1174
   //                 dg->payloadSize));
 
1175
 
 
1176
   *outDg = dg;
 
1177
 
 
1178
   return VMCI_SUCCESS;
 
1179
}
 
1180
 
 
1181
 
 
1182
/*
 
1183
 *-----------------------------------------------------------------------------
 
1184
 *
 
1185
 * VPageChannelSendControl --
 
1186
 *
 
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.
 
1190
 *
 
1191
 * Results:
 
1192
 *      VMCI_SUCCESS if the packet is sent successfully, negative error number
 
1193
 *      otherwise.
 
1194
 *
 
1195
 * Side effects:
 
1196
 *      None.
 
1197
 *
 
1198
 *-----------------------------------------------------------------------------
 
1199
 */
 
1200
 
 
1201
static int
 
1202
VPageChannelSendControl(VPageChannel *channel,       // IN
 
1203
                        char *message,               // IN
 
1204
                        int len,                     // IN
 
1205
                        VPageChannelPacketType type, // IN
 
1206
                        int numElems,                // IN
 
1207
                        VPageChannelElem *elems)     // IN
 
1208
{
 
1209
   int retval;
 
1210
   VPageChannelPacket *packet;
 
1211
   VMCIDatagram *dg;
 
1212
 
 
1213
   ASSERT(channel);
 
1214
   ASSERT(type == VPCPacket_Data ||
 
1215
          type == VPCPacket_GuestConnect ||
 
1216
          type == VPCPacket_SetRecvBuffer);
 
1217
 
 
1218
   dg = NULL;
 
1219
   retval = VPageChannelAllocDatagram(channel, len, numElems, &dg);
 
1220
   if (retval < VMCI_SUCCESS) {
 
1221
      return retval;
 
1222
   }
 
1223
 
 
1224
   packet = (VPageChannelPacket *)VMCI_DG_PAYLOAD(dg);
 
1225
   packet->type = type;
 
1226
   packet->msgLen = len;
 
1227
   packet->numElems = numElems;
 
1228
 
 
1229
   if (len) {
 
1230
      ASSERT(message);
 
1231
      memcpy(VPAGECHANNEL_PACKET_MESSAGE(packet), message, len);
 
1232
   }
 
1233
 
 
1234
   if (numElems) {
 
1235
      ASSERT(elems);
 
1236
      memcpy(VPAGECHANNEL_PACKET_ELEMS(packet), elems,
 
1237
             numElems * sizeof (VPageChannelElem));
 
1238
   }
 
1239
 
 
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",
 
1244
                    channel,
 
1245
                    dg->dst.context,
 
1246
                    dg->dst.resource,
 
1247
                    retval));
 
1248
   } else {
 
1249
      /*
 
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.
 
1252
       */
 
1253
 
 
1254
      retval = VMCI_SUCCESS;
 
1255
   }
 
1256
 
 
1257
   VMCI_FreeKernelMem(dg, VMCI_DG_SIZE(dg));
 
1258
 
 
1259
   return retval;
 
1260
}
 
1261
 
 
1262
 
 
1263
/*
 
1264
 *-----------------------------------------------------------------------------
 
1265
 *
 
1266
 * VPageChannel_SendPacket --
 
1267
 *
 
1268
 *     Send a VMCI packet to the hypervisor.
 
1269
 *
 
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.
 
1272
 *
 
1273
 * Results:
 
1274
 *     VMCI_SUCCESS if sent, negative error number otherwise.
 
1275
 *
 
1276
 * Side effects:
 
1277
 *     None.
 
1278
 *
 
1279
 *-----------------------------------------------------------------------------
 
1280
 */
 
1281
 
 
1282
int
 
1283
VPageChannel_SendPacket(VPageChannel *channel,         // IN
 
1284
                        VPageChannelPacket *packet)    // IN
 
1285
{
 
1286
   int retval;
 
1287
   ssize_t totalSize, sentSize, curSize;
 
1288
   ssize_t freeSpace;
 
1289
 
 
1290
   ASSERT(channel);
 
1291
 
 
1292
   if (!channel->qpConnected) {
 
1293
      VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
 
1294
                    channel));
 
1295
      retval = VMCI_ERROR_DST_UNREACHABLE;
 
1296
      goto error;
 
1297
   }
 
1298
 
 
1299
   ASSERT(packet);
 
1300
 
 
1301
   totalSize = sizeof(VPageChannelPacket) + packet->msgLen +
 
1302
      packet->numElems * sizeof(VPageChannelElem);
 
1303
 
 
1304
   VPageChannelAcquireSendLock(channel);
 
1305
 
 
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",
 
1310
                    channel,
 
1311
                    totalSize,
 
1312
                    freeSpace));
 
1313
      retval = VMCI_ERROR_NO_MEM;
 
1314
      goto unlock;
 
1315
   }
 
1316
 
 
1317
   sentSize = VMCIQPair_Enqueue(channel->qpair, packet, totalSize, 0);
 
1318
   curSize = VMCIQPair_ProduceBufReady(channel->qpair);
 
1319
 
 
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",
 
1327
                       channel,
 
1328
                       channel->peerDoorbellHandle.context,
 
1329
                       channel->peerDoorbellHandle.resource,
 
1330
                       retval));
 
1331
         goto unlock;
 
1332
      }
 
1333
   }
 
1334
 
 
1335
   VPageChannelReleaseSendLock(channel);
 
1336
 
 
1337
   if (sentSize < totalSize) {
 
1338
      /*
 
1339
       * XXX, deal with partial sending.
 
1340
       */
 
1341
 
 
1342
      VMCI_WARNING((LGPFX"No free space in queuepair (channel=%p) "
 
1343
                    "(required=%"FMTSZ"d) (actual=%"FMTSZ"d).\n",
 
1344
                    channel,
 
1345
                    totalSize,
 
1346
                    sentSize));
 
1347
      retval = VMCI_ERROR_NO_MEM;
 
1348
      goto error;
 
1349
   }
 
1350
 
 
1351
   VMCI_DEBUG_LOG(10,
 
1352
                  (LGPFX"Sent packet (channel=%p) (size=%"FMTSZ"d).\n",
 
1353
                   channel,
 
1354
                   sentSize));
 
1355
 
 
1356
   return VMCI_SUCCESS;
 
1357
 
 
1358
unlock:
 
1359
   VPageChannelReleaseSendLock(channel);
 
1360
error:
 
1361
   return retval;
 
1362
}
 
1363
EXPORT_SYMBOL(VPageChannel_SendPacket);
 
1364
 
 
1365
 
 
1366
/*
 
1367
 *-----------------------------------------------------------------------------
 
1368
 *
 
1369
 * VPageChannel_Send --
 
1370
 *
 
1371
 *      A packet is constructed to send the message and buffer to the guest.
 
1372
 *
 
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.
 
1375
 *
 
1376
 * Results:
 
1377
 *      VMCI_SUCCESS if the packet is sent successfully, negative error number
 
1378
 *      otherwise.
 
1379
 *
 
1380
 * Side effects:
 
1381
 *      None.
 
1382
 *
 
1383
 *-----------------------------------------------------------------------------
 
1384
 */
 
1385
 
 
1386
int
 
1387
VPageChannel_Send(VPageChannel *channel,       // IN/OUT
 
1388
                  VPageChannelPacketType type, // IN
 
1389
                  char *message,               // IN
 
1390
                  int len,                     // IN
 
1391
                  VPageChannelBuffer *buffer)  // IN
 
1392
{
 
1393
   int retval;
 
1394
   int numElems;
 
1395
   ssize_t totalSize;
 
1396
   VPageChannelPacket *packet;
 
1397
 
 
1398
   ASSERT(channel);
 
1399
 
 
1400
   if (!channel->qpConnected) {
 
1401
      VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
 
1402
                    channel));
 
1403
      return VMCI_ERROR_DST_UNREACHABLE;
 
1404
   }
 
1405
 
 
1406
   if (buffer) {
 
1407
      numElems = buffer->numElems;
 
1408
   } else {
 
1409
      numElems = 0;
 
1410
   }
 
1411
 
 
1412
   totalSize = sizeof(VPageChannelPacket) + len +
 
1413
      numElems * sizeof(VPageChannelElem);
 
1414
   packet = (VPageChannelPacket *)
 
1415
      VMCI_AllocKernelMem(totalSize, VMCI_MEMORY_NORMAL);
 
1416
   if (!packet) {
 
1417
      VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
 
1418
                    "(size=%"FMTSZ"d).",
 
1419
                    channel,
 
1420
                    totalSize));
 
1421
      return VMCI_ERROR_NO_MEM;
 
1422
   }
 
1423
 
 
1424
   packet->type = type;
 
1425
   packet->msgLen = len;
 
1426
   packet->numElems = numElems;
 
1427
 
 
1428
   if (len) {
 
1429
      ASSERT(message);
 
1430
      memcpy(VPAGECHANNEL_PACKET_MESSAGE(packet), message, len);
 
1431
   }
 
1432
 
 
1433
   if (numElems) {
 
1434
      ASSERT(buffer);
 
1435
      ASSERT(buffer->elems);
 
1436
      memcpy(VPAGECHANNEL_PACKET_ELEMS(packet), buffer->elems,
 
1437
             numElems * sizeof (VPageChannelElem));
 
1438
   }
 
1439
 
 
1440
   retval = VPageChannel_SendPacket(channel, packet);
 
1441
 
 
1442
   VMCI_FreeKernelMem(packet, totalSize);
 
1443
 
 
1444
   return retval;
 
1445
}
 
1446
EXPORT_SYMBOL(VPageChannel_Send);
 
1447
 
 
1448
 
 
1449
/*
 
1450
 *-----------------------------------------------------------------------------
 
1451
 *
 
1452
 * VPageChannel_PollTx --
 
1453
 *
 
1454
 *      The caller does its own coalescing and notifies us that it starts tx.
 
1455
 *
 
1456
 * Results:
 
1457
 *      None.
 
1458
 *
 
1459
 * Side effects:
 
1460
 *      We do not do our own coalescing.
 
1461
 *
 
1462
 *-----------------------------------------------------------------------------
 
1463
 */
 
1464
 
 
1465
void
 
1466
VPageChannel_PollRecvQ(VPageChannel *channel)     // IN
 
1467
{
 
1468
   if (channel->qpConnected) {
 
1469
      VMCIPacketDoDoorbellCallback(channel);
 
1470
   }
 
1471
}
 
1472
EXPORT_SYMBOL(VPageChannel_PollRecvQ);