]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
This is part 11 of a change to support Nested VMs.
authorVMware, Inc <>
Tue, 29 Mar 2011 18:45:42 +0000 (11:45 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Tue, 29 Mar 2011 18:45:42 +0000 (11:45 -0700)
This unifies the doorbell code.  We use the host doorbell
code, with resources and contexts, for both drivers.  The
decision about where to deliver a doorbell is made using
the routing code that was added with the datagram
unification.

The majority of the changes are in vmciDoorbell.c.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
14 files changed:
open-vm-tools/modules/linux/vmci/stubs.c
open-vm-tools/modules/linux/vmci/vmciDatagram.c
open-vm-tools/modules/linux/vmci/vmciDatagram.h
open-vm-tools/modules/linux/vmci/vmciDoorbell.c [new file with mode: 0644]
open-vm-tools/modules/linux/vmci/vmciDoorbell.h
open-vm-tools/modules/linux/vmci/vmciHashtable.c
open-vm-tools/modules/linux/vmci/vmciHashtable.h
open-vm-tools/modules/linux/vmci/vmciNotifications.c [deleted file]
open-vm-tools/modules/linux/vmci/vmciNotifications.h [deleted file]
open-vm-tools/modules/linux/vmci/vmciResource.c
open-vm-tools/modules/linux/vmci/vmciResource.h
open-vm-tools/modules/linux/vmci/vmciRoute.c
open-vm-tools/modules/linux/vmci/vmciRoute.h
open-vm-tools/modules/linux/vmci/vmci_drv.c

index fec98ab2fde9f2a471fc16f16e41a10784150179..c2da3e1955c75d6531d17124f6171f837dc25da5 100644 (file)
@@ -93,48 +93,6 @@ VMCIQPBroker_Detach(VMCIHandle handle,
 }
 
 
-/*
- *------------------------------------------------------------------------------
- *
- *  VMCIDoorbellHostContextNotify --
- *
- *     Stub.  Not called in the guest driver (yet).
- *
- *  Result:
- *     Always VMCI_ERROR_GENERIC.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDoorbellHostContextNotify(VMCIId srcCID,
-                              VMCIHandle handle)
-{
-   return VMCI_ERROR_GENERIC;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- *  VMCIDoorbellGetPrivFlags --
- *
- *     Stub.  Not called in the guest driver (yet).
- *
- *  Result:
- *     Always VMCI_ERROR_GENERIC.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDoorbellGetPrivFlags(VMCIHandle handle,
-                         VMCIPrivilegeFlags *privFlags)
-{
-   return VMCI_ERROR_GENERIC;
-}
-
-
 /*
  *------------------------------------------------------------------------------
  *
index aacf0d751fc60484f6cb2103ef4155beea68cc37..641e4476bd2ad78ba3a01bf875080eea0fb34a5d 100644 (file)
@@ -559,11 +559,11 @@ VMCIDatagramDelayedDispatchCB(void *data) // IN
 /*
  *------------------------------------------------------------------------------
  *
- *  VMCIDatagramDispatchFromHostToSelfOrGuest --
+ *  VMCIDatagramDispatchAsHost --
  *
- *     Dispatch datagram to host or other vm context. This function cannot
- *     dispatch to hypervisor context handlers. This should have been handled
- *     before we get here by VMCIDatagramDispatch.
+ *     Dispatch datagram as a host, to the host or other vm context. This
+ *     function cannot dispatch to hypervisor context handlers. This should
+ *     have been handled before we get here by VMCIDatagramDispatch.
  *
  *  Result:
  *     Number of bytes sent on success, appropriate error code otherwise.
@@ -575,8 +575,8 @@ VMCIDatagramDelayedDispatchCB(void *data) // IN
  */
 
 static int
-VMCIDatagramDispatchFromHostToSelfOrGuest(VMCIId contextID,  // IN:
-                                          VMCIDatagram *dg)  // IN:
+VMCIDatagramDispatchAsHost(VMCIId contextID,  // IN:
+                           VMCIDatagram *dg)  // IN:
 {
    int retval;
    size_t dgSize;
@@ -586,6 +586,7 @@ VMCIDatagramDispatchFromHostToSelfOrGuest(VMCIId contextID,  // IN:
    char dstDomain[VMCI_DOMAIN_NAME_MAXLEN]; /* Not used on hosted. */
 
    ASSERT(dg);
+   ASSERT(VMCI_HasHostDevice());
 
    dgSize = VMCI_DG_SIZE(dg);
 
@@ -804,9 +805,10 @@ VMCIDatagramDispatchFromHostToSelfOrGuest(VMCIId contextID,  // IN:
 /*
  *------------------------------------------------------------------------------
  *
- *  VMCIDatagramDispatchFromGuestToHost --
+ *  VMCIDatagramDispatchAsGuest --
  *
- *     Dispatch datagram down through the VMX, and potentially to the host.
+ *     Dispatch datagram as a guest, down through the VMX and potentially to
+ *     the host.
  *
  *  Result:
  *     Number of bytes sent on success, appropriate error code otherwise.
@@ -818,7 +820,7 @@ VMCIDatagramDispatchFromHostToSelfOrGuest(VMCIId contextID,  // IN:
  */
 
 static int
-VMCIDatagramDispatchFromGuestToHost(VMCIDatagram *dg)
+VMCIDatagramDispatchAsGuest(VMCIDatagram *dg)
 {
 #if defined(VMKERNEL)
    VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
@@ -828,6 +830,8 @@ VMCIDatagramDispatchFromGuestToHost(VMCIDatagram *dg)
    VMCIResource *resource;
    extern int VMCI_SendDatagram(VMCIDatagram *);
 
+   ASSERT(VMCI_HasGuestDevice());
+
    resource = VMCIResource_Get(dg->src, VMCI_RESOURCE_TYPE_DATAGRAM);
    if (NULL == resource) {
       return VMCI_ERROR_NO_HANDLE;
@@ -880,17 +884,15 @@ VMCIDatagram_Dispatch(VMCIId contextID,
       return retval;
    }
 
-   if (VMCI_ROUTE_HOST_TO_SELF == route ||
-       VMCI_ROUTE_HOST_TO_GUEST == route) {
+   if (VMCI_ROUTE_AS_HOST == route) {
       if (VMCI_INVALID_ID == contextID) {
          contextID = VMCI_HOST_CONTEXT_ID;
       }
-      return VMCIDatagramDispatchFromHostToSelfOrGuest(contextID, dg);
+      return VMCIDatagramDispatchAsHost(contextID, dg);
    }
 
-   if (VMCI_ROUTE_GUEST_TO_HOST == route ||
-       VMCI_ROUTE_GUEST_TO_HYPERVISOR == route) {
-      return VMCIDatagramDispatchFromGuestToHost(dg);
+   if (VMCI_ROUTE_AS_GUEST == route) {
+      return VMCIDatagramDispatchAsGuest(dg);
    }
 
    VMCI_WARNING((LGPFX"Unknown route (%d) for datagram.\n", route));
@@ -928,6 +930,7 @@ VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg) // IN
    DatagramEntry *dstEntry;
 
    ASSERT(dg);
+   ASSERT(VMCI_HasGuestDevice());
 
    resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM);
    if (NULL == resource) {
index 2bae0d8ca378fd8e3e6fb69f00dc52362b3e1dec..48436145e9085981d4ea547dd6e37905084521b8 100644 (file)
@@ -43,7 +43,6 @@
 int VMCIDatagram_Init(void);
 void VMCIDatagram_Exit(void);
 
-
 /* Datagram API for non-public use. */
 int VMCIDatagram_Dispatch(VMCIId contextID, VMCIDatagram *dg, Bool fromGuest);
 int VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg);
diff --git a/open-vm-tools/modules/linux/vmci/vmciDoorbell.c b/open-vm-tools/modules/linux/vmci/vmciDoorbell.c
new file mode 100644 (file)
index 0000000..f2e2c95
--- /dev/null
@@ -0,0 +1,1215 @@
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * vmciDoorbell.c --
+ *
+ *    This file implements the VMCI doorbell API on the host.
+ */
+
+#if defined(__linux__) && !defined(VMKERNEL)
+#  include "driver-config.h"
+#  include "compat_kernel.h"
+#  include "compat_module.h"
+#endif // __linux__
+#include "vmci_kernel_if.h"
+#include "vm_assert.h"
+#include "vmci_defs.h"
+#include "vmci_infrastructure.h"
+#include "vmciCommonInt.h"
+#include "vmciDatagram.h"
+#include "vmciDoorbell.h"
+#include "vmciKernelAPI.h"
+#include "vmciResource.h"
+#include "vmciRoute.h"
+#ifdef VMX86_TOOLS
+#  include "vmciInt.h"
+#  include "vmciUtil.h"
+#elif defined(VMKERNEL)
+#  include "vmciVmkInt.h"
+#  include "vm_libc.h"
+#  include "helper_ext.h"
+#  include "vmciDriver.h"
+#else
+#  include "vmciDriver.h"
+#endif
+
+#define LGPFX "VMCIDoorbell: "
+
+#if !defined(SOLARIS) && !defined(__APPLE__)
+
+#if defined(VMKERNEL)
+   /* VMK doesn't need BH locks, so use lower ranks. */
+#  define VMCIDoorbellInitLock(_l, _n) \
+   VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_HIGHER)
+#  define VMCIDoorbellGrabLock(_l, _f)       VMCI_GrabLock(_l, _f)
+#  define VMCIDoorbellReleaseLock(_l, _f)    VMCI_ReleaseLock(_l, _f)
+#else // VMKERNEL
+#  define VMCIDoorbellInitLock(_l, _n) \
+   VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_MIDDLE_BH)
+#  define VMCIDoorbellGrabLock(_l, _f)       VMCI_GrabLock_BH(_l, _f)
+#  define VMCIDoorbellReleaseLock(_l, _f)    VMCI_ReleaseLock_BH(_l, _f)
+#endif // VMKERNEL
+
+#define VMCI_DOORBELL_INDEX_TABLE_SIZE 64
+#define VMCI_DOORBELL_HASH(_idx) \
+   VMCI_HashId((_idx), VMCI_DOORBELL_INDEX_TABLE_SIZE)
+
+
+/*
+ * DoorbellEntry describes the a doorbell notification handle allocated by the
+ * host.
+ */
+
+typedef struct VMCIDoorbellEntry {
+   VMCIResource        resource;
+   uint32              idx;
+   VMCIListItem        idxListItem;
+   VMCIPrivilegeFlags  privFlags;
+   Bool                isDoorbell;
+   Bool                runDelayed;
+   VMCICallback        notifyCB;
+   void                *clientData;
+   VMCIEvent           destroyEvent;
+} VMCIDoorbellEntry;
+
+typedef struct VMCIDoorbellIndexTable {
+   VMCILock lock;
+   VMCIList entries[VMCI_DOORBELL_INDEX_TABLE_SIZE];
+} VMCIDoorbellIndexTable;
+
+
+/* The VMCI index table keeps track of currently registered doorbells. */
+static VMCIDoorbellIndexTable vmciDoorbellIT;
+
+
+/*
+ * The maxNotifyIdx is one larger than the currently known bitmap index in
+ * use, and is used to determine how much of the bitmap needs to be scanned.
+ */
+
+static uint32 maxNotifyIdx;
+
+/*
+ * The notifyIdxCount is used for determining whether there are free entries
+ * within the bitmap (if notifyIdxCount + 1 < maxNotifyIdx).
+ */
+
+static uint32 notifyIdxCount;
+
+/*
+ * The lastNotifyIdxReserved is used to track the last index handed out - in
+ * the case where multiple handles share a notification index, we hand out
+ * indexes round robin based on lastNotifyIdxReserved.
+ */
+
+static uint32 lastNotifyIdxReserved;
+
+/* This is a one entry cache used to by the index allocation. */
+static uint32 lastNotifyIdxReleased = PAGE_SIZE;
+
+
+static void VMCIDoorbellFreeCB(void *clientData);
+static int VMCIDoorbellReleaseCB(void *clientData);
+static void VMCIDoorbellDelayedDispatchCB(void *data);
+extern int VMCI_SendDatagram(VMCIDatagram *);
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbell_Init --
+ *
+ *    General init code.
+ *
+ * Result:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+void
+VMCIDoorbell_Init(void)
+{
+   uint32 bucket;
+
+   for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); ++bucket) {
+      VMCIList_Init(&vmciDoorbellIT.entries[bucket]);
+   }
+
+   VMCIDoorbellInitLock(&vmciDoorbellIT.lock, "VMCIDoorbellIndexTableLock");
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbell_Exit --
+ *
+ *    General init code.
+ *
+ * Result:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+void
+VMCIDoorbell_Exit(void)
+{
+   VMCI_CleanupLock(&vmciDoorbellIT.lock);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellFreeCB --
+ *
+ *    Callback to free doorbell entry structure when resource is no longer used,
+ *    ie. the reference count reached 0.  The entry is freed in
+ *    VMCIDoorbell_Destroy(), which is waiting on the signal that gets fired
+ *    here.
+ *
+ * Result:
+ *    None.
+ *
+ * Side effects:
+ *    Signals VMCI event.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+static void
+VMCIDoorbellFreeCB(void *clientData)  // IN
+{
+   VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData;
+   ASSERT(entry);
+   VMCI_SignalEvent(&entry->destroyEvent);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellReleaseCB --
+ *
+ *     Callback to release the resource reference. It is called by the
+ *     VMCI_WaitOnEvent function before it blocks.
+ *
+ * Result:
+ *     Always 0.
+ *
+ * Side effects:
+ *     None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+static int
+VMCIDoorbellReleaseCB(void *clientData) // IN: doorbell entry
+{
+   VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData;
+   ASSERT(entry);
+   VMCIResource_Release(&entry->resource);
+   return 0;
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellGetPrivFlags --
+ *
+ *    Utility function that retrieves the privilege flags associated
+ *    with a given doorbell handle. For guest endpoints, the
+ *    privileges are determined by the context ID, but for host
+ *    endpoints privileges are associated with the complete
+ *    handle. Hypervisor endpoints are not yet supported.
+ *
+ * Result:
+ *    VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
+ *
+ * Side effects:
+ *    None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+int
+VMCIDoorbellGetPrivFlags(VMCIHandle handle,             // IN
+                         VMCIPrivilegeFlags *privFlags) // OUT
+{
+   if (privFlags == NULL || handle.context == VMCI_INVALID_ID) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+   if (handle.context == VMCI_HOST_CONTEXT_ID) {
+      VMCIDoorbellEntry *entry;
+      VMCIResource *resource;
+
+      resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
+      if (resource == NULL) {
+         return VMCI_ERROR_INVALID_ARGS;
+      }
+      entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
+      *privFlags = entry->privFlags;
+      VMCIResource_Release(resource);
+   } else if (handle.context == VMCI_HYPERVISOR_CONTEXT_ID) {
+       /* Hypervisor endpoints for notifications are not supported (yet). */
+      return VMCI_ERROR_INVALID_ARGS;
+   } else {
+      *privFlags = VMCIContext_GetPrivFlags(handle.context);
+   }
+
+   return VMCI_SUCCESS;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIDoorbellIndexTableFind --
+ *
+ *    Find doorbell entry by bitmap index.
+ *
+ * Results:
+ *    Entry if found, NULL if not.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VMCIDoorbellEntry *
+VMCIDoorbellIndexTableFind(uint32 idx) // IN
+{
+   uint32 bucket = VMCI_DOORBELL_HASH(idx);
+   VMCIListItem *iter;
+
+   ASSERT(VMCI_HasGuestDevice());
+
+   VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
+      VMCIDoorbellEntry *cur =
+         VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
+
+      ASSERT(cur);
+
+      if (idx == cur->idx) {
+         return cur;
+      }
+   }
+
+   return NULL;
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellIndexTableAdd --
+ *
+ *    Add the given entry to the index table.  This will hold() the entry's
+ *    resource so that the entry is not deleted before it is removed from the
+ *    table.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+static void
+VMCIDoorbellIndexTableAdd(VMCIDoorbellEntry *entry) // IN/OUT
+{
+   uint32 bucket;
+   uint32 newNotifyIdx;
+   VMCILockFlags flags;
+
+   ASSERT(entry);
+   ASSERT(VMCI_HasGuestDevice());
+
+   VMCIResource_Hold(&entry->resource);
+
+   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
+
+   /*
+    * Below we try to allocate an index in the notification bitmap with "not
+    * too much" sharing between resources. If we use less that the full bitmap,
+    * we either add to the end if there are no unused flags within the
+    * currently used area, or we search for unused ones. If we use the full
+    * bitmap, we allocate the index round robin.
+    */
+
+   if (maxNotifyIdx < PAGE_SIZE || notifyIdxCount < PAGE_SIZE) {
+      if (lastNotifyIdxReleased < maxNotifyIdx &&
+          !VMCIDoorbellIndexTableFind(lastNotifyIdxReleased)) {
+         newNotifyIdx = lastNotifyIdxReleased;
+         lastNotifyIdxReleased = PAGE_SIZE;
+      } else {
+         Bool reused = FALSE;
+         newNotifyIdx = lastNotifyIdxReserved;
+         if (notifyIdxCount + 1 < maxNotifyIdx) {
+            do {
+               if (!VMCIDoorbellIndexTableFind(newNotifyIdx)) {
+                  reused = TRUE;
+                  break;
+               }
+               newNotifyIdx = (newNotifyIdx + 1) % maxNotifyIdx;
+            } while(newNotifyIdx != lastNotifyIdxReleased);
+         }
+         if (!reused) {
+            newNotifyIdx = maxNotifyIdx;
+            maxNotifyIdx++;
+         }
+      }
+   } else {
+      newNotifyIdx = (lastNotifyIdxReserved + 1) % PAGE_SIZE;
+   }
+   lastNotifyIdxReserved = newNotifyIdx;
+   notifyIdxCount++;
+
+   entry->idx = newNotifyIdx;
+   bucket = VMCI_DOORBELL_HASH(entry->idx);
+   VMCIList_Insert(&entry->idxListItem, &vmciDoorbellIT.entries[bucket]);
+
+   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellIndexTableRemove --
+ *
+ *    Remove the given entry from the index table.  This will release() the
+ *    entry's resource.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+static void
+VMCIDoorbellIndexTableRemove(VMCIDoorbellEntry *entry) // IN/OUT
+{
+   uint32 bucket;
+   VMCILockFlags flags;
+
+   ASSERT(entry);
+   ASSERT(VMCI_HasGuestDevice());
+
+   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
+
+   bucket = VMCI_DOORBELL_HASH(entry->idx);
+   VMCIList_Remove(&entry->idxListItem, &vmciDoorbellIT.entries[bucket]);
+
+   notifyIdxCount--;
+   if (entry->idx == maxNotifyIdx - 1) {
+      /*
+       * If we delete an entry with the maximum known notification index, we
+       * take the opportunity to prune the current max. As there might be other
+       * unused indices immediately below, we lower the maximum until we hit an
+       * index in use.
+       */
+
+      while (maxNotifyIdx > 0 &&
+             !VMCIDoorbellIndexTableFind(maxNotifyIdx - 1)) {
+         maxNotifyIdx--;
+      }
+   }
+   lastNotifyIdxReleased = entry->idx;
+
+   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
+
+   VMCIResource_Release(&entry->resource);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellLink --
+ *
+ *    Creates a link between the given doorbell handle and the given
+ *    index in the bitmap in the device backend.
+ *
+ * Results:
+ *    VMCI_SUCCESS if success, appropriate error code otherwise.
+ *
+ * Side effects:
+ *    Notification state is created in hypervisor.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+static int
+VMCIDoorbellLink(VMCIHandle handle, // IN
+                 Bool isDoorbell,   // IN
+                 uint32 notifyIdx)  // IN
+{
+#if defined(VMKERNEL)
+   VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
+   return VMCI_ERROR_DST_UNREACHABLE;
+#else // VMKERNEL
+   VMCIId resourceID;
+   VMCIDoorbellLinkMsg linkMsg;
+
+   ASSERT(!VMCI_HANDLE_INVALID(handle));
+   ASSERT(VMCI_HasGuestDevice());
+
+   if (isDoorbell) {
+      resourceID = VMCI_DOORBELL_LINK;
+   } else {
+      ASSERT(FALSE);
+      return VMCI_ERROR_UNAVAILABLE;
+   }
+
+   linkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID);
+   linkMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
+   linkMsg.hdr.payloadSize = sizeof linkMsg - VMCI_DG_HEADERSIZE;
+   linkMsg.handle = handle;
+   linkMsg.notifyIdx = notifyIdx;
+
+   return VMCI_SendDatagram((VMCIDatagram *)&linkMsg);
+#endif // VMKERNEL
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellUnlink --
+ *
+ *    Unlinks the given doorbell handle from an index in the bitmap in
+ *    the device backend.
+ *
+ * Results:
+ *      VMCI_SUCCESS if success, appropriate error code otherwise.
+ *
+ * Side effects:
+ *      Notification state is destroyed in hypervisor.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+static int
+VMCIDoorbellUnlink(VMCIHandle handle, // IN
+                   Bool isDoorbell)   // IN
+{
+#if defined(VMKERNEL)
+   VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
+   return VMCI_ERROR_DST_UNREACHABLE;
+#else // VMKERNEL
+   VMCIId resourceID;
+   VMCIDoorbellUnlinkMsg unlinkMsg;
+
+   ASSERT(!VMCI_HANDLE_INVALID(handle));
+   ASSERT(VMCI_HasGuestDevice());
+
+   if (isDoorbell) {
+      resourceID = VMCI_DOORBELL_UNLINK;
+   } else {
+      ASSERT(FALSE);
+      return VMCI_ERROR_UNAVAILABLE;
+   }
+
+   unlinkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID);
+   unlinkMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
+   unlinkMsg.hdr.payloadSize = sizeof unlinkMsg - VMCI_DG_HEADERSIZE;
+   unlinkMsg.handle = handle;
+
+   return VMCI_SendDatagram((VMCIDatagram *)&unlinkMsg);
+#endif // VMKERNEL
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbell_Create --
+ *
+ *    Creates a doorbell with the given callback. If the handle is
+ *    VMCI_INVALID_HANDLE, a free handle will be assigned, if
+ *    possible. The callback can be run immediately (potentially with
+ *    locks held - the default) or delayed (in a kernel thread) by
+ *    specifying the flag VMCI_FLAG_DELAYED_CB. If delayed execution
+ *    is selected, a given callback may not be run if the kernel is
+ *    unable to allocate memory for the delayed execution (highly
+ *    unlikely).
+ *
+ * Results:
+ *    VMCI_SUCCESS on success, appropriate error code otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create)
+int
+VMCIDoorbell_Create(VMCIHandle *handle,            // IN/OUT
+                    uint32 flags,                  // IN
+                    VMCIPrivilegeFlags privFlags,  // IN
+                    VMCICallback notifyCB,         // IN
+                    void *clientData)              // IN
+{
+   VMCIDoorbellEntry *entry;
+   VMCIHandle newHandle;
+   int result;
+
+   if (!handle || !notifyCB || flags & ~VMCI_FLAG_DELAYED_CB ||
+       privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+   entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED);
+   if (entry == NULL) {
+      VMCI_WARNING((LGPFX"Failed allocating memory for datagram entry.\n"));
+      return VMCI_ERROR_NO_MEM;
+   }
+
+   if (!VMCI_CanScheduleDelayedWork() && (flags & VMCI_FLAG_DELAYED_CB)) {
+      result = VMCI_ERROR_INVALID_ARGS;
+      goto freeMem;
+   }
+
+   if (VMCI_HANDLE_INVALID(*handle)) {
+      VMCIId contextID = VMCI_GetContextID();
+      VMCIId resourceID = VMCIResource_GetID(contextID);
+      if (resourceID == VMCI_INVALID_ID) {
+         result = VMCI_ERROR_NO_HANDLE;
+         goto freeMem;
+      }
+      newHandle = VMCI_MAKE_HANDLE(contextID, resourceID);
+   } else {
+      Bool validContext;
+
+      /*
+       * Validate the handle.  We must do both of the checks below because we
+       * can be acting as both a host and a guest at the same time.
+       */
+
+      validContext = FALSE;
+      if (VMCI_HasHostDevice() && VMCI_HOST_CONTEXT_ID == handle->context) {
+         validContext = TRUE;
+      }
+      if (VMCI_HasGuestDevice() && VMCI_GetContextID() == handle->context) {
+         validContext = TRUE;
+      }
+
+      if (!validContext || VMCI_INVALID_ID == handle->resource) {
+         VMCI_DEBUG_LOG(4, (LGPFX"Invalid argument (handle=0x%x:0x%x).\n",
+                            handle->context, handle->resource));
+         result = VMCI_ERROR_INVALID_ARGS;
+         goto freeMem;
+      }
+
+      newHandle = *handle;
+   }
+
+   entry->idx = 0;
+   VMCIList_Init(&entry->idxListItem);
+   entry->privFlags = privFlags;
+   entry->isDoorbell = TRUE;
+   entry->runDelayed = (flags & VMCI_FLAG_DELAYED_CB) ? TRUE : FALSE;
+   entry->notifyCB = notifyCB;
+   entry->clientData = clientData;
+   VMCI_CreateEvent(&entry->destroyEvent);
+
+   result = VMCIResource_Add(&entry->resource, VMCI_RESOURCE_TYPE_DOORBELL,
+                             newHandle, VMCIDoorbellFreeCB, entry);
+   if (result != VMCI_SUCCESS) {
+      VMCI_WARNING((LGPFX"Failed to add new resource (handle=0x%x:0x%x).\n",
+                    newHandle.context, newHandle.resource));
+      goto destroy;
+   }
+
+   if (VMCI_HasGuestDevice()) {
+      result = VMCIDoorbellLink(newHandle, entry->isDoorbell, entry->idx);
+      if (VMCI_SUCCESS != result) {
+         goto destroyResource;
+      }
+      VMCIDoorbellIndexTableAdd(entry);
+   }
+
+   if (VMCI_HANDLE_INVALID(*handle)) {
+      *handle = newHandle;
+   }
+
+   return result;
+
+destroyResource:
+   VMCIResource_Remove(newHandle, VMCI_RESOURCE_TYPE_DOORBELL);
+destroy:
+   VMCI_DestroyEvent(&entry->destroyEvent);
+freeMem:
+   VMCI_FreeKernelMem(entry, sizeof *entry);
+   return result;
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbell_Destroy --
+ *
+ *    Destroys a doorbell previously created with
+ *    VMCIDoorbell_Create. This operation may block waiting for a
+ *    callback to finish.
+ *
+ * Results:
+ *    VMCI_SUCCESS on success, appropriate error code otherwise.
+ *
+ * Side effects:
+ *    May block.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy)
+int
+VMCIDoorbell_Destroy(VMCIHandle handle)  // IN
+{
+   VMCIDoorbellEntry *entry;
+   VMCIResource *resource;
+
+   if (VMCI_HANDLE_INVALID(handle)) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+   resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
+   if (resource == NULL) {
+      VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy doorbell (handle=0x%x:0x%x).\n",
+                         handle.context, handle.resource));
+      return VMCI_ERROR_NOT_FOUND;
+   }
+   entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
+
+   if (VMCI_HasGuestDevice()) {
+      int result;
+
+      VMCIDoorbellIndexTableRemove(entry);
+
+      result = VMCIDoorbellUnlink(handle, entry->isDoorbell);
+      if (VMCI_SUCCESS != result) {
+
+         /*
+          * The only reason this should fail would be an inconsistency between
+          * guest and hypervisor state, where the guest believes it has an
+          * active registration whereas the hypervisor doesn't. One case where
+          * this may happen is if a doorbell is unregistered following a
+          * hibernation at a time where the doorbell state hasn't been restored
+          * on the hypervisor side yet. Since the handle has now been removed
+          * in the guest, we just print a warning and return success.
+          */
+
+         VMCI_DEBUG_LOG(4, (LGPFX"Unlink of %s (handle=0x%x:0x%x) unknown by "
+                            "hypervisor (error=%d).\n",
+                            entry->isDoorbell ? "doorbell" : "queuepair",
+                            handle.context, handle.resource, result));
+      }
+   }
+
+   /*
+    * Now remove the resource from the table.  It might still be in use
+    * after this, in a callback or still on the delayed work queue.
+    */
+
+   VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DOORBELL);
+
+   /*
+    * We now wait on the destroyEvent and release the reference we got
+    * above.
+    */
+
+   VMCI_WaitOnEvent(&entry->destroyEvent, VMCIDoorbellReleaseCB, entry);
+
+   /*
+    * We know that we are now the only reference to the above entry so
+    * can safely free it.
+    */
+
+   VMCI_DestroyEvent(&entry->destroyEvent);
+   VMCI_FreeKernelMem(entry, sizeof *entry);
+
+   return VMCI_SUCCESS;
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellNotifyAsGuest --
+ *
+ *    Notify another guest or the host.  We send a datagram down to the
+ *    host via the hypervisor with the notification info.
+ *
+ * Results:
+ *    VMCI_SUCCESS on success, appropriate error code otherwise.
+ *
+ * Side effects:
+ *    May do a hypercall.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+static int
+VMCIDoorbellNotifyAsGuest(VMCIHandle handle,            // IN
+                          VMCIPrivilegeFlags privFlags) // IN
+{
+#if defined(VMKERNEL)
+   VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
+   return VMCI_ERROR_DST_UNREACHABLE;
+#else // VMKERNEL
+   VMCIDoorbellNotifyMsg notifyMsg;
+
+   ASSERT(VMCI_HasGuestDevice());
+
+   notifyMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
+                                        VMCI_DOORBELL_NOTIFY);
+   notifyMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
+   notifyMsg.hdr.payloadSize = sizeof notifyMsg - VMCI_DG_HEADERSIZE;
+   notifyMsg.handle = handle;
+
+   return VMCI_SendDatagram((VMCIDatagram *)&notifyMsg);
+#endif // VMKERNEL
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbell_Notify --
+ *
+ *    Generates a notification on the doorbell identified by the
+ *    handle. For host side generation of notifications, the caller
+ *    can specify what the privilege of the calling side is.
+ *
+ * Results:
+ *    VMCI_SUCCESS on success, appropriate error code otherwise.
+ *
+ * Side effects:
+ *    May do a hypercall.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify)
+int
+VMCIDoorbell_Notify(VMCIHandle dst,               // IN
+                    VMCIPrivilegeFlags privFlags) // IN
+{
+   int retval;
+   VMCIRoute route;
+   VMCIHandle src;
+
+   if (VMCI_HANDLE_INVALID(dst) || (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS)) {
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+
+   src = VMCI_INVALID_HANDLE;
+   retval = VMCI_Route(&src, &dst, FALSE, &route);
+   if (retval < VMCI_SUCCESS) {
+      return retval;
+   }
+
+   if (VMCI_ROUTE_AS_HOST == route) {
+      return VMCIContext_NotifyDoorbell(VMCI_HOST_CONTEXT_ID, dst, privFlags);
+   }
+
+   if (VMCI_ROUTE_AS_GUEST == route) {
+      return VMCIDoorbellNotifyAsGuest(dst, privFlags);
+   }
+
+   VMCI_WARNING((LGPFX"Unknown route (%d) for doorbell.\n", route));
+   return VMCI_ERROR_DST_UNREACHABLE;
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellDelayedDispatchCB --
+ *
+ *    Calls the specified callback in a delayed context.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+static void
+VMCIDoorbellDelayedDispatchCB(void *data) // IN
+{
+   VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)data;
+
+   ASSERT(data);
+
+   entry->notifyCB(entry->clientData);
+
+   VMCIResource_Release(&entry->resource);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbellHostContextNotify --
+ *
+ *    Dispatches a doorbell notification to the host context.
+ *
+ * Results:
+ *    VMCI_SUCCESS on success. Appropriate error code otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+int
+VMCIDoorbellHostContextNotify(VMCIId srcCID,     // IN
+                              VMCIHandle handle) // IN
+{
+   VMCIDoorbellEntry *entry;
+   VMCIResource *resource;
+   int result;
+
+   ASSERT(VMCI_HasHostDevice());
+
+   resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
+   if (resource == NULL) {
+      VMCI_DEBUG_LOG(4,
+                     (LGPFX"Notifying an invalid doorbell (handle=0x%x:0x%x).\n",
+                      handle.context, handle.resource));
+      return VMCI_ERROR_INVALID_ARGS;
+   }
+   entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
+
+   if (entry->runDelayed) {
+      result = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, entry);
+      if (result < VMCI_SUCCESS) {
+         /*
+          * If we failed to schedule the delayed work, we need to
+          * release the resource immediately. Otherwise, the resource
+          * will be released once the delayed callback has been
+          * completed.
+          */
+
+         VMCI_DEBUG_LOG(10, (LGPFX"Failed to schedule delayed doorbell "
+                             "notification (result=%d).\n", result));
+         VMCIResource_Release(resource);
+      }
+   } else {
+      entry->notifyCB(entry->clientData);
+      VMCIResource_Release(resource);
+      result = VMCI_SUCCESS;
+   }
+   return result;
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbell_Hibernate --
+ *
+ *      When a guest leaves hibernation, the device driver state is out of sync
+ *      with the device state, since the driver state has doorbells registered
+ *      that aren't known to the device.  This function takes care of
+ *      reregistering any doorbells. In case an error occurs during
+ *      reregistration (this is highly unlikely since 1) it succeeded the first
+ *      time 2) the device driver is the only source of doorbell registrations),
+ *      we simply log the error.  The doorbell can still be destroyed using
+ *      VMCIDoorbell_Destroy.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+void
+VMCIDoorbell_Hibernate(Bool enterHibernate)
+{
+   uint32 bucket;
+   VMCIListItem *iter;
+   VMCILockFlags flags;
+
+   if (!VMCI_HasGuestDevice() || enterHibernate) {
+      return;
+   }
+
+   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
+
+   for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); bucket++) {
+      VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
+         int result;
+         VMCIDoorbellEntry *cur;
+
+         cur = VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
+         result = VMCIDoorbellLink(cur->resource.handle, cur->isDoorbell,
+                                   cur->idx);
+         if (result != VMCI_SUCCESS && result != VMCI_ERROR_DUPLICATE_ENTRY) {
+            VMCI_WARNING((LGPFX"Failed to reregister doorbell "
+                          "(handle=0x%x:0x%x) of resource %s to index "
+                          "(error: %d).\n",
+                          cur->resource.handle.context,
+                          cur->resource.handle.resource,
+                          cur->isDoorbell ? "doorbell" : "queue pair", result));
+         }
+      }
+   }
+
+   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCIDoorbell_Sync --
+ *
+ *      Use this as a synchronization point when setting globals, for example,
+ *      during device shutdown.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+void
+VMCIDoorbell_Sync(void)
+{
+   VMCILockFlags flags;
+   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
+   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
+   VMCIResource_Sync();
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCI_RegisterNotificationBitmap --
+ *
+ *      Register the notification bitmap with the host.
+ *
+ * Results:
+ *      TRUE if the bitmap is registered successfully with the device, FALSE
+ *      otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+Bool
+VMCI_RegisterNotificationBitmap(PPN bitmapPPN)
+{
+   int result;
+   VMCINotifyBitmapSetMsg bitmapSetMsg;
+
+   /*
+    * Do not ASSERT() on the guest device here.  This function can get called
+    * during device initialization, so the ASSERT() will fail even though
+    * the device is (almost) up.
+    */
+
+   bitmapSetMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
+                                           VMCI_SET_NOTIFY_BITMAP);
+   bitmapSetMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
+   bitmapSetMsg.hdr.payloadSize = sizeof bitmapSetMsg - VMCI_DG_HEADERSIZE;
+   bitmapSetMsg.bitmapPPN = bitmapPPN;
+
+   result = VMCI_SendDatagram((VMCIDatagram *)&bitmapSetMsg);
+   if (result != VMCI_SUCCESS) {
+      VMCI_DEBUG_LOG(4, (LGPFX"Failed to register (PPN=%u) as "
+                         "notification bitmap (error=%d).\n",
+                         bitmapPPN, result));
+      return FALSE;
+   }
+   return TRUE;
+}
+
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * VMCIDoorbellFireEntries --
+ *
+ *     Executes or schedules the handlers for a given notify index.
+ *
+ * Result:
+ *     Notification hash entry if found. NULL otherwise.
+ *
+ * Side effects:
+ *     Whatever the side effects of the handlers are.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static void
+VMCIDoorbellFireEntries(uint32 notifyIdx) // IN
+{
+   uint32 bucket = VMCI_DOORBELL_HASH(notifyIdx);
+   VMCIListItem *iter;
+   VMCILockFlags flags;
+
+   ASSERT(VMCI_HasGuestDevice());
+
+   VMCIDoorbellGrabLock(&vmciDoorbellIT.lock, &flags);
+
+   VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
+      VMCIDoorbellEntry *cur =
+         VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
+
+      ASSERT(cur);
+
+      if (cur->idx == notifyIdx) {
+         ASSERT(cur->notifyCB);
+         if (cur->runDelayed) {
+            int err;
+
+            VMCIResource_Hold(&cur->resource);
+            err = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, cur);
+            if (err != VMCI_SUCCESS) {
+               VMCIResource_Release(&cur->resource);
+               goto out;
+            }
+         } else {
+            cur->notifyCB(cur->clientData);
+         }
+      }
+   }
+
+out:
+   VMCIDoorbellReleaseLock(&vmciDoorbellIT.lock, flags);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * VMCI_ScanNotificationBitmap --
+ *
+ *      Scans the notification bitmap, collects pending notifications,
+ *      resets the bitmap and invokes appropriate callbacks.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      May schedule tasks, allocate memory and run callbacks.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+void
+VMCI_ScanNotificationBitmap(uint8 *bitmap)
+{
+   uint32 idx;
+
+   ASSERT(bitmap);
+   ASSERT(VMCI_HasGuestDevice());
+
+   for (idx = 0; idx < maxNotifyIdx; idx++) {
+      if (bitmap[idx] & 0x1) {
+         bitmap[idx] &= ~1;
+         VMCIDoorbellFireEntries(idx);
+      }
+   }
+}
+
+
+#else // SOLARIS) || __APPLE__
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIDoorbell_Create/VMCIDoorbell_Destroy/VMCIDoorbell_Notify --
+ *
+ *      The doorbell functions have yet to be implemented for Solaris
+ *      and Mac OS X guest drivers.
+ *
+ * Results:
+ *      VMCI_ERROR_UNAVAILABLE.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create)
+int
+VMCIDoorbell_Create(VMCIHandle *handle,            // IN
+                    uint32 flags,                  // I
+                    VMCIPrivilegeFlags privFlags,  // IN
+                    VMCICallback notifyCB,         // IN
+                    void *clientData)              // IN
+{
+   return VMCI_ERROR_UNAVAILABLE;
+}
+
+
+VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy)
+int
+VMCIDoorbell_Destroy(VMCIHandle handle)  // IN
+{
+   return VMCI_ERROR_UNAVAILABLE;
+}
+
+
+VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify)
+int
+VMCIDoorbell_Notify(VMCIHandle handle,             // IN
+                    VMCIPrivilegeFlags privFlags)  // IN
+{
+   return VMCI_ERROR_UNAVAILABLE;
+}
+
+#endif // SOLARIS) || __APPLE__
index c9c45d5e884ad49d1f51a5d9f974b7894170ca92..73dbf9e4d23312ac085173265d63e5e619fd46b9 100644 (file)
 #include "vmci_kernel_if.h"
 #include "vmci_defs.h"
 
+void VMCIDoorbell_Init(void);
+void VMCIDoorbell_Exit(void);
+void VMCIDoorbell_Hibernate(Bool enterHibernation);
+void VMCIDoorbell_Sync(void);
+
 int VMCIDoorbellHostContextNotify(VMCIId srcCID, VMCIHandle handle);
 int VMCIDoorbellGetPrivFlags(VMCIHandle handle, VMCIPrivilegeFlags *privFlags);
-void VMCIDoorbell_Sync(void);
+
+Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN);
+void VMCI_ScanNotificationBitmap(uint8 *bitmap);
 
 #endif // VMCI_DOORBELL_H
index dbff18db1f7bd83ca1fa8ab7229da7f93d9df68d..cdea16b8c0ba650b3c93cdd13a576c6c5cf64e73 100644 (file)
 
 #define LGPFX "VMCIHashTable: "
 
+#if defined(VMKERNEL)
+   /* VMK doesn't need BH locks, so use lower ranks. */
+#  define VMCIHashTableInitLock(_l, _n) \
+   VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_HIGHEST)
+#  define VMCIHashTableGrabLock(_l, _f)      VMCI_GrabLock(_l, _f)
+#  define VMCIHashTableReleaseLock(_l, _f)   VMCI_ReleaseLock(_l, _f)
+#else // VMKERNEL
+#  define VMCIHashTableInitLock(_l, _n) \
+   VMCI_InitLock(_l, _n, VMCI_LOCK_RANK_HIGH_BH)
+#  define VMCIHashTableGrabLock(_l, _f)      VMCI_GrabLock_BH(_l, _f)
+#  define VMCIHashTableReleaseLock(_l, _f)   VMCI_ReleaseLock_BH(_l, _f)
+#endif // VMKERNEL
+
 #define VMCI_HASHTABLE_HASH(_h, _sz) \
    VMCI_HashId(VMCI_HANDLE_TO_RESOURCE_ID(_h), (_sz))
 
@@ -87,9 +100,7 @@ VMCIHashTable_Create(int size)
    }
    memset(table->entries, 0, sizeof *table->entries * size);
    table->size = size;
-   VMCI_InitLock(&table->lock,
-                 "VMCIHashTableLock",
-                 VMCI_LOCK_RANK_HIGH);   
+   VMCIHashTableInitLock(&table->lock, "VMCIHashTableLock");
 
    return table;
 }
@@ -121,7 +132,7 @@ VMCIHashTable_Destroy(VMCIHashTable *table)
 
    ASSERT(table);
 
-   VMCI_GrabLock(&table->lock, &flags);
+   VMCIHashTableGrabLock(&table->lock, &flags);
 #if 0
 #ifdef VMX86_DEBUG
    for (i = 0; i < table->size; i++) {
@@ -139,8 +150,8 @@ VMCIHashTable_Destroy(VMCIHashTable *table)
 #endif
    VMCI_FreeKernelMem(table->entries, sizeof *table->entries * table->size);
    table->entries = NULL;
-   VMCI_ReleaseLock(&table->lock, flags);
-   VMCI_CleanupLock(&table->lock);   
+   VMCIHashTableReleaseLock(&table->lock, flags);
+   VMCI_CleanupLock(&table->lock);
    VMCI_FreeKernelMem(table, sizeof *table);
 }
 
@@ -188,18 +199,18 @@ VMCIHashTable_AddEntry(VMCIHashTable *table,   // IN
    ASSERT(entry);
    ASSERT(table);
 
-   VMCI_GrabLock(&table->lock, &flags);
+   VMCIHashTableGrabLock(&table->lock, &flags);
 
    /* Do not allow addition of a new entry if the device is being shutdown. */
    if (VMCI_DeviceShutdown()) {
-      VMCI_ReleaseLock(&table->lock, flags);
+      VMCIHashTableReleaseLock(&table->lock, flags);
       return VMCI_ERROR_DEVICE_NOT_FOUND;
    }
 
    if (VMCIHashTableEntryExistsLocked(table, entry->handle)) {
       VMCI_DEBUG_LOG(4, (LGPFX"Entry (handle=0x%x:0x%x) already exists.\n",
                          entry->handle.context, entry->handle.resource));
-      VMCI_ReleaseLock(&table->lock, flags);
+      VMCIHashTableReleaseLock(&table->lock, flags);
       return VMCI_ERROR_DUPLICATE_ENTRY;
    }
 
@@ -210,7 +221,7 @@ VMCIHashTable_AddEntry(VMCIHashTable *table,   // IN
    entry->refCount++;
    entry->next = table->entries[idx];
    table->entries[idx] = entry;
-   VMCI_ReleaseLock(&table->lock, flags);
+   VMCIHashTableReleaseLock(&table->lock, flags);
 
    return VMCI_SUCCESS;
 }
@@ -239,8 +250,8 @@ VMCIHashTable_RemoveEntry(VMCIHashTable *table, // IN
    ASSERT(table);
    ASSERT(entry);
 
-   VMCI_GrabLock(&table->lock, &flags);
-   
+   VMCIHashTableGrabLock(&table->lock, &flags);
+
    /* First unlink the entry. */
    result = HashTableUnlinkEntry(table, entry);
    if (result != VMCI_SUCCESS) {
@@ -254,10 +265,10 @@ VMCIHashTable_RemoveEntry(VMCIHashTable *table, // IN
       result = VMCI_SUCCESS_ENTRY_DEAD;
       goto done;
    }
-   
+
   done:
-   VMCI_ReleaseLock(&table->lock, flags);
-   
+   VMCIHashTableReleaseLock(&table->lock, flags);
+
    return result;
 }
 
@@ -338,15 +349,48 @@ VMCIHashTable_GetEntry(VMCIHashTable *table,  // IN
    }
 
    ASSERT(table);
-   
-   VMCI_GrabLock(&table->lock, &flags);
+
+   VMCIHashTableGrabLock(&table->lock, &flags);
    entry = VMCIHashTableGetEntryLocked(table, handle);
-   VMCI_ReleaseLock(&table->lock, flags);
+   VMCIHashTableReleaseLock(&table->lock, flags);
 
    return entry;
 }
 
 
+/*
+ *------------------------------------------------------------------------------
+ *
+ *  VMCIHashTable_HoldEntry --
+ *
+ *     Hold the given entry.  This will increment the entry's reference count.
+ *     This is like a GetEntry() but without having to lookup the entry by
+ *     handle.
+ *
+ *  Result:
+ *     None.
+ *
+ *  Side effects:
+ *     None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+void
+VMCIHashTable_HoldEntry(VMCIHashTable *table, // IN
+                        VMCIHashEntry *entry) // IN/OUT
+{
+   VMCILockFlags flags;
+
+   ASSERT(table);
+   ASSERT(entry);
+
+   VMCIHashTableGrabLock(&table->lock, &flags);
+   entry->refCount++;
+   VMCIHashTableReleaseLock(&table->lock, flags);
+}
+
+
 /*
  *------------------------------------------------------------------------------
  *
@@ -377,7 +421,7 @@ VMCIHashTableReleaseEntryLocked(VMCIHashTable *table,  // IN
 
    entry->refCount--;
    /* Check if this is last reference and report if so. */
-   if (entry->refCount == 0) { 
+   if (entry->refCount == 0) {
 
       /*
        * Remove entry from hash table if not already removed. This could have
@@ -417,9 +461,9 @@ VMCIHashTable_ReleaseEntry(VMCIHashTable *table,  // IN
    int result;
 
    ASSERT(table);
-   VMCI_GrabLock(&table->lock, &flags);
+   VMCIHashTableGrabLock(&table->lock, &flags);
    result = VMCIHashTableReleaseEntryLocked(table, entry);
-   VMCI_ReleaseLock(&table->lock, flags);
+   VMCIHashTableReleaseLock(&table->lock, flags);
 
    return result;
 }
@@ -450,9 +494,9 @@ VMCIHashTable_EntryExists(VMCIHashTable *table,  // IN
 
    ASSERT(table);
 
-   VMCI_GrabLock(&table->lock, &flags);
+   VMCIHashTableGrabLock(&table->lock, &flags);
    exists = VMCIHashTableEntryExistsLocked(table, handle);
-   VMCI_ReleaseLock(&table->lock, flags);
+   VMCIHashTableReleaseLock(&table->lock, flags);
 
    return exists;
 }
@@ -576,6 +620,6 @@ VMCIHashTable_Sync(VMCIHashTable *table)
 {
    VMCILockFlags flags;
    ASSERT(table);
-   VMCI_GrabLock(&table->lock, &flags);
-   VMCI_ReleaseLock(&table->lock, flags);
+   VMCIHashTableGrabLock(&table->lock, &flags);
+   VMCIHashTableReleaseLock(&table->lock, flags);
 }
index c1e062fdfda5ce9d2d56b26b7bf12ab840dd31d1..a786818ead47934e196c3420ed2c9fdcbcc63224 100644 (file)
@@ -52,6 +52,7 @@ void VMCIHashTable_InitEntry(VMCIHashEntry *entry, VMCIHandle handle);
 int VMCIHashTable_AddEntry(VMCIHashTable *table, VMCIHashEntry *entry);
 int VMCIHashTable_RemoveEntry(VMCIHashTable *table, VMCIHashEntry *entry);
 VMCIHashEntry *VMCIHashTable_GetEntry(VMCIHashTable *table, VMCIHandle handle);
+void VMCIHashTable_HoldEntry(VMCIHashTable *table, VMCIHashEntry *entry);
 int VMCIHashTable_ReleaseEntry(VMCIHashTable *table, VMCIHashEntry *entry);
 Bool VMCIHashTable_EntryExists(VMCIHashTable *table, VMCIHandle handle);
 void VMCIHashTable_Sync(VMCIHashTable *table);
diff --git a/open-vm-tools/modules/linux/vmci/vmciNotifications.c b/open-vm-tools/modules/linux/vmci/vmciNotifications.c
deleted file mode 100644 (file)
index b16a448..0000000
+++ /dev/null
@@ -1,1203 +0,0 @@
-/*********************************************************
- * Copyright (C) 2010 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- *********************************************************/
-
-/*
- * vmciNotifications.c --
- *
- *      Implementation of the VMCI notifications registration and
- *      delivery, and the related doorbell API for the guest driver.
- */
-
-#ifdef __linux__
-#  include "driver-config.h"
-#  include "compat_kernel.h"
-#  include "compat_module.h"
-#endif // linux
-
-#include "vmci_kernel_if.h"
-#include "vm_basic_types.h"
-#include "vm_assert.h"
-#include "vmciKernelAPI.h"
-#include "vmci_defs.h"
-#include "vmci_call_defs.h"
-#include "vmciInt.h"
-#include "vmciUtil.h"
-
-#define LGPFX "VMCINotifications: "
-
-#if !defined(SOLARIS) && !defined(__APPLE__)
-
-/*
- * The VMCI Notify hash table provides two mappings:
- * 1) one maps a given notification index in the bitmap to the
- *    entries, giving the set of handlers registered for that
- *    index. This is mainly used for firing handlers for a given
- *    bitmap index.
- * 2) the other maps a handle and a resource (doorbell/queuepair)
- *    to the entry (used to check for duplicates and delete the
- *    entry)
- */
-
-#define HASH_TABLE_SIZE 64
-#define VMCI_NOTIF_HASH(val) VMCI_HashId(val, HASH_TABLE_SIZE)
-
-typedef struct VMCINotifyHashEntry {
-   uint32         idx; // Bitmap index
-   VMCIHandle     handle;
-   Bool           doorbell;
-   Bool           runDelayed;
-   VMCICallback   notifyCB;
-   void          *callbackData;
-   VMCIEvent      destroyEvent;
-   int            refCount;
-   VMCIListItem   handleListItem;
-   VMCIListItem   idxListItem;
-} VMCINotifyHashEntry;
-
-typedef struct VMCINotifyHashTable {
-   VMCILock lock;
-   VMCIList entriesByIdx[HASH_TABLE_SIZE];
-   VMCIList entriesByHandle[HASH_TABLE_SIZE];
-} VMCINotifyHashTable;
-
-
-static int VMCINotifyHashAddEntry(VMCINotifyHashEntry *entry);
-static void VMCINotifyHashSetEntryCallback(VMCINotifyHashEntry *entry,
-                                           VMCICallback notifyCB);
-static VMCINotifyHashEntry *VMCINotifyHashRemoveEntry(VMCIHandle handle,
-                                                      Bool doorbell);
-static int VMCINotifyReleaseCB(void *clientData);
-static void VMCINotifyHashReleaseEntry(VMCINotifyHashEntry *entry);
-static VMCINotifyHashEntry *VMCINotifyHashFindByIdx(uint32 idx,
-                                                    uint32 *hashBucket);
-static VMCINotifyHashEntry *VMCINotifyHashFindByHandle(VMCIHandle handle,
-                                                       Bool doorbell,
-                                                       uint32 *hashBucket);
-
-static void VMCINotifyDelayedDispatchCB(void *data);
-static void VMCINotifyHashFireEntries(uint32 notifyIdx);
-
-static int LinkNotificationHypercall(VMCIHandle handle, Bool doorbell,
-                                     uint32 notifyIdx);
-static int UnlinkNotificationHypercall(VMCIHandle handle, Bool doorbell);
-
-
-/*
- * The VMCI notify hash table keeps track of currently registered
- * notifications.
- */
-
-static VMCINotifyHashTable vmciNotifyHT;
-
-/*
- * The maxNotifyIdx is one larger than the currently known bitmap
- * index in use, and is used to determine how much of the bitmap needs
- * to be scanned.
- */
-
-static uint32 maxNotifyIdx;
-
-/*
- * the notifyIdxCount is used for determining whether there are free
- * entries within the bitmap (if notifyIdxCount + 1 < maxNotifyIdx).
- */
-
-static uint32 notifyIdxCount;
-
-/*
- * The lastNotifyIdxReserved is used to track the last index handed
- * out - in the case where multiple handles share a notification
- * index, we hand out indexes round robin based on
- * lastNotifyIdxReserved.
- */
-
-static uint32 lastNotifyIdxReserved;
-
-/*
- * lastNotifyIdxReleased is a one entry cache used to by the index
- * allocation.
- */
-
-static uint32 lastNotifyIdxReleased = PAGE_SIZE;
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCINotifications_Init --
- *
- *      General init code.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCINotifications_Init(void)
-{
-   int i;
-
-   for (i = 0; i < ARRAY_SIZE(vmciNotifyHT.entriesByIdx); i++) {
-      VMCIList_Init(&vmciNotifyHT.entriesByIdx[i]);
-   }
-   for (i = 0; i < ARRAY_SIZE(vmciNotifyHT.entriesByHandle); i++) {
-      VMCIList_Init(&vmciNotifyHT.entriesByHandle[i]);
-   }
-
-   VMCI_InitLock(&vmciNotifyHT.lock, "VMCINotifyHashLock",
-                 VMCI_LOCK_RANK_HIGHER_BH);
-   return;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCINotifications_Exit --
- *
- *    General exit code.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCINotifications_Exit(void)
-{
-   uint32 bucket;
-   VMCIListItem *iter, *iter2;
-
-   for (bucket = 0; bucket < HASH_TABLE_SIZE; bucket++) {
-      VMCIList_ScanSafe(iter, iter2, &vmciNotifyHT.entriesByIdx[bucket]) {
-         VMCINotifyHashEntry *cur;
-
-         /*
-          * We should never get here because all notifications should have been
-          * unregistered before we try to unload the driver module.
-          * Also, delayed callbacks could still be firing so this cleanup
-          * would not be safe.
-          * Still it is better to free the memory than not ... so we
-          * leave this code in just in case....
-          *
-          */
-         ASSERT(FALSE);
-
-         cur = VMCIList_Entry(iter, VMCINotifyHashEntry, idxListItem);
-         VMCI_FreeKernelMem(cur, sizeof *cur);
-      }
-   }
-   VMCI_CleanupLock(&vmciNotifyHT.lock);
-
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCINotifications_Sync --
- *
- *      Use this as a synchronization point when setting globals, for example,
- *      during device shutdown.
- *
- * Results:
- *      TRUE.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCINotifications_Sync(void)
-{
-   VMCILockFlags flags;
-   VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
-   VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCINotifications_Hibernate --
- *
- *    When a guest leaves hibernation, the device driver state is out
- *    of sync with the device state, since the driver state has
- *    doorbells registered that aren't known to the device. This
- *    function takes care of reregistering any doorbells. In case an
- *    error occurs during reregistration (this is highly unlikely
- *    since 1) it succeeded the first time 2) the device driver is the
- *    only source of doorbell registrations), we simply log the
- *    error. The doorbell can still be destroyed using
- *    VMCIDoorbell_Destroy.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCINotifications_Hibernate(Bool enterHibernate)  // IN
-{
-   VMCILockFlags flags;
-   uint32 bucket;
-   VMCIListItem *iter;
-
-   if (enterHibernate) {
-      /*
-       * Nothing to do when entering hibernation.
-       */
-
-      return;
-   }
-
-   VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
-
-   for (bucket = 0; bucket < HASH_TABLE_SIZE; bucket++) {
-      VMCIList_Scan(iter, &vmciNotifyHT.entriesByIdx[bucket]) {
-         VMCINotifyHashEntry *cur;
-         int result;
-
-         cur = VMCIList_Entry(iter, VMCINotifyHashEntry, idxListItem);
-         result = LinkNotificationHypercall(cur->handle, cur->doorbell, cur->idx);
-         if (result != VMCI_SUCCESS && result != VMCI_ERROR_DUPLICATE_ENTRY) {
-            VMCI_WARNING((LGPFX"Failed to reregister doorbell (handle=0x%x:0x%x) "
-                          "of resource %s to index (error=%d).\n",
-                          cur->handle.context, cur->handle.resource,
-                          cur->doorbell ? "doorbell" : "queue pair", result));
-         }
-      }
-   }
-
-   VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags);
-}
-
-
-/*
- *-------------------------------------------------------------------------
- *
- * VMCINotifyHashAddEntry --
- *
- *     Given a notification entry, adds it to the hashtable of
- *     notifications.
- *
- * Result:
- *     VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- *     None.
- *
- *-------------------------------------------------------------------------
- */
-
-static int
-VMCINotifyHashAddEntry(VMCINotifyHashEntry *entry) // IN
-{
-   VMCILockFlags flags;
-   uint32 bucket;
-   uint32 newNotifyIdx;
-   int result;
-   static VMCIId notifyRID = 0;
-
-   ASSERT(entry);
-
-   VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
-
-   /* Do not allow addition of a new handle if the device is being shutdown. */
-   if (VMCI_DeviceShutdown()) {
-      result = VMCI_ERROR_DEVICE_NOT_FOUND;
-      goto out;
-   }
-
-   if (VMCI_HANDLE_INVALID(entry->handle)) {
-      VMCIHandle newHandle;
-      VMCIId oldRID = notifyRID;
-      Bool found;
-
-      do {
-         newHandle = VMCI_MAKE_HANDLE(VMCI_GetContextID(), notifyRID);
-         notifyRID++;
-         found = VMCINotifyHashFindByHandle(newHandle, entry->doorbell, NULL) != NULL;
-      } while(found && oldRID != notifyRID);
-      if (UNLIKELY(found)) {
-         /*
-          * We went full circle and still didn't find a free handle.
-          */
-
-         result = VMCI_ERROR_NO_HANDLE;
-         goto out;
-      }
-      entry->handle = newHandle;
-   } else if (VMCI_GetContextID() != entry->handle.context) {
-      /*
-       * The context id passed down should either be invalid or
-       * the context id of the guest.
-       */
-
-      result = VMCI_ERROR_INVALID_ARGS;
-      goto out;
-   }
-
-   if (VMCINotifyHashFindByHandle(entry->handle, entry->doorbell, &bucket)) {
-      result = VMCI_ERROR_ALREADY_EXISTS;
-      goto out;
-   }
-   VMCIList_Insert(&entry->handleListItem,
-                   &vmciNotifyHT.entriesByHandle[bucket]);
-
-   /*
-    * Below we try to allocate an index in the notification bitmap
-    * with "not too much" sharing between resources. If we use less
-    * that the full bitmap, we either add to the end if there are no
-    * unused flags withing the currently used area, or we search for
-    * unused ones. If we use the full bitmap, we allocate the index
-    * round robin.
-    */
-
-   if (maxNotifyIdx < PAGE_SIZE || notifyIdxCount < PAGE_SIZE) {
-      if (lastNotifyIdxReleased < maxNotifyIdx &&
-          !VMCINotifyHashFindByIdx(lastNotifyIdxReleased, NULL)) {
-         newNotifyIdx = lastNotifyIdxReleased;
-         lastNotifyIdxReleased = PAGE_SIZE;
-      } else {
-         Bool reused = FALSE;
-         newNotifyIdx = lastNotifyIdxReserved;
-         if (notifyIdxCount + 1 < maxNotifyIdx) {
-            do {
-               if (!VMCINotifyHashFindByIdx(newNotifyIdx, NULL)) {
-                  reused = TRUE;
-                  break;
-               }
-               newNotifyIdx = (newNotifyIdx + 1) % maxNotifyIdx;
-            } while(newNotifyIdx != lastNotifyIdxReleased);
-         }
-         if (!reused) {
-            newNotifyIdx = maxNotifyIdx;
-            maxNotifyIdx++;
-         }
-      }
-   } else {
-      newNotifyIdx = (lastNotifyIdxReserved + 1) % PAGE_SIZE;
-   }
-   lastNotifyIdxReserved = newNotifyIdx;
-   notifyIdxCount++;
-
-   bucket = VMCI_NOTIF_HASH(newNotifyIdx);
-   entry->refCount++;
-   entry->idx = newNotifyIdx;
-   VMCIList_Insert(&entry->idxListItem, &vmciNotifyHT.entriesByIdx[bucket]);
-   result = VMCI_SUCCESS;
-out:
-   VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags);
-   return result;
-}
-
-
-/*
- *-------------------------------------------------------------------------
- *
- * VMCINotifyHashSetEntryCallback --
- *
- *     Sets the notify callback of the given entry. Once the callback
- *     has been set, it may start firing.
- *
- * Result:
- *     None.
- *
- * Side effects:
- *     None.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-VMCINotifyHashSetEntryCallback(VMCINotifyHashEntry *entry, // IN
-                               VMCICallback notifyCB)      // IN
-{
-   VMCILockFlags flags;
-
-   ASSERT(entry && notifyCB);
-
-   VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
-   entry->notifyCB = notifyCB;
-   VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags);
-}
-
-
-/*
- *-------------------------------------------------------------------------
- *
- * VMCINotifyHashRemoveEntry --
- *
- *     Removes the entry identified by the handle of the given
- *     resource type from the hash table.
- *
- * Result:
- *     Pointer to entry if removed, NULL if not found.
- *
- * Side effects:
- *     None.
- *
- *-------------------------------------------------------------------------
- */
-
-static VMCINotifyHashEntry *
-VMCINotifyHashRemoveEntry(VMCIHandle handle, // IN
-                          Bool doorbell)     // IN
-{
-   VMCILockFlags flags;
-   VMCINotifyHashEntry *entry;
-   uint32 bucket;
-
-   VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
-   entry = VMCINotifyHashFindByHandle(handle, doorbell, &bucket);
-   if (entry) {
-      ASSERT(entry->refCount > 0);
-      VMCIList_Remove(&entry->handleListItem,
-                      &vmciNotifyHT.entriesByHandle[bucket]);
-      bucket = VMCI_NOTIF_HASH(entry->idx);
-      VMCIList_Remove(&entry->idxListItem, &vmciNotifyHT.entriesByIdx[bucket]);
-      notifyIdxCount--;
-      if (entry->idx == maxNotifyIdx - 1) {
-         /*
-          * If we delete an entry with the maximum known notification
-          * index, we take the opportunity to prune the current
-          * max. As there might be other unused indices immediately
-          * below, we lower the maximum until we hit an index in use.
-          */
-
-         while (maxNotifyIdx > 0 &&
-                !VMCINotifyHashFindByIdx(maxNotifyIdx - 1, NULL)) {
-            maxNotifyIdx--;
-         }
-      }
-      lastNotifyIdxReleased = entry->idx;
-   }
-   VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags);
-
-   return entry;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCINotifyReleaseCB --
- *
- *     Callback to release the notification entry reference. It is
- *     called by the VMCI_WaitOnEvent function before it blocks.
- *
- * Result:
- *     0.
- *
- * Side effects:
- *     Releases hash entry (see below).
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCINotifyReleaseCB(void *clientData) // IN
-{
-   VMCINotifyHashEntry *entry = (VMCINotifyHashEntry *)clientData;
-   ASSERT(entry);
-   VMCINotifyHashReleaseEntry(entry);
-
-   return 0;
-}
-
-
-/*
- *-------------------------------------------------------------------------
- *
- * VMCINotifyHashReleaseEntry --
- *
- *     Drops a reference to the current hash entry. If this is the last
- *     reference then the entry is freed.
- *
- * Result:
- *     None.
- *
- * Side effects:
- *     May signal event.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-VMCINotifyHashReleaseEntry(VMCINotifyHashEntry *entry) // IN
-{
-   VMCILockFlags flags;
-
-   VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
-   entry->refCount--;
-
-   /*
-    * Check if this is last reference and signal the destroy event if
-    * so.
-    */
-
-   if (entry->refCount == 0) {
-      VMCI_SignalEvent(&entry->destroyEvent);
-   }
-   VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCINotifyHashFindByIdx --
- *
- *    Find hash entry by bitmap index. Assumes lock is
- *    held. Regardless of whether an entry was found, the bucket that
- *    the entry would have been in is returned in hashBucket (if
- *    valid).
- *
- * Results:
- *    Entry if found, NULL if not.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static VMCINotifyHashEntry *
-VMCINotifyHashFindByIdx(uint32 idx,         // IN
-                        uint32 *hashBucket) // IN/OUT: hash value for idx
-{
-   VMCIListItem *iter;
-   uint32 bucket = VMCI_NOTIF_HASH(idx);
-
-   if (hashBucket) {
-      *hashBucket = bucket;
-   }
-
-   VMCIList_Scan(iter, &vmciNotifyHT.entriesByIdx[bucket]) {
-      VMCINotifyHashEntry *cur =
-         VMCIList_Entry(iter, VMCINotifyHashEntry, idxListItem);
-      if (cur->idx == idx) {
-         return cur;
-      }
-   }
-   return NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCINotifyHashFindByHandle --
- *
- *    Find hash entry by handle and resoruce. Assumes lock is
- *    held. Regardless of whether an entry was found, the bucket that
- *    the entry would have been in is returned in hashBucket (if
- *    valid).
- *
- * Results:
- *    Entry if found, NULL if not.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static VMCINotifyHashEntry *
-VMCINotifyHashFindByHandle(VMCIHandle handle,  // IN
-                           Bool doorbell,      // IN
-                           uint32 *hashBucket) // IN/OUT: hash value for handle
-{
-   VMCIListItem *iter;
-   uint32 bucket = VMCI_NOTIF_HASH(handle.resource);
-
-   if (hashBucket) {
-      *hashBucket = bucket;
-   }
-
-   VMCIList_Scan(iter, &vmciNotifyHT.entriesByHandle[bucket]) {
-      VMCINotifyHashEntry *cur =
-         VMCIList_Entry(iter, VMCINotifyHashEntry, handleListItem);
-      if (VMCI_HANDLE_EQUAL(cur->handle, handle) && cur->doorbell == doorbell) {
-         return cur;
-      }
-   }
-   return NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCINotifyDelayedDispatchCB --
- *
- *      Calls the specified callback in a delayed context.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCINotifyDelayedDispatchCB(void *data) // IN
-{
-   VMCINotifyHashEntry *entry = (VMCINotifyHashEntry *)data;
-
-   ASSERT(data);
-
-   entry->notifyCB(entry->callbackData);
-
-   VMCINotifyHashReleaseEntry(entry);
-}
-
-
-/*
- *-------------------------------------------------------------------------
- *
- * VMCINotifyHashFireEntries --
- *
- *     Executes or schedules the handlers for a given notify index.
- *
- * Result:
- *     Notification hash entry if found. NULL otherwise.
- *
- * Side effects:
- *     Whatever the side effects of the handlers are.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-VMCINotifyHashFireEntries(uint32 notifyIdx) // IN
-{
-   VMCILockFlags flags;
-   VMCIListItem *iter;
-   int bucket = VMCI_NOTIF_HASH(notifyIdx);
-
-   VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags);
-
-   VMCIList_Scan(iter, &vmciNotifyHT.entriesByIdx[bucket]) {
-      VMCINotifyHashEntry *cur = VMCIList_Entry(iter, VMCINotifyHashEntry,
-                                                idxListItem);
-      if (cur->idx == notifyIdx && cur->notifyCB) {
-         if (cur->runDelayed) {
-            int err;
-
-            cur->refCount++;
-            err = VMCI_ScheduleDelayedWork(VMCINotifyDelayedDispatchCB, cur);
-            if (err != VMCI_SUCCESS) {
-               cur->refCount--;
-               goto out;
-            }
-         } else {
-            cur->notifyCB(cur->callbackData);
-         }
-      }
-   }
-out:
-   VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * LinkNotificationHypercall --
- *
- *    Creates a link between the given doorbell handle and the given
- *    index in the bitmap in the device backend.
- *
- * Results:
- *    VMCI_SUCCESS if success, appropriate error code otherwise.
- *
- * Side effects:
- *    Notification state is created in hypervisor.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-LinkNotificationHypercall(VMCIHandle handle,  // IN
-                          Bool doorbell,      // IN
-                          uint32 notifyIdx)   // IN
-{
-   VMCIDoorbellLinkMsg linkMsg;
-   int result;
-   VMCIId resourceID;
-
-   ASSERT(!VMCI_HANDLE_INVALID(handle));
-
-   if (doorbell) {
-      resourceID = VMCI_DOORBELL_LINK;
-   } else {
-      ASSERT(FALSE);
-      return VMCI_ERROR_UNAVAILABLE;
-   }
-
-   linkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID);
-   linkMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
-   linkMsg.hdr.payloadSize = sizeof linkMsg - VMCI_DG_HEADERSIZE;
-   linkMsg.handle = handle;
-   linkMsg.notifyIdx = notifyIdx;
-
-   result = VMCI_SendDatagram((VMCIDatagram *)&linkMsg);
-
-   return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * UnlinkNotificationHypercall --
- *
- *    Unlinks the given doorbell handle from an index in the bitmap in
- *    the device backend.
- *
- * Results:
- *      VMCI_SUCCESS if success, appropriate error code otherwise.
- *
- * Side effects:
- *      Notification state is destroyed in hypervisor.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-UnlinkNotificationHypercall(VMCIHandle handle, // IN
-                            Bool doorbell)     // IN
-{
-   VMCIDoorbellUnlinkMsg unlinkMsg;
-   int result;
-   VMCIId resourceID;
-
-   ASSERT(!VMCI_HANDLE_INVALID(handle));
-
-   if (doorbell) {
-      resourceID = VMCI_DOORBELL_UNLINK;
-   } else {
-      ASSERT(FALSE);
-      return VMCI_ERROR_UNAVAILABLE;
-   }
-
-   unlinkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID);
-   unlinkMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
-   unlinkMsg.hdr.payloadSize = sizeof unlinkMsg - VMCI_DG_HEADERSIZE;
-   unlinkMsg.handle = handle;
-
-   result = VMCI_SendDatagram((VMCIDatagram *)&unlinkMsg);
-
-   return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCINotificationRegister --
- *
- *      Links a resource with an index in the notification bitmap.
- *
- * Results:
- *      VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- *      Notification state is created both in guest and on host.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCINotificationRegister(VMCIHandle *handle,     // IN
-                         Bool doorbell,          // IN
-                         uint32 flags,           // IN
-                         VMCICallback notifyCB,  // IN
-                         void *callbackData)     // IN
-{
-   int result;
-   VMCINotifyHashEntry *entry;
-
-   if (!notifyCB || !handle) {
-      return VMCI_ERROR_INVALID_ARGS;
-   }
-
-   entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED);
-   if (entry == NULL) {
-      return VMCI_ERROR_NO_MEM;
-   }
-
-   entry->runDelayed = (flags & VMCI_FLAG_DELAYED_CB) ? TRUE : FALSE;
-   if (entry->runDelayed && !VMCI_CanScheduleDelayedWork()) {
-      VMCI_FreeKernelMem(entry, sizeof *entry);
-      return VMCI_ERROR_INVALID_ARGS;
-   }
-
-   /*
-    * Reserve an index in the notification bitmap.
-    */
-
-   entry->handle = *handle;
-   entry->doorbell = doorbell;
-   entry->notifyCB = NULL; // Wait with this until link is established in hypervisor
-   entry->callbackData = callbackData;
-   entry->refCount = 0;
-   VMCIList_InitEntry(&entry->handleListItem);
-   VMCIList_InitEntry(&entry->idxListItem);
-   result = VMCINotifyHashAddEntry(entry);
-   if (result != VMCI_SUCCESS) {
-      VMCI_FreeKernelMem(entry, sizeof *entry);
-      return result;
-   }
-
-   VMCI_CreateEvent(&entry->destroyEvent);
-
-   result = LinkNotificationHypercall(entry->handle, doorbell, entry->idx);
-   if (result != VMCI_SUCCESS) {
-      VMCI_DEBUG_LOG(4, (LGPFX"Failed to link (handle=0x%x:0x%x) of resource %s "
-                         "to index (error=%d).\n",
-                         entry->handle.context, entry->handle.resource,
-                         entry->doorbell ? "doorbell" : "queue pair", result));
-      VMCINotifyHashRemoveEntry(entry->handle, entry->doorbell);
-      VMCI_DestroyEvent(&entry->destroyEvent);
-      VMCI_FreeKernelMem(entry, sizeof *entry);
-   } else {
-      /*
-       * When the handle is set, the notification callback may start
-       * to fire. Since flags in the notification bitmap can be
-       * shared, a given callback may fire immediately.
-       */
-
-      VMCINotifyHashSetEntryCallback(entry, notifyCB);
-      *handle = entry->handle;
-   }
-
-   return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCINotificationUnregister --
- *
- *      Unregisters a notification previously created through
- *      VMCINotificationRegister. This function may block. The call
- *      always succeeds if the notification exists.
- *
- * Results:
- *      VMCI_SUCCESS if success, VMCI_ERROR_NOT_FOUND otherwise.
- *
- * Side effects:
- *      Notification state is destroyed both in guest and hypervisor.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCINotificationUnregister(VMCIHandle handle, // IN
-                           Bool doorbell)     // IN
-{
-   VMCINotifyHashEntry *entry;
-   int result;
-
-   entry = VMCINotifyHashRemoveEntry(handle, doorbell);
-   if (!entry) {
-      return VMCI_ERROR_NOT_FOUND;
-   }
-
-   VMCI_WaitOnEvent(&entry->destroyEvent, VMCINotifyReleaseCB, entry);
-   VMCI_DestroyEvent(&entry->destroyEvent);
-   VMCI_FreeKernelMem(entry, sizeof *entry);
-
-   result = UnlinkNotificationHypercall(handle, doorbell);
-   if (result != VMCI_SUCCESS) {
-      /*
-       * The only reason this should fail would be an inconsistency
-       * between guest and hypervisor state, where the guest believes
-       * it has an active registration whereas the hypervisor
-       * doesn't. One case where this may happen is if a doorbell is
-       * unregistered following a hibernation at a time where the
-       * doorbell state hasn't been restored on the hypervisor side
-       * yet. Since the handle has now been removed in the guest, we
-       * just print a warning and return success.
-       */
-
-      VMCI_DEBUG_LOG(4, (LGPFX"Unlink of %s (handle=0x%x:0x%x) unknown by "
-                         "hypervisor (error=%d).\n",
-                         doorbell ? "doorbell" : "queuepair",
-                         handle.context, handle.resource, result));
-   }
-   return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_RegisterNotificationBitmap --
- *
- *      Verify that the host supports the hypercalls we need. If it does not,
- *      try to find fallback hypercalls and use those instead.
- *
- * Results:
- *      TRUE if the bitmap is registered successfully with the device, FALSE
- *      otherwise.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCI_RegisterNotificationBitmap(PPN bitmapPPN) // IN
-{
-   VMCINotifyBitmapSetMsg bitmapSetMsg;
-   int result;
-
-   bitmapSetMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
-                                           VMCI_SET_NOTIFY_BITMAP);
-   bitmapSetMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
-   bitmapSetMsg.hdr.payloadSize = sizeof bitmapSetMsg - VMCI_DG_HEADERSIZE;
-   bitmapSetMsg.bitmapPPN = bitmapPPN;
-
-   result = VMCI_SendDatagram((VMCIDatagram *)&bitmapSetMsg);
-   if (result != VMCI_SUCCESS) {
-      VMCI_DEBUG_LOG(4, (LGPFX"Failed to register (PPN=%u) as "
-                         "notification bitmap (error=%d).\n",
-                         bitmapPPN, result));
-      return FALSE;
-   }
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_ScanNotificationBitmap --
- *
- *      Scans the notification bitmap, collects pending notifications,
- *      resets the bitmap and invokes appropriate callbacks.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      May schedule tasks, allocate memory and run callbacks.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_ScanNotificationBitmap(uint8 *bitmap) // IN
-{
-   size_t idx;
-
-   for (idx = 0; idx < maxNotifyIdx; idx++) {
-      if (bitmap[idx] & 0x1) {
-         bitmap[idx] &= ~1;
-         VMCINotifyHashFireEntries(idx);
-      }
-   }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDoorbell_Create --
- *
- *      Creates a doorbell with the given callback. If the handle is
- *      VMCI_INVALID_HANDLE, a free handle will be assigned, if
- *      possible. The callback can be run in interrupt context (the
- *      default) or delayed (in a kernel thread) by specifying the
- *      flag VMCI_FLAG_DELAYED_CB. If delayed execution is selected, a
- *      given callback may not be run if the kernel is unable to
- *      allocate memory for the delayed execution (highly unlikely).
- *
- * Results:
- *      VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create)
-int
-VMCIDoorbell_Create(VMCIHandle *handle,            // IN
-                    uint32 flags,                  // IN
-                    VMCIPrivilegeFlags privFlags,  // IN: Unused in guest
-                    VMCICallback notifyCB,         // IN
-                    void *clientData)              // IN
-{
-   if (!handle || !notifyCB || flags & ~VMCI_FLAG_DELAYED_CB) {
-      return VMCI_ERROR_INVALID_ARGS;
-   }
-   if (privFlags & ~VMCI_LEAST_PRIVILEGE_FLAGS) {
-      return VMCI_ERROR_NO_ACCESS;
-   }
-
-   return VMCINotificationRegister(handle, TRUE, flags,
-                                   notifyCB, clientData);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDoorbell_Destroy --
- *
- *      Destroys a doorbell previously created with
- *      VMCIDoorbell_Create. This operation may block waiting for a
- *      callback to finish.
- *
- * Results:
- *      VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- *      May block.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy)
-int
-VMCIDoorbell_Destroy(VMCIHandle handle) // IN
-{
-   if (VMCI_HANDLE_INVALID(handle)) {
-      return VMCI_ERROR_INVALID_ARGS;
-   }
-   return VMCINotificationUnregister(handle, TRUE);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDoorbell_Notify --
- *
- *      Generates a notification on the doorbell identified by the
- *      handle.
- *
- * Results:
- *      VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- *      May do a hypercall.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify)
-int
-VMCIDoorbell_Notify(VMCIHandle handle,             // IN
-                    VMCIPrivilegeFlags privFlags)  // IN: Unused in guest
-{
-   VMCIDoorbellNotifyMsg notifyMsg;
-   int result;
-
-   if (VMCI_HANDLE_INVALID(handle)) {
-      return VMCI_ERROR_INVALID_ARGS;
-   }
-
-   if (privFlags & ~VMCI_LEAST_PRIVILEGE_FLAGS) {
-      return VMCI_ERROR_NO_ACCESS;
-   }
-
-   notifyMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_DOORBELL_NOTIFY);
-   notifyMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
-   notifyMsg.hdr.payloadSize = sizeof notifyMsg - VMCI_DG_HEADERSIZE;
-   notifyMsg.handle = handle;
-
-   result = VMCI_SendDatagram((VMCIDatagram *)&notifyMsg);
-
-   return result;
-}
-
-
-#else // defined(SOLARIS) || defined(__APPLE__)
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDoorbell_Create/VMCIDoorbell_Destroy/VMCIDoorbell_Notify --
- *
- *      The doorbell functions have yet to be implemented for Solaris
- *      and Mac OS X guest drivers.
- *
- * Results:
- *      VMCI_ERROR_UNAVAILABLE.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create)
-int
-VMCIDoorbell_Create(VMCIHandle *handle,            // IN
-                    uint32 flags,                  // I
-                    VMCIPrivilegeFlags privFlags,  // IN
-                    VMCICallback notifyCB,         // IN
-                    void *clientData)              // IN
-{
-   return VMCI_ERROR_UNAVAILABLE;
-}
-
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy)
-int
-VMCIDoorbell_Destroy(VMCIHandle handle)  // IN
-{
-   return VMCI_ERROR_UNAVAILABLE;
-}
-
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify)
-int
-VMCIDoorbell_Notify(VMCIHandle handle,             // IN
-                    VMCIPrivilegeFlags privFlags)  // IN
-{
-   return VMCI_ERROR_UNAVAILABLE;
-}
-
-#endif
diff --git a/open-vm-tools/modules/linux/vmci/vmciNotifications.h b/open-vm-tools/modules/linux/vmci/vmciNotifications.h
deleted file mode 100644 (file)
index 43bc5d6..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*********************************************************
- * Copyright (C) 2010 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- *********************************************************/
-
-/*
- * vmciNotifications.h --
- *
- *     VMCI notifications API for OS device drivers.
- */
-
-#ifndef _VMCI_NOTIFICATIONS_H_
-#define _VMCI_NOTIFICATIONS_H_
-
-#include "vm_basic_types.h"
-#include "vmci_defs.h"
-#include "vmciKernelAPI.h"
-
-void VMCINotifications_Init(void);
-void VMCINotifications_Exit(void);
-void VMCINotifications_Sync(void);
-
-Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN);
-void VMCI_ScanNotificationBitmap(uint8 *bitmap);
-
-int VMCINotificationRegister(VMCIHandle *handle, Bool doorbell, uint32 flags,
-                             VMCICallback notifyCB, void *callbackData);
-int VMCINotificationUnregister(VMCIHandle handle, Bool doorbell);
-
-void VMCINotifications_Hibernate(Bool enterHibernation);
-
-#endif /* !_VMCI_NOTIFICATIONS_H_ */
-
index f8a9b286f3837b231ed1fd8dedf9f9d5378f51c1..2034b78cd1b9273fd2dd084a9efbc91f747d7e57 100644 (file)
@@ -60,12 +60,13 @@ static VMCIHashTable *resourceTable = NULL;
 /* Public Resource Access Control API. */
 
 /*
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  *
  * VMCIResource_Init --
  *
  *      Initializes the VMCI Resource Access Control API. Creates a hashtable
- *      to hold all resources, and registers vectors and callbacks for hypercalls.
+ *      to hold all resources, and registers vectors and callbacks for
+ *      hypercalls.
  *
  * Results:
  *      None.
@@ -73,7 +74,7 @@ static VMCIHashTable *resourceTable = NULL;
  * Side effects:
  *      None.
  *
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 int
@@ -92,7 +93,7 @@ VMCIResource_Init(void)
 
 
 /*
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  *
  * VMCIResource_Exit --
  *
@@ -104,7 +105,7 @@ VMCIResource_Init(void)
  * Side effects:
  *      None.
  *
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 void
@@ -120,7 +121,7 @@ VMCIResource_Exit(void)
 
 
 /*
- *-------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  *
  *  VMCIResource_GetID --
  *
@@ -134,7 +135,7 @@ VMCIResource_Exit(void)
  *     None.
  *
  *
- *-------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 VMCIId
@@ -178,7 +179,7 @@ VMCIResource_GetID(VMCIId contextID)
 
 
 /*
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  *
  * VMCIResource_Add --
  *
@@ -188,7 +189,7 @@ VMCIResource_GetID(VMCIId contextID)
  * Side effects:
  *      None.
  *
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 int
@@ -227,7 +228,7 @@ VMCIResource_Add(VMCIResource *resource,                // IN
 
 
 /*
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  *
  * VMCIResource_Remove --
  *
@@ -237,7 +238,7 @@ VMCIResource_Add(VMCIResource *resource,                // IN
  * Side effects:
  *      None.
  *
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 void
@@ -258,7 +259,7 @@ VMCIResource_Remove(VMCIHandle resourceHandle,     // IN:
 
 
 /*
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  *
  * VMCIResource_Get --
  *
@@ -268,7 +269,7 @@ VMCIResource_Remove(VMCIHandle resourceHandle,     // IN:
  * Side effects:
  *      None.
  *
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 VMCIResource *
@@ -281,7 +282,8 @@ VMCIResource_Get(VMCIHandle resourceHandle,     // IN
       return NULL;
    }
    resource = RESOURCE_CONTAINER(entry, VMCIResource, hashEntry);
-   if ((resourceType == VMCI_RESOURCE_TYPE_ANY) || (resource->type == resourceType)) {
+   if (resourceType == VMCI_RESOURCE_TYPE_ANY ||
+       resource->type == resourceType) {
       return resource;
    }
    VMCIHashTable_ReleaseEntry(resourceTable, entry);
@@ -290,7 +292,33 @@ VMCIResource_Get(VMCIHandle resourceHandle,     // IN
 
 
 /*
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
+ *
+ * VMCIResource_Hold --
+ *
+ *      Hold the given resource.  This will hold the hashtable entry.  This
+ *      is like doing a Get() but without having to lookup the resource by
+ *      handle.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+void
+VMCIResource_Hold(VMCIResource *resource)
+{
+   ASSERT(resource);
+   VMCIHashTable_HoldEntry(resourceTable, &resource->hashEntry);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
  *
  * VMCIResourceDoRemove --
  *
@@ -303,7 +331,7 @@ VMCIResource_Get(VMCIHandle resourceHandle,     // IN
  * Side effects:
  *      May deallocate memory and invoke a callback for the removed resource.
  *
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 static void INLINE
@@ -319,7 +347,7 @@ VMCIResourceDoRemove(VMCIResource *resource)
 
 
 /*
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  *
  * VMCIResource_Release --
  *
@@ -329,7 +357,7 @@ VMCIResourceDoRemove(VMCIResource *resource)
  * Side effects:
  *      resource's containerFreeCB will get called if last reference.
  *
- *-----------------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 int
@@ -353,7 +381,7 @@ VMCIResource_Release(VMCIResource *resource)
 
 
 /*
- *-----------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  *
  * VMCIResource_Sync --
  *
@@ -366,7 +394,7 @@ VMCIResource_Release(VMCIResource *resource)
  * Side effects:
  *      None.
  *
- *-----------------------------------------------------------------------------
+ *------------------------------------------------------------------------------
  */
 
 void
index d23f6c67745f64c80fca6f0a6d2e3728c9733937..c149d3bd0f89f5c37dc0a95774649f6030fce2a0 100644 (file)
@@ -72,6 +72,7 @@ void VMCIResource_Remove(VMCIHandle resourceHandle,
                          VMCIResourceType resourceType);
 VMCIResource *VMCIResource_Get(VMCIHandle resourceHandle,
                                VMCIResourceType resourceType);
+void VMCIResource_Hold(VMCIResource *resource);
 int VMCIResource_Release(VMCIResource *resource);
 
 
index 88aa2230ccc5e26b373af893826369eb4fc1f1f9..112337ee7eac05a8bb5b121580d0fae106871455 100644 (file)
@@ -112,7 +112,7 @@ VMCI_Route(VMCIHandle *src,       // IN/OUT
    if (fromGuest && hasHostDevice &&
        (VMCI_WELL_KNOWN_CONTEXT_ID == src->context ||
         VMCI_WELL_KNOWN_CONTEXT_ID == dst->context)) {
-      *route = VMCI_ROUTE_HOST_TO_GUEST;
+      *route = VMCI_ROUTE_AS_HOST;
       return VMCI_SUCCESS;
    }
 
@@ -138,7 +138,7 @@ VMCI_Route(VMCIHandle *src,       // IN/OUT
       }
 
       /* Send from local client down to the hypervisor. */
-      *route = VMCI_ROUTE_GUEST_TO_HYPERVISOR;
+      *route = VMCI_ROUTE_AS_GUEST;
       return VMCI_SUCCESS;
    }
 
@@ -159,7 +159,7 @@ VMCI_Route(VMCIHandle *src,       // IN/OUT
          }
 
          /* Send it from local client down to the host. */
-         *route = VMCI_ROUTE_GUEST_TO_HOST;
+         *route = VMCI_ROUTE_AS_GUEST;
          return VMCI_SUCCESS;
       }
 
@@ -186,7 +186,7 @@ VMCI_Route(VMCIHandle *src,       // IN/OUT
       }
 
       /* Route to local client. */
-      *route = VMCI_ROUTE_HOST_TO_SELF;
+      *route = VMCI_ROUTE_AS_HOST;
       return VMCI_SUCCESS;
    }
 
@@ -207,7 +207,7 @@ VMCI_Route(VMCIHandle *src,       // IN/OUT
          }
 
          /* Pass it up to the guest. */
-         *route = VMCI_ROUTE_HOST_TO_GUEST;
+         *route = VMCI_ROUTE_AS_HOST;
          return VMCI_SUCCESS;
       }
    }
@@ -231,7 +231,7 @@ VMCI_Route(VMCIHandle *src,       // IN/OUT
     * the other guest for us.
     */
 
-   *route = VMCI_ROUTE_GUEST_TO_HOST;
+   *route = VMCI_ROUTE_AS_GUEST;
    return VMCI_SUCCESS;
 }
 
@@ -258,11 +258,10 @@ VMCI_RouteString(VMCIRoute route) // IN
 {
    const char *vmciRouteStrings[] = {
       "none",
-      "host to self",
-      "host to guest",
-      "guest to host/hypervisor",
+      "as host",
+      "as guest",
    };
-   if (route >= VMCI_ROUTE_NONE && route <= VMCI_ROUTE_GUEST_TO_HYPERVISOR) {
+   if (route >= VMCI_ROUTE_NONE && route <= VMCI_ROUTE_AS_GUEST) {
       return vmciRouteStrings[route];
    }
    return "";
index b75f78a2c2a2fd287e752c176c7fe6edbd943a81..a5958622a685d7a51057aa8c02ddd4225ef1a96a 100644 (file)
 
 typedef enum {
    VMCI_ROUTE_NONE,
-   VMCI_ROUTE_HOST_TO_SELF,
-   VMCI_ROUTE_HOST_TO_GUEST,
-   VMCI_ROUTE_GUEST_TO_HOST,
-   VMCI_ROUTE_GUEST_TO_HYPERVISOR = VMCI_ROUTE_GUEST_TO_HOST
+   VMCI_ROUTE_AS_HOST,
+   VMCI_ROUTE_AS_GUEST,
 } VMCIRoute;
 
 
index 681d73670b0f6087d3f65d2774cd9c469b707391..dc49eb0320f87499b7378d90b5450d6cee40397c 100644 (file)
@@ -47,9 +47,9 @@
 #include "vmci_version.h"
 #include "vmciContext.h"
 #include "vmciDatagram.h"
+#include "vmciDoorbell.h"
 #include "vmciEvent.h"
 #include "vmciInt.h"
-#include "vmciNotifications.h"
 #include "vmciQueuePairInt.h"
 #include "vmciResource.h"
 #include "vmciUtil.h"
@@ -419,7 +419,7 @@ vmci_probe_device(struct pci_dev *pdev,           // IN: vmci PCI device
    VMCIDatagram_Init();
    VMCIEvent_Init();
    VMCIUtil_Init();
-   VMCINotifications_Init();
+   VMCIDoorbell_Init();
    VMCIQPGuestEndpoints_Init();
 
    /*
@@ -482,7 +482,7 @@ vmci_probe_device(struct pci_dev *pdev,           // IN: vmci PCI device
 
  components_exit:
    VMCIQPGuestEndpoints_Exit();
-   VMCINotifications_Exit();
+   VMCIDoorbell_Exit();
    VMCIUtil_Exit();
    VMCIEvent_Exit();
    VMCIContext_Exit();
@@ -562,7 +562,7 @@ vmci_remove_device(struct pci_dev* pdev)
 
    release_region(dev->ioaddr, dev->ioaddr_size);
    dev->enabled = FALSE;
-   VMCINotifications_Exit();
+   VMCIDoorbell_Exit();
    if (notification_bitmap) {
       vfree(notification_bitmap);
    }