]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/vmware/vmci/vmci_defs.h
Merge llvm trunk r338150 (just before the 7.0.0 branch point), and
[FreeBSD/FreeBSD.git] / sys / dev / vmware / vmci / vmci_defs.h
1 /*-
2  * Copyright (c) 2018 VMware, Inc.
3  *
4  * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
5  *
6  * $FreeBSD$
7  */
8
9 #ifndef _VMCI_DEFS_H_
10 #define _VMCI_DEFS_H_
11
12 #include <sys/types.h>
13 #include <machine/atomic.h>
14
15 #include "vmci_kernel_defs.h"
16
17 #pragma GCC diagnostic ignored "-Wcast-qual"
18
19 /* Register offsets. */
20 #define VMCI_STATUS_ADDR                0x00
21 #define VMCI_CONTROL_ADDR               0x04
22 #define VMCI_ICR_ADDR                   0x08
23 #define VMCI_IMR_ADDR                   0x0c
24 #define VMCI_DATA_OUT_ADDR              0x10
25 #define VMCI_DATA_IN_ADDR               0x14
26 #define VMCI_CAPS_ADDR                  0x18
27 #define VMCI_RESULT_LOW_ADDR            0x1c
28 #define VMCI_RESULT_HIGH_ADDR           0x20
29
30 /* Status register bits. */
31 #define VMCI_STATUS_INT_ON              0x1
32
33 /* Control register bits. */
34 #define VMCI_CONTROL_RESET              0x1
35 #define VMCI_CONTROL_INT_ENABLE         0x2
36 #define VMCI_CONTROL_INT_DISABLE        0x4
37
38 /* Capabilities register bits. */
39 #define VMCI_CAPS_HYPERCALL             0x1
40 #define VMCI_CAPS_GUESTCALL             0x2
41 #define VMCI_CAPS_DATAGRAM              0x4
42 #define VMCI_CAPS_NOTIFICATIONS         0x8
43
44 /* Interrupt Cause register bits. */
45 #define VMCI_ICR_DATAGRAM               0x1
46 #define VMCI_ICR_NOTIFICATION           0x2
47
48 /* Interrupt Mask register bits. */
49 #define VMCI_IMR_DATAGRAM               0x1
50 #define VMCI_IMR_NOTIFICATION           0x2
51
52 /* Interrupt type. */
53 typedef enum vmci_intr_type {
54         VMCI_INTR_TYPE_INTX =   0,
55         VMCI_INTR_TYPE_MSI =    1,
56         VMCI_INTR_TYPE_MSIX =   2
57 } vmci_intr_type;
58
59 /*
60  * Maximum MSI/MSI-X interrupt vectors in the device.
61  */
62 #define VMCI_MAX_INTRS                  2
63
64 /*
65  * Supported interrupt vectors. There is one for each ICR value above,
66  * but here they indicate the position in the vector array/message ID.
67  */
68 #define VMCI_INTR_DATAGRAM              0
69 #define VMCI_INTR_NOTIFICATION          1
70
71 /*
72  * A single VMCI device has an upper limit of 128 MiB on the amount of
73  * memory that can be used for queue pairs.
74  */
75 #define VMCI_MAX_GUEST_QP_MEMORY        (128 * 1024 * 1024)
76
77 /*
78  * We have a fixed set of resource IDs available in the VMX.
79  * This allows us to have a very simple implementation since we statically
80  * know how many will create datagram handles. If a new caller arrives and
81  * we have run out of slots we can manually increment the maximum size of
82  * available resource IDs.
83  */
84
85 typedef uint32_t vmci_resource;
86
87 /* VMCI reserved hypervisor datagram resource IDs. */
88 #define VMCI_RESOURCES_QUERY            0
89 #define VMCI_GET_CONTEXT_ID             1
90 #define VMCI_SET_NOTIFY_BITMAP          2
91 #define VMCI_DOORBELL_LINK              3
92 #define VMCI_DOORBELL_UNLINK            4
93 #define VMCI_DOORBELL_NOTIFY            5
94 /*
95  * VMCI_DATAGRAM_REQUEST_MAP and VMCI_DATAGRAM_REMOVE_MAP are
96  * obsoleted by the removal of VM to VM communication.
97  */
98 #define VMCI_DATAGRAM_REQUEST_MAP       6
99 #define VMCI_DATAGRAM_REMOVE_MAP        7
100 #define VMCI_EVENT_SUBSCRIBE            8
101 #define VMCI_EVENT_UNSUBSCRIBE          9
102 #define VMCI_QUEUEPAIR_ALLOC            10
103 #define VMCI_QUEUEPAIR_DETACH           11
104 /*
105  * VMCI_VSOCK_VMX_LOOKUP was assigned to 12 for Fusion 3.0/3.1,
106  * WS 7.0/7.1 and ESX 4.1
107  */
108 #define VMCI_HGFS_TRANSPORT             13
109 #define VMCI_UNITY_PBRPC_REGISTER       14
110 /*
111  * This resource is used for VMCI socket control packets sent to the
112  * hypervisor (CID 0) because RID 1 is already reserved.
113  */
114 #define VSOCK_PACKET_HYPERVISOR_RID     15
115 #define VMCI_RESOURCE_MAX               16
116 /*
117  * The core VMCI device functionality only requires the resource IDs of
118  * VMCI_QUEUEPAIR_DETACH and below.
119  */
120 #define VMCI_CORE_DEVICE_RESOURCE_MAX   VMCI_QUEUEPAIR_DETACH
121
122 /*
123  * VMCI reserved host datagram resource IDs.
124  * vsock control channel has resource id 1.
125  */
126 #define VMCI_DVFILTER_DATA_PATH_DATAGRAM        2
127
128 /* VMCI Ids. */
129 typedef uint32_t vmci_id;
130
131 struct vmci_id_range {
132         int8_t  action; /* VMCI_FA_X, for use in filters. */
133         vmci_id begin;  /* Beginning of range. */
134         vmci_id end;    /* End of range. */
135 };
136
137 struct vmci_handle {
138         vmci_id context;
139         vmci_id resource;
140 };
141
142 static inline struct vmci_handle
143 VMCI_MAKE_HANDLE(vmci_id cid, vmci_id rid)
144 {
145         struct vmci_handle h;
146
147         h.context = cid;
148         h.resource = rid;
149         return (h);
150 }
151
152 #define VMCI_HANDLE_TO_CONTEXT_ID(_handle)                              \
153         ((_handle).context)
154 #define VMCI_HANDLE_TO_RESOURCE_ID(_handle)                             \
155         ((_handle).resource)
156 #define VMCI_HANDLE_EQUAL(_h1, _h2)                                     \
157         ((_h1).context == (_h2).context && (_h1).resource == (_h2).resource)
158
159 #define VMCI_INVALID_ID                 0xFFFFFFFF
160 static const struct vmci_handle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID,
161             VMCI_INVALID_ID};
162
163 #define VMCI_HANDLE_INVALID(_handle)                                    \
164         VMCI_HANDLE_EQUAL((_handle), VMCI_INVALID_HANDLE)
165
166 /*
167  * The below defines can be used to send anonymous requests.
168  * This also indicates that no response is expected.
169  */
170 #define VMCI_ANON_SRC_CONTEXT_ID                                        \
171         VMCI_INVALID_ID
172 #define VMCI_ANON_SRC_RESOURCE_ID                                       \
173         VMCI_INVALID_ID
174 #define VMCI_ANON_SRC_HANDLE                                            \
175         VMCI_MAKE_HANDLE(VMCI_ANON_SRC_CONTEXT_ID,                      \
176         VMCI_ANON_SRC_RESOURCE_ID)
177
178 /* The lowest 16 context ids are reserved for internal use. */
179 #define VMCI_RESERVED_CID_LIMIT         16
180
181 /*
182  * Hypervisor context id, used for calling into hypervisor
183  * supplied services from the VM.
184  */
185 #define VMCI_HYPERVISOR_CONTEXT_ID      0
186
187 /*
188  * Well-known context id, a logical context that contains a set of
189  * well-known services. This context ID is now obsolete.
190  */
191 #define VMCI_WELL_KNOWN_CONTEXT_ID      1
192
193 /*
194  * Context ID used by host endpoints.
195  */
196 #define VMCI_HOST_CONTEXT_ID            2
197 #define VMCI_HOST_CONTEXT_INVALID_EVENT ((uintptr_t)~0)
198
199 #define VMCI_CONTEXT_IS_VM(_cid)                                        \
200         (VMCI_INVALID_ID != _cid && _cid > VMCI_HOST_CONTEXT_ID)
201
202 /*
203  * The VMCI_CONTEXT_RESOURCE_ID is used together with VMCI_MAKE_HANDLE to make
204  * handles that refer to a specific context.
205  */
206 #define VMCI_CONTEXT_RESOURCE_ID        0
207
208 /*
209  *------------------------------------------------------------------------------
210  *
211  * VMCI error codes.
212  *
213  *------------------------------------------------------------------------------
214  */
215
216 #define VMCI_SUCCESS_QUEUEPAIR_ATTACH           5
217 #define VMCI_SUCCESS_QUEUEPAIR_CREATE           4
218 #define VMCI_SUCCESS_LAST_DETACH                3
219 #define VMCI_SUCCESS_ACCESS_GRANTED             2
220 #define VMCI_SUCCESS_ENTRY_DEAD                 1
221 #define VMCI_SUCCESS                            0LL
222 #define VMCI_ERROR_INVALID_RESOURCE             (-1)
223 #define VMCI_ERROR_INVALID_ARGS                 (-2)
224 #define VMCI_ERROR_NO_MEM                       (-3)
225 #define VMCI_ERROR_DATAGRAM_FAILED              (-4)
226 #define VMCI_ERROR_MORE_DATA                    (-5)
227 #define VMCI_ERROR_NO_MORE_DATAGRAMS            (-6)
228 #define VMCI_ERROR_NO_ACCESS                    (-7)
229 #define VMCI_ERROR_NO_HANDLE                    (-8)
230 #define VMCI_ERROR_DUPLICATE_ENTRY              (-9)
231 #define VMCI_ERROR_DST_UNREACHABLE              (-10)
232 #define VMCI_ERROR_PAYLOAD_TOO_LARGE            (-11)
233 #define VMCI_ERROR_INVALID_PRIV                 (-12)
234 #define VMCI_ERROR_GENERIC                      (-13)
235 #define VMCI_ERROR_PAGE_ALREADY_SHARED          (-14)
236 #define VMCI_ERROR_CANNOT_SHARE_PAGE            (-15)
237 #define VMCI_ERROR_CANNOT_UNSHARE_PAGE          (-16)
238 #define VMCI_ERROR_NO_PROCESS                   (-17)
239 #define VMCI_ERROR_NO_DATAGRAM                  (-18)
240 #define VMCI_ERROR_NO_RESOURCES                 (-19)
241 #define VMCI_ERROR_UNAVAILABLE                  (-20)
242 #define VMCI_ERROR_NOT_FOUND                    (-21)
243 #define VMCI_ERROR_ALREADY_EXISTS               (-22)
244 #define VMCI_ERROR_NOT_PAGE_ALIGNED             (-23)
245 #define VMCI_ERROR_INVALID_SIZE                 (-24)
246 #define VMCI_ERROR_REGION_ALREADY_SHARED        (-25)
247 #define VMCI_ERROR_TIMEOUT                      (-26)
248 #define VMCI_ERROR_DATAGRAM_INCOMPLETE          (-27)
249 #define VMCI_ERROR_INCORRECT_IRQL               (-28)
250 #define VMCI_ERROR_EVENT_UNKNOWN                (-29)
251 #define VMCI_ERROR_OBSOLETE                     (-30)
252 #define VMCI_ERROR_QUEUEPAIR_MISMATCH           (-31)
253 #define VMCI_ERROR_QUEUEPAIR_NOTSET             (-32)
254 #define VMCI_ERROR_QUEUEPAIR_NOTOWNER           (-33)
255 #define VMCI_ERROR_QUEUEPAIR_NOTATTACHED        (-34)
256 #define VMCI_ERROR_QUEUEPAIR_NOSPACE            (-35)
257 #define VMCI_ERROR_QUEUEPAIR_NODATA             (-36)
258 #define VMCI_ERROR_BUSMEM_INVALIDATION          (-37)
259 #define VMCI_ERROR_MODULE_NOT_LOADED            (-38)
260 #define VMCI_ERROR_DEVICE_NOT_FOUND             (-39)
261 #define VMCI_ERROR_QUEUEPAIR_NOT_READY          (-40)
262 #define VMCI_ERROR_WOULD_BLOCK                  (-41)
263
264 /* VMCI clients should return error code withing this range */
265 #define VMCI_ERROR_CLIENT_MIN                   (-500)
266 #define VMCI_ERROR_CLIENT_MAX                   (-550)
267
268 /* Internal error codes. */
269 #define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT        (-1000)
270
271 #define VMCI_PATH_MAX                           256
272
273 /* VMCI reserved events. */
274 typedef uint32_t vmci_event_type;
275
276 #define VMCI_EVENT_CTX_ID_UPDATE        0       // Only applicable to guest
277                                                 // endpoints
278 #define VMCI_EVENT_CTX_REMOVED          1       // Applicable to guest and host
279 #define VMCI_EVENT_QP_RESUMED           2       // Only applicable to guest
280                                                 // endpoints
281 #define VMCI_EVENT_QP_PEER_ATTACH       3       // Applicable to guest, host
282                                                 // and VMX
283 #define VMCI_EVENT_QP_PEER_DETACH       4       // Applicable to guest, host
284                                                 // and VMX
285 #define VMCI_EVENT_MEM_ACCESS_ON        5       // Applicable to VMX and vmk. On
286                                                 // vmk, this event has the
287                                                 // Context payload type
288 #define VMCI_EVENT_MEM_ACCESS_OFF       6       // Applicable to VMX and vmk.
289                                                 // Same as above for the payload
290                                                 // type
291 #define VMCI_EVENT_GUEST_PAUSED         7       // Applicable to vmk. This
292                                                 // event has the Context
293                                                 // payload type
294 #define VMCI_EVENT_GUEST_UNPAUSED       8       // Applicable to vmk. Same as
295                                                 // above for the payload type.
296 #define VMCI_EVENT_MAX                  9
297
298 /*
299  * Of the above events, a few are reserved for use in the VMX, and other
300  * endpoints (guest and host kernel) should not use them. For the rest of the
301  * events, we allow both host and guest endpoints to subscribe to them, to
302  * maintain the same API for host and guest endpoints.
303  */
304
305 #define VMCI_EVENT_VALID_VMX(_event)                                    \
306         (_event == VMCI_EVENT_QP_PEER_ATTACH ||                         \
307         _event == VMCI_EVENT_QP_PEER_DETACH ||                          \
308         _event == VMCI_EVENT_MEM_ACCESS_ON ||                           \
309         _event == VMCI_EVENT_MEM_ACCESS_OFF)
310
311 #define VMCI_EVENT_VALID(_event)                                        \
312         (_event < VMCI_EVENT_MAX &&                                     \
313         _event != VMCI_EVENT_MEM_ACCESS_ON &&                           \
314         _event != VMCI_EVENT_MEM_ACCESS_OFF &&                          \
315         _event != VMCI_EVENT_GUEST_PAUSED &&                            \
316         _event != VMCI_EVENT_GUEST_UNPAUSED)
317
318 /* Reserved guest datagram resource ids. */
319 #define VMCI_EVENT_HANDLER              0
320
321 /*
322  * VMCI coarse-grained privileges (per context or host process/endpoint. An
323  * entity with the restricted flag is only allowed to interact with the
324  * hypervisor and trusted entities.
325  */
326 typedef uint32_t vmci_privilege_flags;
327
328 #define VMCI_PRIVILEGE_FLAG_RESTRICTED          0x01
329 #define VMCI_PRIVILEGE_FLAG_TRUSTED             0x02
330 #define VMCI_PRIVILEGE_ALL_FLAGS                                        \
331         (VMCI_PRIVILEGE_FLAG_RESTRICTED | VMCI_PRIVILEGE_FLAG_TRUSTED)
332 #define VMCI_NO_PRIVILEGE_FLAGS                 0x00
333 #define VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS       VMCI_NO_PRIVILEGE_FLAGS
334 #define VMCI_LEAST_PRIVILEGE_FLAGS              VMCI_PRIVILEGE_FLAG_RESTRICTED
335 #define VMCI_MAX_PRIVILEGE_FLAGS                VMCI_PRIVILEGE_FLAG_TRUSTED
336
337 /* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
338 #define VMCI_RESERVED_RESOURCE_ID_MAX           1023
339
340 #define VMCI_DOMAIN_NAME_MAXLEN                 32
341
342 #define VMCI_LGPFX                              "vmci: "
343
344 /*
345  * struct vmci_queue_header
346  *
347  * A Queue cannot stand by itself as designed. Each Queue's header contains a
348  * pointer into itself (the producer_tail) and into its peer (consumer_head).
349  * The reason for the separation is one of accessibility: Each end-point can
350  * modify two things: where the next location to enqueue is within its produce_q
351  * (producer_tail); and where the next dequeue location is in its consume_q
352  * (consumer_head).
353  *
354  * An end-point cannot modify the pointers of its peer (guest to guest; NOTE
355  * that in the host both queue headers are mapped r/w). But, each end-point
356  * needs read access to both Queue header structures in order to determine how
357  * much space is used (or left) in the Queue. This is because for an end-point
358  * to know how full its produce_q is, it needs to use the consumer_head that
359  * points into the produce_q but -that- consumer_head is in the Queue header
360  * for that end-points consume_q.
361  *
362  * Thoroughly confused?  Sorry.
363  *
364  * producer_tail: the point to enqueue new entrants.  When you approach a line
365  * in a store, for example, you walk up to the tail.
366  *
367  * consumer_head: the point in the queue from which the next element is
368  * dequeued. In other words, who is next in line is he who is at the head of
369  * the line.
370  *
371  * Also, producer_tail points to an empty byte in the Queue, whereas
372  * consumer_head points to a valid byte of data (unless producer_tail ==
373  * consumer_head in which case consumerHead does not point to a valid byte of
374  * data).
375  *
376  * For a queue of buffer 'size' bytes, the tail and head pointers will be in
377  * the range [0, size-1].
378  *
379  * If produce_q_header->producer_tail == consume_q_header->consumer_head then
380  * the produce_q is empty.
381  */
382 struct vmci_queue_header {
383         /* All fields are 64bit and aligned. */
384         struct vmci_handle      handle;         /* Identifier. */
385         volatile uint64_t       producer_tail;  /* Offset in this queue. */
386         volatile uint64_t       consumer_head;  /* Offset in peer queue. */
387 };
388
389
390 /*
391  * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
392  * size to be less than 4GB, and use 32bit atomic operations on the head and
393  * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
394  * is an atomic read-modify-write. This will cause traces to fire when a 32bit
395  * consumer tries to read the producer's tail pointer, for example, because the
396  * consumer has read-only access to the producer's tail pointer.
397  *
398  * We provide the following macros to invoke 32bit or 64bit atomic operations
399  * based on the architecture the code is being compiled on.
400  */
401
402 #ifdef __x86_64__
403 #define QP_MAX_QUEUE_SIZE_ARCH          CONST64U(0xffffffffffffffff)
404 #define qp_atomic_read_offset(x)        atomic_load_64(x)
405 #define qp_atomic_write_offset(x, y)    atomic_store_64(x, y)
406 #else /* __x86_64__ */
407         /*
408          * Wrappers below are being used because atomic_store_<type> operates
409          * on a specific <type>. Likewise for atomic_load_<type>
410          */
411
412         static inline uint32_t
413         type_safe_atomic_read_32(void *var)
414         {
415                 return (atomic_load_32((volatile uint32_t *)(var)));
416         }
417
418         static inline void
419         type_safe_atomic_write_32(void *var, uint32_t val)
420         {
421                 atomic_store_32((volatile uint32_t *)(var), (uint32_t)(val));
422         }
423
424 #define QP_MAX_QUEUE_SIZE_ARCH          CONST64U(0xffffffff)
425 #define qp_atomic_read_offset(x)        type_safe_atomic_read_32((void *)(x))
426 #define qp_atomic_write_offset(x, y)                                    \
427         type_safe_atomic_write_32((void *)(x), (uint32_t)(y))
428 #endif /* __x86_64__ */
429
430 /*
431  *------------------------------------------------------------------------------
432  *
433  * qp_add_pointer --
434  *
435  *     Helper to add a given offset to a head or tail pointer. Wraps the value
436  *     of the pointer around the max size of the queue.
437  *
438  * Results:
439  *     None.
440  *
441  * Side effects:
442  *     None.
443  *
444  *------------------------------------------------------------------------------
445  */
446
447 static inline void
448 qp_add_pointer(volatile uint64_t *var, size_t add, uint64_t size)
449 {
450         uint64_t new_val = qp_atomic_read_offset(var);
451
452         if (new_val >= size - add)
453                 new_val -= size;
454
455         new_val += add;
456         qp_atomic_write_offset(var, new_val);
457 }
458
459 /*
460  *------------------------------------------------------------------------------
461  *
462  * vmci_queue_header_producer_tail --
463  *
464  *     Helper routine to get the Producer Tail from the supplied queue.
465  *
466  * Results:
467  *     The contents of the queue's producer tail.
468  *
469  * Side effects:
470  *     None.
471  *
472  *------------------------------------------------------------------------------
473  */
474
475 static inline uint64_t
476 vmci_queue_header_producer_tail(const struct vmci_queue_header *q_header)
477 {
478         struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header;
479         return (qp_atomic_read_offset(&qh->producer_tail));
480 }
481
482 /*
483  *------------------------------------------------------------------------------
484  *
485  * vmci_queue_header_consumer_head --
486  *
487  *     Helper routine to get the Consumer Head from the supplied queue.
488  *
489  * Results:
490  *     The contents of the queue's consumer tail.
491  *
492  * Side effects:
493  *     None.
494  *
495  *------------------------------------------------------------------------------
496  */
497
498 static inline uint64_t
499 vmci_queue_header_consumer_head(const struct vmci_queue_header *q_header)
500 {
501         struct vmci_queue_header *qh = (struct vmci_queue_header *)q_header;
502         return (qp_atomic_read_offset(&qh->consumer_head));
503 }
504
505 /*
506  *------------------------------------------------------------------------------
507  *
508  * vmci_queue_header_add_producer_tail --
509  *
510  *     Helper routine to increment the Producer Tail. Fundamentally,
511  *     qp_add_pointer() is used to manipulate the tail itself.
512  *
513  * Results:
514  *     None.
515  *
516  * Side effects:
517  *     None.
518  *
519  *------------------------------------------------------------------------------
520  */
521
522 static inline void
523 vmci_queue_header_add_producer_tail(struct vmci_queue_header *q_header,
524     size_t add, uint64_t queue_size)
525 {
526
527         qp_add_pointer(&q_header->producer_tail, add, queue_size);
528 }
529
530 /*
531  *------------------------------------------------------------------------------
532  *
533  * vmci_queue_header_add_consumer_head --
534  *
535  *     Helper routine to increment the Consumer Head. Fundamentally,
536  *     qp_add_pointer() is used to manipulate the head itself.
537  *
538  * Results:
539  *     None.
540  *
541  * Side effects:
542  *     None.
543  *
544  *------------------------------------------------------------------------------
545  */
546
547 static inline void
548 vmci_queue_header_add_consumer_head(struct vmci_queue_header *q_header,
549     size_t add, uint64_t queue_size)
550 {
551
552         qp_add_pointer(&q_header->consumer_head, add, queue_size);
553 }
554
555 /*
556  *------------------------------------------------------------------------------
557  *
558  * vmci_queue_header_get_pointers --
559  *
560  *     Helper routine for getting the head and the tail pointer for a queue.
561  *     Both the VMCIQueues are needed to get both the pointers for one queue.
562  *
563  * Results:
564  *     None.
565  *
566  * Side effects:
567  *     None.
568  *
569  *------------------------------------------------------------------------------
570  */
571
572 static inline void
573 vmci_queue_header_get_pointers(const struct vmci_queue_header *produce_q_header,
574     const struct vmci_queue_header *consume_q_header, uint64_t *producer_tail,
575     uint64_t *consumer_head)
576 {
577
578         if (producer_tail)
579                 *producer_tail =
580                     vmci_queue_header_producer_tail(produce_q_header);
581
582         if (consumer_head)
583                 *consumer_head =
584                     vmci_queue_header_consumer_head(consume_q_header);
585 }
586
587 /*
588  *------------------------------------------------------------------------------
589  *
590  * vmci_queue_header_reset_pointers --
591  *
592  *     Reset the tail pointer (of "this" queue) and the head pointer (of "peer"
593  *     queue).
594  *
595  * Results:
596  *     None.
597  *
598  * Side effects:
599  *     None.
600  *
601  *------------------------------------------------------------------------------
602  */
603
604 static inline void
605 vmci_queue_header_reset_pointers(struct vmci_queue_header *q_header)
606 {
607
608         qp_atomic_write_offset(&q_header->producer_tail, CONST64U(0));
609         qp_atomic_write_offset(&q_header->consumer_head, CONST64U(0));
610 }
611
612 /*
613  *------------------------------------------------------------------------------
614  *
615  * vmci_queue_header_init --
616  *
617  *     Initializes a queue's state (head & tail pointers).
618  *
619  * Results:
620  *     None.
621  *
622  * Side effects:
623  *     None.
624  *
625  *------------------------------------------------------------------------------
626  */
627
628 static inline void
629 vmci_queue_header_init(struct vmci_queue_header *q_header,
630     const struct vmci_handle handle)
631 {
632
633         q_header->handle = handle;
634         vmci_queue_header_reset_pointers(q_header);
635 }
636
637 /*
638  *------------------------------------------------------------------------------
639  *
640  * vmci_queue_header_free_space --
641  *
642  *     Finds available free space in a produce queue to enqueue more data or
643  *     reports an error if queue pair corruption is detected.
644  *
645  * Results:
646  *     Free space size in bytes or an error code.
647  *
648  * Side effects:
649  *     None.
650  *
651  *------------------------------------------------------------------------------
652  */
653
654 static inline int64_t
655 vmci_queue_header_free_space(const struct vmci_queue_header *produce_q_header,
656     const struct vmci_queue_header *consume_q_header,
657     const uint64_t produce_q_size)
658 {
659         uint64_t free_space;
660         uint64_t head;
661         uint64_t tail;
662
663         tail = vmci_queue_header_producer_tail(produce_q_header);
664         head = vmci_queue_header_consumer_head(consume_q_header);
665
666         if (tail >= produce_q_size || head >= produce_q_size)
667                 return (VMCI_ERROR_INVALID_SIZE);
668
669         /*
670          * Deduct 1 to avoid tail becoming equal to head which causes ambiguity.
671          * If head and tail are equal it means that the queue is empty.
672          */
673
674         if (tail >= head)
675                 free_space = produce_q_size - (tail - head) - 1;
676         else
677                 free_space = head - tail - 1;
678
679         return (free_space);
680 }
681
682 /*
683  *------------------------------------------------------------------------------
684  *
685  * vmci_queue_header_buf_ready --
686  *
687  *     vmci_queue_header_free_space() does all the heavy lifting of determing
688  *     the number of free bytes in a Queue. This routine, then subtracts that
689  *     size from the full size of the Queue so the caller knows how many bytes
690  *     are ready to be dequeued.
691  *
692  * Results:
693  *     On success, available data size in bytes (up to MAX_INT64).
694  *     On failure, appropriate error code.
695  *
696  * Side effects:
697  *     None.
698  *
699  *------------------------------------------------------------------------------
700  */
701
702 static inline int64_t
703 vmci_queue_header_buf_ready(const struct vmci_queue_header *consume_q_header,
704     const struct vmci_queue_header *produce_q_header,
705     const uint64_t consume_q_size)
706 {
707         int64_t free_space;
708
709         free_space = vmci_queue_header_free_space(consume_q_header,
710             produce_q_header, consume_q_size);
711         if (free_space < VMCI_SUCCESS)
712                 return (free_space);
713         else
714                 return (consume_q_size - free_space - 1);
715 }
716
717 #endif /* !_VMCI_DEFS_H_ */