root/sys/dev/vmware/vmci/vmci_defs.h
/*-
 * Copyright (c) 2018 VMware, Inc.
 *
 * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
 */

#ifndef _VMCI_DEFS_H_
#define _VMCI_DEFS_H_

#include <sys/types.h>
#include <machine/atomic.h>

#include "vmci_kernel_defs.h"

#pragma GCC diagnostic ignored "-Wcast-qual"

/* Register offsets. */
#define VMCI_STATUS_ADDR                0x00
#define VMCI_CONTROL_ADDR               0x04
#define VMCI_ICR_ADDR                   0x08
#define VMCI_IMR_ADDR                   0x0c
#define VMCI_DATA_OUT_ADDR              0x10
#define VMCI_DATA_IN_ADDR               0x14
#define VMCI_CAPS_ADDR                  0x18
#define VMCI_RESULT_LOW_ADDR            0x1c
#define VMCI_RESULT_HIGH_ADDR           0x20

/* Status register bits. */
#define VMCI_STATUS_INT_ON              0x1

/* Control register bits. */
#define VMCI_CONTROL_RESET              0x1
#define VMCI_CONTROL_INT_ENABLE         0x2
#define VMCI_CONTROL_INT_DISABLE        0x4

/* Capabilities register bits. */
#define VMCI_CAPS_HYPERCALL             0x1
#define VMCI_CAPS_GUESTCALL             0x2
#define VMCI_CAPS_DATAGRAM              0x4
#define VMCI_CAPS_NOTIFICATIONS         0x8

/* Interrupt Cause register bits. */
#define VMCI_ICR_DATAGRAM               0x1
#define VMCI_ICR_NOTIFICATION           0x2

/* Interrupt Mask register bits. */
#define VMCI_IMR_DATAGRAM               0x1
#define VMCI_IMR_NOTIFICATION           0x2

/* Interrupt type. */
typedef enum vmci_intr_type {
        VMCI_INTR_TYPE_INTX =   0,
        VMCI_INTR_TYPE_MSI =    1,
        VMCI_INTR_TYPE_MSIX =   2
} vmci_intr_type;

/*
 * Maximum MSI/MSI-X interrupt vectors in the device.
 */
#define VMCI_MAX_INTRS                  2

/*
 * Supported interrupt vectors. There is one for each ICR value above,
 * but here they indicate the position in the vector array/message ID.
 */
#define VMCI_INTR_DATAGRAM              0
#define VMCI_INTR_NOTIFICATION          1

/*
 * A single VMCI device has an upper limit of 128 MiB on the amount of
 * memory that can be used for queue pairs.
 */
#define VMCI_MAX_GUEST_QP_MEMORY        (128 * 1024 * 1024)

/*
 * We have a fixed set of resource IDs available in the VMX.
 * This allows us to have a very simple implementation since we statically
 * know how many will create datagram handles. If a new caller arrives and
 * we have run out of slots we can manually increment the maximum size of
 * available resource IDs.
 */

typedef uint32_t vmci_resource;

/* VMCI reserved hypervisor datagram resource IDs. */
#define VMCI_RESOURCES_QUERY            0
#define VMCI_GET_CONTEXT_ID             1
#define VMCI_SET_NOTIFY_BITMAP          2
#define VMCI_DOORBELL_LINK              3
#define VMCI_DOORBELL_UNLINK            4
#define VMCI_DOORBELL_NOTIFY            5
/*
 * VMCI_DATAGRAM_REQUEST_MAP and VMCI_DATAGRAM_REMOVE_MAP are
 * obsoleted by the removal of VM to VM communication.
 */
#define VMCI_DATAGRAM_REQUEST_MAP       6
#define VMCI_DATAGRAM_REMOVE_MAP        7
#define VMCI_EVENT_SUBSCRIBE            8
#define VMCI_EVENT_UNSUBSCRIBE          9
#define VMCI_QUEUEPAIR_ALLOC            10
#define VMCI_QUEUEPAIR_DETACH           11
/*
 * VMCI_VSOCK_VMX_LOOKUP was assigned to 12 for Fusion 3.0/3.1,
 * WS 7.0/7.1 and ESX 4.1
 */
#define VMCI_HGFS_TRANSPORT             13
#define VMCI_UNITY_PBRPC_REGISTER       14
/*
 * This resource is used for VMCI socket control packets sent to the
 * hypervisor (CID 0) because RID 1 is already reserved.
 */
#define VSOCK_PACKET_HYPERVISOR_RID     15
#define VMCI_RESOURCE_MAX               16
/*
 * The core VMCI device functionality only requires the resource IDs of
 * VMCI_QUEUEPAIR_DETACH and below.
 */
#define VMCI_CORE_DEVICE_RESOURCE_MAX   VMCI_QUEUEPAIR_DETACH

/*
 * VMCI reserved host datagram resource IDs.
 * vsock control channel has resource id 1.
 */
#define VMCI_DVFILTER_DATA_PATH_DATAGRAM        2

/* VMCI Ids. */
typedef uint32_t vmci_id;

struct vmci_id_range {
        int8_t  action; /* VMCI_FA_X, for use in filters. */
        vmci_id begin;  /* Beginning of range. */
        vmci_id end;    /* End of range. */
};

struct vmci_handle {
        vmci_id context;
        vmci_id resource;
};

static inline struct vmci_handle
VMCI_MAKE_HANDLE(vmci_id cid, vmci_id rid)
{
        struct vmci_handle h;

        h.context = cid;
        h.resource = rid;
        return (h);
}

#define VMCI_HANDLE_TO_CONTEXT_ID(_handle)                              \
        ((_handle).context)
#define VMCI_HANDLE_TO_RESOURCE_ID(_handle)                             \
        ((_handle).resource)
#define VMCI_HANDLE_EQUAL(_h1, _h2)                                     \
        ((_h1).context == (_h2).context && (_h1).resource == (_h2).resource)

#define VMCI_INVALID_ID                 0xFFFFFFFF
static const struct vmci_handle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID,
            VMCI_INVALID_ID};

#define VMCI_HANDLE_INVALID(_handle)                                    \
        VMCI_HANDLE_EQUAL((_handle), VMCI_INVALID_HANDLE)

/*
 * The below defines can be used to send anonymous requests.
 * This also indicates that no response is expected.
 */
#define VMCI_ANON_SRC_CONTEXT_ID                                        \
        VMCI_INVALID_ID
#define VMCI_ANON_SRC_RESOURCE_ID                                       \
        VMCI_INVALID_ID
#define VMCI_ANON_SRC_HANDLE                                            \
        VMCI_MAKE_HANDLE(VMCI_ANON_SRC_CONTEXT_ID,                      \
        VMCI_ANON_SRC_RESOURCE_ID)

/* The lowest 16 context ids are reserved for internal use. */
#define VMCI_RESERVED_CID_LIMIT         16

/*
 * Hypervisor context id, used for calling into hypervisor
 * supplied services from the VM.
 */
#define VMCI_HYPERVISOR_CONTEXT_ID      0

/*
 * Well-known context id, a logical context that contains a set of
 * well-known services. This context ID is now obsolete.
 */
#define VMCI_WELL_KNOWN_CONTEXT_ID      1

/*
 * Context ID used by host endpoints.
 */
#define VMCI_HOST_CONTEXT_ID            2
#define VMCI_HOST_CONTEXT_INVALID_EVENT ((uintptr_t)~0)

#define VMCI_CONTEXT_IS_VM(_cid)                                        \
        (VMCI_INVALID_ID != _cid && _cid > VMCI_HOST_CONTEXT_ID)

/*
 * The VMCI_CONTEXT_RESOURCE_ID is used together with VMCI_MAKE_HANDLE to make
 * handles that refer to a specific context.
 */
#define VMCI_CONTEXT_RESOURCE_ID        0

/*
 *------------------------------------------------------------------------------
 *
 * VMCI error codes.
 *
 *------------------------------------------------------------------------------
 */

#define VMCI_SUCCESS_QUEUEPAIR_ATTACH           5
#define VMCI_SUCCESS_QUEUEPAIR_CREATE           4
#define VMCI_SUCCESS_LAST_DETACH                3
#define VMCI_SUCCESS_ACCESS_GRANTED             2
#define VMCI_SUCCESS_ENTRY_DEAD                 1
#define VMCI_SUCCESS                            0LL
#define VMCI_ERROR_INVALID_RESOURCE             (-1)
#define VMCI_ERROR_INVALID_ARGS                 (-2)
#define VMCI_ERROR_NO_MEM                       (-3)
#define VMCI_ERROR_DATAGRAM_FAILED              (-4)
#define VMCI_ERROR_MORE_DATA                    (-5)
#define VMCI_ERROR_NO_MORE_DATAGRAMS            (-6)
#define VMCI_ERROR_NO_ACCESS                    (-7)
#define VMCI_ERROR_NO_HANDLE                    (-8)
#define VMCI_ERROR_DUPLICATE_ENTRY              (-9)
#define VMCI_ERROR_DST_UNREACHABLE              (-10)
#define VMCI_ERROR_PAYLOAD_TOO_LARGE            (-11)
#define VMCI_ERROR_INVALID_PRIV                 (-12)
#define VMCI_ERROR_GENERIC                      (-13)
#define VMCI_ERROR_PAGE_ALREADY_SHARED          (-14)
#define VMCI_ERROR_CANNOT_SHARE_PAGE            (-15)
#define VMCI_ERROR_CANNOT_UNSHARE_PAGE          (-16)
#define VMCI_ERROR_NO_PROCESS                   (-17)
#define VMCI_ERROR_NO_DATAGRAM                  (-18)
#define VMCI_ERROR_NO_RESOURCES                 (-19)
#define VMCI_ERROR_UNAVAILABLE                  (-20)
#define VMCI_ERROR_NOT_FOUND                    (-21)
#define VMCI_ERROR_ALREADY_EXISTS               (-22)
#define VMCI_ERROR_NOT_PAGE_ALIGNED             (-23)
#define VMCI_ERROR_INVALID_SIZE                 (-24)
#define VMCI_ERROR_REGION_ALREADY_SHARED        (-25)
#define VMCI_ERROR_TIMEOUT                      (-26)
#define VMCI_ERROR_DATAGRAM_INCOMPLETE          (-27)
#define VMCI_ERROR_INCORRECT_IRQL               (-28)
#define VMCI_ERROR_EVENT_UNKNOWN                (-29)
#define VMCI_ERROR_OBSOLETE                     (-30)
#define VMCI_ERROR_QUEUEPAIR_MISMATCH           (-31)
#define VMCI_ERROR_QUEUEPAIR_NOTSET             (-32)
#define VMCI_ERROR_QUEUEPAIR_NOTOWNER           (-33)
#define VMCI_ERROR_QUEUEPAIR_NOTATTACHED        (-34)
#define VMCI_ERROR_QUEUEPAIR_NOSPACE            (-35)
#define VMCI_ERROR_QUEUEPAIR_NODATA             (-36)
#define VMCI_ERROR_BUSMEM_INVALIDATION          (-37)
#define VMCI_ERROR_MODULE_NOT_LOADED            (-38)
#define VMCI_ERROR_DEVICE_NOT_FOUND             (-39)
#define VMCI_ERROR_QUEUEPAIR_NOT_READY          (-40)
#define VMCI_ERROR_WOULD_BLOCK                  (-41)

/* VMCI clients should return error code within this range */
#define VMCI_ERROR_CLIENT_MIN                   (-500)
#define VMCI_ERROR_CLIENT_MAX                   (-550)

/* Internal error codes. */
#define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT        (-1000)

#define VMCI_PATH_MAX                           256

/* VMCI reserved events. */
typedef uint32_t vmci_event_type;

#define VMCI_EVENT_CTX_ID_UPDATE        0       // Only applicable to guest
                                                // endpoints
#define VMCI_EVENT_CTX_REMOVED          1       // Applicable to guest and host
#define VMCI_EVENT_QP_RESUMED           2       // Only applicable to guest
                                                // endpoints
#define VMCI_EVENT_QP_PEER_ATTACH       3       // Applicable to guest, host
                                                // and VMX
#define VMCI_EVENT_QP_PEER_DETACH       4       // Applicable to guest, host
                                                // and VMX
#define VMCI_EVENT_MEM_ACCESS_ON        5       // Applicable to VMX and vmk. On
                                                // vmk, this event has the
                                                // Context payload type
#define VMCI_EVENT_MEM_ACCESS_OFF       6       // Applicable to VMX and vmk.
                                                // Same as above for the payload
                                                // type
#define VMCI_EVENT_GUEST_PAUSED         7       // Applicable to vmk. This
                                                // event has the Context
                                                // payload type
#define VMCI_EVENT_GUEST_UNPAUSED       8       // Applicable to vmk. Same as
                                                // above for the payload type.
#define VMCI_EVENT_MAX                  9

/*
 * Of the above events, a few are reserved for use in the VMX, and other
 * endpoints (guest and host kernel) should not use them. For the rest of the
 * events, we allow both host and guest endpoints to subscribe to them, to
 * maintain the same API for host and guest endpoints.
 */

#define VMCI_EVENT_VALID_VMX(_event)                                    \
        (_event == VMCI_EVENT_QP_PEER_ATTACH ||                         \
        _event == VMCI_EVENT_QP_PEER_DETACH ||                          \
        _event == VMCI_EVENT_MEM_ACCESS_ON ||                           \
        _event == VMCI_EVENT_MEM_ACCESS_OFF)

#define VMCI_EVENT_VALID(_event)                                        \
        (_event < VMCI_EVENT_MAX &&                                     \
        _event != VMCI_EVENT_MEM_ACCESS_ON &&                           \
        _event != VMCI_EVENT_MEM_ACCESS_OFF &&                          \
        _event != VMCI_EVENT_GUEST_PAUSED &&                            \
        _event != VMCI_EVENT_GUEST_UNPAUSED)

/* Reserved guest datagram resource ids. */
#define VMCI_EVENT_HANDLER              0

/*
 * VMCI coarse-grained privileges (per context or host process/endpoint. An
 * entity with the restricted flag is only allowed to interact with the
 * hypervisor and trusted entities.
 */
typedef uint32_t vmci_privilege_flags;

#define VMCI_PRIVILEGE_FLAG_RESTRICTED          0x01
#define VMCI_PRIVILEGE_FLAG_TRUSTED             0x02
#define VMCI_PRIVILEGE_ALL_FLAGS                                        \
        (VMCI_PRIVILEGE_FLAG_RESTRICTED | VMCI_PRIVILEGE_FLAG_TRUSTED)
#define VMCI_NO_PRIVILEGE_FLAGS                 0x00
#define VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS       VMCI_NO_PRIVILEGE_FLAGS
#define VMCI_LEAST_PRIVILEGE_FLAGS              VMCI_PRIVILEGE_FLAG_RESTRICTED
#define VMCI_MAX_PRIVILEGE_FLAGS                VMCI_PRIVILEGE_FLAG_TRUSTED

/* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
#define VMCI_RESERVED_RESOURCE_ID_MAX           1023

#define VMCI_DOMAIN_NAME_MAXLEN                 32

#define VMCI_LGPFX                              "vmci: "

/*
 * struct vmci_queue_header
 *
 * A Queue cannot stand by itself as designed. Each Queue's header contains a
 * pointer into itself (the producer_tail) and into its peer (consumer_head).
 * The reason for the separation is one of accessibility: Each end-point can
 * modify two things: where the next location to enqueue is within its produce_q
 * (producer_tail); and where the next dequeue location is in its consume_q
 * (consumer_head).
 *
 * An end-point cannot modify the pointers of its peer (guest to guest; NOTE
 * that in the host both queue headers are mapped r/w). But, each end-point
 * needs read access to both Queue header structures in order to determine how
 * much space is used (or left) in the Queue. This is because for an end-point
 * to know how full its produce_q is, it needs to use the consumer_head that
 * points into the produce_q but -that- consumer_head is in the Queue header
 * for that end-points consume_q.
 *
 * Thoroughly confused?  Sorry.
 *
 * producer_tail: the point to enqueue new entrants.  When you approach a line
 * in a store, for example, you walk up to the tail.
 *
 * consumer_head: the point in the queue from which the next element is
 * dequeued. In other words, who is next in line is he who is at the head of
 * the line.
 *
 * Also, producer_tail points to an empty byte in the Queue, whereas
 * consumer_head points to a valid byte of data (unless producer_tail ==
 * consumer_head in which case consumerHead does not point to a valid byte of
 * data).
 *
 * For a queue of buffer 'size' bytes, the tail and head pointers will be in
 * the range [0, size-1].
 *
 * If produce_q_header->producer_tail == consume_q_header->consumer_head then
 * the produce_q is empty.
 */
struct vmci_queue_header {
        /* All fields are 64bit and aligned. */
        struct vmci_handle      handle;         /* Identifier. */
        volatile uint64_t       producer_tail;  /* Offset in this queue. */
        volatile uint64_t       consumer_head;  /* Offset in peer queue. */
};

/*
 * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
 * size to be less than 4GB, and use 32bit atomic operations on the head and
 * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
 * is an atomic read-modify-write. This will cause traces to fire when a 32bit
 * consumer tries to read the producer's tail pointer, for example, because the
 * consumer has read-only access to the producer's tail pointer.
 *
 * We provide the following macros to invoke 32bit or 64bit atomic operations
 * based on the architecture the code is being compiled on.
 */

#ifdef __x86_64__
#define QP_MAX_QUEUE_SIZE_ARCH          CONST64U(0xffffffffffffffff)
#define qp_atomic_read_offset(x)        atomic_load_64(x)
#define qp_atomic_write_offset(x, y)    atomic_store_64(x, y)
#else /* __x86_64__ */
        /*
         * Wrappers below are being used because atomic_store_<type> operates
         * on a specific <type>. Likewise for atomic_load_<type>
         */

        static inline uint32_t
        type_safe_atomic_read_32(void *var)
        {
                return (atomic_load_32((volatile uint32_t *)(var)));
        }

        static inline void
        type_safe_atomic_write_32(void *var, uint32_t val)
        {
                atomic_store_32((volatile uint32_t *)(var), (uint32_t)(val));
        }

#define QP_MAX_QUEUE_SIZE_ARCH          CONST64U(0xffffffff)
#define qp_atomic_read_offset(x)        type_safe_atomic_read_32((void *)(x))
#define qp_atomic_write_offset(x, y)                                    \
        type_safe_atomic_write_32((void *)(x), (uint32_t)(y))
#endif /* __x86_64__ */

/*
 *------------------------------------------------------------------------------
 *
 * qp_add_pointer --
 *
 *     Helper to add a given offset to a head or tail pointer. Wraps the value
 *     of the pointer around the max size of the queue.
 *
 * Results:
 *     None.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline void
qp_add_pointer(volatile uint64_t *var, size_t add, uint64_t size)
{
        uint64_t new_val = qp_atomic_read_offset(var);

        if (new_val >= size - add)
                new_val -= size;

        new_val += add;
        qp_atomic_write_offset(var, new_val);
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_producer_tail --
 *
 *     Helper routine to get the Producer Tail from the supplied queue.
 *
 * Results:
 *     The contents of the queue's producer tail.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline uint64_t
vmci_queue_header_producer_tail(const struct vmci_queue_header *q_header)
{
        struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header;
        return (qp_atomic_read_offset(&qh->producer_tail));
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_consumer_head --
 *
 *     Helper routine to get the Consumer Head from the supplied queue.
 *
 * Results:
 *     The contents of the queue's consumer tail.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline uint64_t
vmci_queue_header_consumer_head(const struct vmci_queue_header *q_header)
{
        struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header;
        return (qp_atomic_read_offset(&qh->consumer_head));
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_add_producer_tail --
 *
 *     Helper routine to increment the Producer Tail. Fundamentally,
 *     qp_add_pointer() is used to manipulate the tail itself.
 *
 * Results:
 *     None.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline void
vmci_queue_header_add_producer_tail(struct vmci_queue_header *q_header,
    size_t add, uint64_t queue_size)
{

        qp_add_pointer(&q_header->producer_tail, add, queue_size);
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_add_consumer_head --
 *
 *     Helper routine to increment the Consumer Head. Fundamentally,
 *     qp_add_pointer() is used to manipulate the head itself.
 *
 * Results:
 *     None.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline void
vmci_queue_header_add_consumer_head(struct vmci_queue_header *q_header,
    size_t add, uint64_t queue_size)
{

        qp_add_pointer(&q_header->consumer_head, add, queue_size);
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_get_pointers --
 *
 *     Helper routine for getting the head and the tail pointer for a queue.
 *     Both the VMCIQueues are needed to get both the pointers for one queue.
 *
 * Results:
 *     None.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline void
vmci_queue_header_get_pointers(const struct vmci_queue_header *produce_q_header,
    const struct vmci_queue_header *consume_q_header, uint64_t *producer_tail,
    uint64_t *consumer_head)
{

        if (producer_tail)
                *producer_tail =
                    vmci_queue_header_producer_tail(produce_q_header);

        if (consumer_head)
                *consumer_head =
                    vmci_queue_header_consumer_head(consume_q_header);
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_reset_pointers --
 *
 *     Reset the tail pointer (of "this" queue) and the head pointer (of "peer"
 *     queue).
 *
 * Results:
 *     None.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline void
vmci_queue_header_reset_pointers(struct vmci_queue_header *q_header)
{

        qp_atomic_write_offset(&q_header->producer_tail, CONST64U(0));
        qp_atomic_write_offset(&q_header->consumer_head, CONST64U(0));
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_init --
 *
 *     Initializes a queue's state (head & tail pointers).
 *
 * Results:
 *     None.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline void
vmci_queue_header_init(struct vmci_queue_header *q_header,
    const struct vmci_handle handle)
{

        q_header->handle = handle;
        vmci_queue_header_reset_pointers(q_header);
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_free_space --
 *
 *     Finds available free space in a produce queue to enqueue more data or
 *     reports an error if queue pair corruption is detected.
 *
 * Results:
 *     Free space size in bytes or an error code.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline int64_t
vmci_queue_header_free_space(const struct vmci_queue_header *produce_q_header,
    const struct vmci_queue_header *consume_q_header,
    const uint64_t produce_q_size)
{
        uint64_t free_space;
        uint64_t head;
        uint64_t tail;

        tail = vmci_queue_header_producer_tail(produce_q_header);
        head = vmci_queue_header_consumer_head(consume_q_header);

        if (tail >= produce_q_size || head >= produce_q_size)
                return (VMCI_ERROR_INVALID_SIZE);

        /*
         * Deduct 1 to avoid tail becoming equal to head which causes ambiguity.
         * If head and tail are equal it means that the queue is empty.
         */

        if (tail >= head)
                free_space = produce_q_size - (tail - head) - 1;
        else
                free_space = head - tail - 1;

        return (free_space);
}

/*
 *------------------------------------------------------------------------------
 *
 * vmci_queue_header_buf_ready --
 *
 *     vmci_queue_header_free_space() does all the heavy lifting of determing
 *     the number of free bytes in a Queue. This routine, then subtracts that
 *     size from the full size of the Queue so the caller knows how many bytes
 *     are ready to be dequeued.
 *
 * Results:
 *     On success, available data size in bytes (up to MAX_INT64).
 *     On failure, appropriate error code.
 *
 * Side effects:
 *     None.
 *
 *------------------------------------------------------------------------------
 */

static inline int64_t
vmci_queue_header_buf_ready(const struct vmci_queue_header *consume_q_header,
    const struct vmci_queue_header *produce_q_header,
    const uint64_t consume_q_size)
{
        int64_t free_space;

        free_space = vmci_queue_header_free_space(consume_q_header,
            produce_q_header, consume_q_size);
        if (free_space < VMCI_SUCCESS)
                return (free_space);
        else
                return (consume_q_size - free_space - 1);
}

#endif /* !_VMCI_DEFS_H_ */